Networking

TLS Handshake

Encryption, authentication, and key exchange — in 1 RTT (TLS 1.3)

TLS (Transport Layer Security) is the protocol that turns plain TCP into HTTPS. Its handshake exchanges identity (via certificates), agrees on a cryptographic suite, and derives shared session keys — all in 1 RTT for TLS 1.3 (down from 2 in TLS 1.2). After the handshake, every byte is encrypted with symmetric ciphers like AES-GCM or ChaCha20-Poly1305.

  • TLS 1.3 handshake RTT1 (down from 2 in TLS 1.2)
  • 0-RTT resumptionYes (TLS 1.3) — risky against replay attacks
  • Symmetric cipher (modern)AES-GCM or ChaCha20-Poly1305
  • Key exchangeECDHE (forward secrecy) — RSA key exchange removed in 1.3
  • Certificate chainRoot CA → intermediate(s) → server cert
  • Replaces SSL 3.0Yes (deprecated 2015, vulnerable to POODLE)

Interactive visualization

Press play, or step through manually. The visualization is yours to drive — try it before reading on.

Open visualization fullscreen ↗

Watch the 60-second explainer

A condensed visual walkthrough — narrated, captioned, under a minute.

How the TLS 1.3 handshake works

The TLS 1.3 handshake takes 1 round-trip (down from 2 in TLS 1.2) for fresh connections, or 0 RTT for resumed sessions. Here's the flow for a fresh connection:

  1. ClientHello. Client sends supported TLS versions, cipher suites, ECDHE key share (its public ephemeral key), Server Name Indication (which domain it's connecting to), and supported extensions. Crucially, TLS 1.3 sends the key share immediately — no negotiation round needed.
  2. ServerHello. Server picks the cipher suite, sends its ECDHE public key share, signs the handshake transcript with its certificate's private key, and sends the certificate chain. All of this in one flight. The server now knows the shared secret (derived from both ECDHE shares); the client will know it after this packet arrives.
  3. Finished. Both sides exchange Finished messages encrypted with the freshly derived session keys, confirming the handshake completed without tampering. Application data can flow immediately.

By the end of the second packet (server → client), both sides have the session key and can encrypt/decrypt application data. That's the 1-RTT bound.

TLS 1.2 vs TLS 1.3

TLS 1.2TLS 1.3
Released20082018
Handshake RTTs (fresh)21
0-RTT resumptionNoYes (with replay risk)
Cipher suite count~300 supported5 allowed
Forward secrecyOptional (ECDHE)Mandatory
RSA key exchangeAllowedRemoved
Authenticated encryptionOptional (AES-GCM)Mandatory (AEAD)
Encrypted server certNoYes — protects identity
Vulnerabilities of older versionsBEAST, CRIME, Lucky 13 (mostly fixed)Designed to avoid them

TLS 1.3 was a major redesign — not an incremental update. It removed every cryptographic option that had been broken or weakened over the previous decade: static RSA, MD5, SHA-1, RC4, CBC mode, compression. The result is a much smaller attack surface and a much faster handshake.

The certificate chain explained

A server's certificate is a public statement: "this public key belongs to example.com." For the client to trust it, the certificate must be signed by an authority the client already trusts. The chain works like this:

example.com cert (signed by) → DigiCert TLS RSA SHA256 (intermediate)
                          (signed by) → DigiCert Global Root CA (in browser trust store)

The client verifies each signature working up the chain. Roots are pre-installed in operating systems and browsers — Apple, Microsoft, Mozilla, Google curate these trust stores. If any link in the chain is invalid or expired, or the chain doesn't end in a trusted root, the connection fails with a certificate error.

Modern best practice: don't sign with the root directly. Roots stay offline (cold storage); intermediates are signed by the root and used to sign individual server certs. If an intermediate is compromised, you revoke just that intermediate, not the root. Let's Encrypt issues hundreds of millions of certs annually via this model.

Cipher suites in TLS 1.3

SuiteBulk cipherHashUsed by
TLS_AES_256_GCM_SHA384AES-256-GCMSHA-384High-security defaults
TLS_AES_128_GCM_SHA256AES-128-GCMSHA-256Default for most servers
TLS_CHACHA20_POLY1305_SHA256ChaCha20-Poly1305SHA-256Mobile devices without AES hardware acceleration
TLS_AES_128_CCM_SHA256AES-128-CCMSHA-256IoT / constrained devices
TLS_AES_128_CCM_8_SHA256AES-128-CCM (8-byte tag)SHA-256Smaller authentication tag for low-bandwidth

The Curve25519 (X25519) ECDHE group is the modern default for key exchange. P-256 and P-384 NIST curves are also widely supported.

When TLS handshake details matter

  • Web performance. The 1-RTT TLS 1.3 handshake combined with TCP's 1-RTT setup means HTTPS starts producing data after 2 RTT — vs 3 RTT under TLS 1.2. On a 100ms-RTT link, that's 200ms saved per fresh connection. HTTP/3 + QUIC combines TCP and TLS into one handshake, dropping it to 1 RTT total.
  • Service-to-service authentication (mTLS). When microservices need to authenticate each other, mTLS provides cryptographic identity without passwords. Kubernetes service meshes (Istio, Linkerd) use mTLS extensively.
  • Certificate management at scale. Each TLS connection requires a valid certificate. Let's Encrypt's free 90-day certs require auto-renewal; commercial CAs offer 1-year certs at a price. Automating renewal (cert-manager on Kubernetes, certbot on Linux) is the modern operational practice.
  • Key rotation and incident response. Forward secrecy means past sessions stay safe even if a key leaks. Without it (RSA key exchange in old TLS), one stolen private key compromises every recorded session. Always use ECDHE.

Famous TLS-era attacks (mostly historical)

  • POODLE (2014). Padding-Oracle attack on SSL 3.0. Forced the deprecation of SSLv3.
  • Heartbleed (2014). Bug in OpenSSL's heartbeat extension allowed reading server memory remotely. 17% of the internet was vulnerable; widespread certificate revocations followed.
  • BEAST (2011). Browser exploit against TLS 1.0's CBC mode. Mitigated by mode selection workarounds; fully fixed in TLS 1.1+.
  • FREAK / Logjam (2015). Attacks against export-grade weak ciphers that should have been long removed but weren't. Forced removal of all "EXPORT" cipher suites.
  • SLOTH (2016). Length extension and collision attacks against MD5 and SHA-1 in TLS. Forced removal of those hashes from the handshake.

The pattern: every weak cryptographic primitive eventually becomes a CVE. TLS 1.3's design philosophy is to allow only primitives believed to be secure for the foreseeable future and remove everything else — a stark contrast to TLS 1.2's "negotiate any of 300+ options" approach.

Inspecting a TLS handshake with curl

# See the certificate chain and protocol details
curl -v https://example.com 2>&1 | grep -E 'TLS|certificate|SSL|subject|issuer'

# Force TLS 1.3 only
curl --tlsv1.3 --tls-max 1.3 https://example.com

# Show the full handshake with openssl
openssl s_client -connect example.com:443 -servername example.com -tls1_3

Common TLS issues and pitfalls

  • Expired or self-signed certificates. Browsers will refuse to connect. Production servers must auto-renew (Let's Encrypt + certbot) before expiration. Self-signed certs are fine for internal testing, never for public services.
  • Hostname mismatch. The certificate's subject or Subject Alternative Names (SANs) must include the hostname being connected to. Wildcard certs (*.example.com) cover one level; multi-domain SANs cover specific hosts.
  • Mixed-content warnings. An HTTPS page loading HTTP resources triggers browser warnings or blocks. Always use HTTPS for sub-resources, or use protocol-relative URLs (//example.com/foo).
  • Weak cipher suites. Servers must reject deprecated ciphers (RC4, 3DES, NULL, EXPORT) regardless of what clients propose. Tools like SSL Labs grade configurations; A+ requires excluding all weak suites.
  • Replay attacks against 0-RTT. Don't enable 0-RTT for state-changing requests. The standard mitigation is to allow 0-RTT only for idempotent HTTP methods (GET, HEAD).
  • Certificate transparency requirements. Modern browsers require certificates to appear in CT logs. Commercial CAs handle this automatically; private CAs running pre-CT-logging may produce certs that browsers reject.

Frequently asked questions

What's the difference between SSL and TLS?

TLS is the modern name. SSL 1.0-3.0 were Netscape's original versions (1990s). TLS 1.0 (1999) was a rebranding with security fixes. SSL 3.0 was deprecated in 2015 due to the POODLE attack. Today everyone says "SSL" colloquially but every modern deployment uses TLS 1.2 or 1.3. The name stuck because of "SSL certificate" terminology.

Why does TLS 1.3 have 1 RTT instead of 2?

TLS 1.2 negotiates the cipher suite first, then exchanges keys — two round trips. TLS 1.3 sends the client's key share in the first message (assuming a default ECDHE curve) and the server replies with its key share + certificate + finished signal. The handshake completes in one RTT and the client can send encrypted data immediately. For repeat connections, TLS 1.3 supports 0-RTT — encrypted data in the very first packet — at the cost of some replay vulnerability.

What's perfect forward secrecy?

A property of key exchange where compromising the server's long-term private key does NOT let an attacker decrypt past sessions. ECDHE achieves this by deriving session keys from ephemeral key pairs that are discarded after each session. RSA key exchange (used in older TLS) does NOT have forward secrecy — recovering the server's private key lets you decrypt any past traffic. TLS 1.3 mandates forward secrecy.

How does certificate verification work?

The server sends its certificate (a signed statement "this domain belongs to this public key") plus a chain back to a trusted root certificate authority (CA). The client verifies each signature in the chain — server cert signed by intermediate, intermediate signed by root, root in the OS/browser's trust store. If any signature is invalid or the chain doesn't reach a trusted root, the connection fails.

What's mutual TLS (mTLS)?

Standard TLS authenticates only the server (client knows server's identity). mTLS additionally authenticates the client — the client also presents a certificate. Used in service-to-service communication where both sides need to prove identity (microservices, internal APIs). Adds operational complexity (certificate distribution per client) but is the gold standard for zero-trust internal networks.

Why is 0-RTT in TLS 1.3 risky?

0-RTT lets the client send encrypted data in the very first packet, using a key derived from the previous session. The trade-off: an attacker can record and replay 0-RTT data — the server can't distinguish a fresh request from a replay. Safe for idempotent operations (GET requests), unsafe for state-changing ones (POST, payment). HTTPS implementations restrict 0-RTT to safe methods.

What does cipher suite negotiation look like?

The client lists ciphers it supports (e.g., TLS_AES_256_GCM_SHA384). The server picks one (typically the strongest mutually supported). The cipher suite specifies key exchange (ECDHE), authentication (RSA or ECDSA via certificate), bulk cipher (AES-GCM or ChaCha20), and hash (SHA-384). TLS 1.3 dramatically simplified this — only 5 cipher suites are allowed, all forward-secret AEAD combinations.