t-hybrid-share-length
· draft-kwiatkowski-tls-ecdhe-mlkem §3.1.2, RFC 8446 §6.2, RFC 9001 §4.8 · correctness · layer tls · udp/4517 · MUST
Passing this means: Rejected something invalid, with the code the RFC names.
Anomaly type: transport
How each client answered
| Client | Version | Verdict | What happened |
|---|---|---|---|
| curl | libcurl/8.23.0 ngtcp2/1.25.0 | Fail | abandoned the handshake without any alert. §3.1.2 requires the abort to carry illegal_parameter, and RFC 9001 §4.8 delivers an alert -- a generic one is permitted -- in a CONNECTION_CLOSE. None was sent: this client runs on the endpoint's own host, where nothing is lost in transit. |
| quinn | noq fork (189b0ed) | Pass | Responded correctly: aborted with illegal_parameter (alert 47) over a server share of the wrong length for X25519MLKEM768, which is the check §3.1.2 asks the client to make and the code it names. |
| aioquic | 1.3.0 (PyPI wheel) | Unsupported | The client offers no key exchange group this port will negotiate, so it was refused before a handshake existed (the cryptographic handshake failed: error 40: peer is incompatible: NoKxGroupsInCommon). That is a capability this client does not have, rather than something the run failed to measure. |
| chromium | build 1248 | Pass | Responded correctly: aborted the handshake with TLS alert 80 rather than illegal_parameter. §3.1.2 requires the abort and RFC 9001 §4.8 permits replacing the alert over QUIC, so the code is reported and not judged -- though note that a truncated share also breaks the key schedule, so this abort does not on its own show the length was what the client objected to. |
| quic-go | quic-go v0.61.0 (h1:9So2anK4Tp22) | Pass | Responded correctly: aborted with illegal_parameter (alert 47) over a server share of the wrong length for X25519MLKEM768, which is the check §3.1.2 asks the client to make and the code it names. |
| quiche | 0.30.0 (1c8e976) | Pass | Responded correctly: aborted the handshake with TLS alert 80 rather than illegal_parameter. §3.1.2 requires the abort and RFC 9001 §4.8 permits replacing the alert over QUIC, so the code is reported and not judged -- though note that a truncated share also breaks the key schedule, so this abort does not on its own show the length was what the client objected to. |
| neqo | 0.31.1 (cac2b74) | Pass | Responded correctly: aborted with illegal_parameter (alert 47) over a server share of the wrong length for X25519MLKEM768, which is the check §3.1.2 asks the client to make and the code it names. |
| picoquic | 8162550 | Pass | Responded correctly: aborted the handshake with CONNECTION_CLOSE 0x1, a transport error code, rather than the illegal_parameter alert. §3.1.2 requires the abort and RFC 9000 §11 lets a generic code stand in for a specific one, so the code is reported and not judged -- though a truncated share also breaks the key schedule, so this abort does not on its own show the length was what the client objected to. |
| ngtcp2 | 3c23148 | Pass | Responded correctly: aborted the handshake with TLS alert 80 rather than illegal_parameter. §3.1.2 requires the abort and RFC 9001 §4.8 permits replacing the alert over QUIC, so the code is reported and not judged -- though note that a truncated share also breaks the key schedule, so this abort does not on its own show the length was what the client objected to. |
| lsquic | 4.9.4 (2b30189) | Fail | abandoned the handshake without any alert. §3.1.2 requires the abort to carry illegal_parameter, and RFC 9001 §4.8 delivers an alert -- a generic one is permitted -- in a CONNECTION_CLOSE. None was sent: this client runs on the endpoint's own host, where nothing is lost in transit. |
| xquic | 2060a44 | Pass | Responded correctly: aborted the handshake with TLS alert 40 rather than illegal_parameter. §3.1.2 requires the abort and RFC 9001 §4.8 permits replacing the alert over QUIC, so the code is reported and not judged -- though note that a truncated share also breaks the key schedule, so this abort does not on its own show the length was what the client objected to. |
| msquic | 2.7.0 (7e6525d) | Unsupported | The client offers no key exchange group this port will negotiate, so it was refused before a handshake existed (the cryptographic handshake failed: error 40: peer is incompatible: NoKxGroupsInCommon). That is a capability this client does not have, rather than something the run failed to measure. |
| quico | 0.7.0 (npm) | Pass | Responded correctly: aborted with illegal_parameter (alert 47) over a server share of the wrong length for X25519MLKEM768, which is the check §3.1.2 asks the client to make and the code it names. |
What the clause requires
Abort rather than proceed. §3.1.2 is explicit: "For all groups, the client MUST check if the ciphertext length matches the selected group, and abort with an illegal_parameter alert if it fails." The port sends 1,088 bytes where X25519MLKEM768 fixes the server share at 1,120 — the ML-KEM ciphertext whole and the 32-byte X25519 tail removed. It parses cleanly as an opaque vector, so the only thing wrong with it is its length for the group it is named with. Neither outcome lets a client derive our keys, because the shared secret needs both halves. What separates them is where it notices: a client that checks the length rejects this at the ServerHello, while one that does not carries a truncated share into decapsulation and fails later and less clearly. What is judged is the abort, not the alert value. RFC 9001 §4.8 lets a QUIC endpoint replace any alert with a generic one, so the code a client chooses is reported and not scored — and a handshake that ends with no CONNECTION_CLOSE at all is inconclusive rather than a failure, because a close that was never sent cannot be told from one that was lost.
Judged against RFC 8446, RFC 9001.
Run this one yourself
Every test is reachable from your own client. Nothing here needs an account.
curl -s https://conformance.pqcrypta.com/catalog.json \
| jq '.tests[] | select(.id == "t-hybrid-share-length")'