The Handshake
29.0 What this chapter gives you#
- You will be able to state the three things a TLS connection promises you — secrecy, tamper-detection, and knowing who is at the far end — and say which of the three the mathematics gives you for nothing.
- You will be able to walk through a TLS 1.2 handshake message by message and say, for each message, what an eavesdropper learns from it and what it proves.
- You will be able to do the same for TLS 1.3, explain why one round trip replaced two, and name which messages moved inside the encryption.
- You will be able to separate key exchange from authentication, and name the single message that proves the server holds the private key belonging to the certificate it just sent.
- You will be able to describe what CertificateVerify signs, byte for byte, including the sixty-four space characters in front of it, and say what each part of that blob is there to prevent.
- You will be able to explain why the name of the site you are visiting travels in clear text, what Encrypted Client Hello does about it, and what it still does not fix as of August 2026.
- You will be able to draw the mutual-TLS message flow for both protocol versions and name the ways it fails in production.
- You will be able to explain session resumption, pre-shared keys and 0-RTT early data, and say exactly why early data can be replayed when ordinary data cannot.
- You will be able to run openssl s_client against a real server, read every line of its output, and decrypt a captured handshake in a packet analyser.
- You will be able to look at any handshake and say which parts of it proved an identity and which parts merely arranged a secret.
Two things happen when your browser connects to a bank. The first is that the traffic becomes unreadable to everyone in between: the coffee-shop wireless network, the internet provider, the country’s border routers, the data centre technician with a network tap. The second is that your browser satisfies itself that the unreadable traffic is going to the bank and not to somebody who has inserted themselves in the middle. Those are different achievements. They use different mathematics. They can be done well or badly independently of each other, and the most common misunderstanding in the whole of applied security is the belief that the first one implies the second.
It does not. Encryption without authentication gets you a private conversation with a stranger. You have kept the crowd out and let the impostor in. The whole purpose of the certificate machinery — the authorities of chapter 28, the chains of chapter 27, the certificate format of chapter 26 — is to hang an identity on one end of an encrypted pipe. But the certificate itself is only the paperwork. The moment where an identity is actually proved is a single message inside the handshake, and if you cannot name it, you are following a ritual rather than reading a protocol.
This chapter is about that handshake: the short conversation, measured in milliseconds and a few thousand bytes, in which two machines that have never met agree on a secret, agree on which of them is who, and agree on what was said, all while a hostile network carries every word. We will do it twice, for TLS 1.2 and for TLS 1.3, because the world still runs both and the differences are where the interesting mistakes live, reading real bytes from captures taken while this chapter was written. And we will keep returning to the only question that matters here: which message proved something, and what did it prove?
One boundary, stated once. Certificates can be cancelled before they expire, and the mechanisms for announcing that are a subject of their own that chapter 30, “Revocation”, handles. We take the certificate as given and ask what the handshake does with it.
The plain version#
The stall in the covered market#
Picture an enormous covered market. Thousands of stalls, thousands of customers, and a crowd so dense that everything anybody says is overheard by dozens of people. You want to buy something from a jeweller called Rekha, and you will have to say your card number out loud to do it.
Three problems, and they are separate problems.
First, the crowd will hear your card number. You need a way of speaking to Rekha that the crowd cannot follow, even though the crowd hears every sound you both make.
Second, somebody in the crowd may change what you said as it travels. If you say “send me the small ring” and a helpful bystander repeats it as “send me the large ring”, you need to find out.
Third, and this is the one people forget, you need to be sure that the person answering you is Rekha. The market is dark and crowded. Anybody can stand in front of Rekha’s stall and answer to her name.
A market solves these three problems with three different tricks, and so does a computer. Keeping the crowd out is one, detecting changes is a second, and knowing who you are speaking to is a third, which is the hardest of them, because unlike the other two it cannot be solved by cleverness alone. It needs somebody who checked something in advance.
Two people shouting numbers agree on a secret#
Here is the trick that lets two strangers agree a secret while everybody listens. It sounds impossible the first time you meet it.
You and Rekha each pick a private number and keep it to yourselves. You each perform a public calculation on your private number, one that is easy to do forwards and effectively impossible to undo, and shout the answer across the stall. The crowd hears both shouted answers. Then you take her shouted answer and combine it with your private number; she takes yours and combines it with hers. Because of the way the calculation is built, you both end up holding the same result, and the crowd, holding only the two shouted answers, cannot get to it.
The colour version is easier to hold in your head. You each start with a pot of yellow paint that everyone can see. You add a splash of your own secret colour and stir; she does the same with hers. You swap the mixed pots in full view. Now you add your secret colour to her mixture, and she adds hers to yours. Both pots end up the same shade, and anyone watching saw two mixed pots go past and cannot separate the paint back out.
That shared shade is your secret code for the rest of the conversation. Both of you scramble everything you say with it, and the crowd hears noise. Problem one solved. Problem two comes almost free: along with each scrambled sentence you attach a short tag computed from the sentence and the secret shade, so that changing even one word makes the tag wrong. Problem two solved.
Now hold on to the important part, because everything else in this chapter hangs off it.
Nothing in that paint-mixing tells you who you mixed paint with.
You mixed with whoever was standing at the stall. If a stranger stepped in front of Rekha and mixed with you, the mixing worked perfectly. You have a beautiful private channel to a person you cannot name. The secrecy trick and the identity trick are separate, and no amount of extra cleverness in the mixing will fix that, because the mixing has no opinion about who is holding the pot.
The sealed card is not the proof#
So the person at the stall has to prove they are Rekha. The first thing they do is hand you a card issued by an office in town that checks such things. The card says: the person who can open the blue lockbox marked with this pattern is Rekha the jeweller, and it is sealed by the office so nobody can alter the words. Your family has trusted that office for years, and you can recognize its seal.
Almost everybody stops here, and it is wrong. The card is a piece of paper, and a piece of paper can be picked up anywhere. Rekha’s real card is public; she gives a copy to every customer, all day, every day, so the impostor could have collected one this morning. What the card says is a conditional: whoever can do a particular thing — open that blue lockbox, use that private knowledge — is Rekha. It does not say that the person handing it to you can do that thing. The card is a claim about someone who is not necessarily present.
The proof has to be a demonstration. The person at the stall must do the thing that only Rekha can do, and they must do it here, now, in front of you, in a way that cannot be prepared in advance or replayed from a recording of an earlier customer’s visit.
The signature that repeats the conversation back#
Here is the demonstration. The person at the stall takes a sheet of paper and writes on it a summary of everything said at this stall in this conversation so far: your opening greeting word for word, including the random gibberish word you threw in at the start; their reply, including the random word they threw in; the pot of paint they showed you; the card they handed over. Every word, in order. Then they sign that summary using the private knowledge the card is about, and hand you the signature.
Now think about what an impostor would need. The summary contains the random word you invented thirty seconds ago and have never said before. No signature prepared in advance can match it. The summary contains the exact paint pot that was shown to you in this conversation, so a recording of Rekha signing yesterday’s conversation is useless. The signature can only have been produced, in the last few seconds, by somebody holding Rekha’s private knowledge.
That is the moment identity is proved. Not the card. The signature over the conversation. If you remember one thing from this chapter, remember that the card is a claim and the signature over the transcript is the proof.
Reading the whole conversation back to each other#
There is a last step, and it is a lovely piece of design. Once you both hold the shared paint shade, each of you writes out the entire conversation so far from your own notes, scrambles it with the shared shade, and hands it across. Each checks that the other’s version matches their own.
The signature already settled who is who, so this catches a different case. Suppose somebody in the crowd quietly altered the very first thing you shouted, the list of scrambling methods you said you could handle, so that you and Rekha ended up agreeing on a weak one the crowd can break. Reading the conversation back catches it, because your memory of what you shouted and Rekha’s memory of what she heard would not match. It also proves both of you derived the same shade, so neither is about to start talking in a code the other cannot read.
The name you have to shout before anyone can answer#
One awkwardness. Rekha’s stall is not really a stall. In the modern market, one counter serves hundreds of traders, and the clerk behind it needs to know which trader you want before he can produce the right card. So the very first thing you say, before any paint is mixed and before anything is private, is the name of the trader you are looking for. You have to shout it, in the open, in front of the crowd.
That is a real privacy hole and everybody knows it. There is a fix, only recently finished, in which you shout the name of the building rather than the trader, and hand over a sealed envelope containing the trader’s name that only the building’s front desk can open. It works. It is also useless if the crowd can see you looking up the trader’s address in a public directory on your way to the market, which most people still do in plain sight.
The chit for coming back tomorrow#
Doing the whole ritual — paint, card, signature, read-back — takes time, and you visit Rekha’s stall forty times a day. So at the end she hands you a chit: a slip of paper that means nothing to anyone else, which she can recognize as one of her own. Come back with the chit and you skip the card and the signature. You show the chit, you both use it to derive a fresh shade of paint, and you are talking in seconds.
Two things about that chit deserve care. The first is that on the second visit, nobody proved anything about identity. The chit only means “the person holding this had a proper conversation with me earlier”; the proof of who Rekha is happened yesterday and is being inherited.
The second is what happens when you get greedy. If you are in a hurry you can shout your order at the same moment you hand over the chit, before any of the back-and-forth. That saves a whole exchange. But now your order is carried on nothing but yesterday’s secret, and yesterday’s secret does not know that today is today. Somebody in the crowd who recorded you doing this can walk up tomorrow, replay the recording of you handing over the chit and shouting “send me the large ring”, and it will work. Your order will be placed twice. That is not a bug that better paint can fix. It is a consequence of speaking before the other side has said anything fresh.
When the stall asks for your card#
Sometimes it runs the other way. Some traders will not deal with the public at all and serve only customers carrying a card from the same office. The clerk asks you for your card, and you must do exactly what Rekha did: produce the card, then sign a summary of the conversation to show that the card is yours and not one you found on the floor.
It fails in two extra places. Ordinary customers do not carry cards, so this only makes sense between machines set up in advance. And in the newer version of the ritual the trader finishes his own side of the conversation and seals the deal from his end before discovering that your card is unacceptable, so you can walk away believing you have a deal a full second before the refusal arrives.
At this point the plain names can be swapped for the real ones. The ritual is called TLS, the letters standing for transport layer security. The paint-mixing is a key exchange. The card is a certificate. The signature over the summary of the conversation is a message called CertificateVerify. The reading-back is a message called Finished. The name you shout at the start is called Server Name Indication, the sealed envelope is Encrypted Client Hello, and the chit is a session ticket. Everything else in this chapter is detail on top of the shape you now have.
Where the plain version stops being true#
Nobody mixes paint, and the pots are burned afterwards#
The paint story hides the single most valuable property of a modern handshake. Real key exchange does not reuse a secret colour. Each machine generates a brand new private number for each connection, uses it once, and destroys it when the connection ends.
That matters enormously. If Rekha used the same private shade all year, then somebody who recorded a year of conversations and later stole that shade could unscramble all of them retrospectively. Because the private numbers are fresh per connection and thrown away, a thief who breaks into the server tomorrow and takes everything on the disk still cannot read yesterday’s recorded traffic, and the certificate’s private key does not help either, because that key was used to sign rather than to encrypt.
The honest version: the property is called forward secrecy, and it is not automatic. It is a property of the particular key exchange chosen during the handshake. TLS 1.2 also permitted a mode in which the client encrypted the secret directly to the server’s certificate key, which has no forward secrecy at all; anybody with that key and a recording could decrypt everything, for ever. TLS 1.3 removed that mode from the protocol entirely. That removal, not the speed, is the most important thing about TLS 1.3.
The card is dangerous in a way the analogy softens#
In the market, you know the office that seals the cards. A browser trusts well over a hundred organizations, scattered across many jurisdictions, any one of which can issue a card for any name, and the handshake accepts a card from any of them without comment. Chapter 28 covers who those organizations are and what they check, and chapter 35 covers what happens when one of them fails.
The name is shouted, but so is the address lookup#
The fix, the sealed envelope, is often described as though it makes your browsing private, and it does not, by itself. Before your machine can connect at all it has to turn the name into an address, and that lookup normally travels in clear text to whichever directory service your network points at. If that lookup is visible, sealing the name inside the handshake buys very little, because an observer watched you ask for the address thirty milliseconds earlier. The envelope is also useless unless many traders share one front desk: if you are the only trader behind it, hiding your name inside the envelope tells the watcher nothing they could not infer from the address they saw you dial.
The honest version: hiding the server name is a property of a whole system — encrypted address lookups, plus a large shared front end, plus the sealed envelope — and not of any one message.
There is no conversation; there are records, and the record layer lies#
The market analogy has two people speaking in turns. The real protocol has a packing layer underneath the handshake that chops everything into records and labels each one, and that labelling causes a great deal of confusion, because the version number on the outside of a record is a fossil. A modern TLS 1.3 connection sends its first record labelled version 1.0 and every subsequent record labelled 1.2, and negotiates 1.3 in an extension inside. The outside label is deliberately a lie, told to network equipment that would otherwise drop anything it did not recognize.
The handshake also does not stop when the conversation starts. New chits, key changes and in some configurations a demand for the client’s card all arrive after the connection is in use, so anything that assumes the handshake is a self-contained prelude will eventually be surprised.
The signature proves possession, not virtue#
The signature proves that whoever is at the far end holds the private key matching a certificate for the name you asked for. It proves nothing else, and four of the things it does not prove are worth saying out loud.
It does not prove the far end is the organization you have in mind; it proves control of a name, and if the name merely resembles the one you meant, the handshake is perfectly happy. It does not prove the far end is a computer at that organization, because content delivery networks and cloud load balancers legitimately hold private keys for names they do not own, with the name owner’s consent, and your handshake terminates at their machine. It does not prove the private key is on that machine at all: it may sit in a hardware module in another rack or another country. And it proves nothing about the application, so a correct handshake to a correctly named server running vulnerable software is still a correct handshake.
A successful handshake can end at a box that is not the server#
This is easy to demonstrate. The machine on which this chapter was written sits behind a network gateway that terminates TLS, inspects the traffic and makes its own connection onwards. Every handshake from that machine succeeds and every certificate verifies. Here is what a connection to a well-known public site actually returned:
depth=0 CN = pypi.org
verify return:1
Certificate chain
0 s:CN = pypi.org
i:O = Anthropic, CN = Egress Gateway SDS Issuing CA
1 s:O = Anthropic, CN = Egress Gateway SDS Issuing CA
i:O = Anthropic, CN = sandbox-egress-gateway CA
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Verification: OK
The name on the certificate is right and the verification passed, but the issuer is not a public certificate authority at all; it is the gateway, whose root was installed into this machine’s trust store when the machine was built. The handshake proved that the far end holds a private key for a certificate naming that site, signed by something this machine trusts. All of that is true. It is simply not the site.
The honest version: a handshake authenticates the endpoint that terminates it, against the trust store you are carrying. Both halves of that sentence are load-bearing. Change the trust store and you change what the handshake means.
One round trip is a claim about the protocol, not about your waiting time#
TLS 1.3 is described everywhere as a one-round-trip handshake, and it is, but the phrase measures only the part after the connection exists. Before it come a name lookup and a connection setup. A first visit to a site on a link with 40 milliseconds of one-way delay spends roughly 80 milliseconds establishing the connection and another 80 on the handshake before the request can go out.
The honest version: the number to compare is round trips before the first byte of your request can be sent. Over classic transport, TLS 1.2 costs three, TLS 1.3 costs two, and TLS 1.3 with a chit and early data costs one. Over the newer transport used by HTTP/3, where the connection setup and the handshake are merged, a full handshake costs one and a resumed one costs zero.
The chit inherits an identity decision that may have gone stale#
Resumption is presented as a pure speed optimization, but it is also a decision to carry forward a judgement made earlier. When you resume, no certificate is presented and nothing is verified; the server’s identity is inherited from the original handshake, which may have been hours ago, and if the certificate was cancelled in the meantime, resumption does not notice. That is one reason the standard caps how long a chit may live, and one of the reasons the industry has turned to short certificate lifetimes instead of cancellation, which is chapter 30’s subject.
The client’s card says even less than the server’s#
When the trader asks for your card, what he learns is that you hold a private key whose certificate was signed by an authority he chose to trust. That is worth having between two machines configured together, but it is not a statement about a human being. The key may sit in a file readable by every process on a shared build server, or have been copied to a laptop, or belong to a service account that forty engineers can deploy. Treating a client certificate as proof of a person is a category error, and it is made constantly in security architecture diagrams.
The technical version#
What TLS provides, and the layers it arrives in#
Transport Layer Security, specified for version 1.3 in RFC 8446 of August 2018 and republished as RFC 9846 in July 2026, provides three properties to the application above it.
Confidentiality: data written into the connection is encrypted with keys known only to the two endpoints, so a party on the path learns nothing about the content beyond its timing and approximate length.
Integrity: data is protected by an authenticated encryption construction, so any modification, reordering, replay or truncation of records is detected and the connection is torn down rather than silently corrupted.
Server authentication: the client obtains cryptographic evidence that the endpoint terminating the connection holds the private key for a certificate naming the host the client asked for, and that the certificate chains to a trust anchor the client already holds.
Client authentication is optional and off by default. Everything else people attribute to TLS — that the site is honest, the software patched, the data stored safely, the operator who the brand suggests — is outside the protocol.
One further property is worth naming because it is not obvious: negotiation integrity. The handshake is built so that an attacker on the path cannot steer the endpoints into a weaker choice of algorithm than they would have made alone, and the mechanism in both versions is the same, which is that everything anybody said is fed into the final checks.
Now the layering, because the handshake does not sit directly on the network. TLS sits on a reliable byte stream and imposes a record layer on it. Each record has a five-byte header: one byte of content type, two bytes of a legacy version field, two bytes of length. The content types are 20 for change cipher spec, 21 for alert, 22 for handshake, and 23 for application data.
The handshake is a sequence of messages carried inside records of content type 22. Each handshake message has a four-byte header of its own: one byte of message type and three bytes of length. The types that matter here are 1 for ClientHello, 2 for ServerHello, 4 for NewSessionTicket, 5 for EndOfEarlyData, 8 for EncryptedExtensions, 11 for Certificate, 12 for ServerKeyExchange, 13 for CertificateRequest, 14 for ServerHelloDone, 15 for CertificateVerify, 16 for ClientKeyExchange, 20 for Finished, and 24 for KeyUpdate.
In TLS 1.3 the record’s version field is frozen. The specification requires it to carry 0x0303, the value that once meant TLS 1.2, on every record except the first, where 0x0301 is permitted. Here is the evidence from a real capture, made with OpenSSL against a live public server while writing this chapter:
>>> TLS 1.0, RecordHeader [length 0005]
>>> TLS 1.3, Handshake [length 00ed], ClientHello
<<< TLS 1.2, RecordHeader [length 0005]
<<< TLS 1.3, Handshake [length 007a], ServerHello
The record headers claim 1.0 and 1.2; the messages inside are TLS 1.3. This is a standard requirement, not an implementation quirk, and it exists because middleboxes that inspected the version field dropped connections carrying anything they had not seen before. Encrypted records disguise themselves further: the real content type moves inside the encrypted body and the outer type is set to 23, application data, for every encrypted record including handshake records.
TLS 1.2, message by message, and what each proves#
RFC 5246, published in August 2008 and now obsoleted by RFC 9846, defines the full handshake in its section 7.3. Here is a real TLS 1.2 exchange, captured against a live server, with the record headers stripped for readability:
>>> TLS 1.2, Handshake [length 00c8], ClientHello
<<< TLS 1.2, Handshake [length 003f], ServerHello
<<< TLS 1.2, Handshake [length 0aac], Certificate
<<< TLS 1.2, Handshake [length 012c], ServerKeyExchange
<<< TLS 1.2, Handshake [length 0004], ServerHelloDone
>>> TLS 1.2, Handshake [length 0025], ClientKeyExchange
>>> TLS 1.2, ChangeCipherSpec [length 0001]
>>> TLS 1.2, Handshake [length 0010], Finished
<<< TLS 1.2, Handshake [length 00ca], NewSessionTicket
<<< TLS 1.2, ChangeCipherSpec [length 0001]
<<< TLS 1.2, Handshake [length 0010], Finished
Taking them in order.
ClientHello carries a 32-byte client random, a session identifier, an ordered list of cipher suites, a compression list that must now contain only the null method, and extensions: the server name requested, the signature algorithms the client accepts, the elliptic curve groups it supports, the application protocols it can speak. It proves nothing; it commits the client to a set of choices and contributes freshness.
ServerHello carries a 32-byte server random, the chosen cipher suite and the server’s selected extensions. It proves nothing, and contributes the other half of the freshness. Certificate carries the server’s certificate and usually the intermediates needed to build a chain. It proves nothing either: it is a claim, and public data anybody can collect from the same server.
ServerKeyExchange is where a TLS 1.2 handshake with forward secrecy does its real work. For an ECDHE suite it carries the named group, the server’s ephemeral public key, and a signature computed with the private key belonging to the certificate over the concatenation of the client random, the server random and those key exchange parameters. That signature is the proof of possession. It is fresh because it covers the client’s random value, which the client invented moments earlier.
CertificateRequest, present only when the server wants client authentication, lists acceptable certificate types, acceptable signature algorithms, and acceptable certificate authority names. ServerHelloDone is an empty marker, four bytes on the wire, saying this flight is over.
ClientKeyExchange carries the client’s ephemeral public key for ECDHE suites, or, in the static RSA mode, the premaster secret encrypted to the server’s certificate key. CertificateVerify, sent by the client only when it is authenticating, carries a signature over every handshake message so far. ChangeCipherSpec is not a handshake message at all but a single byte in its own content type, meaning “from my next record onwards I am using the newly negotiated keys”.
Finished carries 12 bytes of verify data by default, computed by the protocol’s pseudorandom function over the master secret and a hash of the entire handshake transcript, with the label “client finished” or “server finished”. It proves that both sides derived the same master secret and saw the same messages.
Two subtleties are worth having.
In the static RSA mode there is no ServerKeyExchange and therefore no signature. Possession of the private key is proved only implicitly: the server cannot compute the correct Finished unless it decrypted the premaster secret. That construction is why the Bleichenbacher attack of 1998 against RSA encryption padding, and its many descendants, kept returning for two decades, and it is why TLS 1.3 deleted the mode.
The master secret in plain TLS 1.2 is derived from the premaster secret and the two randoms alone, which allowed the triple handshake attack published in 2014 to relate two different connections. The fix, RFC 7627 of September 2015, binds the master secret to a hash of the handshake instead. It is an extension, so it has to be negotiated; TLS 1.3 builds the equivalent binding in structurally.
TLS 1.3: the same job in one round trip#
RFC 8446 restructured the flight order so that the server can send everything it needs to send immediately after ServerHello, and so that everything after ServerHello is encrypted. Here is the real capture, again with record headers removed:
>>> TLS 1.3, Handshake [length 00ed], ClientHello
<<< TLS 1.3, Handshake [length 007a], ServerHello
<<< TLS 1.3, Handshake [length 0006], EncryptedExtensions
<<< TLS 1.3, Handshake [length 0ab3], Certificate
<<< TLS 1.3, Handshake [length 0108], CertificateVerify
<<< TLS 1.3, Handshake [length 0034], Finished
>>> TLS 1.3, ChangeCipherSpec [length 0001]
>>> TLS 1.3, Handshake [length 0034], Finished
Three changes are visible in that list and one is invisible.
The client sends its key share in the very first message, guessing which group the server will choose. If the guess is right, and it almost always is, the server derives the shared secret the moment it reads ClientHello, so its entire response can be encrypted from EncryptedExtensions onwards. That is how one round trip is achieved: not by removing messages but by removing the wait for the server to state its parameters.
The certificate is now inside the encryption, so a passive observer of a TLS 1.3 connection does not see which certificate was served; in TLS 1.2 it was in clear text for anyone on the path to collect. EncryptedExtensions is new, and carries the server’s responses to extensions not needed to establish keys — the acknowledgement of the server name, the negotiated application protocol — which is the point of splitting it out from ServerHello.
The invisible change is version negotiation. A TLS 1.3 ClientHello still writes 0x0303 in its legacy version field and announces 1.3 in the supported_versions extension, number 43, so a middlebox that reads only the legacy field sees a TLS 1.2 handshake.
The ChangeCipherSpec in that capture is pure theatre. RFC 8446 Appendix D.4 defines a middlebox compatibility mode in which both sides send a dummy change cipher spec record and the client echoes a non-empty session identifier, purely so equipment on the path believes it is watching a familiar TLS 1.2 resumption. This is a standard, deliberately specified as fiction, and it exists because of a measurement: when Cloudflare and browser vendors tried early drafts in December 2017, connection success rates fell from 97.8 per cent with TLS 1.2 to 96.1 per cent with TLS 1.3 for Firefox against Cloudflare, and from 98.3 to 92.3 per cent for Chrome against Gmail. Those percentage points are millions of broken connections, caused not by servers but by boxes in the middle. The specification went to 28 drafts between April 2014 and August 2018, and the compatibility mode is the scar tissue.
If the client guesses the wrong group, the server sends a HelloRetryRequest, a ServerHello carrying a fixed special random value, and the client sends a second ClientHello with a share for the requested group. That costs an extra round trip and is the one common case where TLS 1.3 is not one round trip.
| Property | TLS 1.2 | TLS 1.3 |
|---|---|---|
| Round trips to first byte | 2 | 1 |
| Server certificate | in clear | encrypted |
| Client certificate | in clear | encrypted |
| Static RSA key exchange | allowed | removed |
| Renegotiation | allowed | removed |
| Extended master secret | extension | built in |
Key exchange and authentication are two separate jobs#
The most useful discipline when reading a handshake is to sort every message into one of two piles: the pile that establishes a shared secret, and the pile that establishes who you are sharing it with.
The secret pile in TLS 1.3 contains exactly two messages, the key_share extension in ClientHello and the key_share extension in ServerHello. Each carries an ephemeral public key. The shared secret is computed by each side from its own private value and the other’s public value, and both private values are discarded when the connection closes. The default group in almost every current client is x25519, registry value 29; the traditional elliptic curve alternative secp256r1 is value 23.
The identity pile contains Certificate, the claim, and CertificateVerify, the proof. Nothing in the key exchange contributes to identity, and nothing in the identity messages contributes to the secret.
This separation is why post-quantum migration has proceeded in two independent stages. Key exchange is the urgent half, because traffic recorded today can be decrypted later if a capable quantum computer is ever built, whereas a signature that cannot be forged today cannot be forged retrospectively. Key exchange therefore moved first, using hybrid groups that combine a classical elliptic curve with a lattice-based mechanism so that breaking either alone is not enough. RFC 10024 of August 2026 standardizes those groups; the widely deployed one, X25519MLKEM768, is registry value 4588 and the only post-quantum entry marked as recommended. Cloudflare reported in March 2024 that nearly two per cent of TLS 1.3 connections to its network used post-quantum key agreement, and in April 2026 that over 65 per cent of human traffic did, while setting 2029 as its target for post-quantum authentication. The two piles are on visibly different timetables, which is the clearest practical proof that they are different problems.
| Job | Message | Fails if |
|---|---|---|
| Secret | key_share (both sides) | group broken |
| Identity | Certificate | chain invalid |
| Identity | CertificateVerify | key not held |
| Agreement | Finished | transcripts differ |
A real ClientHello, byte by byte#
Here is an actual TLS 1.3 ClientHello, captured for this chapter on a connection to a test server running on the same machine, which is why the name inside it is localhost. It is 238 bytes including its four-byte header.
01 00 00 ea 03 03 5f 50 c6 d1 af 9c 6b 07 4b 3e
37 33 b6 0f 52 b9 dc 44 f2 76 c2 ce 68 31 00 c9
6e 4c fd fb b8 dc 20 b6 b5 67 81 7e d5 5d 0c d7
13 22 22 af 92 1e 09 29 04 f0 30 ed 21 24 8f 52
51 59 4b ac 2f f5 8e 00 08 13 02 13 03 13 01 00
ff 01 00 00 99 00 00 00 0e 00 0c 00 00 09 6c 6f
63 61 6c 68 6f 73 74 00 0b 00 04 03 00 01 02 00
0a 00 16 00 14 00 1d 00 17 00 1e 00 19 00 18 01
00 01 01 01 02 01 03 01 04 00 23 00 00 00 16 00
00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 06
03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08
06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 2d
00 02 01 01 00 33 00 26 00 24 00 1d 00 20 c4 47
17 1d e3 af 7f b5 77 3a 4a e0 d2 7b 15 00 2d f5
ed 89 d1 b0 a7 0c b6 d0 22 b3 2d 90 08 50
Parsing it in order, which anybody can reproduce with a few lines of script: the first byte, 01, is the handshake message type, ClientHello, and the next three, 00 00 ea, are the length, 234 bytes of body. Then 03 03, the legacy version, meaning TLS 1.2 regardless of what is actually being negotiated, and 32 bytes of client random beginning 5f 50 c6 d1.
Then 20, a length of 32, followed by a legacy session identifier beginning b6 b5 67 81. In TLS 1.3 that field has no protocol meaning; it is filled with random bytes only so the exchange resembles a TLS 1.2 session to anything watching.
Then 00 08, eight bytes of cipher suites: 13 02, 13 03, 13 01 and 00 ff. The first three are TLS_AES_256_GCM_SHA384, TLS_CHACHA20_POLY1305_SHA256 and TLS_AES_128_GCM_SHA256. The fourth is not a cipher suite at all but a signalling value meaning “this is an initial handshake and I support secure renegotiation”, specified in RFC 5746 of February 2010 after the renegotiation vulnerability disclosed in 2009. Then 01 00, one compression method, null, and then 00 99, 153 bytes of extensions, of which four matter here.
00 00 00 0e 00 0c 00 00 09 6c 6f 63 61 6c 68 6f
73 74
Extension 0 is server_name, 14 bytes long: a list of 12 bytes, containing entry type 0 (host name) of length 9, whose bytes spell localhost. That is the name of the site, in clear text, in the first message, before any key exists.
00 2b 00 03 02 03 04
Extension 43 is supported_versions: a list of one two-byte version, 0x0304, which is TLS 1.3. This is the field that actually negotiates the version.
00 33 00 26 00 24 00 1d 00 20 c4 47 17 1d ...
Extension 51 is key_share, 38 bytes: a client shares list of 36 bytes, containing group 0x001d (x25519) with a 32-byte public key beginning c4 47 17 1d. That single field is the client’s entire contribution to the secret.
00 2d 00 02 01 01
Extension 45 is psk_key_exchange_modes, announcing mode 1, psk_dhe_ke, meaning “if we ever resume, I insist on mixing in a fresh key exchange as well”. Mode 0, psk_ke, resumes on the ticket alone and has no forward secrecy.
The remaining extensions are supported_groups (number 10, listing x25519 first, then secp256r1, x448, secp521r1, secp384r1 and five finite-field groups) and signature_algorithms (number 13, listing 14 acceptable schemes beginning 04 03, ecdsa_secp256r1_sha256).
CertificateVerify and Finished: the proof and the agreement#
RFC 8446 section 4.4.3, which is section 4.5.2 in the July 2026 republication as RFC 9846, defines the message. Its body is short: two bytes naming the signature scheme, two bytes of length, and the signature.
What is signed is not the certificate, and not the handshake bytes directly. It is a constructed blob, assembled in this order:
- 64 bytes, every one of them 0x20, the ASCII space character.
- A context string, in ASCII, either “TLS 1.3, server CertificateVerify” or “TLS 1.3, client CertificateVerify”.
- One byte of zero, as a separator.
- The transcript hash: a hash over every handshake message from ClientHello up to and including the Certificate message just sent.
Every part earns its place. The transcript hash makes the signature fresh and unrepeatable: it covers the client’s random value and the client’s key share, both invented seconds earlier, so no recorded or precomputed signature can match. The context string separates a server signature from a client signature, so one cannot be replayed as the other. And the 64 spaces exist so the signed blob can never be confused with a structure signed for another purpose in another protocol version; a verifier of TLS 1.2 signatures, which cover the two randoms followed by key exchange parameters, never sees 64 spaces at the front.
The size of this message in the capture is exactly what the theory predicts. It was 0x0108 bytes, 264 in decimal: four bytes of handshake header, two of signature scheme, two of length, and 256 bytes of signature, precisely the size of an RSA signature under a 2048-bit key.
One rule catches implementers: TLS 1.3 forbids the old PKCS number 1 version 1.5 signature schemes in CertificateVerify. An RSA key must sign with the PSS padding schemes, whose codepoints begin 08 04, 08 05 and 08 06. The older 04 01 codepoints may still appear in the client’s list, because they remain permitted for signatures inside certificates, but not for this message. That is why OpenSSL prints “Peer signature type: RSA-PSS” for a TLS 1.3 server with an RSA certificate.
In TLS 1.2 the equivalent proof lives in ServerKeyExchange and covers only the client random, the server random and the key exchange parameters. That is a smaller commitment than TLS 1.3’s, which covers the whole transcript, and the difference is the sort of gap that cross-protocol attacks live in.
Finished is the other half of the pair: a message authentication code over the transcript, keyed by a value derived from the handshake secret with the label “finished”, whose length is the length of the negotiated hash, so 32 bytes with SHA-256 and 48 bytes with SHA-384. The capture confirms it. The TLS 1.3 Finished messages were 0x0034 bytes, 52 in decimal, being 4 bytes of header plus 48 of verify data under TLS_AES_256_GCM_SHA384; the TLS 1.2 ones were 0x0010, 16 bytes, being 4 bytes of header plus the 12 bytes of verify data that version uses by default.
Finished proves three things at once. Key confirmation: both sides really did derive the same secrets. Transcript agreement: both saw byte-for-byte the same handshake, so tampering with the negotiation is caught before application data flows. And in a resumed connection, where no certificate and no signature appear, the server’s Finished is the only proof that the far end holds the resumption secret.
A second downgrade defence is worth knowing. A server that supports TLS 1.3 but negotiates TLS 1.2 must plant a sentinel in the last eight bytes of its server random: the ASCII bytes for DOWNGRD followed by 0x01, or ending 0x00 for a downgrade to TLS 1.1 or below. A TLS 1.3-capable client seeing that sentinel knows an attacker forced the downgrade and aborts, and because the server random is covered by both the signature and the Finished check, it cannot be stripped.
Server Name Indication, and Encrypted Client Hello#
Server Name Indication is defined in RFC 6066 of January 2011, section 3, which carried it forward from RFC 4366 of April 2006 and RFC 3546 before that. It is extension number 0. The name is a list of entries, each with a type byte, of which only host_name, type 0, has ever been defined. The rules are strict: the name is the ASCII host name, without a trailing dot, and literal IP addresses are not permitted. A server that does not recognize the name may send the alert unrecognized_name, number 112, though in practice most servers serve a default site instead.
SNI exists because one address serves many names: a server holding a thousand certificates has no other way to know which to present, since the certificate must be chosen before anything is encrypted. The cost is that the most sensitive routing information in the connection travels in the very first message in clear text, as the byte dump above shows.
Encrypted Client Hello closes that hole. Its long journey ended with publication as RFC 9849 in March 2026, its DNS half appearing the same month as RFC 9848. The server operator publishes an ECHConfig — a public key, a cipher suite list, and a public_name naming the front-end operator rather than the customer — and the client fetches it from DNS in the HTTPS resource record type defined by RFC 9460 of November 2023.
The client then constructs two ClientHello messages. The ClientHelloInner contains the truth: the real server name and the client’s real preferences. The ClientHelloOuter contains the public_name in its SNI field and otherwise innocuous values. The inner one is encrypted to the published key using Hybrid Public Key Encryption, RFC 9180 of February 2022, and carried inside the outer one in extension number 65037. A front-end server that can decrypt proceeds with the inner hello, and the customer’s name never appears on the wire. One that cannot, because the key has rotated, completes the handshake against the public name and returns a fresh configuration in a retry_configs field for the client to retry with. Clients are told to send a fake, randomized ECH extension when they have no configuration at all, so that using ECH does not by itself mark a connection as interesting.
Two limits are stated in the specification itself. The privacy gain depends on the size of the anonymity set, so section 10.1 tells operators to use one configuration for as many names as possible: if one customer sits alone behind a front end, the outer name identifies the inner one. And ECH protects the handshake, not the name lookup before it; without encrypted DNS the observer already knows where you are going.
Deployment, as of the most recent measurement study available in August 2026, is thin and highly concentrated. The paper “The Fragile Privacy of Encrypted Client Hello”, presented at IFIP Networking 2026 by Hajda, Oezdil, Bauer, Hoffmann and Bajpai, scanned 13,428,012 domains and found ECH support on 8.2 per cent of them, of which 99.99 per cent sat behind a single provider; on the client side it found an average of 21.46 per cent of Firefox connections attempting ECH. Firefox introduced the feature in version 118 and enabled it by default in version 119, in the autumn of 2023, and Chrome shipped it enabled by default in milestone 117 the same season.
| ECH fact | Value | As of |
|---|---|---|
| Standard | RFC 9849 | March 2026 |
| DNS bootstrap | RFC 9848 | March 2026 |
| Extension number | 65037 | March 2026 |
| Domains supporting | 8.2 per cent | IFIP 2026 study |
Client certificates and mutual TLS#
Mutual TLS means the client is authenticated by certificate as well as the server, and the message flow is the mirror image of the server’s. This is a genuine TLS 1.3 handshake between an OpenSSL client and an OpenSSL server configured to require a client certificate, run for this chapter:
>>> ClientHello
<<< ServerHello
<<< {EncryptedExtensions} [length 0006]
<<< {CertificateRequest} [length 0055]
<<< {Certificate} [length 066a]
<<< {CertificateVerify} [length 0108]
<<< {Finished} [length 0034]
>>> {Certificate} [length 0658]
>>> {CertificateVerify} [length 0108]
>>> {Finished} [length 0034]
Braces mark messages encrypted under handshake keys, and note what that means: in TLS 1.3 the client’s certificate, which frequently names a person, a device or a service account, is not visible to the network, whereas in TLS 1.2 it is, because the client’s Certificate message is sent before the change of cipher.
CertificateRequest carries a request context, a signature algorithms list, and optionally a certificate_authorities extension listing the distinguished names of acceptable issuers and an oid_filters extension for demanding particular certificate extension values. The client’s CertificateVerify is computed exactly like the server’s, over a transcript that now includes the server’s whole flight and the client’s own certificate, with the context string “TLS 1.3, client CertificateVerify”. The same discipline applies: the certificate is the claim, this message is the proof.
Now the failure, which is more instructive than the success. Here is what happens when the same client connects without a certificate. From the client:
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Verify return code: 0 (ok)
error:0A00045C:SSL routines:ssl3_read_bytes:
tlsv13 alert certificate required:SSL alert number 116
From the server:
>>> TLS 1.3, Alert [length 0002], fatal certificate_required
error:0A0000C7:SSL routines:tls_process_client_certificate:
peer did not return a certificate
Read the client output again. It printed a successful connection line and a verification code of zero, and only afterwards received a fatal alert. In TLS 1.3 the client finishes its own handshake before the server has evaluated the client’s certificate, so client authentication failures arrive after the client believes it is connected; in TLS 1.2 the server’s Finished came last, so the rejection landed inside the handshake. This is the commonest source of confusing mutual-TLS bug reports: a connected socket, then an unexplained error on first write.
The characteristic production failures, in rough order of how often they are seen:
- The client sends a leaf certificate with no intermediates and the server cannot build a chain, because servers rarely carry the fetching path builder that browsers do.
- The server’s list of acceptable authority names is truncated or ignored, so a client with several certificates picks the wrong one and is rejected without a useful message.
- TLS is terminated at a load balancer that verifies the certificate and then forwards a plain header naming the client, which any internal caller can forge unless the internal hop is itself protected.
- Client certificates expire silently, because nothing renews them the way ACME renews server certificates, and expiry is discovered by outage.
- Someone demands a client certificate only for certain paths. In TLS 1.2 that required renegotiation, removed in TLS 1.3; TLS 1.3 offers post-handshake authentication instead, but RFC 8740 of February 2020 forbids that under HTTP/2, so on a modern connection there is no supported way to ask for a certificate only when a particular URL is requested.
- Revocation of client certificates is checked even less reliably than that of server certificates, which chapter 30 covers.
Resumption, pre-shared keys, and 0-RTT#
After a handshake completes, a TLS 1.3 server may send NewSessionTicket messages. Each carries a lifetime in seconds, a random age obfuscation value, a nonce, the ticket itself, and optional extensions including the maximum early data the ticket allows; the standard caps the advertised lifetime at 604800 seconds, seven days. Here is a real session, saved from an OpenSSL client and printed back:
Protocol : TLSv1.3
Cipher : TLS_AES_256_GCM_SHA384
Resumption PSK: BDCBE93EE5648BD6929C063249F74521
483D229F5A314D988EC2D46D99070916
16195C7BB5786275EC46EC796339A4FB
TLS session ticket lifetime hint: 7200 (seconds)
Max Early Data: 0
The two-hour lifetime is an implementation default of that server, not a standard. The zero for early data means this server would not accept 0-RTT.
On the next connection the client puts the ticket into a pre_shared_key extension, which must be the last extension in ClientHello, together with a binder: a message authentication code over the truncated ClientHello, keyed from the resumption secret, which stops somebody replaying a stolen ticket inside a different hello. The server recognizes the ticket, and both sides derive fresh keys from the resumption secret and, if psk_dhe_ke was offered, a fresh key exchange as well.
The two runs are easy to tell apart in the client output:
first connection : New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
second connection: Reused, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
The word Reused is the whole story: no Certificate, no CertificateVerify, no identity proof of any kind on the second connection. The server’s identity is inherited from the first handshake through the resumption secret.
0-RTT, also called early data, goes one step further. If the ticket allows it, the client sends application data in its very first flight, encrypted under a key derived from the resumption secret alone, saving a full round trip. The cost is not an implementation defect but a property of the construction: early data carries no freshness from the server, because it is sent before the server has said anything, so an attacker who records a first flight can send the same bytes again to the same server, or to another in the same cluster, and they will be accepted as new. Everything else ever sent over TLS is protected against replay by the server’s contribution of randomness.
RFC 8446 section 8 offers three partial defences: single-use tickets, which force the server to keep state; recording client hellos within a time window and rejecting duplicates; and freshness checks using the obfuscated ticket age. None of them composes cleanly across a fleet of servers behind a load balancer.
The application layer therefore has to help. RFC 8470 of September 2018 defines how HTTP uses early data: a client sends only requests it is willing to have executed more than once, and a server that will not take the risk replies with status 425, Too Early, telling the client to retry on the completed handshake. Early data also lacks forward secrecy, being protected by an earlier secret.
| Resumption fact | Value or rule | Source |
|---|---|---|
| Max ticket lifetime | 604800 seconds | RFC 8446 4.6.1 |
| Early data replay | not prevented | RFC 8446 section 8 |
| HTTP retry status | 425 Too Early | RFC 8470 |
| Identity proof on resume | none sent | RFC 8446 2.2 |
There is one more trap in the pre-shared key machinery, and it applies to externally configured keys rather than tickets. If two parties share one symmetric key and both can act as client and server, the protocol on its own does not stop a machine being tricked into completing a handshake with itself, a reflection that Drucker and Gueron published in 2019 under the name Selfie. The remedy is to bind each key to a role or an identity outside TLS. It is a good illustration of the chapter’s thesis: with a pre-shared key there is no CertificateVerify, so there is no message that proves who is at the far end, only a message that proves someone knows the key.
Reading a handshake yourself#
Everything in this chapter can be reproduced with one command-line tool. The captures here were made with OpenSSL 3.0.13 on Ubuntu in August 2026; the current series is OpenSSL 4.0, published on 14 April 2026, with 4.0.1 following on 9 June 2026. To see what version, suite and certificate a server offers:
openssl s_client -connect example.com:443 \
-servername example.com </dev/null
To force a version and print every handshake message, which is how the message lists in this chapter were produced, and to decode them symbolically:
openssl s_client -connect example.com:443 \
-servername example.com -tls1_2 -msg </dev/null
openssl s_client -connect example.com:443 \
-servername example.com -trace </dev/null
To save a session and resume it on the next connection, and to offer a client certificate for mutual TLS:
openssl s_client -connect example.com:443 -sess_out s.pem
openssl s_client -connect example.com:443 -sess_in s.pem
openssl s_client -connect example.com:443 \
-cert client.crt -key client.key
The lines to read in the output, and what each one tells you:
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server Temp Key: X25519, 253 bits
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Verification: OK
Verify return code: 0 (ok)
New against Reused says whether this was a full handshake. Server Temp Key names the group used for the ephemeral key exchange, and its presence confirms forward secrecy. Peer signature type names the scheme used in CertificateVerify, the proof of possession. Verification reports the chain check, and s_client reports a failed chain and carries on regardless unless you pass -verify_return_error.
Running a server locally is the fastest way to see mutual TLS. The lab for this chapter was a self-signed authority, a server certificate, a client certificate and then
openssl s_server -accept 4433 -cert server.crt \
-key server.key -CAfile ca.crt -Verify 1 -tls1_3 -msg
where -Verify 1 makes a client certificate mandatory; the difference between -Verify and -verify is what produces the certificate_required alert shown earlier.
In a packet capture the handshake is visible but everything after ServerHello is encrypted in TLS 1.3. Filter on tls.handshake.type equal to 1 for client hellos and 2 for server hellos, and read the SNI straight out of the first packet. To see inside, set the SSLKEYLOGFILE environment variable before starting the client and point the analyser at the resulting file, into which browsers and most libraries write the handshake secrets. That format was for years an undocumented convention shared by NSS, Firefox, Chrome and Wireshark, and was finally written down as RFC 9850 in July 2026, which defines labels including CLIENT_HANDSHAKE_TRAFFIC_SECRET and CLIENT_TRAFFIC_SECRET_0. Treat any machine with that variable set as having no transport security at all.
One connection, end to end, with the numbers#
Pulling the whole chapter into a single worked example: the mutual-TLS connection captured for this chapter, with every size explained.
| Message | Bytes | Composition |
|---|---|---|
| ClientHello | 238 | 4 header, 234 body |
| ServerHello | 122 | 4 header, 118 body |
| EncryptedExtensions | 6 | 4 header, empty list |
| CertificateRequest | 85 | 4 header, 81 body |
| Certificate (server) | 1642 | 4 header, one cert |
| CertificateVerify | 264 | 4 + 2 + 2 + 256 |
| Finished | 52 | 4 header, 48 byte MAC |
The CertificateVerify line is the one to dwell on. Of those 264 bytes, 256 are a single RSA-PSS signature under a 2048-bit key, and that signature is the only thing in the exchange tying the far end to a name. Remove it and everything else still works: keys agreed, data encrypted, Finished messages matching. You would simply have no idea who you were talking to.
Here is the flow, drawn once, with the proof marked.
client server
| |
|--- ClientHello ------------------------->| no proof
| key_share, server_name |
|<-- ServerHello --------------------------| no proof
| key_share (encryption starts) |
|<-- {EncryptedExtensions} ----------------| no proof
|<-- {CertificateRequest}* ----------------| a demand
|<-- {Certificate} ------------------------| a claim
|<-- {CertificateVerify} ------------------| THE PROOF
|<-- {Finished} ---------------------------| agreement
| |
|--- {Certificate}* ---------------------->| a claim
|--- {CertificateVerify}* ---------------->| THE PROOF
|--- {Finished} -------------------------->| agreement
|--- [application data] ------------------>|
| |
|<-- {NewSessionTicket} -------------------| a bearer chit
Braces mark encryption under handshake keys, square brackets under application keys, and a star marks messages that appear only when client authentication is in use.
What the versions look like in the field#
A short history, because the shape of the protocol is the residue of its accidents.
| Version | Document | Date |
|---|---|---|
| SSL 2.0 | Netscape, no RFC | 1995 |
| SSL 3.0 | RFC 6101, historic | August 2011 |
| TLS 1.0 | RFC 2246 | January 1999 |
| TLS 1.1 | RFC 4346 | April 2006 |
| TLS 1.2 | RFC 5246 | August 2008 |
| TLS 1.3 | RFC 8446 | August 2018 |
| TLS 1.3 | RFC 9846 | July 2026 |
Netscape shipped SSL 2.0 in 1995 under Taher Elgamal as chief scientist; SSL 1.0 was never released. SSL 3.0 was a redesign whose specification reached the RFC series only in August 2011, marked historic, essentially as an archive. The IETF renamed the protocol on adoption, which is why version 3.1 on the wire is called TLS 1.0. Versions 1.0 and 1.1 were deprecated by RFC 8996 in March 2021, part of best current practice 195, whose companion is RFC 9325 of November 2022; those two documents, not folklore, are the current guidance for a server.
The July 2026 republication of TLS 1.3 as RFC 9846 changes what to cite. It obsoletes RFC 8446 and also RFC 5246, the TLS 1.2 specification, along with RFC 5077 on session tickets, RFC 6961, RFC 7627 on the extended master secret and RFC 8422 on elliptic curves, folding their content in. Section numbers moved: what was section 4.4.3, CertificateVerify, is now 4.5.2, and Finished moved from 4.4.4 to 4.5.3.
The most recent large-scale share figure this chapter could confirm is Cloudflare’s, published in March 2024: more than 93 per cent of connections to its network used TLS 1.3. [UNVERIFIED: the share of connections using TLS 1.3 as of August 2026]
29.98 Common wrong ideas#
Wrong: The certificate proves the server’s identity. Right: The certificate is a public claim that anyone can collect by connecting to the same server; identity is proved by CertificateVerify, a signature made during this handshake over a transcript containing the client’s fresh random value, which no impostor can produce without the private key.
Wrong: Encryption means you are talking to the right party. Right: Key exchange establishes a secret with whoever is at the far end, and works perfectly with an impostor; authentication is a separate mechanism using separate messages, which is why a handshake through an intercepting gateway succeeds and shows a valid chain to whatever root that gateway installed.
Wrong: TLS 1.3 is faster because it removed messages. Right: It carries almost the same messages, but the client guesses the key exchange group and sends its share in the first flight, so the server can encrypt its entire reply immediately; the saving is one round trip of waiting, and a wrong guess costs that round trip back through HelloRetryRequest.
Wrong: The version in the record header tells you the protocol version. Right: In TLS 1.3 the record header is deliberately frozen at the TLS 1.2 value, with 1.0 allowed on the first record, and the real version is carried in the supported_versions extension, number 43, because middleboxes dropped connections whose version fields they did not recognize.
Wrong: Encrypted Client Hello makes browsing private. Right: It encrypts the server name inside the handshake, which helps only when the address lookup is also encrypted and when many names share one front end; section 10.1 of RFC 9849 says so, and the 2026 IFIP Networking measurement found 8.2 per cent of scanned domains supporting it with 99.99 per cent of those behind one provider.
Wrong: Mutual TLS authenticates the user. Right: It proves that the far end holds a private key whose certificate chains to an authority the server trusts, which is a statement about a key file that may be readable by many processes and copied to many machines, not about a person.
Wrong: A failed client certificate makes the connection fail immediately. Right: In TLS 1.3 the client completes its own handshake before the server evaluates its certificate, so the client can report a successful connection and receive the fatal alert certificate_required, number 116, only on a later read.
Wrong: Session resumption is just a cache and carries no security meaning. Right: A resumed connection contains no certificate and no signature, so the server’s identity is inherited from the earlier handshake for as long as the ticket lives, which the standard caps at seven days.
Wrong: 0-RTT is safe because the data is encrypted. Right: Early data is encrypted but not fresh, since it is sent before the server has contributed anything, so a recorded first flight can be replayed; RFC 8446 section 8 offers only partial defences and RFC 8470 tells HTTP clients to send only repeatable requests and servers to answer 425 Too Early when in doubt.
Wrong: Forward secrecy comes automatically with TLS. Right: It comes from ephemeral key exchange, which TLS 1.2 made optional and which its static RSA mode lacked entirely; TLS 1.3 removed that mode, which is why every TLS 1.3 connection has forward secrecy and not every TLS 1.2 connection does.
29.99 Chapter summary in 20 lines#
- TLS provides three things: confidentiality, integrity and authentication of the endpoint that terminates the connection.
- Key exchange and authentication are separate jobs done by separate messages, and mixing them up is the root of most misunderstandings about web security.
- Ephemeral key exchange, written as ECDHE, gives both sides a shared secret that an eavesdropper cannot compute and that is destroyed at close.
- That shared secret says nothing about who is holding the other end, because the arithmetic has no opinion about identity.
- The certificate is a claim: it is public, every client that connects copies it, and possessing a copy proves nothing.
- CertificateVerify is the proof: a signature made during this handshake over a transcript that includes the client’s freshly invented random value.
- In TLS 1.3 that signature covers 64 space characters, a context string naming client or server, a zero byte and the transcript hash, and it may not use the old PKCS number 1 version 1.5 padding.
- In TLS 1.2 the equivalent proof lives in ServerKeyExchange and covers only the two random values and the key exchange parameters.
- Finished proves that both sides derived the same keys and saw the same handshake, which is what defeats attempts to force a weaker negotiation.
- TLS 1.2 needs two round trips before application data and sends the certificate in clear text; TLS 1.3 needs one and encrypts everything after ServerHello.
- TLS 1.3 was published as RFC 8446 in August 2018 after 28 drafts and republished as RFC 9846 in July 2026, which also obsoletes the TLS 1.2 specification.
- The record layer’s version field is a deliberate fiction, and the dummy ChangeCipherSpec in a TLS 1.3 handshake exists only to satisfy middleboxes that broke real connections in 2017 measurements.
- Server Name Indication, RFC 6066 section 3, puts the requested host name in clear text in the first message, because the server must choose a certificate before any encryption exists.
- Encrypted Client Hello, RFC 9849 of March 2026 with its DNS half in RFC 9848, hides that name inside an encrypted inner hello addressed to a front-end operator’s public key.
- ECH helps only in proportion to the number of names sharing a front end and only when the name lookup is encrypted too, and its measured deployment in 2026 is small and concentrated in one provider.
- Mutual TLS mirrors the server’s messages, is encrypted in TLS 1.3, and proves possession of a key file rather than the presence of a person.
- Client authentication failures in TLS 1.3 arrive after the client believes it has connected, which is why mutual TLS bug reports so often describe a connection that succeeds and then fails.
- Session resumption replaces the certificate and the signature with a ticket, so a resumed connection carries no fresh identity proof and inherits the earlier judgement for up to seven days.
- Early data sent with 0-RTT can be replayed because it is sent before the server contributes any freshness, so it must be limited to requests that are safe to execute twice.
- Anyone can check all of this with openssl s_client, a local s_server and a packet capture decrypted through an SSLKEYLOGFILE, which is the difference between understanding the handshake and reciting it.
Chapter sources: RFC 8446, “The Transport Layer Security (TLS) Protocol Version 1.3”, E. Rescorla, August 2018, sections 2, 2.3, 4.1.1, 4.2.1, 4.4.2, 4.4.3, 4.4.4, 4.6.1, 5.1, 6.2, 7.1 and 8, and Appendix D.4, together with its republication as RFC 9846 of July 2026, which obsoletes RFCs 5077, 5246, 6961, 7627, 8422 and 8446, updates RFCs 5705 and 6066, and renumbers CertificateVerify to section 4.5.2 and Finished to section 4.5.3; RFC 5246, “The Transport Layer Security (TLS) Protocol Version 1.2”, Dierks and Rescorla, August 2008, section 7.3 and section 7.4.1.4; RFC 2246 of January 1999 and RFC 4346 of April 2006 for the earlier versions, and RFC 6101 of August 2011, historic, for SSL 3.0; RFC 6066, “TLS Extensions: Extension Definitions”, January 2011, section 3, and its predecessor RFC 4366 of April 2006; RFC 9849, “TLS Encrypted Client Hello”, Rescorla, Oku, Sullivan and Wood, March 2026, sections 3.2, 4, 5, 6.2.1, 7.1 and 10.1, with RFC 9848, “Bootstrapping TLS Encrypted ClientHello with DNS Service Bindings”, March 2026, RFC 9460 of November 2023 for the HTTPS resource record, and RFC 9180 of February 2022 for Hybrid Public Key Encryption; the IANA TLS ExtensionType Values registry, recording encrypted_client_hello as 65037, and the TLS Supported Groups registry, recording x25519 as 29, secp256r1 as 23 and X25519MLKEM768 as 4588, both retrieved in August 2026; RFC 10024, “Post-Quantum Traditional (PQ/T) Hybrid Key Agreement Mechanisms for TLS 1.3”, Kwiatkowski, Kampanakis, Westerbaan and Stebila, August 2026; RFC 5746 of February 2010 on renegotiation indication; RFC 5077 of January 2008 on stateless resumption; RFC 7627 of September 2015 on the extended master secret; RFC 8470, “Using Early Data in HTTP”, September 2018, defining status 425; RFC 8740, “Using TLS 1.3 with HTTP/2”, February 2020; RFC 9001, “Using TLS to Secure QUIC”, May 2021; RFC 8996 of March 2021 and RFC 9325 of November 2022, both part of BCP 195; RFC 9850, “The SSLKEYLOGFILE Format for TLS”, Thomson, Rosomakho and Tschofenig, July 2026; Cloudflare’s “Why TLS 1.3 isn’t in browsers yet”, 26 December 2017, for the middlebox measurements, “The state of the post-quantum Internet”, 5 March 2024, for the 93 per cent TLS 1.3 figure, and “Cloudflare targets 2029 for full post-quantum security”, 7 April 2026, for the 65 per cent figure; the IETF blog post “TLS 1.3: One Year Later” by Salowey, Turner and Wood, 17 December 2019; Hajda, Oezdil, Bauer, Hoffmann and Bajpai, “The Fragile Privacy of Encrypted Client Hello: Quantifying Systemic Gaps in a Centralized Ecosystem”, IFIP Networking 2026; Drucker and Gueron, “Selfie: reflections on TLS 1.3 with PSK”, IACR ePrint 2019/347; and Bleichenbacher’s 1998 CRYPTO paper with Bhargavan and colleagues’ 2014 triple handshake work for the two attacks named in the text. All captures, byte dumps and message sizes here were produced with OpenSSL 3.0.13 on Ubuntu in August 2026, against a live public server and a local s_server built for the purpose; OpenSSL 4.0.0 was released on 14 April 2026 and 4.0.1 on 9 June 2026.