Every HTTPS connection pays a latency tax before the first byte of your request moves: the TCP handshake, then the TLS handshake. TLS 1.3 cut the TLS half from two round trips to one — a change worth more than any CDN — and added a resumption mechanism that can cut it to zero. Here is exactly which bytes go where, what each proves, and why the fastest mode is also the riskiest.
The old bill: TLS 1.2 cost two RTTs
TLS 1.2's handshake was a conversation: ClientHello, then ServerHello and the certificate, then a client premaster secret (the key material), then a server Finished — and only then could the client send its first request. Total: two round trips beyond TCP's one. On a 50 ms RTT, that's 150 ms before your GET leaves the machine. Worse, the client's key contribution arrived in the second flight, so nothing was forward-secret until then.
TLS 1.3: one flight, both sides' keys, encrypted
TLS 1.3 (RFC 8446) collapsed the negotiation. The client guesses — it sends its ephemeral key share (ECDHE) inside the ClientHello, along with the list of cipher suites it speaks. The server picks one, sends its own key share back, and the two sides compute the same session key immediately:
Client → Server: ClientHello
cipher suites, key_share (client's ephemeral X25519 key)
Server → Client: ServerHello
chosen suite, key_share (server's ephemeral key)
EncryptedExtensions ← now everything is encrypted
Certificate ← leaf + intermediates
CertificateVerify ← signs the whole transcript
Finished ← first MAC under the session key
Client → Server: Finished + application data ← 1 RTT totalThe critical property: the server's signature arrives under encryption, proving the
transcript — every byte of both hellos — is exactly what the client sent. No attacker
can swap a cipher suite or inject a certificate without breaking CertificateVerify,
and because both key shares are ephemeral, the session key is forward-secret from
minute zero. The first request rides in the same flight as the client's Finished:
1 RTT, always.
$ openssl s_client -connect example.com:443 -tls1_3 </dev/null 2>/dev/null |
grep -E "New|Protocol|Cipher"
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256Session resumption: the PSK shortcut
Doing a full handshake on every connection is still expensive — the certificate chain alone can be several kilobytes of signatures to verify. So TLS 1.3 offers resumption: after the first handshake, the server hands the client a ticket — an opaque blob containing a session key, encrypted so only the server can read it. The client stores it and, on the next connection, offers it back as a PSK (pre-shared key):
Client → Server: ClientHello + pre_shared_key (ticket from last time)
+ key_share (fresh ephemeral — forward secrecy preserved)
Server → Client: ServerHello + Finished (ticket accepted, session key derived)
Client → Server: Finished + application dataThe handshake is still one flight each way, but the server sends no certificate and does no signature — it just derives the key from the ticket. This is what your browser does when it reconnects minutes later: same 1 RTT, vastly less server work. The client still sends a fresh key share: the new session key mixes the PSK with fresh ephemeral material, so resumption never abandons forward secrecy.
0-RTT: the request goes before the handshake
The ticket contains more than a key — it carries an early data allowance. A resumed client may attach encrypted application data to the very first flight. The server can process it the instant the ticket validates, with no round trip at all:
Client → Server: ClientHello + PSK + 0-RTT data (encrypted, replayable)
Server → Client: ServerHello + Finished + response to the 0-RTT data0-RTT is the difference between "new tab feels instant" and "new tab waits 50 ms". But the cost is structural:
The full cost table
| Setup | Round trips | Notes |
|---|---|---|
| TCP + TLS 1.2 | 3 | 1 TCP + 2 TLS; no forward secrecy until flight 2 |
| TCP + TLS 1.3 | 2 | 1 TCP + 1 TLS; forward-secret immediately |
| TCP + TLS 1.3 + PSK | 2 | 1 TLS, but no certificate/signature work |
| QUIC (TLS 1.3 built in) | 1 | transport + crypto handshakes merged |
| QUIC + 0-RTT | 0 | first request encrypted with the ticket, replayable |
On a 40 ms RTT, TLS 1.3 over 1.2 saves 40 ms per cold connection; 0-RTT saves another 40 ms.
The mental model
- TLS 1.3's one RTT comes from guessing the key share — negotiation became a confirmation, not a discovery.
- PSK resumption trades certificate verification for a server-side ticket check — same RTTs, less work, same forward secrecy.
- 0-RTT is a replay by design. Treat early data like a cacheable GET: fine to process, never safe to execute.