Start here: sending a password over a wire everyone can read#
TL;DRthe 30-second version
- TLS gives a TCP connection three guarantees: confidentiality (nobody on the path can read the bytes), integrity (nobody can change them undetected), and authentication (you're really talking to bank.com).
- The handshake lets two strangers agree on a secret key over a wire an eavesdropper is reading. The secret itself is never transmitted.
- Identity comes from a certificate: the server's public key tied to its domain, signed by a Certificate Authority (CA) your device already trusts.
- TLS 1.3 (2018) finishes the handshake in one round trip and makes forward secrecy mandatory. HTTPS is HTTP running inside this channel.
You're on café Wi-Fi and you log in to bank.com. With plain TCP and HTTP, every byte travels in the clear. The person at the next table with a packet sniffer, the café's router, and your ISP can all read your password. That's the confidentiality problem.
An attacker on the path can also rewrite messages, like the account number on a transfer. That's the integrity problem. And even if you could encrypt, how do you know the other end is really bank.com? An attacker could sit in the middle, relaying and reading everything. That's a man-in-the-middle, and shutting it out is the authentication problem. TLS has to solve all three, between two parties who share no secret in advance.
How the handshake works#
Symmetric encryption is the fast part: both sides hold the same key, and ciphers like AES-GCM run at gigabytes per second. The snag is that both sides need the same key first. If Alice sends it over the wire, Eve the eavesdropper reads it too.
The fix is a key exchange called Diffie–Hellman (DH). Each side generates a private value it never reveals and a public value it can broadcast. They swap the public values. Then each side combines its own private value with the other's public value and lands on the same shared secret. Eve sees both public values and still can't compute it, because reversing the math is infeasible. That shared secret becomes the session key, and it was never sent on the wire.
In TLS the DH keys are ephemeral: fresh for every connection, thrown away when it ends. That buys forward secrecy. If an attacker records your traffic today and steals the server's long-term private key next year, they still can't decrypt the recording. The per-connection DH keys are long gone.
Diffie–Hellman gets you a secret with whoever is on the other end. It says nothing about who that is. So the server also proves its identity. It has a separate long-term keypair and signs the handshake with the private key. To tie the matching public key to bank.com, it presents a certificate: an X.509 document binding that key to the domain, signed by a Certificate Authority (CA). Your operating system and browser ship with a few hundred trusted root CAs. A CA only signs for someone who proved they control the domain, so Eve can't get a certificate for bank.com. A self-signed one fails the check, and that's the scary browser warning.
PredictIn TLS 1.3 the client sends its key share in the very first message, before it has seen the server's certificate. Why is that safe?
The DH key share is just a public value. Revealing it leaks nothing, so sending it early costs nothing. The client won't send any sensitive data until it has verified the server's certificate and signature. If that fails, the handshake aborts and nothing was exposed.
Under the hood: how the certificate stops a man-in-the-middle
Without identity, Eve could do her own DH exchange with Alice while pretending to be the bank, and a separate one with the bank while pretending to be Alice. She'd hold two shared secrets and read everything in the middle. Here is why the certificate shuts that down.
- Root CAin your trust store (pre-trusted)
- Intermediate CAsigned by the root
- bank.com leaf certpublic key + domain, signed by intermediate
- Intermediate CAsigned by the root
- The certificate is public. Eve can copy bank.com's. But it holds only the public key; the matching private key never leaves the real bank.
- Proving you own a certificate means signing with its private key. Eve doesn't have it, so she can't.
- The server signs the handshake transcript, not a fixed phrase Eve could replay. That transcript includes the DH shares just exchanged.
- In a man-in-the-middle, Alice's transcript carries Eve's DH share, not the bank's. The real bank never signs a transcript with Eve's share in it. So any signature Eve can get is over the wrong shares, and Alice's check fails.
What it costs: round trips and CPU#
The dominant cost of TLS is latency, not CPU. Before any HTTPS byte flows, you pay TCP's handshake (1 round trip, or RTT) plus the TLS handshake on top.
| Setup | TLS round trips | First request after… | Notes |
|---|---|---|---|
| TLS 1.2, full handshake | 2 RTT | 3 RTT (incl. TCP) | The old default. |
| TLS 1.3, full handshake | 1 RTT | 2 RTT (incl. TCP) | Client's early key share cuts a round trip. |
| TLS 1.3, resumption (0-RTT) | 0 RTT | 1 RTT (incl. TCP) | Reuse a prior session; send data on the first flight. |
| QUIC / HTTP-3 | 0–1 RTT combined | 1 RTT (or 0) | TLS 1.3 is folded into the transport handshake itself. |
A round trip to a server 100 ms away costs 100 ms of waiting no matter how fast your CPU is. Two TLS round trips on a mobile connection can add a quarter-second before the first byte. The CPU cost is the handful of asymmetric operations in the handshake, which is why asymmetric crypto is used only to bootstrap. At scale you amortize the handshake with session resumption for returning clients, and you terminate TLS at a load balancer or CDN edge close to the user to shrink the round trip.
What TLS does and doesn't give you#
| TLS protects | TLS does not protect |
|---|---|
| The contents of your bytes (confidentiality) | That you're talking to bank.com at all. The IP and, without Encrypted Client Hello, the SNI hostname still leak. |
| Bytes from tampering in transit (integrity) | Anything once it's decrypted at the other end. A compromised server sees plaintext. |
| The identity of the server (authentication) | Whether that server is honest. A phishing site gets a valid certificate and the same padlock. |
| Past traffic if the server key later leaks (forward secrecy) | Traffic metadata. Packet sizes and timing can still leak information. |
The deepest trade-off is that TLS moves your trust rather than removing it. You no longer have to trust the network. You now have to trust the CA system: any root CA can, in principle, issue a certificate for any domain. The DigiNotar breach in 2011 issued fraudulent Google certificates. That's why Certificate Transparency exists: every issued certificate goes into public, append-only logs, so a domain owner can spot one they never requested.
If this comes up in an interview#
Why not just encrypt the session key with the server's public key and skip Diffie–Hellman?
That's the old RSA key exchange TLS 1.2 allowed, and it has no forward secrecy. If the server's private key is ever stolen, every recorded past session can be decrypted. Ephemeral DH makes a throwaway secret per connection, so a future key theft can't unlock the past. TLS 1.3 removed RSA key exchange for this reason.
We'll put the API behind HTTPS. Where does the protection stop?
At the TLS termination point. If TLS ends at the load balancer or CDN edge, the hop from there to your backend may be plaintext unless you secure it too. 'Behind HTTPS' says nothing about the internal network, the database connection, or data at rest. Name the termination point and what protects each leg after it.
What is mutual TLS, and when would you use it?
The client also presents a certificate, so both ends authenticate each other. It's overkill for public websites, because users don't have certificates. It's the backbone of zero-trust service meshes like Istio and Linkerd, where every service proves its identity instead of relying on network location.
Pitfalls & gotchas
- Expired certificates. A forgotten renewal is the number one real-world TLS outage (the browser shows NET::ERR_CERT_DATE_INVALID). Let's Encrypt fixed this with the ACME protocol: a script proves you control the domain and gets a 90-day certificate, auto-renewed. That is the single biggest reason the web went from about 40% to over 95% HTTPS.
- Self-signed certificates on the public internet. The encryption is identical, but no CA vouched for the key, so the client can't rule out a man-in-the-middle. Fine for internal testing where you control both ends.
- Downgrade attacks. An active attacker tampers with the ClientHello so both sides negotiate an older, weaker protocol or cipher. TLS 1.3 covers the whole transcript in the Finished check, so the altered negotiation is caught and the handshake aborts.
- Relying on revocation. Killing a certificate before it expires is messy: CRLs (big download lists) and OCSP (an online query per cert) both have availability and privacy problems. The industry leans on short-lived certificates and OCSP stapling instead.
- 0-RTT replay. On a resumed connection the client can send data in its very first flight, before the handshake's anti-replay protection is in place, so an attacker can capture and resend it. Only use 0-RTT for idempotent requests like GETs, never a 'transfer money' POST.
- HTTP downgrade. HSTS (HTTP Strict Transport Security) is a header that tells browsers to only ever use HTTPS for a domain, so an attacker can't push a user back to plain HTTP.
References
- RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3 — The authoritative spec: handshake, 1-RTT/0-RTT, mandatory forward secrecy.
- Cloudflare — A Detailed Look at RFC 8446 (TLS 1.3) — Readable walkthrough of what 1.3 changed and why.
- Let's Encrypt — How It Works (ACME) — Automated domain-validated certificate issuance and renewal.
- Certificate Transparency — Public append-only logs that make CA mis-issuance detectable.