Skip to content
Open
50 changes: 50 additions & 0 deletions doc/dox_comments/header_files/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3200,6 +3200,31 @@ int wolfSSL_GetSessionAtIndex(int index, WOLFSSL_SESSION* session);
wolfSSL_CTX_get_verify_mode() will not report it back. Including it in
mode has no effect on any of the other flags.

A non-zero return from verify_callback accepts a certificate the library
rejected. Without such a callback, or when it returns preverify_ok, the
rejection stands and the handshake ends with a fatal alert as before.

How far the acceptance reaches depends on why the certificate was
rejected. A chain certificate whose signature was confirmed against a
trusted anchor, and which failed a later check such as its validity
dates, its revocation status or its key usage, is still added to the
certificate manager: accepting it also makes it a trust anchor for later
connections from the same context, and verify_callback is not consulted
about it again. A certificate whose signature was never confirmed is not
added, so that acceptance applies to this handshake alone. It is then not
available as the signer of the next certificate in the chain, which is
reported to verify_callback in its turn, and accepting each one in turn
completes the handshake.

OCSP is the exception. A stapled response is verified against the
certificate manager, which does not hold the accepted certificate, so the
responder's own certificate cannot be verified; the handshake ends with
BAD_CERTIFICATE_STATUS_ERROR and a fatal alert without consulting
verify_callback, and only a callback set with
wolfSSL_CTX_SetOCSP_StatusVerifyCb() can accept that result. A live OCSP
lookup fails for the same reason, but its error does reach
verify_callback and can be accepted there.

\return none No return.

\param ctx pointer to the SSL context, created with wolfSSL_CTX_new().
Expand Down Expand Up @@ -3252,6 +3277,31 @@ void wolfSSL_CTX_set_verify(WOLFSSL_CTX* ctx, int mode,
wolfSSL_CTX_get_verify_mode() will not report it back. Including it in
mode has no effect on any of the other flags.

A non-zero return from verify_callback accepts a certificate the library
rejected. Without such a callback, or when it returns preverify_ok, the
rejection stands and the handshake ends with a fatal alert as before.

How far the acceptance reaches depends on why the certificate was
rejected. A chain certificate whose signature was confirmed against a
trusted anchor, and which failed a later check such as its validity
dates, its revocation status or its key usage, is still added to the
certificate manager: accepting it also makes it a trust anchor for later
connections from the same session's context, and verify_callback is not
consulted about it again. A certificate whose signature was never
confirmed is not added, so that acceptance applies to this handshake
alone. It is then not available as the signer of the next certificate in
the chain, which is reported to verify_callback in its turn, and
accepting each one in turn completes the handshake.

OCSP is the exception. A stapled response is verified against the
certificate manager, which does not hold the accepted certificate, so the
responder's own certificate cannot be verified; the handshake ends with
BAD_CERTIFICATE_STATUS_ERROR and a fatal alert without consulting
verify_callback, and only a callback set with
wolfSSL_CTX_SetOCSP_StatusVerifyCb() can accept that result. A live OCSP
lookup fails for the same reason, but its error does reach
verify_callback and can be accepted there.

\return none No return.

\param ssl pointer to the SSL session, created with wolfSSL_new().
Expand Down
24 changes: 24 additions & 0 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -17560,6 +17560,17 @@ PRAGMA_GCC_DIAG_POP
if (ret == 0 || (sigRet != 0 && IsPostSigParseErr(ret))) {
ret = sigRet;
}
/* ParseCertRelative() ran with VERIFY_NAME and left the signature to
* wc_CheckCertSignature() above, so it could not record the result. */
if (args->dCert != NULL) {
args->dCert->sigVerified = (verify == VERIFY_NAME) && (sigRet == 0);
Comment thread
miyazakh marked this conversation as resolved.
#ifdef WOLFSSL_DUAL_ALG_CERTS
/* wc_CheckCertSignature() checks the primary signature only. */
if (args->dCert->extAltSigAlgSet && args->dCert->extAltSigValSet) {
args->dCert->sigVerified = 0;
}
#endif
}
#endif

if (pSubjectHash)
Expand Down Expand Up @@ -19259,6 +19270,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#endif /* WOLFSSL_TRUST_PEER_CERT */
) {
int skipAddCA = 0;
int preCbRet = 0;
#if defined(HAVE_OCSP) && defined(HAVE_CRL)
int ocspNoUrl = 0;
int ocspStapleDeferred = 0;
Expand Down Expand Up @@ -19570,6 +19582,7 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
#endif /* defined(__APPLE__) && defined(WOLFSSL_SYS_CA_CERTS) */

/* Do verify callback */
preCbRet = ret;
ret = DoVerifyCallback(SSL_CM(ssl), ssl, ret, args);
if (ssl->options.verifyNone &&
(ret == WC_NO_ERR_TRACE(CRL_MISSING) ||
Expand All @@ -19585,6 +19598,17 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
skipAddCA = 1;
}
#endif

/* A chain cert whose signature was never confirmed against
* a trusted anchor stays out of the cache even when the
* verify callback waved it through: cached CAs are trust
* anchors for every later connection and the callback only
Comment thread
miyazakh marked this conversation as resolved.
* runs on an error. A failure raised after the signature
* verified leaves the key authentic, and the rest of the
* chain needs the cached entry. */
if (preCbRet != 0 && !args->dCert->sigVerified) {
skipAddCA = 1;
}
#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)
if (ret == 0 && addToPendingCAs && !alreadySigner &&
!ssl->options.verifyNone && !skipAddCA) {
Expand Down
Loading
Loading