PQ Crypta Logo

425 (Too Early) in answer to a request sent as early data

Handle being told the request arrived too early. §5.2 says a user agent "SHOULD retry automatically, but any retries MUST NOT be sent in early data" — so retrying on the 1-RTT keys and handing the 425 back to the caller are both conformant, and the report says which happened. Falling over is not one of the options. This is the only port that *accepts* early data instead of refusing it, which is what makes the 425 exchange possible at all. What it does not check is §4's rule that unsafe methods must never be sent in early data: reading the method would mean QPACK-decoding the request, which this suite deliberately never does. Reaching it needs a session ticket from an earlier connection to this same port, so a client that connects once has none.

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.

q-zero-rtt-replay · RFC 8470 §5.2 · discretionary · layer quic · udp/4497 · SHOULD

Passing this means: The RFC permits either behaviour; the report says which was chosen.

Anomaly type: response_stream

How each client answered

ClientVersionVerdictWhat happened
curl libcurl/8.23.0 ngtcp2/1.25.0 Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
quinn noq fork (189b0ed) Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
aioquic 1.3.0 (PyPI wheel) Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
chromium build 1248 Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
quic-go quic-go v0.61.0 (h1:9So2anK4Tp22) Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
quiche 0.30.0 (1c8e976) Unsupported does not deliver early data to an endpoint that negotiates versions, so it was never answered 425. It offered a GREASE QUIC version first, which this endpoint answered with Version Negotiation (RFC 8999 §6), and it did not re-offer early data on the v1 retry -- so the 0-RTT it intended never reached the wire. Both sides are conformant; the early data is lost between them.
neqo 0.31.1 (cac2b74) Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
picoquic 8162550 Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
ngtcp2 3c23148 Pass Rejected it (rejected at the QUIC layer with INTERNAL_ERROR). The specification permits this but does not require it; a client that ignored it would also be conformant.
lsquic 4.9.4 (2b30189) Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
xquic 2060a44 Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.
msquic 2.7.0 (7e6525d) Unsupported does not resume sessions, so it was never answered 425. An earlier connection to this port in the same session completed its exchange, and with it received session tickets that permit 0-RTT; this connection, opened afterwards, ran a full handshake instead of resuming, and a client that does not resume cannot offer early data.
quico 0.7.0 (npm) Pass Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant.

What the clause requires

Handle being told the request arrived too early. §5.2 says a user agent "SHOULD retry automatically, but any retries MUST NOT be sent in early data" — so retrying on the 1-RTT keys and handing the 425 back to the caller are both conformant, and the report says which happened. Falling over is not one of the options. This is the only port that *accepts* early data instead of refusing it, which is what makes the 425 exchange possible at all. What it does not check is §4's rule that unsafe methods must never be sent in early data: reading the method would mean QPACK-decoding the request, which this suite deliberately never does. Reaching it needs a session ticket from an earlier connection to this same port, so a client that connects once has none.

Judged against RFC 8470.

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 == "q-zero-rtt-replay")'