Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions src/ssl_certman.c
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,45 @@ int wolfSSL_CertManagerSetCRLUnknownExtCallbackEx(WOLFSSL_CERT_MANAGER* cm,
#endif /* HAVE_CRL */
#endif /* WC_ASN_UNKNOWN_EXT_CB */

#if !defined(NO_WOLFSSL_CM_VERIFY) && \
(!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH))
/* Certificate verdicts a verify callback may override, matching the errors the
* TLS path also hands to it: validity dates, an untrusted or self-signed chain,
* a failed signature, weak key sizes, name, path length, key usage, unhandled
* critical extensions, and revocation. This is an allowlist, so any other error
* such as a parse, algorithm, resource, or lock failure that left no verified
* certificate fails closed and never reaches the callback. */
static int cm_verify_err_overridable(int err)
{
if ((err == WC_NO_ERR_TRACE(ASN_BEFORE_DATE_E)) ||
(err == WC_NO_ERR_TRACE(ASN_AFTER_DATE_E)) ||
(err == WC_NO_ERR_TRACE(ASN_NO_SIGNER_E)) ||
(err == WC_NO_ERR_TRACE(ASN_SELF_SIGNED_E)) ||
(err == WC_NO_ERR_TRACE(ASN_SIG_CONFIRM_E)) ||
(err == WC_NO_ERR_TRACE(BAD_PADDING_E)) ||
(err == WC_NO_ERR_TRACE(ASN_NAME_INVALID_E)) ||
(err == WC_NO_ERR_TRACE(ASN_PATHLEN_INV_E)) ||
(err == WC_NO_ERR_TRACE(ASN_PATHLEN_SIZE_E)) ||
(err == WC_NO_ERR_TRACE(ASN_CRIT_EXT_E)) ||
(err == WC_NO_ERR_TRACE(KEYUSAGE_E)) ||
(err == WC_NO_ERR_TRACE(EXTKEYUSAGE_E)) ||
(err == WC_NO_ERR_TRACE(RSA_KEY_SIZE_E)) ||
(err == WC_NO_ERR_TRACE(ECC_KEY_SIZE_E)) ||
(err == WC_NO_ERR_TRACE(FALCON_KEY_SIZE_E)) ||
(err == WC_NO_ERR_TRACE(MLDSA_KEY_SIZE_E))) {
return 1;
}
#ifdef HAVE_CRL
if ((err == WC_NO_ERR_TRACE(CRL_CERT_REVOKED)) ||
(err == WC_NO_ERR_TRACE(CRL_MISSING)) ||
(err == WC_NO_ERR_TRACE(CRL_CERT_DATE_ERR))) {
return 1;
}
#endif
return 0;
}
#endif

#if (!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH)) || \
defined(OPENSSL_EXTRA)
/* Verify the certificate.
Expand Down Expand Up @@ -862,6 +901,20 @@ int CM_VerifyBuffer_ex(WOLFSSL_CERT_MANAGER* cm, const unsigned char* buff,

#if !defined(NO_WOLFSSL_CM_VERIFY) && \
(!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH))
/* Only a certificate-policy verdict may be handed to the callback; any
* other error leaves no verified certificate and fails closed. Classify
* this attempt's own result first so it cannot be lost. */
if ((ret != 0) && !cm_verify_err_overridable(ret)) {
fatal = 1;
}
/* A prior load failure is what the callback should see, but only when this
* attempt did not fail closed; it too fails closed when not a verdict. */
if ((!fatal) && (prev_err != 0)) {
ret = prev_err;
if (!cm_verify_err_overridable(ret)) {
fatal = 1;
}
}
/* Use callback to perform verification too if available. */
if ((!fatal) && cm->verifyCallback) {
WC_DECLARE_VAR(args, ProcPeerCertArgs, 1, 0);
Expand Down Expand Up @@ -890,10 +943,6 @@ int CM_VerifyBuffer_ex(WOLFSSL_CERT_MANAGER* cm, const unsigned char* buff,
args->dCert = cert;
args->dCertInit = 1;

/* Replace value in ret with an error value passed in. */
if (prev_err != 0) {
ret = prev_err;
}
/* Use callback to verify certificate. */
ret = DoVerifyCallback(cm, NULL, ret, args);
}
Expand Down
71 changes: 71 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -3883,6 +3883,76 @@ static int test_wolfSSL_OtherName(void)
return EXPECT_RESULT();
}

#if !defined(NO_CERTS) && !defined(NO_WOLFSSL_CM_VERIFY) && \
(!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH))
static int cm_override_cb(int preverify, WOLFSSL_X509_STORE_CTX* store)
{
(void)preverify;
(void)store;
return 1; /* override any error */
}
#endif

static int test_wolfSSL_CertManagerVerifyBuffer_internal_err(void)
{
EXPECT_DECLS;
#if !defined(NO_CERTS) && !defined(NO_WOLFSSL_CM_VERIFY) && \
(!defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH))
WOLFSSL_CERT_MANAGER* cm = NULL;
unsigned char bad[64];
#if defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) && !defined(NO_SHA256)
/* sha256WithRSAEncryption, the algorithm of server_cert_der_2048 */
static const unsigned char sigAlgOid[9] =
{ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b };
unsigned char certBuf[2048];
int i;
int last = -1;
#endif

/* Malformed DER, so parsing fails with an internal error rather than a
* certificate verification verdict. */
XMEMSET(bad, 0x30, sizeof(bad));
bad[1] = 0x3e;

/* A verify callback that overrides every error must not turn an internal
* error into a success. */
ExpectNotNull(cm = wolfSSL_CertManagerNew());
wolfSSL_CertManagerSetVerify(cm, cm_override_cb);
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, bad, (long)sizeof(bad),
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

/* The certificate-loading path also reverifies with the callback, so a
* malformed CA must fail closed there too. */
ExpectIntNE(wolfSSL_CertManagerLoadCABuffer(cm, bad, (long)sizeof(bad),
WOLFSSL_FILETYPE_ASN1), WOLFSSL_SUCCESS);

#if defined(USE_CERT_BUFFERS_2048) && !defined(NO_RSA) && !defined(NO_SHA256)
/* A mismatched outer signature-algorithm OID means the signature was
* never checked, so it must fail closed as well. */
ExpectIntLE(sizeof_server_cert_der_2048, (int)sizeof(certBuf));
if (EXPECT_SUCCESS()) {
XMEMCPY(certBuf, server_cert_der_2048,
(size_t)sizeof_server_cert_der_2048);
for (i = 0; i + (int)sizeof(sigAlgOid) <=
(int)sizeof_server_cert_der_2048; i++) {
if (XMEMCMP(certBuf + i, sigAlgOid, sizeof(sigAlgOid)) == 0) {
last = i;
}
}
ExpectIntGT(last, 0);
}
if (EXPECT_SUCCESS()) {
certBuf[last + sizeof(sigAlgOid) - 1] ^= 0x01;
ExpectIntNE(wolfSSL_CertManagerVerifyBuffer(cm, certBuf,
(long)sizeof_server_cert_der_2048, WOLFSSL_FILETYPE_ASN1),
WOLFSSL_SUCCESS);
}
#endif
wolfSSL_CertManagerFree(cm);
#endif
return EXPECT_RESULT();
}

#ifdef HAVE_CERT_CHAIN_VALIDATION
#ifndef WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION
static int test_wolfSSL_CertRsaPss(void)
Expand Down Expand Up @@ -40354,6 +40424,7 @@ TEST_CASE testCases[] = {
!defined(WOLFSSL_TEST_APPLE_NATIVE_CERT_VALIDATION)
TEST_DECL(test_wolfSSL_CertRsaPss),
#endif
TEST_DECL(test_wolfSSL_CertManagerVerifyBuffer_internal_err),
TEST_DECL(test_wolfSSL_CTX_load_verify_locations_ex),
TEST_DECL(test_wolfSSL_CTX_load_verify_buffer_ex),
TEST_DECL(test_wolfSSL_CTX_load_verify_chain_buffer_format),
Expand Down
Loading