A test gap rather than a known defect, but on a verifier where the gap is the whole point.
MutualTlsTests has a group for exactly this on TCP — a client certificate that chains correctly to a trusted anchor and must be refused anyway:
- expired
- not yet valid
- extended key usage of serverAuth rather than clientAuth
- an EC leaf
- a leaf that chains through an intermediate
QuicMutualTlsTests covers only the clean pair from EnsureMutualTls against a rogue CA — own-CA accepted, foreign-CA refused. Everything above is untested there.
That matters because it is a different verifier: TCP verification is OpenSSLs (SSL_CTX_load_verify_locations plus SSL_VERIFY_PEER), QUICs is picotls over an X509_STORE built by the shim, with iq_allow_anonymous layered on top for the optional-mTLS case. QuicEngines own doc comment promises three things — "the chain builds to one of these anchors, the signatures verify, and the certificate is inside its validity window" — and only the first is currently held to.
TestCert.EnsureClientCert(ClientCertSpec) already mints every shape needed (expiry window, EKU, EC), so this is porting MutualTlsTests.RegisterBadClientCertificates to QuicMutualTlsTests with the clean client as the control on the same engine. From nginxs ssl_verify_client.t and haproxys ssl_client_auth.vtc, both of which assert each refusal by its distinct error rather than merely that it failed.
A test gap rather than a known defect, but on a verifier where the gap is the whole point.
MutualTlsTestshas a group for exactly this on TCP — a client certificate that chains correctly to a trusted anchor and must be refused anyway:QuicMutualTlsTestscovers only the clean pair fromEnsureMutualTlsagainst a rogue CA — own-CA accepted, foreign-CA refused. Everything above is untested there.That matters because it is a different verifier: TCP verification is OpenSSLs (
SSL_CTX_load_verify_locationsplusSSL_VERIFY_PEER), QUICs is picotls over anX509_STOREbuilt by the shim, withiq_allow_anonymouslayered on top for the optional-mTLS case.QuicEngines own doc comment promises three things — "the chain builds to one of these anchors, the signatures verify, and the certificate is inside its validity window" — and only the first is currently held to.TestCert.EnsureClientCert(ClientCertSpec)already mints every shape needed (expiry window, EKU, EC), so this is portingMutualTlsTests.RegisterBadClientCertificatestoQuicMutualTlsTestswith the clean client as the control on the same engine. From nginxsssl_verify_client.tand haproxysssl_client_auth.vtc, both of which assert each refusal by its distinct error rather than merely that it failed.