TLS 1.3 Handshake — A Visual Walkthrough

TLS 1.3 Handshake — A Visual Walkthrough

2026-03-23

Every HTTPS page load, every API call, every database connection over TLS starts with the same ritual: the TLS 1.3 handshake. One round trip. Four messages. At the end, both sides have a shared symmetric key, the server is authenticated, and all data is encrypted.

Here's exactly what happens.

The Full Handshake

Client Server

1 ClientHello supported ciphers + ECDHE public key + random

2 ServerHello chosen cipher + ECDHE public key + random

both compute shared secret

--- everything below is encrypted ---

3 Certificate + CertificateVerify server cert chain + signature over handshake

Finished MAC over entire handshake transcript

4 Finished client MAC over entire handshake transcript

Application data (HTTP, etc.) GET /index.html 200 OK + page content

Four messages, one round trip. Compare TLS 1.2, which needed two round trips (separate key exchange and authentication phases). That extra round trip added 50-100ms on every new connection.

Message 1: ClientHello

The client sends:

  • Supported cipher suites — the encryption and hash algorithms the client supports. TLS 1.3 reduced this to 5 cipher suites (down from dozens in TLS 1.2).
  • Key share — the client's ECDHE public value. In TLS 1.2, this came later. In 1.3, the client guesses which curve the server will choose (usually X25519) and includes the key share upfront. This saves a round trip.
  • Random — 32 bytes of randomness, used in key derivation.
  • SNI — Server Name Indication, the domain name the client wants to connect to. This is the last piece sent in plaintext (Encrypted Client Hello will fix this).

Message 2: ServerHello

The server sends:

  • Chosen cipher suite — e.g., TLS_AES_256_GCM_SHA384.
  • Key share — the server's ECDHE public value.
  • Random — 32 bytes.

At this point, both sides have exchanged Diffie-Hellman public values. Both compute the shared secret: client_private × server_public = server_private × client_public. The shared secret is fed through HKDF (HMAC-based Key Derivation Function) to produce:

  • Handshake traffic key (encrypts the rest of the handshake)
  • Application traffic key (encrypts application data after the handshake)

From this point, everything is encrypted. Even the server's certificate is sent encrypted — an eavesdropper can't see which certificate the server presents.

Message 3: Server Authentication

The server sends (encrypted):

  • Certificate — the server's certificate chain. The client verifies: is the domain correct? Is the certificate valid? Is it signed by a trusted CA?
  • CertificateVerify — a digital signature over the entire handshake transcript so far, using the server's private key. This proves the server actually possesses the private key matching the certificate.
  • Finished — a MAC (Message Authentication Code) over the entire handshake transcript. This detects any tampering with the handshake messages.

Message 4: Client Confirmation

The client sends (encrypted):

  • Finished — a MAC over the handshake transcript from the client's perspective. The server verifies this matches.

After this, the handshake is complete. Application data (HTTP requests, API calls) flows over the encrypted connection.

Why Is This Better Than TLS 1.2?

TLS 1.2TLS 1.3
Round trips21
Key exchange in ClientHelloNoYes (key_share)
Certificate encryptedNoYes
Cipher suites37+5
Forward secrecyOptionalMandatory
RSA key exchangeAllowedRemoved
0-RTT resumptionNoYes (with replay risk)

The single biggest change: the client sends its key share in ClientHello, before the server responds. In TLS 1.2, the client waited for the server to choose parameters, then sent the key share — adding an extra round trip. TLS 1.3 guesses (correctly, almost always) and saves 50-100ms per new connection.

0-RTT Resumption

If the client has connected to this server before, TLS 1.3 supports 0-RTT — sending application data in the very first message, before the handshake completes.

The client uses a pre-shared key (PSK) from the previous session to encrypt the early data. The server decrypts it and processes the request while the handshake continues in parallel.

The risk: 0-RTT data can be replayed. An attacker who records the ClientHello can resend it, and the server will process the request again. This is safe for idempotent requests (GET) but dangerous for non-idempotent ones (POST with side effects). Servers should only accept 0-RTT for safe operations.

What Does a Real Handshake Look Like?

In tcpdump:

15:30:01.000 client → server  TLSv1.3 ClientHello
15:30:01.025 server → client  TLSv1.3 ServerHello
15:30:01.025 server → client  TLSv1.3 EncryptedExtensions, Certificate, CertificateVerify, Finished
15:30:01.026 client → server  TLSv1.3 Finished
15:30:01.026 client → server  TLSv1.3 Application Data

25ms for the server to respond. 1ms for the client to verify and confirm. Application data flows at 26ms. On a local network, this entire handshake takes under 5ms.

The cryptographic primitives that make this possible: ECDHE key exchange (shared secret without transmitting it), AES-GCM (authenticated encryption of all data), Ed25519/ECDSA signatures (server authentication), SHA-384 (handshake integrity).

Every HTTPS connection you make — every page load, every API call — starts exactly like this. Understanding the handshake means understanding the security model of the internet.