Before your browser sends the first byte of an HTTP request, it has to perform a small ritual with the server. That ritual is the handshake: the two sides agree on a protocol version and algorithms, the server proves who it is, and both ends derive keys that nobody watching the wire can compute.

Not a huge ritual anymore. TLS 1.3 made sure of that. But it is still a real exchange of promises, proofs, and key material, and it costs a single network round trip — tens of milliseconds on a typical connection, quickly enough that most developers never think about it. They type https://, the page loads, and the handshake disappears under the paint.

It shouldn’t disappear. It is one of the best pieces of engineering in the modern web stack.

(A note on names: people still say “SSL handshake.” SSL 3.0 was the last protocol called SSL, and it was replaced by TLS 1.0 in 1999. Everything a browser negotiates today is TLS 1.2 or 1.3, specified in RFC 5246 and RFC 8446.)

Step 1: ClientHello

The client opens by laying its cards on the table.

The ClientHello message contains: the TLS versions the browser supports, a list of cipher suites, a random 32-byte value, the server name via SNI, the key-exchange groups and signature algorithms it accepts, and — most importantly — a key_share.

In TLS 1.3 a cipher suite is only the encryption-and-hash pair (for example TLS_AES_128_GCM_SHA256). Key exchange and signatures are negotiated separately, through those extensions. In TLS 1.2 a suite name bundled all of it together, which is why the old names are so long.

The key_share is the big speed change from older handshakes. In TLS 1.2, the browser had to wait for the server to pick a key exchange before sending its own key material. TLS 1.3 doesn’t wait. The client guesses which group the server will accept, generates ephemeral key material for it, and includes it upfront. For years the guess was usually X25519; current Chrome and Firefox also send a hybrid post-quantum share, X25519MLKEM768. If the guess is wrong, the server answers with a HelloRetryRequest and the client tries again — one extra round trip, which is rare in practice.

That one decision is why TLS 1.3 feels faster. The protocol stopped being polite about waiting.

Step 2: ServerHello

The server picks from the client’s offerings. It selects a cipher suite, responds with its own random value, and — if it accepts the client’s key exchange guess — includes its own key_share.

At this point both sides have exchanged random values and key shares. They can each independently derive the same shared secret using (elliptic-curve) Diffie-Hellman. The handshake encryption keys are computed. Everything the server sends after this — starting with a short EncryptedExtensions message — is encrypted.

In TLS 1.2, the equivalent negotiation took two round trips. TLS 1.3 collapses it into one.

Step 3: Server Certificate

The server sends its certificate chain — the leaf certificate for the domain and any intermediate certificates. The root CA at the top of the chain usually isn’t sent; the browser already has it. The chain is the server’s identity claim: “I am example.com, and here’s a signature from an authority you trust vouching for that.”

The browser checks the chain against its root store — a curated list of a hundred-odd root certificates. If any link in the chain is broken, expired, or untrusted, the handshake fails.

This is where things go wrong most often in practice. Expired certificates, missing intermediates, hostname mismatches. The cryptography is fine. The PKI housekeeping is where humans make mistakes.

Step 4: CertificateVerify

The server proves it actually holds the private key for the certificate. It signs a hash of the entire handshake transcript so far — every message exchanged up to this point — with its private key.

This is what prevents someone from just copying a certificate and pretending to be the server. The certificate is public. The private key is not. Only the real server can produce this signature.

Step 5: Server Finished

The server sends a Finished message containing a MAC (Message Authentication Code) over the full handshake transcript. This proves the server saw the same messages the client sent and that nothing was tampered with in transit.

At this point the server is done talking about the handshake. It’s ready for application data.

Step 6: Client Verification

The client’s turn. It verifies the certificate chain against its root store. It checks that the hostname matches one of the certificate’s Subject Alternative Name entries. It verifies the CertificateVerify signature against the certificate’s public key. It confirms the Finished MAC is valid.

If anything fails — wrong hostname, expired cert, bad signature, untrusted CA — the browser kills the connection and shows an error page. There’s no partial trust. It’s all or nothing.

The client also derives the application traffic keys at this point, using the shared secret from the Diffie-Hellman exchange plus the handshake transcript.

Step 7: Client Finished

The client sends its own Finished message — another MAC over the handshake transcript from the client’s perspective. Handshake complete. Both sides now have identical symmetric keys derived from the shared secret.

Application data flows. Your HTTP request — the GET, the POST, the headers, the cookies — travels through the encrypted channel. The handshake is over. The invisible negotiation that took one round trip is done.

The TLS 1.2 Handshake, for Comparison

Plenty of servers still speak TLS 1.2, and you will meet its handshake in packet captures, so it helps to see the older shape:

  1. ClientHello — versions, cipher suites, random value. No key share.
  2. ServerHello, Certificate, ServerKeyExchange, ServerHelloDone — the server picks a suite, sends its certificate in the clear, and (for ECDHE suites) sends its Diffie-Hellman parameters signed with its private key.
  3. ClientKeyExchange, ChangeCipherSpec, Finished — the client sends its half of the key exchange, switches to encryption, and sends its Finished.
  4. ChangeCipherSpec, Finished — the server switches over and sends its own Finished.

That is two full round trips before the first HTTP request can go out. Three other differences matter more than the speed. In TLS 1.2 the certificate travels unencrypted, so anyone on the path can read which certificate you were given. TLS 1.2 still allowed plain RSA key exchange, where the client encrypts the secret to the server’s certificate key — record that traffic, steal the key years later, and you can decrypt it all. TLS 1.3 removed RSA key exchange entirely, so every TLS 1.3 connection has forward secrecy. And TLS 1.3 threw out a long list of legacy options (CBC-mode suites, RC4, renegotiation, compression) that had produced a decade of attacks.

Why TLS 1.3 Is Faster

TLS 1.2 needed two full round trips before application data could flow. TLS 1.3 needs one. The speculative key share in ClientHello is the trick — by guessing the server’s preferred group, the client saves an entire round trip.

There’s even a 0-RTT mode for repeat connections. The client keeps a pre-shared key from a previous session (delivered as a session ticket) and sends early application data in its very first flight. The server can process it immediately. Zero round trips before data flows.

The catch: 0-RTT data can be replayed. An attacker who captures the first message can resend it. This means 0-RTT should only carry idempotent requests — GETs, not POSTs. The speed comes with a tradeoff, and not everyone should use it.

What Goes Wrong

At each step, things can break. Certificate expired — the most common failure, usually because someone forgot to renew. Hostname mismatch — the cert says www.example.com but you connected to example.com. Missing intermediate — the server only sends the leaf cert and the client can’t build the chain. Clock skew — the client’s system clock is wrong, so a valid certificate looks expired. No shared parameters — the server and client have no protocol version or cipher suite in common, usually because one side is outdated.

Most TLS failures aren’t cryptographic. They’re operational. The math works. The humans maintaining the certificates are the fragile part.