A peer that presents a certificate it cannot prove it holds reports SSLError. So does a peer whose certificate will not parse. Both are failures to authenticate the peer, and neither reaches SSLAuthFail, so an application wrapping the session in SSLConnection gets no auth_failed for either.
Certificates are public, so presenting a copy of the real one is what an impersonator without the matching key does. That is the case this misses.
SSL._peer_auth_failed decides by asking SSL_get_verify_result whether the chain check failed, and by looking for SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE on the error queue. In both cases above the chain check passes — the certificate is genuine, or the failure happened before the chain was reached — so the verify result is X509_V_OK. Measured against OpenSSL 3.6.2, the SSL-layer reasons are 123 (SSL_R_BAD_SIGNATURE) for a tampered handshake signature and 524301 for a Certificate message that will not decode.
Both reported SSLAuthFail before #126, along with every other SSL-layer handshake failure. #126 narrowed the state to the cases it can identify from the certificate check, and these two fall outside it.
A reason-code test is not enough to close this. On LibreSSL the client-authentication direction of the signature failure raises from the EVP library rather than the SSL library, so matching a set of SSL reason codes would classify the same failure differently on different backends. Catching it portably likely needs a verify callback installed on the session rather than an inspection after the fact.
net/ssl/SSL.receive/unproven_certificate asserts the current behaviour, so changing it means changing that test.
A peer that presents a certificate it cannot prove it holds reports
SSLError. So does a peer whose certificate will not parse. Both are failures to authenticate the peer, and neither reachesSSLAuthFail, so an application wrapping the session inSSLConnectiongets noauth_failedfor either.Certificates are public, so presenting a copy of the real one is what an impersonator without the matching key does. That is the case this misses.
SSL._peer_auth_faileddecides by askingSSL_get_verify_resultwhether the chain check failed, and by looking forSSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATEon the error queue. In both cases above the chain check passes — the certificate is genuine, or the failure happened before the chain was reached — so the verify result isX509_V_OK. Measured against OpenSSL 3.6.2, the SSL-layer reasons are 123 (SSL_R_BAD_SIGNATURE) for a tampered handshake signature and 524301 for a Certificate message that will not decode.Both reported
SSLAuthFailbefore #126, along with every other SSL-layer handshake failure. #126 narrowed the state to the cases it can identify from the certificate check, and these two fall outside it.A reason-code test is not enough to close this. On LibreSSL the client-authentication direction of the signature failure raises from the EVP library rather than the SSL library, so matching a set of SSL reason codes would classify the same failure differently on different backends. Catching it portably likely needs a verify callback installed on the session rather than an inspection after the fact.
net/ssl/SSL.receive/unproven_certificateasserts the current behaviour, so changing it means changing that test.