skip to content

When a TLS server aborts with handshake_failure(40) rather than protocol_version(70), what does each narrow the mismatch to?

level: middleimportance: must knowfreq 62%

answer

  1. one of the two pins a dimension
  2. catch-all versus version-specific
  3. the direction of the mismatch matters
  4. insufficient_security(71) is signed
  5. no certificate usable also yields handshake_failure(40)

basics

~10 s

protocol_version(70) narrows the failure to version selection: the version offered was recognised and not supported. handshake_failure(40) narrows nothing - it is the catch-all for no acceptable set of security parameters, whichever dimension failed.

solid answer

~40 s

`protocol_version(70)` is the only one of the two that pins a dimension. It says the version the peer attempted to negotiate is recognised but not supported, which removes cipher suites, named groups, signature algorithms and certificates from the investigation in a single step. `handshake_failure(40)` says only that the sender could not negotiate an acceptable set of security parameters given the options available - a shared suite may be missing, no named group may have been usable, no offered signature algorithm may have suited the server's certificate, or a policy may simply have refused the offer. Two narrower descriptions are worth recognising alongside them: `insufficient_security(71)`, which a server sends when its requirements exceed what the client offered, and `no_application_protocol(120)`, which says the application-protocol list was the problem rather than the cryptography.

code

pseudocode · 17 lines
pseudocode
function server_negotiate(client_hello):
    if no version in client_hello is one we still accept:
        return alert protocol_version(70)

    if a mandatory extension for that version is absent:
        return alert missing_extension(109)

    if client advertised application protocols and none is supported:
        return alert no_application_protocol(120)

    if our required parameters exceed everything offered:
        return alert insufficient_security(71)

    if no suite, group, signature algorithm or usable certificate remains:
        return alert handshake_failure(40)

    return proceed

go deeper

for a junior

Remember the asymmetry rather than the list: one of these two descriptions tells you the failure was about versions, the other tells you only that no acceptable parameters were found.

for a middle

Explain what handshake_failure(40) actually asserts and enumerate the dimensions it covers, then contrast that with protocol_version(70) eliminating all of them at once. Know that insufficient_security(71) carries a direction.

for a senior

Show the triage: which comparison you run first for each description, why the absence of a specific alert is not evidence, and why a certificate that cannot be used for the offered parameters surfaces as a negotiation alert.

for a principal

The lead's angle is the cost of vague failures across an estate of mixed vintages: how much diagnosis time the catch-all buys back, weighed against how much a peer should reveal about its own configuration in an alert.

## The one thing handshake_failure(40) actually asserts `handshake_failure(40)` means the sender was unable to negotiate an acceptable set of security parameters given the options available. That is the whole claim. It is the catch-all of the negotiation alerts, and treating it as a specific diagnosis is the most common mistake made with it. Causes that all land on the same description: - no cipher suite the two peers both accept; - no named group either peer is willing to use for the key exchange, including after a `HelloRetryRequest` failed to converge; - no signature algorithm in the client's `signature_algorithms` that the server can use; - no certificate the server is able to present for the parameters offered; - a local policy that declines an offer the implementation could technically have accepted. So `handshake_failure(40)` leaves the whole offer under suspicion. It is a starting gun, not a finding. ## protocol_version(70) pins exactly one dimension `protocol_version(70)` reports that the version the peer attempted to negotiate is recognised but not supported - the description is worded for a version the sender knows about and declines, typically because it has been retired. That single fact is worth a great deal during an incident, because it removes every other dimension at once: suites, groups, signature algorithms and certificates are all irrelevant to a handshake that never agreed a version. In a mixed estate - a modern front end in front of components of very different vintages - this is the difference between one hypothesis and five. ## The narrower descriptions worth recognising - **`insufficient_security(71)`** - sent by a server when negotiation failed specifically because the server requires parameters more secure than those the client supports. It is strictly narrower than `handshake_failure(40)`: it gives you the *direction* of the mismatch. - **`no_application_protocol(120)`** - sent by a server when the client advertised, through `application_layer_protocol_negotiation(16)`, only application protocols the server does not support. The cryptography agreed; the application-protocol list did not. - **`missing_extension(109)`** - a handshake message did not carry an extension that is mandatory to send for the version being negotiated, such as a `ClientHello` lacking `supported_versions(43)` or `key_share(51)` where they are required. - **`illegal_parameter(47)`** - a field in the handshake was incorrect or inconsistent with other fields. That is a *malformed* offer rather than an *unacceptable* one, and the distinction matters: one is a bug, the other is a configuration gap. - **`certificate_required(116)`** - sent by a server that wanted a client certificate and received none. ## Who sends what, and what it pins | Alert | Typical sender | What it pins down | |---|---|---| | `handshake_failure(40)` | either peer | nothing beyond "no acceptable parameters" | | `protocol_version(70)` | usually the server | version selection alone | | `insufficient_security(71)` | the server | the server's requirements exceeded the offer | | `no_application_protocol(120)` | the server | the application-protocol list | | `missing_extension(109)` | either peer | a mandatory extension absent | | `illegal_parameter(47)` | either peer | a malformed or inconsistent field | ## Turning the description into a next step 1. On `protocol_version(70)`, compare only the versions each side will negotiate. Nothing else can be the cause. 2. On `insufficient_security(71)`, read it as a signed quantity: the server is above the client, so change the client's offer or the server's requirement, and you already know which way. 3. On `handshake_failure(40)`, do not guess a dimension. Vary one thing at a time - the suites offered, the groups offered, the signature algorithms offered - and see which change moves the failure. ## What none of them tell you - **Which parameter.** `handshake_failure(40)` never names the dimension, and it is emphatically not a synonym for "no shared cipher suite", though that is the most frequent single cause. - **Whether the peer had a choice.** A server that supports a suite but declines it by policy sends the same alert as one that never implemented it. - **Anything about certificates.** A certificate problem surfaces as a certificate verdict from the validating peer, not as a negotiation alert - with one trap: a server that has no certificate it can use for the parameters offered falls back to `handshake_failure(40)`, so a certificate cause can hide behind a negotiation description.

  • A client offers only retired versions and receives handshake_failure(40) rather than protocol_version(70). Is the server wrong?
    No. A peer is free to answer with the catch-all, and several implementations do so deliberately to say as little as possible about their configuration. The consequence is only that the alert cost you information: the absence of protocol_version(70) is not evidence that versions were acceptable, so a version hypothesis stays on the list until you test it directly.
  • Why does insufficient_security(71) help more than handshake_failure(40) even though both end the handshake?
    Because it carries a direction. It is sent when a server requires parameters stronger than the client offered, so the mismatch is known to be the client falling short rather than the server refusing something it dislikes. That halves the search: you compare the client's offer against the server's floor, instead of testing every dimension of the offer in turn.
  • What does no_application_protocol(120) rule out?
    Everything cryptographic. Reaching that point means the peers agreed a version and a set of security parameters, and the server then found none of the advertised application protocols acceptable. The fix is in the protocol list on one side or the other, and nothing about suites, groups or certificates is implicated.

saying these in an interview costs you the question

  • Treats handshake_failure(40) as meaning no shared cipher suite
  • Thinks protocol_version(70) can follow a certificate being rejected
  • Believes only servers ever send handshake_failure(40)
  • Reads insufficient_security(71) as a client-side complaint
  • Assumes the absence of protocol_version(70) clears versions of suspicion
  • Confuses illegal_parameter(47), a malformed field, with an unacceptable one