PQ Crypta Logo

Hybrid key share whose length does not match the group named with it

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.

PQ CRYPTA PLATFORM

🏠 Main

📰 News

👤 Account

⟨ QUANTUM ERROR PORTAL ⟩

Navigate the Error Dimensions

Jump to an anomaly59

Every one of these is a page: what the server emits, the clause it is judged against, and how each client answered. The full list carries the verdict tallies too.

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

ClientVersionVerdictWhat 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")'