Every HTTPS request begins with a small miracle of applied cryptography. Two machines that have never communicated before, exchanging messages over a network any number of parties can observe, must end up sharing a secret key — without ever sending that key across the wire. They also have to confirm the server is who it claims to be, and settle on which algorithms to use. All of this finishes before your first byte of application data moves. That negotiation is the TLS handshake, and it's worth understanding properly, because it explains a real share of your connection latency.
The three jobs of a handshake
A handshake exists to accomplish three things at once:
- Authentication — prove the server actually owns the domain you asked for, so you aren't talking to an impostor.
- Negotiation — agree on a cipher suite both sides support.
- Key establishment — derive symmetric session keys that will encrypt the actual traffic.
That third point surprises people: TLS uses public-key cryptography only to set up the connection. Asymmetric operations are computationally expensive, so once both sides hold a shared secret, everything after the handshake is protected with fast symmetric encryption. The expensive math happens once, up front.
The key that's never sent
The central trick is ephemeral Diffie-Hellman key exchange. Rather than one side inventing a key and shipping it to the other, both sides exchange public values and then independently compute the same shared secret from their own private value plus the peer's public one. An eavesdropper capturing every packet sees both public halves and still cannot derive the result. The secret is never transmitted, because it never needed to be.
"Ephemeral" is the important word. The key pair is generated fresh for this one connection and discarded afterward, which delivers forward secrecy: an attacker who records your encrypted traffic today and later steals the server's long-term private key still cannot decrypt those past sessions, because the keys that protected them no longer exist anywhere.
This is precisely what older TLS often failed at. The legacy RSA key transport mode had the client encrypt a pre-master secret with the server's static RSA public key — meaning that single long-lived private key could unlock every session ever recorded. TLS 1.3 removed static RSA key exchange outright, making forward secrecy structural rather than an option someone has to configure correctly.
Where the certificate fits
Diffie-Hellman gives you a shared secret with somebody — but it says nothing about who. On its own it's wide open to a machine-in-the-middle who runs one exchange with you and another with the real server.
That's the certificate's job. The server presents an X.509 certificate binding its domain name to a public key, signed by a Certificate Authority your system already trusts. Crucially, presenting the certificate isn't enough — anyone can copy a public certificate. The server must also prove it holds the matching private key, which it does by signing the handshake transcript. In TLS 1.3 that proof is the CertificateVerify message. Your client checks the CA signature chain, confirms the domain matches, verifies the certificate hasn't expired, and validates that signature. Only then is the peer authenticated.
One round trip
TLS 1.2 needed two round trips: the client said hello, the server replied with its parameters, and only then could the client send its key material. On a link with 100 ms latency, that's an extra 200 ms before any data flows — on top of the TCP handshake underneath it.
TLS 1.3's central optimization is a well-placed guess. The client sends its key share immediately, in the very first message: "the client sends its key share upfront in ClientHello, allowing the server to derive the shared secret immediately." It predicts which Diffie-Hellman group the server will pick and includes its public value straight away. The server can then compute the shared secret from that first message alone and reply with everything at once — ServerHello + key_share, {EncryptedExtensions, Certificate, CertificateVerify, Finished} — with most of that flight already encrypted.
The result: "TLS 1.3 completes a full handshake in 1 round trip (1-RTT), compared to TLS 1.2's 2-RTT." If the client guesses the group wrong, the server asks it to retry, costing an extra trip — but the common case is a hit.
One more detail worth knowing: the raw Diffie-Hellman output isn't used as a key directly. "TLS 1.3 uses HKDF (HMAC-based Key Derivation Function) to derive multiple keys" from it — separate keys for each direction and each stage, so no single key is overused.
# Illustrative: watch a real handshake, including the negotiated version and cipher
openssl s_client -connect example.com:443 -tls1_3 </dev/null 2>/dev/null \
| grep -E "Protocol|Cipher|Verify return code"
# Inspect the certificate chain the server presents
openssl s_client -connect example.com:443 -showcerts </dev/null 2>/dev/null \
| grep -E "subject=|issuer="Key Takeaways
- A handshake does three jobs: authenticate the server, negotiate a cipher suite, and establish symmetric session keys. Public-key crypto is only used for setup.
- Ephemeral Diffie-Hellman lets both sides compute a shared secret that is never transmitted, and discarding the keys afterward gives forward secrecy.
- TLS 1.3 removed static RSA key exchange, so forward secrecy is mandatory rather than a configuration choice.
- The certificate plus
CertificateVerifyis what stops a machine-in-the-middle — the server must prove it holds the private key, not merely present a certificate. - TLS 1.3 is 1-RTT vs TLS 1.2's 2-RTT because the client sends its key share in the
ClientHello; keys are then derived via HKDF.
