Stack: ngtcp2 + nghttp3 (direct) ·
Language: C ·
Version: 3c23148
· Measured 2026-09-18
Badge for a README:
https://pqcrypta.com/conformance/badge/ngtcp2.svg
By class
Rolled up by what the clause requires rather than into one number. A client that ignores unknown extensions correctly but never emits the right error codes has a specific, nameable problem, and an average is exactly what hides it.
| Class | Passing means | Pass | Fail | Inconclusive |
|---|---|---|---|---|
| correctness | Rejected something invalid, with the code the RFC names. | 21 | 3 | 1 |
| discretionary | The RFC permits either behaviour; the report says which was chosen. | 12 | 1 | 0 |
| extensibility | Ignored something unknown and carried on. | 5 | 0 | 0 |
| interoperability | Correctly decoded something valid but demanding. | 6 | 0 | 2 |
| resilience | Recovered rather than giving up. | 6 | 0 | 2 |
Every result
| Test | Clause | Verdict | What happened |
|---|---|---|---|
| Version Negotiation offering a reserved version alongside v1 | RFC 9000 §6 | Pass | Responded correctly: sent Version Negotiation for 1 datagram(s); the client did not persist with an unsupported version. |
| Retry packet for source-address validation | RFC 9000 §8.1.2 | Pass | Responded correctly: echoed the Retry token and completed the handshake. |
| Reserved transport parameter (31·N+27) | RFC 9000 §18.1 | Pass | Ignored the unrecognised element and carried on: completed a handshake carrying a reserved transport parameter. |
| Unknown frame type in a 1-RTT packet | RFC 9000 §12.4 | Pass | Responded correctly: closed with FRAME_ENCODING_ERROR, which is the code §12.4 requires for a frame of unknown type. |
| NEW_CONNECTION_ID followed by RETIRE_CONNECTION_ID | RFC 9000 §5.1 | Inconclusive | The run did not exercise this test: the connection was too short-lived to require a rotation. |
| Stateless reset | RFC 9000 §10.3 | Pass | Responded correctly: was sent a Stateless Reset and went quiet — nothing further arrived in the 3 seconds that followed, which is the draining period §10.3.1 requires. |
| Deliberately tight MAX_DATA and MAX_STREAM_DATA | RFC 9000 §4 | Pass | Handled it: respected the window without sending a BLOCKED frame, which §4.1 permits. |
| ACK Frequency extension offered | draft-ietf-quic-ack-frequency | Pass | Handled it: ignored the extension, which the specification permits. |
| Packets marked ECT(0) | RFC 9000 §13.4 | Pass | Responded correctly: echoed ECN counts back in its ACKs: 21 ECT(0), 0 ECT(1), 0 ECN-CE. |
| Path MTU black hole above a threshold | RFC 9000 §14, RFC 8899 | Pass | Recovered: detected the black hole 1 time(s) and settled on a 1293-byte path MTU (360 datagram(s) swallowed). |
| Server-initiated PATH_CHALLENGE | RFC 9000 §8.2 | Pass | Responded correctly: answered with 1 PATH_RESPONSE. |
| 0-RTT rejected after the client sends early data | RFC 9001 §4.6.2 | Inconclusive | The run did not exercise this test: the client sent no early data, so nothing was rejected. 0-RTT needs a session ticket from an earlier connection to this same port, and a client that connects once has none. |
| A second path offered mid-connection | draft-ietf-quic-multipath | Pass | Handled it: declined the multipath offer and stayed on one path, which is conformant. |
| Spontaneous 1-RTT key update | RFC 9001 §6.2 | Pass | Decoded it and completed the request. |
| Stream limits set to the minimum a request needs | RFC 9000 §4.6 | Pass | Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant. |
| One datagram in twelve dropped once the path is established | RFC 9000 §2.2, §13.3 | Pass | Recovered and completed the follow-up request. |
| Datagrams arriving from a second server address | RFC 9000 §9.6 | Pass | Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant. |
| Transport parameter carrying a value the specification forbids | RFC 9000 §7.4, §18.2 | Pass | Responded correctly: closed with TRANSPORT_PARAMETER_ERROR, which is the code §7.4 requires for a parameter carrying an invalid value (ack_delay_exponent = 21, where §18.2 permits at most 20). |
| 425 (Too Early) in answer to a request sent as early data | RFC 8470 §5.2 | Fail | Neither rejected it nor continued. Both outcomes are allowed; stalling is not one of them. |
| Path marking packets CE, not just ECT(0) | RFC 9000 §13.4 | Pass | Responded correctly: reported the congestion back: 21 ECN-CE among 0 ECT(0) and 0 ECT(1), after 326 datagram(s) were marked. |
| A second key update after the first is acknowledged | RFC 9001 §6.1, §6.5 | Pass | Decoded it and completed the request. |
| No stream credit at first, then MAX_STREAMS mid-connection | RFC 9000 §4.6 | Pass | Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant. |
| Reserved SETTINGS identifier (0x1f·N+0x21) | RFC 9114 §7.2.4.1 | Pass | Ignored the unrecognised element and completed the follow-up request. |
| Reserved frame type on the response stream | RFC 9114 §7.2.8 | Pass | Ignored the unrecognised element and completed the follow-up request. |
| Unidirectional stream with a reserved stream type | RFC 9114 §6.2.3 | Pass | Ignored the unrecognised element and completed the follow-up request. |
| SETTINGS containing the same identifier twice | RFC 9114 §7.2.4 | Pass | Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant. |
| A DATA frame on the control stream | RFC 9114 §7.2.1 | Pass | Rejected with the required error code 0x105. |
| Control stream whose first frame is not SETTINGS | RFC 9114 §6.2.1 | Pass | Rejected with the required error code 0x10a. |
| A second control stream opened by the server | RFC 9114 §6.2.1 | Pass | Rejected with the required error code 0x103. |
| Field lines referencing dynamic table insertions | RFC 9204 §4.3.3, §4.5.2 | Inconclusive | The run did not exercise this test: the client advertised SETTINGS_QPACK_MAX_TABLE_CAPACITY of 0 and SETTINGS_QPACK_BLOCKED_STREAMS of 0, which forbid the server's encoder from using the dynamic table at all. |
| Huffman-coded field lines with maximal padding | RFC 9204 §4.1.2, RFC 7541 §5.2 | Pass | Decoded it and completed the request. |
| Field section larger than the client's advertised maximum | RFC 9114 §4.2.2 | Pass | Decoded it and completed the request. |
| Trailing field section after the body | RFC 9114 §4.1 | Pass | Decoded it and completed the request. |
| 103 Early Hints before the final response | RFC 9110 §15.2, RFC 8297 | Pass | Recovered and completed the follow-up request. |
| GOAWAY sent mid-connection | RFC 9114 §5.2 | Pass | Recovered and completed the follow-up request. |
| MAX_PUSH_ID sent by the server | RFC 9114 §7.2.7 | Pass | Rejected with the required error code 0x105. |
| SETTINGS frame on a request stream | RFC 9114 §7.2.4 | Pass | Rejected with the required error code 0x105. |
| DATA frame before any HEADERS on the response stream | RFC 9114 §4.1 | Pass | Rejected with the required error code 0x105. |
| CANCEL_PUSH for a push ID that was never promised | RFC 9114 §7.2.3 | Fail | Rejected, but with error 0x105 where the specification requires 0x108. The violation was detected; the code reported is wrong. |
| Field section that blocks until the encoder stream catches up | RFC 9204 §2.1.2, §2.2.1 | Inconclusive | The run did not exercise this test: the client advertised SETTINGS_QPACK_MAX_TABLE_CAPACITY of 0 and SETTINGS_QPACK_BLOCKED_STREAMS of 0, which forbid the server's encoder from using the dynamic table at all. |
| Response stream reset mid-body with H3_REQUEST_CANCELLED | RFC 9114 §8, §4.1 | Pass | Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant. |
| PRIORITY_UPDATE sent by the server | RFC 9218 §7.2 | Pass | Rejected with error 0x105. The specification permits this but does not require it; a client that ignored it would also be conformant. |
| SETTINGS_ENABLE_CONNECT_PROTOCOL with a value outside 0 and 1 | RFC 9220 §3, RFC 8441 §3 | Pass | Rejected with error 0x109. The specification permits this but does not require it; a client that ignored it would also be conformant. |
| PUSH_PROMISE for a push the client never allowed | RFC 9114 §7.2.5, §4.6 | Fail | Rejected, but with error 0x105 where the specification requires 0x108. The violation was detected; the code reported is wrong. |
| SETTINGS_H3_DATAGRAM with a value that is neither 0 nor 1 | RFC 9297 §2.1.1 | Pass | Rejected with the required error code 0x109. |
| Encoder stream setting a dynamic table capacity above the client's limit | RFC 9204 §4.3.1, §6 | Inconclusive | The client completed its request and then said nothing further before the window closed. A rejection whose CONNECTION_CLOSE was lost cannot be told apart from a client that never objected: QUIC re-sends that frame only in answer to an incoming packet, so one that goes missing is simply never seen. |
| A second GOAWAY naming a larger identifier than the first | RFC 9114 §5.2 | Pass | Rejected with the required error code 0x108. |
| Push stream opened for a push nobody allowed | RFC 9114 §6.2.2 | Fail | Rejected, but with error 0x103 where the specification requires 0x108. The violation was detected; the code reported is wrong. |
| Field line indexing a static table entry that does not exist | RFC 9204 §3.1, §4.5.2 | Pass | Rejected with the required error code 0x200. |
| Datagrams delivered out of order | RFC 9000 §2.2 | Pass | Recovered and completed the follow-up request. |
| Encoder instruction naming a static index that does not exist | RFC 9204 §3.1, §4.3.2 | Pass | Rejected with the required error code 0x201. |
| Server negotiates only the post-quantum hybrid X25519MLKEM768 | RFC 8446 §4.1.4, draft-ietf-tls-hybrid-design | Pass | Decoded it and completed the request. |
| Server negotiates only classical X25519 against a hybrid offer | RFC 8446 §4.1.1, draft-ietf-tls-hybrid-design §5 | Pass | Tolerated it and continued. The specification permits this but does not require it; a client that rejected it would also be conformant. |
| Hybrid key share large enough to split the Initial across packets | RFC 9000 §8.1, §14.1, RFC 9001 §4.4 | Pass | Recovered and completed the follow-up request. |
| Server selects a key exchange group the client never offered | RFC 8446 §4.1.3, §4.2.8, RFC 9001 §4.8 | Pass | Responded correctly: aborted with illegal_parameter (alert 47) over a key_share naming a group it never offered, which is exactly what RFC 8446 §4.1.3 requires. |
| Hybrid key share with an intact X25519 half and a corrupt ML-KEM half | draft-ietf-tls-hybrid-design §3.2, RFC 8446 §4.1.3 | Pass | Responded correctly: did not complete the handshake (timed out). The shared secret is both halves through the key schedule, so a corrupt ML-KEM half must break it -- and this client did not fall back to the intact X25519 half. |
| Hybrid key share whose length does not match the group named with it | draft-kwiatkowski-tls-ecdhe-mlkem §3.1.2, RFC 8446 §6.2, RFC 9001 §4.8 | 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. |
| Post-quantum certificate chain, compressed per RFC 8879 | RFC 8879 §4, RFC 8446 §4.4.2 | Pass | Handled it: completed the handshake against an ML-DSA-87 chain: the compressed certificate message was decompressed, the chain parsed, and a post-quantum signature verified. Note that a client run with certificate verification disabled reaches this point without trusting anything, so what this shows is that the chain was processed, not that it was trusted. |
| GREASE named group a client must tolerate | RFC 8701 §4, RFC 8446 §4.2.7 | Pass | Ignored the unrecognised element and completed the follow-up request. |
What this suite is · The full grid · All clients · All tests · Findings