Abstract
Every HTTPS connection starts with a TLS handshake. It’s the security check, answering “are you who you say you are?” and “how are we going to keep this conversation secret?”.
There’s a lot going on during the handshake, and there used to be even more before it all got hacked and removed. And that’s useful to understand, the modern TLS 1.3 handshake is short because everything else got compromised.
What a TLS handshake does
A TLS handshake does three jobs:
- The client and server agree on which cryptography to use.
- The server proves its identity with a certificate.
- Both sides establish the session keys that will encrypt everything that follows.
SSL and TLS are the same thing. SSL was renamed TLS in 1999, and the SSL name stuck around, like how we call our pocket computers “phones”. Every “SSL certificate” you’ve ever installed was doing TLS handshakes.
The TLS 1.3 handshake
Here’s the modern TLS handshake sequence:
CLIENT SERVER
│ ─────────────── ClientHello ───────────────► │ (1)
│ I speak TLS 1.3, with ciphers: │
│ TLS_AES_128_GCM_SHA256 │
│ ... only 4 more │
│ KeyShare: my half of the key │
│ │
│ ◄────────────── ServerHello ──────────────── │ (2)
│ Let's use TLS_AES_128_GCM_SHA256 │
│ KeyShare: my half of the key │
│ ┌─ encrypted from here on ─────────┐ │
│ │ Certificate │ │ (3)
│ │ Signature: SHA-256 │ │
│ │ Public Key: Elliptic Curve │ │
│ │ CertificateVerify │ │
│ │ Finished │ │
│ └──────────────────────────────────┘ │
│ │
│ ─────────────── Finished ──────────────────► │ (4)
│ ◄=========== encrypted traffic ============► │ (5)
- The client says hello: the protocol version it speaks, the cipher suites it supports, which server it wants to reach, and its half of a fresh Diffie-Hellman key exchange (the KeyShare).
- The server picks the cipher suite, and sends back its own KeyShare. Both sides can compute the session encryption keys, but neither ever transmitted it. This exchange is what enables perfect forward secrecy. Everything after this point is encrypted.
- The server sends its certificate chain, then CertificateVerify: a signature over the handshake. That signature is the identity proof, and it’s what prevents man-in-the-middle attacks.
- The client verifies the certificate chain against its trust store, and checks the signature
One round trip.
There are only 5 cipher suites in TLS 1.3. Older versions had dozens of suites and a whole stack of negotiable parts. A lot went wrong with those parts, which brings us to how we got here.
How we got here: the SSL 3.0 handshake
Here’s the handshake as it worked from the mid-90s through most of the 2010s:
CLIENT SERVER
│ ─────────────── ClientHello ───────────────► │ (1)
│ I speak SSL 3.0, with ciphers: │
│ SSL_RSA_WITH_3DES_EDE_CBC_SHA │
│ ... up to 36 more │
│ │
│ ◄────────────── ServerHello ──────────────── │ (2)
│ Let's use SSL_RSA_WITH_3DES_EDE_CBC_SHA │
│ ┌─────────────────────────┐ │
│ │ Certificate │ │
│ │ Signature: sha1WithRSA │ │
│ │ Public Key: RSA 2048 │ │
│ └─────────────────────────┘ │
│ │
│ ───────────── ClientKeyExchange ───────────► │ (3)
│ Here's our secret: │
│ [pre_master_secret] # encrypted with │
│ # server public key │
│ ◄=========== encrypted traffic ============► │ (4)
- The client says hello and offers a (long) list of cipher suites it supports.
- The server picks one and sends back its certificate to prove who it is.
- The client generates a secret, encrypts it with the server’s public key from that certificate, and sends it over.
- Both sides derive session keys from the secret, and encrypted traffic begins.
Two full round trips before any data moves.
The cipher suite names were long and complicated, like SSL_RSA_WITH_3DES_EDE_CBC_SHA. Every segment is a separate choice. SSL is the protocol version. RSA is the key exchange. 3DES_EDE is the encryption algorithm. CBC is the block cipher mode. SHA is the hash, SHA-1. Over the next twenty years, an attack arrived for nearly every segment.
| Year | Attack | What it killed |
|---|---|---|
| 2011 | BEAST | CBC block cipher mode |
| 2012 | CRIME | TLS compression |
| 2013 | Snowden disclosures | Static RSA key exchange |
| 2014 | POODLE | SSL 3.0 entirely |
| 2015 | FREAK, Logjam | 1990s export-grade ciphers |
| 2017 | SHAttered | SHA-1 signatures |
| 2020 | Browser removal | TLS 1.0 and 1.1 |
BEAST broke the block cipher mode (2011)
BEAST attacked CBC. In CBC mode, each block of plaintext gets mixed with the previous ciphertext block before encryption. TLS 1.0 took a shortcut: the mixing value for the first block of a new record was the last ciphertext block of the previous record. Which the attacker, watching the wire, has already seen.
That made the mixing value predictable, and predictable mixing makes it a guessing game. Researchers Thai Duong and Juliano Rizzo built a working exploit with carefully crafted requests while the attacker watches the encrypted traffic, confirming guesses one byte at a time until the session cookie falls out.
The embarrassing part is that the fix already existed. TLS 1.1, published in 2006, gave every record its own unpredictable mixing value. Five years later, almost no-one had upgraded, because the old version worked and compatibility felt more important than a theoretical weakness.
TLS 1.3 ended the whole category. CBC mode is gone.
CRIME broke compression (2012)
TLS could compress data before encrypting it. CRIME attacked it.
Compression works by removing repetition, so the compressed size leaks information about the content. If the attacker injects a guess into the request and the result compresses smaller, the guess matched something already in the request. Like, say, the session cookie. Inject guesses, watch the encrypted packet sizes, and recover the secret one byte at a time. No cipher was broken. The ciphertext length alone was the side channel.
Snowden broke the key exchange (2013)
The biggest flaw in the old handshake wasn’t a cipher segment. It was step 3, the key exchange itself:
│ ───────────── ClientKeyExchange ───────────► │
│ Here's our secret: │
│ [pre_master_secret] # over the wire, │
│ # encrypted with the │
│ # server public key │
The pre_master_secret did two jobs: it proved identity and encrypted the traffic. If you got your hands on the private key, you could decrypt all the past traffic. The Snowden documents showed this wasn’t theoretical. “Harvest now, decrypt later” was operational doctrine.
The fix was to split the two jobs apart. Certificates keep proving identity. Encryption moved to ephemeral keys, generated fresh for every session through Diffie-Hellman key exchange:
CLIENT SERVER
│ │
generate random a generate random b
│ │
│ ────────────── g^a mod p ──────────────► │
│ ◄───────────── g^b mod p ────────────── │
│ │
(g^b mod p)^a mod p (g^a mod p)^b mod p
= g^ab mod p = g^ab mod p
Both sides compute the same secret. Neither side ever transmits it. This is perfect forward secrecy, and it’s the single biggest change between the handshake you learned and the handshake running today. The KeyShare messages in the TLS 1.3 diagram are this exchange, folded into the hello messages. In TLS 1.3 it’s mandatory. Static RSA key exchange doesn’t exist anymore.
POODLE killed SSL 3.0
POODLE found another CBC flaw, this one specific to SSL 3.0: the protocol didn’t fully protect its padding bytes, so an attacker could tamper with them and use the server’s accept-or-reject behavior as an oracle, decrypting a byte per roughly 256 requests.
By 2014, SSL 3.0 was an eighteen-year-old protocol, so this shouldn’t have mattered. It mattered because of the downgrade dance. When a handshake failed, clients helpfully retried with an older protocol version, and attackers could trigger that failure on purpose. Two peers who both spoke modern TLS could be tricked into speaking SSL 3.0 to each other, and then POODLE applied. The backwards compatibility everyone kept for the stragglers was the attack surface.
The response killed the protocol. Browsers and servers disabled SSL 3.0 within months, and a new signal (TLS_FALLBACK_SCSV) let clients tell servers “this is a downgrade retry, refuse it if we both know better.”
FREAK and Logjam dug up the 1990s (2015)
The original SSL/TLS flow had “up to 36 more” cipher suites. Some of them were export-grade crypto: deliberately weakened 512-bit suites that 1990s US export regulations required for software shipped overseas. The regulations died in 2000. The cipher suites didn’t. They sat in the negotiation list for fifteen years, because removing things is hard and nobody was choosing them anyway.
FREAK showed why that mattered: a man-in-the-middle could rewrite the ClientHello to request weak ciphers, and a lot of servers would happily comply.
The lesson was bigger than stale ciphers: negotiation itself was the vulnerability. If both sides can be talked into a weak option, the weak option is the security level. TLS 1.3 responded by having almost nothing to negotiate. Five suites, all strong, and vetted key exchange groups with enforced minimums. There is no weak fallback to force anymore.
SHAttered finally killed SHA-1 (2017)
SHA-1 is how old certificates were signed. Cryptographers warned it was weakening as early as 2005. The CAs kept signing with it anyway, dismissing the collision attacks as theoretical.
For certificates, a hash collision is fatal: two documents with the same hash means one signature validates both. An attacker who can collide SHA-1 can present a CA with an innocent certificate request and receive a signature that also validates a forged certificate for someone else’s domain.
Microsoft killed it by announcing it would stop accepting SHA-1 certificates after 2016. But SHA-1 certificates kept working for years, because certificates issued in 2016 with 3-year lifetimes stayed valid until 2019. The industry had deprecated the algorithm and still had to wait out the inventory. Long certificate lifetimes don’t just delay renewal work, they delay every security fix that certificates carry. That lesson is a big part of why lifetimes keep shrinking.
What the modern handshake means for your certificates
There’s a quieter consequence of this redesign that most explainers skip.
In the old handshake, the certificate’s private key protected every session ever recorded. Losing it was catastrophic, so we treated it with extreme caution: manual issuance, hardware modules, change advisory boards, three-year lifetimes to avoid touching anything.
In the modern handshake, the certificate does one job: identity. The encryption keys are ephemeral and vanish with each session. A leaked key is still bad, but the blast radius shrank from “all recorded history” to “impersonation until revoked.”
That shift is what made automated certificate issuance reasonable, and it’s why the industry keeps shrinking certificate lifetimes toward 47 days. Short-lived, automatically rotated identity documents are the logical endpoint of the handshake’s redesign. The protocol already did its part. The remaining work is operational: getting the right certificate to the right server, every time, without a human in the loop.
CertKit automates certificate lifecycle management, so the identity check at the start of every handshake is never the reason your site went down.
Comments