skip to content

An audit narrows a server's TLS 1.2 suite list, yet live TLS 1.3 connections still negotiate an unlisted suite — why?

level: middleimportance: nice to knowfreq 30%

answer

  1. one wire list, two deployment policies
  2. version is settled before the suite
  3. 1.3 code points start 0x13
  4. the two families name different things
  5. editing one list leaves the other untouched

basics

~20 s

TLS 1.3 suites are a separate family with their own code points, chosen by their own policy once version 1.3 is negotiated. Narrowing the 1.2 list constrains only connections that settle on 1.2, so a 1.3 connection is unaffected by it.

solid answer

~40 s

A TLS 1.3 suite value is never "the same suite" as a TLS 1.2 one, even when both names contain AES-128-GCM: the 1.3 entries are registered code points `{0x13,0x01}` upward whose meaning is defined only for 1.3, and a 1.2 suite token additionally names an exchange and an authentication algorithm that a 1.3 suite does not. On the wire the client sends **one** `cipher_suites` list in its `ClientHello` carrying both families. The server first settles the version through `supported_versions(43)`, then selects a suite valid for that version. So a deployment carries two policies behind one wire list, and an audit that edits only the 1.2 policy leaves every 1.3 handshake exactly as it was.

code

json · 8 lines
json
{
  "cabinet_tls_profile": {
    "min_version": "TLS 1.2",
    "tls12_cipher_suites": ["TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"],
    "tls13_cipher_suites": ["TLS_AES_128_GCM_SHA256", "TLS_CHACHA20_POLY1305_SHA256"],
    "honour_server_order": true
  }
}

go deeper

for a junior

Remember that the two TLS versions have separate suite families with separate code points, so a suite list written for one has no effect on connections using the other.

for a middle

Explain the order of operations: the version is negotiated first, then a suite valid for that version is selected, from one wire list but two server-side policies.

for a senior

When diagnosing, establish the negotiated version before reasoning about the suite, and check the group and signature policies too, since on 1.3 they carry what a 1.2 suite token used to constrain.

for a principal

Set a policy shape that survives staff turnover: a version floor first, then one acceptable set per permitted version, then the group and signature policy, each reviewable without knowing why the original was written.

## One list on the wire, two policies behind it This failure is common precisely because the wire picture and the configuration picture do not match. On the **wire** there is one list. A `ClientHello` carries a single `cipher_suites` field holding code points from both families — the TLS 1.3 entries and whatever TLS 1.2 entries the client also supports. There is no separate per-version list in the message. In a **deployment** there are two policies, because the server must decide independently which 1.2 suites and which 1.3 suites it will accept. The order of operations is what ties them together: 1. The server reads `supported_versions(43)` and selects the protocol version. 2. Only then does it select a cipher suite — from the family valid for that version. 3. Its acceptable set for the *other* version plays no part in that selection. An audit that tightens the 1.2 list has therefore changed step 3 for one branch of step 1 and nothing at all for the other. Every connection that negotiated 1.3 goes on choosing from the 1.3 policy, untouched. ## Why a 1.3 suite can never be the same suite as a 1.2 one Two independent reasons, and it is worth giving both: - **Different code points, defined for different versions.** The 1.3 entries were registered as new values — `{0x13,0x01}` through `{0x13,0x05}` — and their meaning is defined for TLS 1.3. A 1.2 suite's code point is not usable to mean a 1.3 suite, and the reverse is equally untrue. - **Different contents.** A 1.2 token names four things: exchange, authentication, bulk cipher, and MAC or PRF hash. A 1.3 token names two: the AEAD algorithm and the derivation hash. Even where the record protection matches exactly, the 1.2 entry is additionally constraining an exchange and a signature type that the 1.3 entry says nothing about, because those moved into `supported_groups(10)` and `signature_algorithms(13)`. So "we allow AES-128-GCM" is not a single policy statement. It is two, and they are enforced on different connections. ## What the audit should have checked For a fleet of fixed-function hospital pharmacy dispensing cabinets whose profile was written at commissioning and is being reviewed years later by someone who did not write it, the checklist is: 1. **The version floor**, because it decides which suite policy is even reachable. 2. **The 1.2 acceptable set**, if 1.2 is still permitted at all. 3. **The 1.3 acceptable set**, separately, as its own list. 4. **The group policy and the signature policy**, because on 1.3 those carry decisions that used to sit inside a suite token — an audit confined to suite lists cannot see them. 5. **The ordering policy**, understood as a tiebreak among accepted suites rather than as a control on which are accepted. ## The reverse mistake, which is just as common The mirror-image error is tightening only the 1.3 list and assuming the deployment is hardened, while 1.2 remains enabled with a permissive set behind it. Any client that cannot do 1.3 — and on a fleet commissioned over many years there will be some — lands on 1.2 and is governed entirely by the list nobody edited. The habit that prevents both: **read a suite policy as a function of the negotiated version, never as a single global list**, and confirm which version the connection you are looking at actually negotiated before you reason about which suite it chose. A capture, or a log line that records both the negotiated version and the selected suite together, settles it in one line; a configuration file read on its own never will.

  • If the deployment holds two suite policies, how many suite lists does the client actually send?
    One. The ClientHello carries a single cipher_suites field containing code points from both families together. The split into two policies exists on the server side, and it is applied after the version has been selected through supported_versions(43).
  • A log line shows a suite name containing AES-128-GCM. Does that tell you which version was negotiated?
    Effectively yes, because the two families spell it differently: a TLS 1.3 suite name has only the AEAD algorithm and a hash, while a TLS 1.2 one additionally names the exchange and the authentication algorithm before WITH. Even so, log the negotiated version explicitly rather than inferring it from the token.
  • What does the 1.3 suite policy fail to constrain that the 1.2 one did?
    The key exchange and the server's signature algorithm. In 1.2 both were named inside the suite token, so restricting the suite list restricted them. In 1.3 they are negotiated in supported_groups(10) and signature_algorithms(13), which are separate policies an audit must review on their own.

saying these in an interview costs you the question

  • Treating one suite list as governing every TLS version
  • Believing a 1.3 suite is a renamed 1.2 suite
  • Thinking the client sends a separate list per version
  • Assuming the suite is chosen before the version
  • Hardening only the 1.3 list while 1.2 stays permissive