SSL/TLS — Deep Dive

The Actual TLS 1.3 Handshake (Wire Level)

Most explanations of TLS stop at “client says hello, server says hello, they agree on a key.” Here’s what’s actually happening in the bytes.

ClientHello

The client sends:

  • Protocol version: TLS 1.3, but actually coded as TLS 1.2 (0x0303) for legacy middlebox compatibility. The real version is in a supported_versions extension.
  • Random: 32 bytes of cryptographically random data — used in key derivation
  • Session ID: Legacy field, now set to 32 random bytes for middlebox compatibility
  • Cipher Suites: In TLS 1.3, only 5 are allowed: TLS_AES_128_GCM_SHA256, TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256, and two others. The 300+ cipher suites from TLS 1.2 are gone.
  • key_share extension: The client doesn’t just propose key exchange groups — it sends actual key shares for its guessed top picks (typically X25519). If the server accepts one, no extra round trip needed.

ServerHello + Key Derivation

The server picks a cipher suite, sends its own key share. At this point, both sides can compute the handshake secret using the Diffie-Hellman exchange:

ECDH shared_secret = server_private_key * client_public_key
                   = client_private_key * server_public_key

(This works because of elliptic curve math — both computations arrive at the same point on the curve.)

From that shared secret, TLS 1.3 derives a hierarchy of keys using HKDF (HMAC-based Key Derivation Function):

early_secret  = HKDF-Extract(0, PSK or 0)
handshake_secret = HKDF-Extract(ECDHE_output, derived(early_secret))
master_secret = HKDF-Extract(0, derived(handshake_secret))

Each key in the tree is used for a specific purpose: handshake encryption, application data, resumption tokens. If one key is compromised, the derivation structure limits what else can be exposed.

Why TLS 1.3 Encrypts More of the Handshake

In TLS 1.2, the Certificate message was sent in plaintext. An observer watching your connection could see which site’s certificate was being used — and therefore which site you were connecting to, even without breaking the encryption.

TLS 1.3 encrypts the Certificate, CertificateVerify, and Finished messages using the handshake_secret derived above. This means the server’s identity is hidden from passive observers — an improvement for privacy even when the IP address itself is visible.

The remaining unencrypted parts (ClientHello, ServerHello) still leak the SNI (Server Name Indication) extension, which contains the hostname. Encrypted Client Hello (ECH), finalized in RFC 9258 in 2024, addresses this by encrypting the inner ClientHello using a public key published in DNS via HTTPS records. ECH adoption is still early as of 2026.

HKDF and the Key Schedule in Detail

TLS 1.3’s key schedule is notably different from TLS 1.2’s PRF-based approach. HKDF has two operations:

  • Extract: Takes a salt and input keying material, outputs a pseudorandom key of fixed length
  • Expand: Stretches a key to arbitrary length using a label and context

The labels used in TLS 1.3 expansion are ASCII strings like "tls13 c hs traffic" — meaning you can audit exactly which derived key is for what purpose. This auditability was a deliberate design choice by the RFC authors.

Certificate Chains and the PKI Problem

A server certificate is almost never signed directly by a root CA. The chain is:

Root CA → Intermediate CA → Leaf Certificate (your server)

Root CA private keys are kept offline — sometimes in hardware security modules in physically secured vaults, with multi-party access controls. Intermediate CA keys are online but still highly protected. Leaf certificates are what servers use day-to-day.

Your browser trusts the root. It follows the chain: “the intermediate was signed by the root I trust, the leaf was signed by the intermediate, therefore I trust the leaf.” This chain must be complete — servers must send intermediate certificates, not just their own. A misconfigured server that omits the intermediate will work in some browsers (they cache intermediates) and fail in others. This causes roughly 20% of TLS-related support tickets at any large company.

OCSP and CRL: Certificate Revocation

What happens when a certificate’s private key is stolen? The CA needs to revoke it. There are two mechanisms:

CRL (Certificate Revocation List): A signed list of revoked serial numbers, published periodically by the CA. The problem: they can be megabytes large, browsers have to download them, and they have staleness windows.

OCSP (Online Certificate Status Protocol): Browser queries the CA’s OCSP responder with a specific certificate serial number and gets a signed “good” or “revoked” response. Faster, but adds a network round trip to every TLS handshake, and OCSP responders have availability problems (when Let’s Encrypt had an OCSP outage in 2023, it created widespread cert-validation failures).

OCSP Stapling: The server fetches its own OCSP response from the CA periodically and includes it in the TLS handshake. Client doesn’t need to contact the CA at all. This is the right approach but still not universally deployed.

In practice, Chrome has largely abandoned OCSP for soft-fail revocation checking. If OCSP is unavailable, the browser accepts the cert anyway — which means revocation checking provides minimal actual security in most consumer browsers. The only reliable revocation mechanism currently is short-lived certificates (< 24 hours), pushed by Apple and Google’s “Moving Forward Together” initiative that would reduce maximum cert validity to 47 days by 2026.

0-RTT and Its Tradeoffs

TLS 1.3’s 0-RTT resumption lets a client that has previously connected to a server send application data on the very first packet of a new connection. The server issues a session ticket (a resumption PSK) during the previous session; the client uses it to derive early traffic keys without a fresh key exchange.

The cost: 0-RTT data has no forward secrecy for replay. An attacker who records network traffic can replay the first flight of 0-RTT data to the server, potentially causing duplicate state mutations (imagine a double POST to a payment endpoint).

Servers that enable 0-RTT must:

  1. Only accept idempotent requests in 0-RTT data (GET requests, not POSTs)
  2. Or implement anti-replay mechanisms (single-use tickets, server-side state tracking)

Cloudflare, which processes roughly 3 trillion TLS connections per month and was among the first to deploy TLS 1.3 at scale, uses a bloom filter-based anti-replay mechanism for 0-RTT. The filter has a false-positive rate — it occasionally rejects valid 0-RTT — but the tradeoff is acceptable at that scale.

Elliptic Curves: Why X25519 Won

TLS 1.2 used NIST P-256 and P-384 curves by default. These were designed by NIST with heavy NSA involvement, and the curve constants (called “seeds”) were never explained — they’re just random-looking numbers that were declared correct. This created longstanding suspicion that the curves might have backdoors.

Daniel Bernstein designed Curve25519 in 2006 with fully explained, auditable constants. Every parameter choice is documented. X25519 (the Diffie-Hellman function built on Curve25519) is faster than P-256 on most hardware, has simpler constant-time implementation (reducing side-channel risk), and is considered resistant to the classes of attack that might affect NIST curves.

TLS 1.3 made X25519 mandatory-to-implement. When you connect to most modern servers, you’re doing X25519 key exchange.

Post-Quantum TLS

Shor’s algorithm, running on a sufficiently powerful quantum computer, breaks RSA and elliptic curve discrete log problems in polynomial time. The “harvest now, decrypt later” threat model — where adversaries record encrypted traffic today to decrypt once quantum computers are powerful enough — is taken seriously by intelligence agencies and large tech companies.

NIST finalized its first three post-quantum cryptography standards in August 2024:

  • ML-KEM (CRYSTALS-Kyber) — key encapsulation mechanism, lattice-based
  • ML-DSA (CRYSTALS-Dilithium) — digital signatures, lattice-based
  • SLH-DSA (SPHINCS+) — digital signatures, hash-based

Google began experimenting with post-quantum hybrid key exchange in Chrome in 2023, combining X25519 with Kyber in what they called X25519Kyber768. Cloudflare deployed this across their network. The hybrid approach (classical + post-quantum combined) is considered safer than switching entirely to new, less-battle-tested algorithms.

TLS integration is happening via the key_share extension — the same mechanism that makes TLS 1.3 fast. A client can offer X25519MLKEM768 as a key share group alongside X25519, and a post-quantum-capable server picks it.

Certificate signatures are the harder problem — post-quantum signature schemes like ML-DSA have much larger signatures (2,420 bytes for ML-DSA-65, vs ~71 bytes for an ECDSA P-256 signature), which increases TLS handshake size meaningfully. Migrating the certificate ecosystem to post-quantum signatures will take longer than migrating key exchange.

QUIC and TLS Without TCP

HTTP/3 runs over QUIC, which integrates TLS 1.3 at the protocol level rather than running it over TCP. A few important differences:

  • QUIC encrypts packet headers — including stream IDs and sequence numbers. TCP’s equivalent metadata is plaintext, enabling middleboxes to track and manipulate connections.
  • 0-RTT is built into QUIC at the connection level, not just TLS — the handshake can interleave with connection establishment.
  • Connection migration: QUIC connections have a Connection ID separate from the 4-tuple (IP + port). If your mobile device switches from WiFi to cellular, a QUIC connection can survive the IP address change. A TCP/TLS connection would need to restart entirely.

TLS 1.3 running over QUIC can’t use TLS record-layer framing — QUIC provides its own packet framing. The TLS spec had to be extended (RFC 9001) to define exactly how TLS handshake messages map to QUIC CRYPTO frames.

Practical Engineering Considerations

Certificate Pinning: Apps can pin specific certificates or public keys, refusing connections if the cert doesn’t match expectations. This protects against CA compromise but creates painful deployment problems when certs rotate. The mobile ecosystem largely moved away from hard pinning to backup-pin strategies after several high-profile apps went dark during cert rotation.

TLS Inspection (MITM): Enterprise networks often run TLS inspection — a corporate proxy intercepts TLS connections, decrypts, inspects, re-encrypts. This is technically a man-in-the-middle attack authorized by the certificate trust store. The intercepting proxy installs its own root CA on corporate devices. TLS 1.3’s encrypted handshake doesn’t prevent this — the proxy terminates the connection before re-establishing it to the origin.

Mutual TLS (mTLS): Normally only the server presents a certificate. In mTLS, the client does too — proving its identity to the server. Used heavily in service mesh architectures (Istio, Linkerd) where every service-to-service connection is mutually authenticated. This is how zero-trust networking authenticates workloads without VPNs.

One Thing to Remember

The padlock you’ve seen a thousand times is doing something genuinely elegant: it solves the key-distribution problem (how strangers agree on a secret) using math that’s been audited for decades, wraps it in a PKI system that’s messy in practice but functional at scale, and does it fast enough that you never notice. The real action is in what it doesn’t protect: which site you connected to, whether the site itself is trustworthy, and — looking ahead — whether the encryption algorithms will survive quantum computing. The next ten years of TLS are going to be more interesting than the last thirty.

Related topics: Encryption, Zero-Knowledge Proofs, Cloud Computing

securitynetworkinghttpsencryptionwebtlssslcryptographypki

See Also

  • Zero Knowledge Proofs How can you prove you know a secret without revealing the secret? The magic trick that's changing privacy on the internet.