TLS

Chapter 6
The TLS 1.2 Handshake
Putting keys, certificates, and the chain together — message by message

Everything so far — symmetric/asymmetric crypto, key exchange, certificates, the trust chain — comes together in the handshake: the short negotiation at the start of every HTTPS connection that authenticates the server and establishes the shared symmetric key. This chapter walks the TLS 1.2 handshake message by message. (Chapter 7 shows how 1.3 streamlines it; understanding 1.2 first makes that contrast clear.)

What the Handshake Must Accomplish

Before the first byte of HTTP is sent, the two parties must agree on four things. Keep these goals in mind — every message below serves one of them:

  • Agree the protocol & cipher — which TLS version and cipher suite both support (Chapter 8).
  • Authenticate the server — verify its certificate chains to a trusted root (Chapters 4–5).
  • Establish a shared secret — via key exchange, ideally ephemeral for forward secrecy (Chapter 3).
  • Confirm both sides match — verify nothing was tampered with before switching to encryption.

The Handshake, Message by Message (ECDHE)

CLIENTSERVER
ClientHello
ServerHello
Certificate (+ chain)
ServerKeyExchange (signed)
ServerHelloDone
ClientKeyExchange
ChangeCipherSpec + Finished
ChangeCipherSpec + Finished
🔒 Application Data (HTTP)
◀▶
🔒 Application Data

1. ClientHello

The client opens with its capabilities: the highest TLS version it supports, a list of cipher suites it can use, a freshly generated client random (random bytes), and extensions — notably SNI (the hostname it wants, so a server hosting many sites returns the right certificate) and the supported elliptic curves.

2. ServerHello

The server replies with its choices from what the client offered: the agreed TLS version, the single cipher suite it selected, and its own server random. These two randoms aren't the secret — but they feed into deriving the final keys, ensuring every session is unique even with the same long-term key.

3. Certificate

The server sends its certificate plus the intermediate chain (Chapter 5). The client verifies it now: walks the chain to a trusted root, checks validity dates, and confirms the SAN matches the SNI hostname. If any check fails, the handshake aborts here with a warning — this is the authentication goal.

4. ServerKeyExchange (signed — the crucial step)

For ephemeral key exchange (ECDHE), the server generates its ephemeral DH public value and sends it — signed with the private key from its certificate. This single message is where Chapter 3's two roles fuse:

# the server's DH value is signed over both randoms + the DH params signature = Sign(server_private_key, client_random + server_random + server_DH_public) # the client verifies with the public key FROM THE CERTIFICATE it just checked Verify(cert_public_key, signature) ? ok -> this DH value really came from the authenticated server else abort

The signature binds the ephemeral key to the authenticated identity, defeating the man-in-the-middle: an attacker can't substitute their own DH value because they can't produce a valid signature without the server's private key. This is the heart of the handshake — authentication and key agreement joined in one step.

5. ServerHelloDone

A short marker: "I'm done with my side of the hello." The client now has everything it needs to contribute its half of the key exchange.

6. ClientKeyExchange

The client generates its ephemeral DH public value and sends it. Now both sides hold the other's DH public value, so each independently computes the same shared pre-master secret (the Diffie–Hellman magic from Chapter 3 — the secret itself is never transmitted).

From pre-master secret to session keys
Both sides now combine the pre-master secret with the client random and server random through a key-derivation function (the PRF) to produce the master secret, and from it the actual symmetric keys used for the rest of the session. Because the two randoms feed in, two sessions never reuse the same keys even if every other input repeats. This is the moment the connection transitions from the slow asymmetric setup to the fast symmetric phase — the hybrid model (Chapter 2) in action.

7. ChangeCipherSpec + Finished

Each side sends ChangeCipherSpec ("everything I send after this is now encrypted with the new keys") followed immediately by an encrypted Finished message. Finished contains a hash of the entire handshake transcript so far. Each side checks the other's Finished against its own view of the transcript:

Finished is the anti-tampering seal on the whole handshake
The early handshake messages (ClientHello, ServerHello, cipher list) were sent in the clear. A man-in-the-middle could try to tamper with them — for instance, stripping the strong cipher suites to force a weak one (a downgrade attack). The Finished message defeats this: it's a hash of every handshake message exchanged. If an attacker altered anything, the two sides' transcripts differ, the Finished hashes won't match, and the connection aborts before any real data flows. The handshake validates its own integrity retroactively.

8. Application Data

Both Finished messages verified, the tunnel is live. All HTTP now flows as encrypted, integrity-protected TLS records using the negotiated symmetric AEAD cipher (Chapter 2). The handshake is over.

Why It's "2-RTT" — and Why That Motivated 1.3

Count the round trips: ClientHello → (server's flight) → ClientKeyExchange/Finished → (server's Finished) → data. The client must wait two full round trips before sending application data. On a high-latency mobile link that's a visible delay on every new connection.

Handshake goalWhich message(s) achieve it
Negotiate version + cipherClientHello / ServerHello
Authenticate the serverCertificate + signed ServerKeyExchange
Establish shared secretServerKeyExchange + ClientKeyExchange (ECDHE)
Confirm integrity / no tamperingChangeCipherSpec + Finished (both sides)

That 2-RTT cost — plus the lingering option of non-forward-secret RSA key transport and a menu of legacy ciphers — is exactly what TLS 1.3 set out to fix. The next chapter shows how it collapses this dance into a single round trip while removing the insecure options entirely.

Hands-On Exercises

Exercise 1

Run openssl s_client -connect example.com:443 -tls1_2 -msg and match the messages it prints (ClientHello, ServerHello, Certificate, ServerKeyExchange, etc.) to the eight steps in this chapter. Note which messages flow before encryption begins.

📄 View solution
Exercise 2

Explain, step by step, how the signed ServerKeyExchange stops a man-in-the-middle from substituting their own Diffie–Hellman value. Identify exactly which earlier step the signature depends on, and what the attacker would need to forge it.

📄 View solution
Exercise 3

A downgrade attacker tampers with the ClientHello in transit to delete the strong cipher suites, hoping to force a weak one. Trace what happens and identify precisely which handshake message causes the connection to abort, and why the attacker can't cover their tracks.

📄 View solution

Chapter 6 Quick Reference

  • The handshake negotiates cipher, authenticates the server, establishes the shared key, and confirms integrity — before any HTTP
  • ClientHello — client's versions, cipher list, client random, SNI (hostname)
  • ServerHello — server's chosen version + cipher, server random
  • Certificate — leaf + chain; client verifies to a trusted root & checks SAN vs SNI
  • ServerKeyExchange — ephemeral DH value signed with the cert key (auth + key agreement fused; the MITM defence)
  • ClientKeyExchange — client's DH value; both derive the pre-master → master secret using the two randoms
  • ChangeCipherSpec + Finished — switch to encryption; Finished hashes the whole transcript (defeats downgrade/tampering)
  • TLS 1.2 needs 2 round trips before data — the cost that motivated TLS 1.3
  • Next chapter: TLS 1.3 — 1-RTT handshakes, 0-RTT resumption, and removed legacy crypto