diff --git a/src/internal.c b/src/internal.c index 60f13ef08f8..21162b2cb0b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -10578,6 +10578,10 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl) * example with the RNG, it isn't used beyond the handshake except when * using stream ciphers where it is retained. */ +#ifndef NO_CERTS + SslWaivedCAsFree(ssl); +#endif + if (ssl->options.side == WOLFSSL_SERVER_END) { WOLFSSL_MSG("Free'ing server ssl"); } @@ -16872,6 +16876,7 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 status_length, int idx) { int ret = 0; + Signer* waivedTail = NULL; OcspRequest* request; #if defined(HAVE_CERTIFICATE_STATUS_REQUEST) TLSX* ext = TLSX_Find(ssl->extensions, TLSX_STATUS_REQUEST); @@ -16946,6 +16951,8 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* InitOcspResponse sets single and status to response struct. */ InitOcspResponse(response, single, status, input +*inOutIdx, status_length, ssl->heap); + response->pendingCAs = SslWaivedCAsJoin(ssl, response->pendingCAs, + &waivedTail); /* Extract producedDate */ if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 1, 1) != 0) { @@ -16961,6 +16968,8 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, FreeOcspResponse(response); InitOcspResponse(response, single, status, input + *inOutIdx, status_length, ssl->heap); + response->pendingCAs = SslWaivedCAsJoin(ssl, response->pendingCAs, + &waivedTail); if (OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 0, 0) != 0) ret = BAD_CERTIFICATE_STATUS_ERROR; @@ -16981,6 +16990,7 @@ static int ProcessCSR_ex(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* FreeOcspResponse frees status and single only if * single->isDynamic is set. */ FreeOcspResponse(response); + SslWaivedCAsSplit(waivedTail); WC_FREE_VAR_EX(status, ssl->heap, DYNAMIC_TYPE_OCSP_STATUS); WC_FREE_VAR_EX(single, ssl->heap, DYNAMIC_TYPE_OCSP_ENTRY); @@ -17075,6 +17085,40 @@ int InitSigPkCb(WOLFSSL* ssl, SignatureCtx* sigCtx) #endif /* HAVE_PK_CALLBACKS */ +/* Join the connection's accepted CAs onto base for one lookup. */ +Signer* SslWaivedCAsJoin(WOLFSSL* ssl, Signer* base, Signer** pTail) +{ + Signer* tail = NULL; + + if (ssl != NULL && ssl->waivedCAs != NULL) { + tail = ssl->waivedCAs; + while (tail->next != NULL) + tail = tail->next; + tail->next = base; + base = ssl->waivedCAs; + } + *pTail = tail; + + return base; +} + +void SslWaivedCAsSplit(Signer* tail) +{ + if (tail != NULL) + tail->next = NULL; +} + +/* Drop the CAs that were accepted by a verify callback */ +void SslWaivedCAsFree(WOLFSSL* ssl) +{ + while (ssl->waivedCAs != NULL) { + Signer* waived = ssl->waivedCAs; + + ssl->waivedCAs = waived->next; + FreeSigner(waived, SSL_CM(ssl)->heap); + } +} + #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) #ifdef WOLFSSL_CHAIN_VERIFY_CB @@ -17559,6 +17603,117 @@ void DoCrlCallback(WOLFSSL_CERT_MANAGER* cm, WOLFSSL* ssl, } #endif +#ifndef NO_ASN +/* Parse a chain certificate as a CA and return it as a filled signer. */ +static int ProcessPeerCertMakeChainSigner(WOLFSSL* ssl, buffer* cert, int type, + Signer* extraCa, Signer** out) +{ + int ret = 0; + WC_DECLARE_VAR(dCertAdd, DecodedCert, 1, 0); + int dCertAdd_inited = 0; + DerBuffer* derBuffer = NULL; + Signer* s = NULL; + + *out = NULL; + + WC_ALLOC_VAR_EX(dCertAdd, DecodedCert, 1, ssl->heap, + DYNAMIC_TYPE_TMP_BUFFER, + { + ret = MEMORY_E; + goto exit_mcs; + }); + InitDecodedCert(dCertAdd, cert->buffer, cert->length, SSL_CM(ssl)->heap); + dCertAdd_inited = 1; +#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) + /* A signer doesn't keep the X509_NAMEs, don't build them. */ + dCertAdd->noX509Name = 1; +#endif +#ifdef WC_ASN_UNKNOWN_EXT_CB + if (SSL_CM(ssl)->unknownExtCallback != NULL) + wc_SetUnknownExtCallback(dCertAdd, SSL_CM(ssl)->unknownExtCallback); +#endif + ret = ParseCertEx(dCertAdd, CA_TYPE, NO_VERIFY, SSL_CM(ssl), extraCa); + if (ret != 0) + goto exit_mcs; + + if (!dCertAdd->isCA) { + WOLFSSL_MSG("Chain cert is not a CA, not usable as a signer"); + goto exit_mcs; + } +#ifndef ALLOW_INVALID_CERTSIGN + /* A CA needs keyCertSign once a Key Usage extension is present. Report + * the same error AddCA() would. */ + if (!dCertAdd->selfSigned && dCertAdd->extKeyUsageSet && + (dCertAdd->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { + WOLFSSL_MSG("Chain cert doesn't have key usage certificate signing"); + ret = NOT_CA_ERROR; + goto exit_mcs; + } +#endif + /* The Extended Key Usage purpose check is deliberately not repeated here. + * ProcessPeerCerts() applies it to this same certificate before offering it + * to a signer, and AddCA() does not apply it either, so repeating it would + * only take effect after a verify callback had already overridden the + * rejection, silently undoing that decision. */ + + ret = AllocDer(&derBuffer, cert->length, CA_TYPE, ssl->heap); + if (ret != 0 || derBuffer == NULL) + goto exit_mcs; + XMEMCPY(derBuffer->buffer, cert->buffer, cert->length); + + s = MakeSigner(SSL_CM(ssl)->heap); + if (s == NULL) { + ret = MEMORY_E; + goto exit_mcs; + } + ret = FillSigner(s, dCertAdd, type, derBuffer); + if (ret != 0) + goto exit_mcs; + + *out = s; + s = NULL; + +exit_mcs: + if (s != NULL) + FreeSigner(s, SSL_CM(ssl)->heap); + if (derBuffer != NULL) + FreeDer(&derBuffer); + if (dCertAdd_inited) + FreeDecodedCert(dCertAdd); + WC_FREE_VAR_EX(dCertAdd, ssl->heap, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/* Add a chain CA the verify callback accepted to the connection's list. */ +static int ProcessPeerCertAddWaivedCA(WOLFSSL* ssl, buffer* cert) +{ + Signer* s = NULL; + int ret; + + ret = ProcessPeerCertMakeChainSigner(ssl, cert, WOLFSSL_TEMP_CA, + ssl->waivedCAs, &s); + if (ret == 0 && s != NULL) { + s->next = ssl->waivedCAs; + ssl->waivedCAs = s; + } + + return ret; +} + +static int ProcessPeerCertIsWaivedCA(WOLFSSL* ssl, const Signer* ca) +{ + const Signer* s; + + for (s = ssl->waivedCAs; s != NULL; s = s->next) { + if (s == ca) + return 1; + } + + return 0; +} +#endif /* !NO_ASN */ + static void FreeProcPeerCertArgs(WOLFSSL* ssl, void* pArgs) { ProcPeerCertArgs* args = (ProcPeerCertArgs*)pArgs; @@ -17862,6 +18017,7 @@ static int ProcessPeerCertParse(WOLFSSL* ssl, ProcPeerCertArgs* args, byte* subjectHash = NULL; int alreadySigner = 0; Signer *extraSigners = NULL; + Signer *waivedTail = NULL; #if defined(HAVE_RPK) int cType; #endif @@ -17994,6 +18150,8 @@ PRAGMA_GCC_DIAG_POP } #endif /* Parse Certificate */ + extraSigners = SslWaivedCAsJoin(ssl, extraSigners, &waivedTail); + ret = ParseCertRelative(args->dCert, certType, verify, SSL_CM(ssl), extraSigners); #ifdef WOLFSSL_SMALL_CERT_VERIFY /* Self signed: the key that verified the signature is its own */ @@ -18005,6 +18163,8 @@ PRAGMA_GCC_DIAG_POP } #endif + SslWaivedCAsSplit(waivedTail); + #if defined(HAVE_RPK) /* Confirm the received certificate's form (X.509 vs raw public key) matches * the type negotiated with the peer. An un-negotiated bare key is reported @@ -18034,6 +18194,15 @@ PRAGMA_GCC_DIAG_POP } #ifdef WOLFSSL_SMALL_CERT_VERIFY + /* The check above searched the cert manager only; redo it on the key. */ + if (sigRet != 0 && args->dCert->ca != NULL && + args->dCert->ca->publicKey != NULL && + ProcessPeerCertIsWaivedCA(ssl, args->dCert->ca)) { + sigRet = CheckCertSignaturePubKey(cert->buffer, cert->length, + ssl->heap, args->dCert->ca->publicKey, + args->dCert->ca->pubKeySize, (int)args->dCert->ca->keyOID); + } + /* get signature check failures from above (a negotiated RPK leaf is parsed * with NO_VERIFY, so no signature check was run for it) */ if (ret == 0 || (sigRet != 0 && IsPostSigParseErr(ret))) { @@ -18459,88 +18628,21 @@ static int CheckChainCAExtKeyUsage(const WOLFSSL* ssl, const DecodedCert* cert) * for Certificate Status Request v2. */ static int ProcessPeerCertAddPendingCA(WOLFSSL* ssl, buffer* cert) { - int ret = 0; - WC_DECLARE_VAR(dCertAdd, DecodedCert, 1, 0); - int dCertAdd_inited = 0; - DerBuffer *derBuffer = NULL; - Signer *s = NULL; + Signer* s = NULL; + int ret; - WC_ALLOC_VAR_EX(dCertAdd, DecodedCert, 1, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER, - { - ret=MEMORY_E; - goto exit_req_v2; - }); - InitDecodedCert(dCertAdd, cert->buffer, cert->length, - ssl->heap); -#if defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL) - /* A signer doesn't keep the X509_NAMEs, don't build them. */ - dCertAdd->noX509Name = 1; -#endif - dCertAdd_inited = 1; - ret = ParseCert(dCertAdd, CA_TYPE, NO_VERIFY, - SSL_CM(ssl)); - if (ret != 0) { - goto exit_req_v2; - } - /* Only a certificate that is actually usable as a CA may enter the pending - * signer pool. ParseCertRelative() consults that pool ahead of the - * certificate manager and uses the signer as a verification key without - * further checks, so admission has to enforce the same capabilities AddCA() - * requires of a chain CA. - * - * A non-CA is skipped rather than reported as an error, because - * ProcessPeerCerts() only offers a chain cert to AddCA() when isCA is set: - * such a certificate is already left out of the certificate manager without - * failing the handshake. */ - if (!dCertAdd->isCA) { - WOLFSSL_MSG("Chain cert is not a CA, not adding as pending CA"); - goto exit_req_v2; - } -#ifndef ALLOW_INVALID_CERTSIGN - /* A CA needs keyCertSign once a Key Usage extension is present. Fail the - * handshake rather than quietly leaving it out of the pool. */ - if (!dCertAdd->selfSigned && dCertAdd->extKeyUsageSet && - (dCertAdd->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { - WOLFSSL_MSG("Chain cert doesn't have key usage certificate signing"); - ret = NOT_CA_ERROR; - goto exit_req_v2; - } -#endif - /* The Extended Key Usage purpose check is deliberately not repeated here. - * ProcessPeerCerts() applies it to this same certificate before offering it - * to the pool, and AddCA() does not apply it either, so repeating it would - * only take effect after a verify callback had already overridden the - * rejection, silently undoing that decision in CSR v2 builds alone. */ - ret = AllocDer(&derBuffer, cert->length, CA_TYPE, ssl->heap); - if (ret != 0 || derBuffer == NULL) { - goto exit_req_v2; - } - XMEMCPY(derBuffer->buffer, cert->buffer, cert->length); - s = MakeSigner(SSL_CM(ssl)->heap); - if (s == NULL) { - ret = MEMORY_E; - goto exit_req_v2; - } - /* WOLFSSL_CHAIN_CA, not CA_TYPE: TLSX_CSR2_MergePendingCA() promotes this - * signer into the certificate manager, and the unload path + /* WOLFSSL_CHAIN_CA, not WOLFSSL_TEMP_CA: TLSX_CSR2_MergePendingCA() + * promotes this signer into the certificate manager, and the unload path * (wolfSSL_CertManagerUnloadIntermediateCerts()) selects entries by that * type. AddCA() records chain CAs the same way. */ - ret = FillSigner(s, dCertAdd, WOLFSSL_CHAIN_CA, derBuffer); - if (ret != 0) { - goto exit_req_v2; + ret = ProcessPeerCertMakeChainSigner(ssl, cert, WOLFSSL_CHAIN_CA, + NULL, &s); + if (ret == 0 && s != NULL) { + ret = TLSX_CSR2_AddPendingSigner(ssl->extensions, s); + if (ret != 0) + FreeSigner(s, SSL_CM(ssl)->heap); } - ret = TLSX_CSR2_AddPendingSigner(ssl->extensions, s); -exit_req_v2: - if (s && (ret != 0)) - FreeSigner(s, SSL_CM(ssl)->heap); - if (derBuffer) - FreeDer(&derBuffer); - if (dCertAdd_inited) - FreeDecodedCert(dCertAdd); - WC_FREE_VAR_EX(dCertAdd, ssl->heap, - DYNAMIC_TYPE_TMP_BUFFER); return ret; } #endif /* HAVE_CERTIFICATE_STATUS_REQUEST_V2 */ @@ -19886,6 +19988,8 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2)) int holdCrl = 0; #endif + int preCbRet; + int caIsTemp = 0; /* select last certificate */ args->certIdx = args->count - 1; @@ -20223,7 +20327,13 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, SetRevocationVerifyRet(ssl, ret); /* Do verify callback */ + preCbRet = ret; ret = DoVerifyCallbackHeldCrl(ssl, args, ret, &heldCrlRet); + if (ret == 0 && preCbRet != 0) + caIsTemp = 1; + if (ret == 0 && args->dCert->ca != NULL && + ProcessPeerCertIsWaivedCA(ssl, args->dCert->ca)) + caIsTemp = 1; if (CrlErrWaived(ssl, ret)) ret = ssl->error = 0; #if defined(HAVE_OCSP) && defined(HAVE_CRL) && \ @@ -20248,7 +20358,8 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, #endif #if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) if (ret == 0 && addToPendingCAs && !alreadySigner && - !ssl->options.verifyNone && !skipAddCA) { + !ssl->options.verifyNone && !skipAddCA && + !caIsTemp) { /* The verifyNone and skipAddCA conditions mirror the * guards on the AddCA() call below. A certificate the * surrounding code has already declined to admit as a @@ -20283,7 +20394,10 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx, cert->buffer, cert->length); } #endif /* SESSION_CERTS && WOLFSSL_ALT_CERT_CHAINS */ - if (!alreadySigner) { + if (caIsTemp) { + ret = ProcessPeerCertAddWaivedCA(ssl, cert); + } + else if (!alreadySigner) { DerBuffer* add = NULL; ret = AllocDer(&add, cert->length, CA_TYPE, ssl->heap); if (ret < 0) @@ -21182,6 +21296,7 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, word32 list_length = status_length; byte idx = 0; Signer *pendingCAs = NULL; + Signer *waivedTail = NULL; #ifdef WOLFSSL_SMALL_STACK CertStatus* status; @@ -21240,7 +21355,8 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, ) { InitOcspResponse(response, single, status, input +*inOutIdx, status_length, ssl->heap); - response->pendingCAs = pendingCAs; + response->pendingCAs = SslWaivedCAsJoin(ssl, pendingCAs, + &waivedTail); if ((OcspResponseDecode(response, SSL_CM(ssl), ssl->heap, 0, 0) != 0) || (response->responseStatus != OCSP_SUCCESSFUL) @@ -21266,6 +21382,8 @@ static int DoCertificateStatus(WOLFSSL* ssl, byte* input, word32* inOutIdx, /* only frees 'single' if single->isDynamic is set */ FreeOcspResponse(response); + SslWaivedCAsSplit(waivedTail); + waivedTail = NULL; ret = CsrDoStatusVerifyCb(ssl, input + *inOutIdx, status_length, idx, ret); diff --git a/src/ocsp.c b/src/ocsp.c index c5b1f0ed102..7236c390212 100644 --- a/src/ocsp.c +++ b/src/ocsp.c @@ -351,6 +351,9 @@ int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int responseSz, #endif int ret; int validated = 0; /* ocsp validation flag */ +#ifndef NO_CERTS + Signer* waivedTail = NULL; +#endif (void)heap; @@ -377,9 +380,12 @@ int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int responseSz, if (ssl != NULL && TLSX_CSR2_IsMulti(ssl->extensions)) { ocspResponse->pendingCAs = TLSX_CSR2_GetPendingSigners(ssl->extensions); } -#else - (void)ssl; #endif +#ifndef NO_CERTS + ocspResponse->pendingCAs = SslWaivedCAsJoin(ssl, ocspResponse->pendingCAs, + &waivedTail); +#endif + (void)ssl; ret = OcspResponseDecode(ocspResponse, ocsp->cm, ocsp->cm->heap, 0, 0); if (ret != 0) { ocsp->error = ret; @@ -455,6 +461,9 @@ int CheckOcspResponse(WOLFSSL_OCSP *ocsp, byte *response, int responseSz, wc_UnLockMutex(&ocsp->ocspLock); end: +#ifndef NO_CERTS + SslWaivedCAsSplit(waivedTail); +#endif if (ret == 0 && validated == 1) { WOLFSSL_MSG("New OcspResponse validated"); } diff --git a/src/ssl.c b/src/ssl.c index 3773badb1d9..bd108a9845a 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -5827,6 +5827,11 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out, #endif } +#ifndef NO_CERTS + /* Trust for the previous peer must not carry into the next. */ + SslWaivedCAsFree(ssl); +#endif + /* reset error */ ssl->error = 0; diff --git a/tests/api.c b/tests/api.c index 0e2747575fa..415033ad982 100644 --- a/tests/api.c +++ b/tests/api.c @@ -42098,6 +42098,81 @@ static int test_override_alt_cert_chain(void) } #endif +#if defined(HAVE_SSL_MEMIO_TESTS_DEPENDENCIES) && \ + defined(WOLFSSL_PEM_TO_DER) && !defined(WOLFSSL_ALT_CERT_CHAINS) +static int test_chain_ca_no_persist_verify_cb(int preverify, + WOLFSSL_X509_STORE_CTX* store) +{ + (void)preverify; + (void)store; + return 1; +} + +static int test_chain_ca_no_persist_client_ctx(WOLFSSL_CTX* ctx) +{ + EXPECT_DECLS; + + ExpectIntEQ(wolfSSL_CertManagerUnloadCAs(wolfSSL_CTX_GetCertManager(ctx)), + WOLFSSL_SUCCESS); + wolfSSL_CTX_set_verify(ctx, WOLFSSL_VERIFY_PEER, + test_chain_ca_no_persist_verify_cb); + + return EXPECT_RESULT(); +} + +static int test_chain_ca_no_persist_server_ctx(WOLFSSL_CTX* ctx) +{ + EXPECT_DECLS; + + ExpectIntEQ(wolfSSL_CTX_use_certificate_chain_file(ctx, + "./certs/intermediate/server-chain.pem"), WOLFSSL_SUCCESS); + + return EXPECT_RESULT(); +} + +static int test_chain_ca_no_persist_result(WOLFSSL* ssl) +{ + EXPECT_DECLS; + WOLFSSL_CERT_MANAGER* cm = NULL; + + ExpectNotNull(cm = wolfSSL_CTX_GetCertManager(wolfSSL_get_SSL_CTX(ssl))); + /* The CA trusted via callback must not be usable as a signer afterwards */ + ExpectIntNE(wolfSSL_CertManagerVerify(cm, + "./certs/intermediate/ca-int2-cert.pem", WOLFSSL_FILETYPE_PEM), + WOLFSSL_SUCCESS); + /* Nor the CA that only verified because the aforementioned one vouched for + * it */ + ExpectIntNE(wolfSSL_CertManagerVerify(cm, + "./certs/intermediate/server-int-cert.pem", WOLFSSL_FILETYPE_PEM), + WOLFSSL_SUCCESS); + + return EXPECT_RESULT(); +} + +static int test_chain_ca_no_persist(void) +{ + EXPECT_DECLS; + test_ssl_cbf client_cbs, server_cbs; + + XMEMSET(&client_cbs, 0, sizeof(client_cbs)); + XMEMSET(&server_cbs, 0, sizeof(server_cbs)); + + client_cbs.ctx_ready = test_chain_ca_no_persist_client_ctx; + client_cbs.on_result = test_chain_ca_no_persist_result; + server_cbs.ctx_ready = test_chain_ca_no_persist_server_ctx; + + ExpectIntEQ(test_wolfSSL_client_server_nofail_memio(&client_cbs, + &server_cbs, NULL), TEST_SUCCESS); + + return EXPECT_RESULT(); +} +#else +static int test_chain_ca_no_persist(void) +{ + return TEST_SKIPPED; +} +#endif + static int test_rpk_set_xxx_cert_type(void) { EXPECT_DECLS; @@ -47976,6 +48051,7 @@ TEST_CASE testCases[] = { /* Can't memory test as client/server Asserts. */ TEST_DECL(test_harden_no_secure_renegotiation), TEST_DECL(test_override_alt_cert_chain), + TEST_DECL(test_chain_ca_no_persist), TEST_DECL(test_rpk_set_xxx_cert_type), TEST_DECL(test_short_session_id), /* Can't memory test as client/server hangs. */ diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 4b9eeaaec70..162bcadd009 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -25098,7 +25098,8 @@ static int DecodeCertReq(DecodedCert* cert, int* criticalExt) #endif /* WOLFSSL_ASN_TEMPLATE */ -int ParseCert(DecodedCert* cert, int type, int verify, WOLFSSL_CERT_MANAGER* cm) +int ParseCertEx(DecodedCert* cert, int type, int verify, + WOLFSSL_CERT_MANAGER* cm, Signer* extraCa) { int ret; #if (!defined(WC_ASN_NO_HEAP) && !defined(NO_WOLFSSL_CM_VERIFY)) || \ @@ -25106,7 +25107,7 @@ int ParseCert(DecodedCert* cert, int type, int verify, WOLFSSL_CERT_MANAGER* cm) char* ptr; #endif - ret = ParseCertRelative(cert, type, verify, cm, NULL); + ret = ParseCertRelative(cert, type, verify, cm, extraCa); if (ret < 0) return ret; @@ -25149,6 +25150,11 @@ int ParseCert(DecodedCert* cert, int type, int verify, WOLFSSL_CERT_MANAGER* cm) return ret; } +int ParseCert(DecodedCert* cert, int type, int verify, WOLFSSL_CERT_MANAGER* cm) +{ + return ParseCertEx(cert, type, verify, cm, NULL); +} + int wc_ParseCert(DecodedCert* cert, int type, int verify, WOLFSSL_CERT_MANAGER* cm) { @@ -25872,12 +25878,8 @@ static Signer* FindSignerByAkidOrName(WOLFSSL_CERT_MANAGER* cm, Signer* extraCAList, Signer* cert) { Signer* signer = NULL; -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 - #ifndef NO_SKID +#ifndef NO_SKID Signer* exCaSigner; - #endif -#else - (void)extraCAList; #endif #ifndef NO_SKID @@ -25898,7 +25900,6 @@ static Signer* FindSignerByAkidOrName(WOLFSSL_CERT_MANAGER* cm, signer = GetCA(cm, cert->issuerNameHash); #endif -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 if (signer == NULL && extraCAList != NULL) { #ifndef NO_SKID if (cert->authKeyIdSet) { @@ -25923,7 +25924,6 @@ static Signer* FindSignerByAkidOrName(WOLFSSL_CERT_MANAGER* cm, signer = findSignerByName(extraCAList, cert->issuerNameHash); #endif } -#endif return signer; } @@ -26507,11 +26507,30 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, if (!cert->selfIssued || (verify != NO_VERIFY && type != CA_TYPE && type != TRUSTED_PEER_TYPE)) { cert->ca = NULL; -#ifdef HAVE_CERTIFICATE_STATUS_REQUEST_V2 - if (extraCAList != NULL) { - cert->ca = findSignerByName(extraCAList, cert->issuerHash); - } -#endif + if (extraCAList != NULL) { + #ifndef NO_SKID + if (cert->extAuthKeyIdSet) { + Signer* exCa; + + for (exCa = extraCAList; exCa != NULL; exCa = exCa->next) { + if (XMEMCMP(exCa->subjectKeyIdHash, + cert->extAuthKeyId, + SIGNER_DIGEST_SIZE) == 0 && + XMEMCMP(exCa->subjectNameHash, cert->issuerHash, + SIGNER_DIGEST_SIZE) == 0) { + cert->ca = exCa; + break; + } + } + /* AKID is authoritative; do not fall back to name. */ + } + else + #endif + { + cert->ca = findSignerByName(extraCAList, + cert->issuerHash); + } + } #ifndef NO_SKID if (cert->ca == NULL && cert->extAuthKeyIdSet) { cert->ca = GetCA(cm, cert->extAuthKeyId); @@ -26567,7 +26586,8 @@ int ParseCertRelative(DecodedCert* cert, int type, int verify, } #endif /* WOLFSSL_NO_TRUSTED_CERTS_VERIFY */ #else - cert->ca = GetCA(cm, cert->issuerHash); + if (cert->ca == NULL) + cert->ca = GetCA(cm, cert->issuerHash); #endif /* !NO_SKID */ if (cert->ca) { @@ -38041,7 +38061,7 @@ static Signer *OcspFindSigner(OcspResponse *resp, WOLFSSL_CERT_MANAGER *cm) if (s) return s; } -#if defined(HAVE_CERTIFICATE_STATUS_REQUEST_V2) +#ifndef NO_CERTS if (resp->pendingCAs == NULL) return NULL; diff --git a/wolfssl/internal.h b/wolfssl/internal.h index d0aa5473165..c5faa748062 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2997,6 +2997,11 @@ WOLFSSL_LOCAL int CM_VerifyBuffer_ex(WOLFSSL_CERT_MANAGER* cm, const byte* buff, #ifndef NO_CERTS +WOLFSSL_LOCAL Signer* SslWaivedCAsJoin(WOLFSSL* ssl, Signer* base, + Signer** pTail); +WOLFSSL_LOCAL void SslWaivedCAsSplit(Signer* tail); +WOLFSSL_LOCAL void SslWaivedCAsFree(WOLFSSL* ssl); + #if !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) typedef struct ProcPeerCertArgs { buffer* certs; @@ -7320,6 +7325,9 @@ struct WOLFSSL { #ifdef WOLFSSL_LOCAL_X509_STORE WOLFSSL_X509_STORE* x509_store_pt; /* take ownership of external store */ #endif +#ifndef NO_CERTS + Signer* waivedCAs; /* callback-accepted chain CAs */ +#endif #ifdef KEEP_PEER_CERT #ifdef WOLFSSL_DYNAMIC_PEER_CERT WOLFSSL_X509* peerCert; /* X509 peer cert, NULL when none. diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index ad14fcf5ab4..e56909539c5 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -4196,8 +4196,9 @@ enum { WOLFSSL_USER_CA = 1, /* user added as trusted */ WOLFSSL_CHAIN_CA = 2, /* added to cache from trusted chain */ - WOLFSSL_TEMP_CA = 3, /* Temp intermediate CA, only for use by - * X509_STORE */ + WOLFSSL_TEMP_CA = 3, /* Temp intermediate CA, scoped to a single + * X509_STORE verification or Certificate + * message */ WOLFSSL_USER_INTER = 4 /* user added intermediate cert */ }; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 9fa398d8652..cd6eea61faa 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -2653,6 +2653,8 @@ WOLFSSL_ASN_API int AddSignature(byte* buf, int bodySz, const byte* sig, int sig WOLFSSL_LOCAL int ParseCertRelative(DecodedCert* cert, int type, int verify, WOLFSSL_CERT_MANAGER* cm, Signer *extraCa); +WOLFSSL_LOCAL int ParseCertEx(DecodedCert* cert, int type, int verify, + WOLFSSL_CERT_MANAGER* cm, Signer* extraCa); WOLFSSL_LOCAL int DecodeToKey(DecodedCert* cert, int verify); #ifdef WOLFSSL_ASN_TEMPLATE WOLFSSL_LOCAL int DecodeCert(DecodedCert* cert, int verify, int* criticalExt);