Skip to main content

Hello TLS!

This is a pure Python, dependency-less* implementation of SSL/TLS Client Hello and basic scaning.

Its purpose is to quickly discover what cipher suites and SSL/TLS protocols are enabled on a server. Since the server doesn't advertise this list, instead picking from what is offered by the client, hello_tls.py sends a sequence of Client Hello with different cipher suite and protocol combinations. It usually needs less than 8 requests and 300 ms, but for servers with many cipher suites or high latency, bumping max_workers splits discovery over many threads.

There's no actual cryptography, just sending a stream of bytes and seeing if the server reply vaguely looks ok or not. Supports TLS 1.3, TLS 1.2, TLS 1.1, TLS 1.0, and SSLv3.

* Optionally, the certificate chain can be fetched and parsed, at the cost of relying on pyOpenSSL.

Installation

Install via pip:

pip install hello_tls
python -m hello_tls boppreh.com --no-certs

or clone this repo:

git clone https://github.com/boppreh/hello_tls.git
cd hello_tls/src
python -m hello_tls boppreh.com --no-certs

As a library

Main function signature:

def scan_server(
    connection_settings: Union[ConnectionSettings, str],
    client_hello: Optional[ClientHello] = None,
    do_enumerate_cipher_suites: bool = True,
    do_enumerate_groups: bool = True,
    fetch_cert_chain: bool = True,
    max_workers: int = DEFAULT_MAX_WORKERS,
    progress: Callable[[int, int], None] = lambda current, total: None,
    ) -> ServerScanResult:
    ...

Usage:

from hello_tls import scan_server
result = scan_server('boppreh.com')
print(result)

Output:

ServerScanResult(
    connection=ConnectionSettings(
        host="boppreh.com",
        port=443,
        proxy=None,
        timeout_in_seconds=2,
        date=datetime(2024, 1, 14, 23, 49, 33, tzinfo=datetime.timezone.utc),
    ),
    protocols={
        SSLv3: None,
        TLS1_0: None,
        TLS1_1: None,
        TLS1_2: ProtocolResult(
            has_compression=False,
            has_cipher_suite_order=None,
            has_post_quantum=None,
            groups=None,
            cipher_suites=[
                TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
                TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
            ],
        ),
        TLS1_3: ProtocolResult(
            has_compression=False,
            has_cipher_suite_order=False,
            has_post_quantum=False,
            groups=[x25519, secp256r1],
            cipher_suites=[
                TLS_AES_128_GCM_SHA256,
                TLS_AES_256_GCM_SHA384,
                TLS_CHACHA20_POLY1305_SHA256,
            ],
        ),
    },
    requires_sni=True,
    accepts_bad_sni=False,
    client_ca_names=[]
    certificate_chain=[
        Certificate(...),
        Certificate(...),
        Certificate(...),
    ],
)

As a command line application

python -m hello_tls boppreh.com
{
  "connection": {
    "host": "boppreh.com",
    "port": 443,
    "proxy": null,
    "timeout_in_seconds": 2,
    "date": "2024-07-02 17:17:36+00:00"
  },
  "protocols": {
    "TLS1_3": null,
    "TLS1_2": {
      "has_compression": false,
      "has_cipher_suite_order": null,
      "has_post_quantum": null,
      "groups": null,
      "cipher_suites": [
        "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
        "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
        "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
      ]
    },
    "TLS1_1": null,
    "TLS1_0": null,
    "SSLv3": null
  },
  "requires_sni": true,
  "accepts_bad_sni": false,
  "client_ca_names": [],
  "certificate_chain": [
    {
      "serial_number": "295893172444948417823726078506384416865360",
      "fingerprint_sha256": "5F:32:F6:D8:AE:F6:66:18:8D:93:14:21:43:67:AF:CC:8F:23:C2:8C:CC:BB:CC:90:B0:71:84:8F:FE:7A:81:0E",
      "subject": {
        "CN": "boppreh.com"
      },
      "issuer": {
        "C": "US",
        "O": "Let's Encrypt",
        "CN": "R3"
      },
      "subject_alternative_names": [
        "boppreh.com"
      ],
      "key_type": "EC",
      "key_length_in_bits": 256,
      "all_key_usage": [
        "Digital Signature",
        "TLS Web Server Authentication",
        "TLS Web Client Authentication"
      ],
      "not_before": "2024-05-15 07:04:08+00:00",
      "not_after": "2024-08-13 07:04:07+00:00",
      "is_expired": false,
      "days_until_expiration": 41,
      "signature_algorithm": "sha256WithRSAEncryption",
      "extensions": {
        "keyUsage": "Digital Signature",
        "extendedKeyUsage": "TLS Web Server Authentication, TLS Web Client Authentication",
        "basicConstraints": "CA:FALSE",
        "subjectKeyIdentifier": "4A:9A:3C:75:B0:74:58:A9:C1:A0:6F:83:3E:2A:A0:24:6B:19:26:34",
        "authorityKeyIdentifier": "14:2E:B3:17:B7:58:56:CB:AE:50:09:40:E6:1F:AF:9D:8B:14:C2:C6",
        "authorityInfoAccess": "OCSP - URI:http://r3.o.lencr.org\nCA Issuers - URI:http://r3.i.lencr.org/",
        "subjectAltName": "DNS:boppreh.com",
        "certificatePolicies": "Policy: 2.23.140.1.2.1",
        "ct_precert_scts": "Signed Certificate Timestamp:\n    Version   : v1 (0x0)\n    Log ID    : 48:B0:E3:6B:DA:A6:47:34:0F:E5:6A:02:FA:9D:30:EB:\n                1C:52:01:CB:56:DD:2C:81:D9:BB:BF:AB:39:D8:84:73\n    Timestamp : May 15 08:04:08.781 2024 GMT\n    Extensions: none\n    Signature : ecdsa-with-SHA256\n
       30:45:02:20:2E:B3:9A:98:2F:87:09:0B:2A:FE:1B:44:\n                8C:CD:A0:3B:03:61:4C:CF:6F:61:7C:27:89:4D:B3:5A:\n                97:1A:20:CE:02:21:00:F3:2D:8F:9A:F1:72:E3:50:CF:\n                DF:7B:14:D0:07:D9:47:3C:DA:3C:2C:52:83:73:02:0D:\n                23:95:FD:09:62:B6:2E\nSigned Certificate Timestamp:\n    
Version   : v1 (0x0)\n    Log ID    : DF:E1:56:EB:AA:05:AF:B5:9C:0F:86:71:8D:A8:C0:32:\n                4E:AE:56:D9:6E:A7:F5:A5:6A:01:D1:C1:3B:BE:52:5C\n    Timestamp : May 15 08:04:09.015 2024 GMT\n    Extensions: none\n    Signature : ecdsa-with-SHA256\n                30:44:02:20:26:A7:E6:DA:8B:9A:6F:D2:92:E3:F6:B2:\n      
          5D:6C:B3:34:7A:47:F5:5D:86:F4:CB:DD:E7:F7:D4:02:\n                27:87:DE:14:02:20:3E:25:03:7E:52:4B:3B:4C:08:AD:\n                5C:AB:81:1F:27:0B:2D:06:DD:C4:E2:D4:69:8E:51:8D:\n                EB:70:DD:51:59:74"
      },
      "pem": "-----BEGIN CERTIFICATE-----\nMIIEFzCCAv+gAwIBAgISA2WNSB16OSm7PhT3t6zOvHxQMA0GCSqGSIb3DQEBCwUA\nMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MQswCQYDVQQD\nEwJSMzAeFw0yNDA1MTUwNzA0MDhaFw0yNDA4MTMwNzA0MDdaMBYxFDASBgNVBAMT\nC2JvcHByZWguY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEorAmsmsRficI\nyYDurgDeqSzX1WfuscgVS/e2wkYSIuyoDT4K/kNonCwC+qe6MSgybvSZH9UIAxzI\nsDJ4O9Yhf6OCAgwwggIIMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEF\nBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUSpo8dbB0WKnB\noG+DPiqgJGsZJjQwHwYDVR0jBBgwFoAUFC6zF7dYVsuuUAlA5h+vnYsUwsYwVQYI\nKwYBBQUHAQEESTBHMCEGCCsGAQUFBzABhhVodHRwOi8vcjMuby5sZW5jci5vcmcw\nIgYIKwYBBQUHMAKGFmh0dHA6Ly9yMy5pLmxlbmNyLm9yZy8wFgYDVR0RBA8wDYIL\nYm9wcHJlaC5jb20wEwYDVR0gBAwwCjAIBgZngQwBAgEwggEDBgorBgEEAdZ5AgQC\nBIH0BIHxAO8AdgBIsONr2qZHNA/lagL6nTDrHFIBy1bdLIHZu7+rOdiEcwAAAY97\nR7fNAAAEAwBHMEUCIC6zmpgvhwkLKv4bRIzNoDsDYUzPb2F8J4lNs1qXGiDOAiEA\n8y2PmvFy41DP33sU0AfZRzzaPCxSg3MCDSOV/Qliti4AdQDf4VbrqgWvtZwPhnGN\nqMAyTq5W2W6n9aVqAdHBO75SXAAAAY97R7i3AAAEAwBGMEQCICan5tqLmm/SkuP2\nsl1sszR6R/VdhvTL3ef31AInh94UAiA+JQN+Uks7TAitXKuBHycLLQbdxOLUaY5R\njetw3VFZdDANBgkqhkiG9w0BAQsFAAOCAQEAm7klMy/QfRKXw09ongrJz4HuOC99\n+r2I0UmhPE5aFVRV1tWSUUs8XEp2WOkZ/is1xKRauDdbncxbHOSM4+Oki/GHCw1O\nBuzfhB5kV2+IIJCMhaXIyejFttZso3FFTBELMrXeEqLgyc2H6Xsr46OBa0kH74nH\n/axER6z99vt1nFslhPj0I/2Q9jFijA+bAErcV0sFhFQch80ynLOmaeTX573nAEmT\nuHItoIfwgNsNWkTKhHHslMfDX6XTe7//5SUcoRbygNH3bVfH/Atvz5M7+Thf9pup\nj+u32K2uEE+KLUSQUBPM3rb//E7VoGb3aJNV3EAslZ4Ml+qoAtg7HeF3PA==\n-----END CERTIFICATE-----\n"
    },
    {
      "serial_number": "192961496339968674994309121183282847578",
      "fingerprint_sha256": "67:AD:D1:16:6B:02:0A:E6:1B:8F:5F:C9:68:13:C0:4C:2A:A5:89:96:07:96:86:55:72:A3:C7:E7:37:61:3D:FD",
      "subject": {
        "C": "US",
        "O": "Let's Encrypt",
        "CN": "R3"
      },
      "issuer": {
        "C": "US",
        "O": "Internet Security Research Group",
        "CN": "ISRG Root X1"
      },
      "subject_alternative_names": [],
      "key_type": "RSA",
      "key_length_in_bits": 2048,
      "all_key_usage": [
        "Digital Signature",
        "Certificate Sign",
        "CRL Sign",
        "TLS Web Client Authentication",
        "TLS Web Server Authentication"
      ],
      "not_before": "2020-09-04 00:00:00+00:00",
      "not_after": "2025-09-15 16:00:00+00:00",
      "is_expired": false,
      "days_until_expiration": 439,
      "signature_algorithm": "sha256WithRSAEncryption",
      "extensions": {
        "keyUsage": "Digital Signature, Certificate Sign, CRL Sign",
        "extendedKeyUsage": "TLS Web Client Authentication, TLS Web Server Authentication",
        "basicConstraints": "CA:TRUE, pathlen:0",
        "subjectKeyIdentifier": "14:2E:B3:17:B7:58:56:CB:AE:50:09:40:E6:1F:AF:9D:8B:14:C2:C6",
        "authorityKeyIdentifier": "79:B4:59:E6:7B:B6:E5:E4:01:73:80:08:88:C8:1A:58:F6:E9:9B:6E",
        "authorityInfoAccess": "CA Issuers - URI:http://x1.i.lencr.org/",
        "crlDistributionPoints": "Full Name:\n  URI:http://x1.c.lencr.org/",
        "certificatePolicies": "Policy: 2.23.140.1.2.1\nPolicy: 1.3.6.1.4.1.44947.1.1.1"
      },
      "pem": "-----BEGIN CERTIFICATE-----\nMIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw\nTzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\ncmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw\nWhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\nRW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP\nR5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx\nsxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm\nNHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg\nZ3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG\n/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC\nAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB\nAf8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA\nFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw\nAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw\nOi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB\ngt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W\nPTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl\nikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz\nCkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm\nlJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4\navAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2\nyJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O\nyK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids\nhCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+\nHlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv\nMldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX\nnLRbwHOoq7hHwg==\n-----END CERTIFICATE-----\n"
    }
  ]
}

Metadata

Release files for hello-tls 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for hello-tls 0.4.0
File Size Uploaded
hello_tls-0.4.0.tar.gz 30.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for hello-tls 0.4.0
File Interpreter ABI Platform
hello_tls-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 55.7 kB

Release files / hello_tls-0.4.0.tar.gz

Download URL hello_tls-0.4.0.tar.gz
Size 30.0 kB
Tags Source
SHA-256 checksum
How to use checksums
b0350259c8f7e3679bc5b5e371a06ef8ee370f8fb29f0f9847c247b2f9a0974c
BLAKE2b-256 checksum
How to use checksums
82f18f8b94bdaaae10b53c4a05145153ff655be0f301a4894afff2a744126fb7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.1.0 CPython/3.12.4

Release files / hello_tls-0.4.0-py3-none-any.whl

Download URL hello_tls-0.4.0-py3-none-any.whl
Size 25.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2d253155d5d78c78c61ff0d9936dd30a00e7a47799dbc20e008849ec38756f41
BLAKE2b-256 checksum
How to use checksums
677f3895a90d1d009d85684bb677da300b4eb1700f5080780aa0c8e771d44c28
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/5.1.0 CPython/3.12.4

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.10

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page