Clients abort a TLS 1.3 handshake when the server returns an extension they never offered — which rule is that?
answer
- answers only to questions that were asked
- extensions are legal per message
- tolerance would become the protocol
- misplaced means illegal_parameter
- one documented exception, in a retry
basics
~20 sExtension negotiation is strictly offer-then-answer: a server may only respond with extensions the client actually offered, and each extension type is legal only in the specific handshake messages the specification permits. Violations are fatal, not ignorable.
solid answer
~40 sTwo separate rules are being enforced. First, **responses must be solicited**: an endpoint must not send an extension response for something the peer never requested, and a peer receiving one aborts with a fatal `unsupported_extension` alert. The documented exception is the `cookie(44)` extension in a `HelloRetryRequest`. Second, **placement is fixed**: every extension type is permitted only in named messages — some in `ClientHello` only, some in `ClientHello` and the hello responses, some in `EncryptedExtensions` — and a recognised extension appearing where it is not permitted must be aborted with `illegal_parameter(47)`. In TLS 1.3 this is what keeps `ServerHello` down to the handful of extensions needed to establish keys, with the rest moved into `EncryptedExtensions`.
code
pseudocode · 14 lineson receiving a server extension E in message M:
if E is not recognised:
ignore E // unknown types are skipped
else if M is not in permitted_messages(E):
abort with illegal_parameter(47)
else if E was not offered in our ClientHello:
if not (E is cookie(44) and M is HelloRetryRequest):
abort with a fatal unsupported_extension alert
else:
apply E to the connection statego deeper
Remember the shape: the client offers extensions and the server may only answer what was offered. An answer to a question nobody asked ends the handshake.
Separate the two rules — solicited responses, and per-message placement — and give the outcome of each. Note that unknown types are ignored while recognised misplaced ones are fatal.
Recognise the production symptom: handshakes failing against one intermediary or one client population and not another, with nothing in application logs. Compare the offered extension set against what came back, which is readable on the path.
Treat strictness as a compatibility decision across the estate. Tolerant peers hide a defect until a stricter one meets it, so where your fleet sits on that line determines which upgrades will surface problems and when.
## The rule, stated exactly TLS extension negotiation is not a free-form bag of attributes. It has two constraints, and both are enforced by aborting rather than by ignoring: 1. **Solicited responses only.** An endpoint must not send an extension response unless the peer sent the corresponding request. If one arrives anyway, the receiver must abort the handshake with a fatal `unsupported_extension` alert. The one documented exception is the `cookie(44)` extension in a `HelloRetryRequest`, which the server may send without it having been offered. 2. **Fixed placement.** Every extension type is defined as permitted in a specific set of messages — `ClientHello` only, or `ClientHello` together with the hello responses, or `EncryptedExtensions`, or a certificate entry. A recognised extension appearing in a message it is not defined for must be aborted with `illegal_parameter(47)`. The second rule is what shapes the TLS 1.3 server flight: `ServerHello` may carry only the extensions that establish the cryptographic context, which is why everything else the server has to say moved into `EncryptedExtensions`. ## Why abort rather than ignore The tolerant instinct — ignore what you do not recognise, keep the connection up — is exactly wrong here, for reasons that are about negotiation rather than parsing: - **An unsolicited response is state the client never agreed to.** Every extension changes how the connection behaves. Accepting an answer to a question that was never asked means a peer, or something between the peers, has added behaviour to the connection unilaterally. - **Negotiation must be provable afterwards.** `Finished` covers the whole transcript, so both sides can show they saw the same negotiation. That guarantee is worth much less if either side quietly discards parts of what it saw. - **Tolerance becomes a de facto protocol.** If clients ignore misplaced extensions, servers ship that mistake, and the placement rules stop meaning anything within a release cycle. ## How this shows up operationally The classic sighting is an upgrade that fails in one environment and not another. A gateway is moved behind a different intermediary, or a TLS library is upgraded, and suddenly a subset of clients abort during the handshake while browsers on the same path are fine. The mechanism is nearly always one of these: - something in the path is **adding or rewriting** extensions, so what the server sends is no longer what the client offered; - a peer is sending an extension **in the wrong message** — correct on the wire in 1.2, not permitted in the 1.3 message where it now appears; - one side is sending an extension response as a matter of course rather than **only when offered**. All three produce a connection that dies mid-handshake with no application-level evidence. The diagnostic that separates them is comparing what was offered with what came back, which is possible because the hello messages are readable on the path in both versions. ## The placement table in outline | Extension role | Permitted where | |---|---| | Establishing keys and version | `ClientHello`, `ServerHello`, `HelloRetryRequest` | | Client-only offers such as the host name | `ClientHello`, answered in `EncryptedExtensions` | | Server answers not needed for key establishment | `EncryptedExtensions` | | Per-certificate extensions | inside the certificate entry that carries them | That is a shape rather than a complete registry: the point to carry into an interview is that the set is **per message**, not global, and that this is checked rather than advisory. ## Required, not recommended This is a place where the specification genuinely says *must*: both the unsolicited case and the misplaced case are stated as requirements to abort, not as advice. That distinction is worth keeping straight, because plenty of TLS guidance is a *should* being repeated as a rule, and this is the opposite — a rule that people repeat as advice and then implement tolerantly. ## Version note The solicited-response rule is not new; TLS 1.2 stated it too, and a 1.2 client receiving an extension in the `ServerHello` that it did not request aborts in the same way. What TLS 1.3 added is the per-message placement table and the `EncryptedExtensions` slot that makes it necessary, so the placement half of the answer is specific to 1.3.
- Why is an unrecognised extension ignored while a misplaced recognised one is fatal?An unrecognised type carries no meaning for the receiver, so skipping it changes nothing about the connection and is what lets the registry grow. A recognised type in a message where it is not defined is different: the receiver knows what it means and cannot tell whether the sender is broken or the message was tampered with, so the safe outcome is to stop.
- What does the placement rule leave in the TLS 1.3 ServerHello?Only the extensions needed to establish the cryptographic context — the version and key-exchange responses, and the pre-shared-key indication where one is in use. Everything else the server has to say is in `EncryptedExtensions`, which is both the placement rule and the reason that message exists.
- Clients abort against a new intermediary but browsers on the same path do not. Where do you look?At what was offered versus what came back. The hello messages are readable on the path in both versions, so compare the extension set in the `ClientHello` with the set in the response. An intermediary adding, dropping or rewriting extensions shows up immediately, and the difference between client populations is usually just which of them enforce the rule strictly.
saying these in an interview costs you the question
- Says a client should ignore extensions it did not ask for
- Thinks any extension may appear in any handshake message
- Treats the abort requirement as merely recommended
- Believes unknown extension types must also be fatal
- Assumes the placement rules are the same in 1.2 and 1.3