How TLS Handshakes Work: The Cryptography Behind HTTPS
A step-by-step guide to TLS 1.3 handshakes covering key exchange, certificate chain validation, cipher suites, forward secrecy, and session resumption with 0-RTT.
Infrastructure engineer with 10+ years building production systems on AWS, GCP,…

The Security Negotiation That Happens Before Every HTTPS Request
Every time your browser connects to an HTTPS site, a TLS handshake happens before a single byte of your actual data crosses the wire. This handshake negotiates encryption algorithms, verifies the server's identity, and derives the session keys that protect everything you send and receive. It takes 1-2 round trips and involves asymmetric cryptography, certificate chains, and key derivation functions -- all in under 100 milliseconds.
Most developers treat TLS as a black box: install a certificate, things work. But when something breaks -- certificate errors, handshake failures, performance problems -- you need to understand what's actually happening. This guide walks through the TLS 1.3 handshake step by step, explains the cryptographic primitives involved, and covers the failure modes you'll encounter in production.
What Is TLS?
Definition: TLS (Transport Layer Security) is a cryptographic protocol that provides confidentiality, integrity, and authentication for network communication. It sits between the transport layer (TCP) and the application layer (HTTP), encrypting data in transit using a combination of asymmetric and symmetric cryptography negotiated during the handshake.
TLS 1.3, standardized in 2018 (RFC 8446), stripped away the accumulated complexity of earlier versions. It removed insecure algorithms, reduced the handshake from 2 round trips to 1, and eliminated entire categories of attacks. If you're configuring a server today, TLS 1.3 should be your target.
Asymmetric vs Symmetric Encryption: The Key Distinction
TLS uses both types of cryptography, and understanding why is essential to understanding the handshake:
| Property | Asymmetric (Public Key) | Symmetric |
|---|---|---|
| Keys | Public/private key pair | Single shared secret |
| Speed | Slow (1000x slower) | Fast |
| Use in TLS | Key exchange and authentication | Bulk data encryption |
| Algorithms | ECDHE, RSA, Ed25519 | AES-128-GCM, ChaCha20-Poly1305 |
The handshake uses asymmetric crypto to establish a shared secret that both sides know but nobody else does. Then everything after the handshake uses fast symmetric encryption with that shared secret. It's the best of both worlds: the security of public key cryptography for key exchange, the speed of symmetric cryptography for data transfer.
The TLS 1.3 Handshake: Step by Step
- ClientHello -- The client sends supported TLS versions, cipher suites, and key shares (precomputed Diffie-Hellman public values). TLS 1.3 sends key shares upfront, which is why the handshake is one round trip faster than TLS 1.2.
- ServerHello -- The server picks the cipher suite, selects a key share, and sends its own Diffie-Hellman public value. At this point, both sides can compute the shared secret.
- Server Certificate -- The server sends its certificate chain. The client validates the chain up to a trusted root CA.
- CertificateVerify -- The server proves it owns the private key corresponding to the certificate by signing a hash of the handshake transcript.
- Server Finished -- The server sends a MAC (message authentication code) of the entire handshake, proving nothing was tampered with.
- Client Finished -- The client sends its own Finished message. The handshake is complete. Application data can flow.
Client Server
| |
|--- ClientHello ------------------->| (versions, cipher suites, key shares)
| |
|<-- ServerHello --------------------| (chosen cipher, key share)
|<-- Certificate --------------------| (certificate chain)
|<-- CertificateVerify --------------| (signature proving key ownership)
|<-- Finished -----------------------| (MAC of handshake)
| |
|--- Finished ---------------------->| (MAC of handshake)
| |
|<== Encrypted Application Data ====>| (symmetric encryption)
| |
Total: 1 round trip (TLS 1.3) vs 2 round trips (TLS 1.2)
Pro tip: Inspect a real TLS handshake with
openssl s_client -connect example.com:443 -tls1_3. It prints every handshake message, the negotiated cipher suite, and the certificate chain. Add-msgfor raw hex of each message.
Key Exchange: How Both Sides Agree on a Secret
TLS 1.3 uses Ephemeral Elliptic Curve Diffie-Hellman (ECDHE) for key exchange. Here's the mental model:
- The client generates a random private key and computes a public key on an elliptic curve (typically X25519 or P-256).
- The server does the same.
- Both sides exchange public keys in ClientHello/ServerHello.
- Each side combines their private key with the other's public key to compute the same shared secret -- without that secret ever crossing the wire.
The "ephemeral" part is critical: new keys are generated for every connection. If an attacker compromises the server's long-term private key later, they can't decrypt past sessions because the session keys were ephemeral and discarded. This property is called forward secrecy.
Certificate Chains and Validation
The certificate the server sends isn't just one certificate -- it's a chain:
- Leaf certificate -- Issued for your specific domain (e.g.,
techplained.com). Contains the server's public key. - Intermediate certificate(s) -- Issued by a Certificate Authority (CA) to bridge between the leaf and the root. Most chains have 1-2 intermediates.
- Root certificate -- A self-signed certificate pre-installed in your operating system or browser's trust store. Not sent in the chain -- the client already has it.
Validation walks the chain from leaf to root, verifying each certificate's signature with its parent's public key. If the chain leads to a trusted root, the certificate is valid. The client also checks the domain name matches, the certificate hasn't expired, and it hasn't been revoked.
# View the full certificate chain
openssl s_client -connect techplained.com:443 -showcerts
# Check certificate expiration
echo | openssl s_client -connect techplained.com:443 2>/dev/null | openssl x509 -noout -dates
# Verify the chain explicitly
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt chain.pem
Watch out: The most common TLS error in production is a missing intermediate certificate. The leaf cert is valid, the root cert is trusted, but the server didn't send the intermediate that connects them. Browsers sometimes cache intermediates (which masks the problem), but API clients and mobile apps will reject the connection. Always test with
openssl s_client, not just a browser.
Session Resumption and 0-RTT
A full handshake costs 1 round trip. For returning clients, TLS 1.3 offers two faster paths:
PSK Resumption (Pre-Shared Key)
After a successful handshake, the server sends a session ticket encrypted with a key only the server knows. On the next connection, the client includes this ticket in ClientHello. If the server recognizes it, both sides derive session keys from the PSK without a full key exchange. This still costs 1 RTT but skips certificate validation and some computation.
0-RTT Early Data
The client can send application data with the very first ClientHello packet, encrypted with keys derived from the PSK. The server processes this data before the handshake completes -- zero round trips of latency for the first request.
Watch out: 0-RTT data has no forward secrecy (it uses the PSK, not ephemeral keys) and is vulnerable to replay attacks. An attacker who captures the ClientHello can replay it, causing the server to process the early data again. Only use 0-RTT for idempotent requests like GET. Never for POST, PUT, or anything that changes state.
Cipher Suites in TLS 1.3
TLS 1.3 dramatically reduced the number of supported cipher suites from dozens to five:
| Cipher Suite | Key Exchange | Encryption | Notes |
|---|---|---|---|
| TLS_AES_128_GCM_SHA256 | ECDHE | AES-128-GCM | Most common, hardware-accelerated on modern CPUs |
| TLS_AES_256_GCM_SHA384 | ECDHE | AES-256-GCM | Higher security margin, slightly slower |
| TLS_CHACHA20_POLY1305_SHA256 | ECDHE | ChaCha20-Poly1305 | Faster on devices without AES hardware (older mobile) |
| TLS_AES_128_CCM_SHA256 | ECDHE | AES-128-CCM | Constrained environments |
| TLS_AES_128_CCM_8_SHA256 | ECDHE | AES-128-CCM-8 | IoT with limited bandwidth |
All five use ECDHE for key exchange (forward secrecy is mandatory in TLS 1.3) and AEAD (authenticated encryption with associated data) for bulk encryption. The dangerous options from TLS 1.2 -- RSA key exchange, CBC mode, RC4, 3DES -- are gone entirely.
Certificate Providers: Cost Comparison
| Provider | DV Certificate | Wildcard | Automation |
|---|---|---|---|
| Let's Encrypt | Free | Free | ACME protocol (certbot) |
| Cloudflare | Free (with proxy) | Free (with proxy) | Automatic |
| AWS ACM | Free (for AWS services) | Free | Automatic renewal |
| DigiCert | $268/year | $688/year | API available |
| Sectigo | $76/year | $250/year | API available |
Pro tip: There's no security difference between a free Let's Encrypt certificate and a $268 DigiCert DV certificate. Both validate domain ownership and provide the same encryption. Paid certificates offer extended validation (EV), longer validity periods, and warranty -- but browsers have removed visual EV indicators, making the practical benefit minimal for most sites.
Frequently Asked Questions
What is the difference between TLS and SSL?
SSL (Secure Sockets Layer) is the predecessor to TLS. SSL 3.0 was the last SSL version, released in 1996. TLS 1.0 (1999) was effectively SSL 3.1 with security improvements. All SSL versions are now deprecated and insecure. When people say "SSL certificate," they mean a TLS certificate -- the name stuck even though the protocol changed. Use TLS 1.3 and disable everything older than TLS 1.2.
Why does TLS 1.3 only take 1 round trip?
TLS 1.2 required 2 round trips because the key exchange and cipher negotiation happened in separate messages after the initial hello. TLS 1.3 moves the client's key share into the ClientHello message, so the server has everything it needs to compute the shared secret immediately. The server responds with its key share, certificate, and Finished in a single flight.
What is forward secrecy and why does it matter?
Forward secrecy (also called perfect forward secrecy) means that compromising the server's long-term private key doesn't expose past encrypted sessions. TLS 1.3 achieves this by generating ephemeral Diffie-Hellman keys for every session. Even if an attacker records encrypted traffic and later obtains the server's private key, they can't derive the session keys because those were ephemeral and destroyed.
How do I check if my server supports TLS 1.3?
Run openssl s_client -connect yoursite.com:443 -tls1_3. If the connection succeeds, TLS 1.3 is supported. For a comprehensive scan, use testssl.sh or Qualys SSL Labs (ssllabs.com/ssltest) which grades your configuration and reports supported protocols, cipher suites, and common misconfigurations. Aim for an A+ rating.
Should I disable TLS 1.2?
Not yet for public-facing services. As of 2025, about 2-5% of clients can't negotiate TLS 1.3 -- older Android devices, legacy corporate systems, and some IoT devices. Support both TLS 1.2 and 1.3. For internal services where you control all clients, TLS 1.3-only is reasonable and simplifies your security posture. Disable TLS 1.0 and 1.1 immediately if you haven't already.
What causes "certificate not trusted" errors?
Three common causes: (1) Missing intermediate certificate -- the server sends the leaf cert but not the intermediates needed to chain to the root. Fix by configuring the full chain. (2) Expired certificate -- the cert's notAfter date has passed. Automate renewal with certbot or your cloud provider. (3) Wrong domain -- the certificate's Subject Alternative Names don't include the domain being accessed. Reissue with the correct domains.
Is HTTPS slower than HTTP?
The TLS handshake adds 1 round trip (TLS 1.3) of latency to the initial connection. For subsequent requests on the same connection, there's no additional overhead -- symmetric encryption on modern hardware adds less than 1% CPU overhead thanks to AES-NI instructions. With session resumption and HTTP/2 connection reuse, the practical performance impact is negligible. The security is worth it, and search engines penalize HTTP-only sites.
Conclusion
The TLS handshake is one of those things that works so well you forget it exists -- until a certificate expires at 3 AM. Use TLS 1.3, automate certificate renewal with Let's Encrypt or your cloud provider, and verify your configuration with SSL Labs. Make sure your server sends the complete certificate chain, not just the leaf. Enable HSTS to prevent protocol downgrade attacks. The cryptography is sound; the failures are almost always operational: expired certs, missing intermediates, or misconfigured cipher suites. Automate everything you can, and you'll rarely think about TLS again.
Written by
Abhishek Patel
Infrastructure engineer with 10+ years building production systems on AWS, GCP, and bare metal. Writes practical guides on cloud architecture, containers, networking, and Linux for developers who want to understand how things actually work under the hood.
Related Articles
Certificate Management at Scale: Let's Encrypt, ACME, and cert-manager
Automate TLS certificates with Let's Encrypt, ACME protocol, and cert-manager in Kubernetes. Covers HTTP-01, DNS-01, wildcards, private CAs, and expiry monitoring.
9 min read
SecurityZero Trust Architecture: What It Means Beyond the Buzzword
Zero Trust eliminates implicit trust based on network location. Learn the five pillars, mTLS, SPIFFE/SPIRE, and a practical implementation roadmap.
8 min read
NetworkingDNS Explained: From Domain Name to IP Address, Step by Step
DNS translates domain names into IP addresses in milliseconds. Trace the full resolution chain step by step, learn every record type, and debug common failures like NXDOMAIN and SERVFAIL.
12 min read
Enjoyed this article?
Get more like this in your inbox. No spam, unsubscribe anytime.