TLS Handshake Deep-Dive
AdvancedThe TLS handshake is the cryptographic negotiation that establishes a secure, authenticated session before any application data is sent — combining asymmetric crypto for key exchange with symmetric crypto for bulk encryption.
Overview
Every HTTPS connection begins with a TLS handshake. In TLS 1.2 this takes 2 round-trips; TLS 1.3 reduced it to 1 round-trip (0-RTT for resumption). The handshake achieves three things: cipher suite negotiation, server (and optionally client) authentication via X.509 certificates, and derivation of shared symmetric session keys using Diffie-Hellman key exchange. Understanding the TLS handshake is essential for backend engineers diagnosing latency, implementing mutual TLS (mTLS), or designing zero-trust architectures.
TLS 1.3 Handshake Steps
TLS 1.3 streamlined the handshake from 2 to 1 round-trip by merging steps. The client sends its key share immediately in ClientHello; the server can respond with its key share plus the certificate in a single flight, then application data begins.
// TLS 1.3 — 1-RTT Handshake
// ─────────────────────────────────────────────────────────
// Client Server
// │ │
// │── ClientHello ────────────────▶│
// │ (supported ciphers, │
// │ key_share: ECDH pub-key, │
// │ supported_versions: TLS1.3) │
// │ │
// │◀─ ServerHello ─────────────────│
// │ (chosen cipher, │
// │ key_share: ECDH pub-key) │
// │◀─ {Certificate} ───────────────│
// │◀─ {CertificateVerify} ─────────│ (server signs handshake transcript)
// │◀─ {Finished} ──────────────────│
// │ │
// │── {Finished} ─────────────────▶│
// │ │
// │══ Application Data (AES-GCM) ══│ ← 1 RTT total
//
// Keys derived via HKDF from ECDH shared secret:
// client_write_key, server_write_key, client_write_IV, server_write_IVTLS 1.2 vs TLS 1.3
TLS 1.2 required 2 round-trips, supported weaker ciphers (RSA key exchange — no forward secrecy), and left many fields unencrypted in the handshake. TLS 1.3 mandates Diffie-Hellman key exchange (providing forward secrecy), removes broken algorithms (RC4, 3DES, SHA-1, RSA key exchange), and encrypts more of the handshake.
// TLS 1.2 (2-RTT, legacy)
// Client → ClientHello (ciphers, random)
// Server → ServerHello + Certificate + ServerHelloDone
// Client → ClientKeyExchange (encrypted pre-master secret with server RSA pub key)
// → ChangeCipherSpec + Finished
// Server → ChangeCipherSpec + Finished
// ── 2 RTTs before application data ──
// TLS 1.3 improvements:
// ✓ Mandatory forward secrecy (ECDHE / DHE — RSA key exchange removed)
// ✓ 1-RTT handshake (key_share in ClientHello)
// ✓ 0-RTT resumption (PSK — replay risk; only for idempotent requests)
// ✓ Encrypted certificate (eavesdropper can't see server identity)
// ✓ Removed: RC4, 3DES, SHA-1, MD5, RSA key transport, CBC + HMAC suites
// ✓ Only 5 cipher suites allowed (all AEAD: AES-GCM, AES-CCM, ChaCha20-Poly1305)Mutual TLS (mTLS)
In standard TLS only the server presents a certificate. In mTLS both client and server authenticate with certificates — critical for service-to-service communication in microservices and zero-trust networks.
// mTLS — both sides authenticate
// Used in: Kubernetes service mesh (Istio/Linkerd), banking APIs, zero-trust
// Server config (Spring Boot / application.yml):
server:
ssl:
enabled: true
key-store: classpath:server-keystore.p12
key-store-password: ${SSL_KEYSTORE_PASSWORD}
trust-store: classpath:server-truststore.p12
trust-store-password: ${SSL_TRUSTSTORE_PASSWORD}
client-auth: need # ← enforce client certificate
// Java client with client certificate:
SSLContext sslContext = SSLContextBuilder.create()
.loadKeyMaterial(keyStore, keyPassword) // client cert + key
.loadTrustMaterial(trustStore, null) // trusted CA for server
.build();
CloseableHttpClient client = HttpClients.custom()
.setSSLContext(sslContext)
.build();Forward Secrecy & Session Resumption
Forward secrecy means that if the server's private key is compromised in the future, past session recordings cannot be decrypted — because the session keys were derived from ephemeral Diffie-Hellman values that are discarded after the session. TLS 1.3 session resumption uses Pre-Shared Keys (PSK) to avoid a full handshake for returning clients.
// Forward secrecy — why ECDHE is mandatory in TLS 1.3
// Session key = HKDF(ECDHE_shared_secret + randoms)
// ECDHE private keys are generated per-session and immediately discarded.
// Even if server's long-term RSA/EC key is stolen later,
// the attacker cannot decrypt past recordings — no permanent key was used.
// Session resumption (TLS 1.3 PSK):
// 1. After a full handshake, server sends a NewSessionTicket
// (encrypted blob containing resumption key)
// 2. Client stores the ticket; on reconnect sends it in ClientHello
// 3. Server decrypts ticket, verifies, jumps to application data (0-RTT or 1-RTT)
// 0-RTT risk: replay attacks
// Mitigation: only use 0-RTT for idempotent requests (GET, not POST/PUT)Key Points to Remember
- 1TLS 1.3 completes in 1 RTT vs 2 RTT for TLS 1.2, directly reducing HTTPS connection latency.
- 2TLS 1.3 mandates forward secrecy via ECDHE — RSA key transport (no forward secrecy) is removed.
- 3mTLS authenticates both client and server — essential for zero-trust and service mesh architectures.
- 40-RTT resumption saves a round-trip but is vulnerable to replay attacks — restrict to idempotent requests.
- 5The certificate in TLS 1.3 is encrypted — an eavesdropper cannot determine the server identity from the handshake.
Interview Questions
Sign in to ask AriaWhat is the difference between TLS 1.2 and TLS 1.3?
What is forward secrecy and why does it matter?
How does mTLS differ from standard TLS and when would you use it?
What are the risks of TLS 1.3 0-RTT resumption?
Walk me through what happens during a TLS 1.3 handshake step by step.
Ask Aria about TLS Handshake Deep-Dive
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.