From 17c9e92b7f780c7e122b2bfb2a27985a3273354a Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Wed, 16 Oct 2024 16:34:57 -0700 Subject: [PATCH 01/17] Initial rewrite of X509 STORE to replicate openssl behavior --- src/ssl_certman.c | 21 +- src/x509.c | 11 +- src/x509_str.c | 488 ++++++++++++++++++++++++++++++++++++++------- tests/api.c | 382 ++++++++++++++++++++++++++++++++++- wolfssl/internal.h | 2 + wolfssl/ssl.h | 11 +- 6 files changed, 818 insertions(+), 97 deletions(-) diff --git a/src/ssl_certman.c b/src/ssl_certman.c index a5b622dede..700216c55a 100644 --- a/src/ssl_certman.c +++ b/src/ssl_certman.c @@ -455,11 +455,12 @@ int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm) return ret; } -int wolfSSL_CertManagerUnloadIntermediateCerts(WOLFSSL_CERT_MANAGER* cm) +static int wolfSSL_CertManagerUnloadIntermediateCertsEx(WOLFSSL_CERT_MANAGER* cm, + int type) { int ret = WOLFSSL_SUCCESS; - WOLFSSL_ENTER("wolfSSL_CertManagerUnloadIntermediateCerts"); + WOLFSSL_ENTER("wolfSSL_CertManagerUnloadIntermediateCertsEx"); /* Validate parameter. */ if (cm == NULL) { @@ -471,7 +472,7 @@ int wolfSSL_CertManagerUnloadIntermediateCerts(WOLFSSL_CERT_MANAGER* cm) } if (ret == WOLFSSL_SUCCESS) { /* Dispose of CA table. */ - FreeSignerTableType(cm->caTable, CA_TABLE_SIZE, WOLFSSL_CHAIN_CA, + FreeSignerTableType(cm->caTable, CA_TABLE_SIZE, type, cm->heap); /* Unlock CA table. */ @@ -481,6 +482,20 @@ int wolfSSL_CertManagerUnloadIntermediateCerts(WOLFSSL_CERT_MANAGER* cm) return ret; } +#if defined(OPENSSL_EXTRA) +static int wolfSSL_CertManagerUnloadTempIntermediateCerts(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerUnloadTempIntermediateCerts"); + return wolfSSL_CertManagerUnloadIntermediateCertsEx(cm, WOLFSSL_INTER_CA); +} +#endif + +int wolfSSL_CertManagerUnloadIntermediateCerts(WOLFSSL_CERT_MANAGER* cm) +{ + WOLFSSL_ENTER("wolfSSL_CertManagerUnloadIntermediateCerts"); + return wolfSSL_CertManagerUnloadIntermediateCertsEx(cm, WOLFSSL_CHAIN_CA); +} + #ifdef WOLFSSL_TRUST_PEER_CERT /* Unload the trusted peers table. * diff --git a/src/x509.c b/src/x509.c index d130f9fe19..c440de498d 100644 --- a/src/x509.c +++ b/src/x509.c @@ -5559,7 +5559,7 @@ WOLFSSL_EVP_PKEY* wolfSSL_X509_get_pubkey(WOLFSSL_X509* x509) * size of this subset and its memory usage */ #endif /* OPENSSL_EXTRA_X509_SMALL || KEEP_PEER_CERT || SESSION_CERTS */ -#if defined(OPENSSL_ALL) +#if defined(OPENSSL_ALL) || defined(OPENSSL_EXTRA) /* * Converts a and b to DER and then does an XMEMCMP to check if they match. * Returns 0 when certificates match and WOLFSSL_FATAL_ERROR when they don't. @@ -7536,7 +7536,6 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, byte* pem = NULL; byte* curr = NULL; byte* prev = NULL; - WOLFSSL_X509* x509; const char* header = NULL; const char* footer = NULL; @@ -7597,12 +7596,8 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, } else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) { - x509 = wolfSSL_X509_load_certificate_buffer(curr, (int)sz, - WOLFSSL_FILETYPE_PEM); - if (x509 == NULL) - goto end; - ret = wolfSSL_X509_STORE_add_cert(lookup->store, x509); - wolfSSL_X509_free(x509); + ret = wolfSSL_X509_STORE_load_cert_buffer(lookup->store, curr, sz, + WOLFSSL_FILETYPE_PEM); if (ret != WOLFSSL_SUCCESS) goto end; curr = (byte*)XSTRNSTR((char*)curr, footer, (unsigned int)sz); diff --git a/src/x509_str.c b/src/x509_str.c index dfb11fb026..ff1e72701d 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -36,6 +36,17 @@ #ifndef NO_CERTS +#ifdef OPENSSL_EXTRA +static int wolfSSL_X509_STORE_get_issuer_ex(WOLFSSL_X509 **issuer, + WOLFSSL_STACK *certs, WOLFSSL_X509 *x); +static int wolfSSL_X509_STORE_add_ca(WOLFSSL_X509_STORE* store, + WOLFSSL_X509* x509, int type); +#endif + +#ifndef WOLFSSL_X509_STORE_DEFAULT_MAX_DEPTH +#define WOLFSSL_X509_STORE_DEFAULT_MAX_DEPTH 100 +#endif + /******************************************************************************* * START OF X509_STORE_CTX APIs ******************************************************************************/ @@ -78,6 +89,14 @@ void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx) #ifdef OPENSSL_EXTRA XFREE(ctx->param, ctx->heap, DYNAMIC_TYPE_OPENSSL); ctx->param = NULL; + + if (ctx->ctxIntermediates != NULL) { + wolfSSL_sk_X509_free(ctx->ctxIntermediates); + } + + if (ctx->chain != NULL) { + wolfSSL_sk_X509_free(ctx->chain); + } #endif XFREE(ctx, ctx->heap, DYNAMIC_TYPE_X509_CTX); @@ -97,7 +116,7 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx, WOLF_STACK_OF(WOLFSSL_X509)* sk) { int ret = 0; - (void)sk; + int i = 0; WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_init"); if (ctx != NULL) { @@ -106,51 +125,37 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx, ctx->current_cert = x509; #else if(x509 != NULL){ - ctx->current_cert = wolfSSL_X509_d2i_ex(NULL, x509->derCert->buffer, - x509->derCert->length, x509->heap); + ctx->current_cert = wolfSSL_X509_d2i_ex(NULL, + x509->derCert->buffer, + x509->derCert->length, + x509->heap); if(ctx->current_cert == NULL) return WOLFSSL_FAILURE; } else ctx->current_cert = NULL; #endif - ctx->chain = sk; - /* Add intermediate certs, that verify to a loaded CA, to the store */ if (sk != NULL) { - byte addedAtLeastOne = 1; - WOLF_STACK_OF(WOLFSSL_X509)* head = wolfSSL_shallow_sk_dup(sk); - if (head == NULL) - return WOLFSSL_FAILURE; - while (addedAtLeastOne) { - WOLF_STACK_OF(WOLFSSL_X509)* cur = head; - WOLF_STACK_OF(WOLFSSL_X509)** prev = &head; - addedAtLeastOne = 0; - while (cur) { - WOLFSSL_X509* cert = cur->data.x509; - if (cert != NULL && cert->derCert != NULL && - wolfSSL_CertManagerVerifyBuffer(store->cm, - cert->derCert->buffer, - cert->derCert->length, - WOLFSSL_FILETYPE_ASN1) == WOLFSSL_SUCCESS) { - ret = wolfSSL_X509_STORE_add_cert(store, cert); - if (ret < 0) { - wolfSSL_sk_free(head); - return WOLFSSL_FAILURE; - } - addedAtLeastOne = 1; - *prev = cur->next; - wolfSSL_sk_free_node(cur); - cur = *prev; - } - else { - prev = &cur->next; - cur = cur->next; - } + if (ctx->ctxIntermediates == NULL) { + ctx->ctxIntermediates = sk_X509_new_null(); + if (ctx->ctxIntermediates == NULL) { + return WOLFSSL_FAILURE; + } + } + + for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { + ret = wolfSSL_sk_X509_push(ctx->ctxIntermediates, + wolfSSL_sk_X509_value(sk, i)); + if (ret <= 0) { + return WOLFSSL_FAILURE; } } - wolfSSL_sk_free(head); } + if (ctx->chain != NULL) { + wolfSSL_sk_X509_free(ctx->chain); + ctx->chain = NULL; + } ctx->sesChain = NULL; ctx->domain = NULL; #ifdef HAVE_EX_DATA @@ -192,10 +197,14 @@ void wolfSSL_X509_STORE_CTX_cleanup(WOLFSSL_X509_STORE_CTX* ctx) } -void wolfSSL_X509_STORE_CTX_trusted_stack(WOLFSSL_X509_STORE_CTX *ctx, WOLF_STACK_OF(WOLFSSL_X509) *sk) +void wolfSSL_X509_STORE_CTX_trusted_stack(WOLFSSL_X509_STORE_CTX *ctx, + WOLF_STACK_OF(WOLFSSL_X509) *sk) { if (ctx != NULL) { - ctx->chain = sk; + if (ctx->setTrustedSk != NULL) { + wolfSSL_sk_X509_free(ctx->setTrustedSk); + } + ctx->setTrustedSk = sk; } } @@ -255,19 +264,15 @@ static void SetupStoreCtxError(WOLFSSL_X509_STORE_CTX* ctx, int ret) wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth); } -/* Verifies certificate chain using WOLFSSL_X509_STORE_CTX - * returns 0 on success or < 0 on failure. - */ -int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) +static int wolfSSL_X509_verify_cert_ex(WOLFSSL_X509_STORE_CTX* ctx) { - WOLFSSL_ENTER("wolfSSL_X509_verify_cert"); + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); - if (ctx != NULL && ctx->store != NULL && ctx->store->cm != NULL - && ctx->current_cert != NULL && ctx->current_cert->derCert != NULL) { - int ret = wolfSSL_CertManagerVerifyBuffer(ctx->store->cm, - ctx->current_cert->derCert->buffer, - ctx->current_cert->derCert->length, - WOLFSSL_FILETYPE_ASN1); + if (ctx->current_cert != NULL && ctx->current_cert->derCert != NULL) { + ret = wolfSSL_CertManagerVerifyBuffer(ctx->store->cm, + ctx->current_cert->derCert->buffer, + ctx->current_cert->derCert->length, + WOLFSSL_FILETYPE_ASN1); SetupStoreCtxError(ctx, ret); #if defined(OPENSSL_ALL) || defined(WOLFSSL_QT) if (ctx->store && ctx->store->verify_cb) @@ -278,9 +283,9 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) if (ret != WC_NO_ERR_TRACE(ASN_BEFORE_DATE_E) && ret != WC_NO_ERR_TRACE(ASN_AFTER_DATE_E)) { /* wolfSSL_CertManagerVerifyBuffer only returns ASN_AFTER_DATE_E or - ASN_BEFORE_DATE_E if there are no additional errors found in the - cert. Therefore, check if the cert is expired or not yet valid - in order to return the correct expected error. */ + ASN_BEFORE_DATE_E if there are no additional errors found in the + cert. Therefore, check if the cert is expired or not yet valid + in order to return the correct expected error. */ byte *afterDate = ctx->current_cert->notAfter.data; byte *beforeDate = ctx->current_cert->notBefore.data; @@ -300,10 +305,157 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) #endif } #endif + } + + return ret; +} + +/* Verifies certificate chain using WOLFSSL_X509_STORE_CTX + * returns 0 on success or < 0 on failure. + */ +int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) +{ + WOLFSSL_ENTER("wolfSSL_X509_verify_cert"); + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + int done = 0; + int added = 0; + int i = 0; + int numInterAdd = 0; + int depth = 0; + WOLFSSL_X509 *issuer = NULL; + WOLFSSL_X509 *orig = NULL; + WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL; + + if (ctx == NULL || ctx->store == NULL || ctx->store->cm == NULL + || ctx->current_cert == NULL || ctx->current_cert->derCert == NULL) { + return WOLFSSL_FATAL_ERROR; + } + + certs = ctx->store->certs; + if (ctx->chain != NULL) { + wolfSSL_sk_X509_free(ctx->chain); + } + ctx->chain = wolfSSL_sk_X509_new_null(); + + if (ctx->setTrustedSk != NULL) { + certs = ctx->setTrustedSk; + } - return ret >= 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + if (certs == NULL && + wolfSSL_sk_X509_num(ctx->ctxIntermediates) > 0) { + certs = ctx->ctxIntermediates; } - return WOLFSSL_FATAL_ERROR; + else { + /* Add the intermediates provided on init to the list of untrusted + * intermediates to be used */ + for (i = 0; i < wolfSSL_sk_X509_num(ctx->ctxIntermediates); i++) { + ret = wolfSSL_sk_X509_push(certs, + wolfSSL_sk_X509_value(ctx->ctxIntermediates, i)); + if (ret <= 0) { + return WOLFSSL_FAILURE; + } + + numInterAdd++; + } + } + + if (ctx->depth > 0) { + depth = ctx->depth + 1; + } + else { + depth = WOLFSSL_X509_STORE_DEFAULT_MAX_DEPTH + 1; + } + + orig = ctx->current_cert; + while(done == 0 && depth > 0) { + issuer = NULL; + + /* Try to find an untrusted issuer first */ + ret = wolfSSL_X509_STORE_get_issuer_ex(&issuer, certs, + ctx->current_cert); + if (ret == WOLFSSL_SUCCESS) { + if (ctx->current_cert == issuer) { + wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); + break; + } + + /* We found our issuer in the non-trusted cert list, add it + * to the CM and verify the current cert against it */ + ret = wolfSSL_X509_STORE_add_ca(ctx->store, issuer, + WOLFSSL_INTER_CA); + if (ret != WOLFSSL_SUCCESS) { + goto exit; + } + + added = 1; + + ret = wolfSSL_X509_verify_cert_ex(ctx); + if (ret != WOLFSSL_SUCCESS) { + goto exit; + } + + /* Add it to the current chain and look at the issuer cert next */ + wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); + ctx->current_cert = issuer; + } + else if (ret == WOLFSSL_FAILURE) { + /* Could not find in untrusted list, only place left is + * a trusted CA in the CM */ + ret = wolfSSL_X509_verify_cert_ex(ctx); + if (ret != WOLFSSL_SUCCESS) { + goto exit; + } + + /* Cert verified, finish building the chain */ + wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); + #ifdef WOLFSSL_SIGNER_DER_CERT + x509GetIssuerFromCM(&issuer, ctx->store->cm, ctx->current_cert); + if (issuer != NULL && ctx->store->owned != NULL) { + wolfSSL_sk_X509_push(ctx->store->owned, issuer); + } + #else + if (ctx->setTrustedSk == NULL) { + wolfSSL_X509_STORE_get_issuer_ex(&issuer, + ctx->store->trusted, ctx->current_cert); + } + else { + wolfSSL_X509_STORE_get_issuer_ex(&issuer, + ctx->setTrustedSk, ctx->current_cert); + } + #endif + if (issuer != NULL) { + wolfSSL_sk_X509_push(ctx->chain, issuer); + } + + done = 1; + } + else { + goto exit; + } + + depth--; + } + +exit: + /* Remove additional intermediates from init from the store */ + if (ctx != NULL && numInterAdd > 0) { + for (i = 0; i < numInterAdd; i++) { + wolfSSL_sk_X509_pop(ctx->store->certs); + } + } + /* Remove intermediates that were added to CM */ + if (ctx != NULL) { + if (ctx->store != NULL) { + if (added == 1) { + wolfSSL_CertManagerUnloadTempIntermediateCerts(ctx->store->cm); + } + } + if (orig != NULL) { + ctx->current_cert = orig; + } + } + + return ret == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } #endif /* OPENSSL_EXTRA */ @@ -743,7 +895,7 @@ int wolfSSL_X509_STORE_CTX_get1_issuer(WOLFSSL_X509 **issuer, for (node = ctx->chain; node != NULL; node = node->next) { if (wolfSSL_X509_check_issued(node->data.x509, x) == WOLFSSL_X509_V_OK) { - *issuer = x; + *issuer = node->data.x509; return WOLFSSL_SUCCESS; } } @@ -755,6 +907,31 @@ int wolfSSL_X509_STORE_CTX_get1_issuer(WOLFSSL_X509 **issuer, } #endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */ +#ifdef OPENSSL_EXTRA + +static int wolfSSL_X509_STORE_get_issuer_ex(WOLFSSL_X509 **issuer, + WOLFSSL_STACK * certs, WOLFSSL_X509 *x) +{ + int i; + + if (issuer == NULL || x == NULL) + return WOLFSSL_FATAL_ERROR; + + if (certs != NULL) { + for (i = 0; i < wolfSSL_sk_X509_num(certs); i++) { + if (wolfSSL_X509_check_issued(wolfSSL_sk_X509_value(certs, i), x) == + WOLFSSL_X509_V_OK) { + *issuer = wolfSSL_sk_X509_value(certs, i); + return WOLFSSL_SUCCESS; + } + } + } + + return WOLFSSL_FAILURE; +} + +#endif + /******************************************************************************* * END OF X509_STORE_CTX APIs ******************************************************************************/ @@ -789,6 +966,17 @@ WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void) if ((store->cm = wolfSSL_CertManagerNew()) == NULL) goto err_exit; + if ((store->certs = wolfSSL_sk_X509_new_null()) == NULL) + goto err_exit; + + if ((store->owned = wolfSSL_sk_X509_new_null()) == NULL) + goto err_exit; + +#if !defined(WOLFSSL_SIGNER_DER_CERT) + if ((store->trusted = wolfSSL_sk_X509_new_null()) == NULL) + goto err_exit; +#endif + #ifdef HAVE_CRL store->crl = store->cm->crl; #endif @@ -849,6 +1037,20 @@ void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store) wolfSSL_CertManagerFree(store->cm); store->cm = NULL; } + if (store->certs != NULL) { + wolfSSL_sk_X509_free(store->certs); + store->certs = NULL; + } + if (store->owned != NULL) { + wolfSSL_sk_X509_pop_free(store->owned, wolfSSL_X509_free); + store->owned = NULL; + } +#if !defined(WOLFSSL_SIGNER_DER_CERT) + if (store->trusted != NULL) { + wolfSSL_sk_X509_free(store->trusted); + store->trusted = NULL; + } +#endif #ifdef OPENSSL_ALL if (store->objs != NULL) { wolfSSL_sk_X509_OBJECT_pop_free(store->objs, NULL); @@ -1010,22 +1212,56 @@ WOLFSSL_X509_LOOKUP* wolfSSL_X509_STORE_add_lookup(WOLFSSL_X509_STORE* store, return &store->lookup; } -int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509) +static int wolfSSL_X509_STORE_add_ca(WOLFSSL_X509_STORE* store, + WOLFSSL_X509* x509, int type) { int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + DerBuffer* derCert = NULL; - WOLFSSL_ENTER("wolfSSL_X509_STORE_add_cert"); - if (store != NULL && store->cm != NULL && x509 != NULL - && x509->derCert != NULL) { - DerBuffer* derCert = NULL; - + WOLFSSL_ENTER("wolfSSL_X509_STORE_add_ca"); + if (store != NULL && x509 != NULL && x509->derCert != NULL) { result = AllocDer(&derCert, x509->derCert->length, x509->derCert->type, NULL); if (result == 0) { /* AddCA() frees the buffer. */ XMEMCPY(derCert->buffer, x509->derCert->buffer, x509->derCert->length); - result = AddCA(store->cm, &derCert, WOLFSSL_USER_CA, VERIFY); + result = AddCA(store->cm, &derCert, type, VERIFY); + } + } + + return result; +} + + +int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509) +{ + int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); + + WOLFSSL_ENTER("wolfSSL_X509_STORE_add_cert"); + if (store != NULL && store->cm != NULL && x509 != NULL + && x509->derCert != NULL) { + /* Mimic the openssl behavior, must be self signed to be considered + * trusted, addCA() internals will do additional checks for + * CA=TRUE */ + if (wolfSSL_X509_NAME_cmp(&x509->issuer, &x509->subject) == 0) { + result = wolfSSL_X509_STORE_add_ca(store, x509, WOLFSSL_USER_CA); + #if !defined(WOLFSSL_SIGNER_DER_CERT) + if (result == WOLFSSL_SUCCESS && store->trusted != NULL) { + result = wolfSSL_sk_X509_push(store->trusted, x509); + result = (result > 0) ? WOLFSSL_SUCCESS : WOLFSSL_FATAL_ERROR; + } + #endif + } + else { + if (store->certs != NULL) { + result = wolfSSL_sk_X509_push(store->certs, x509); + result = (result > 0) ? WOLFSSL_SUCCESS : WOLFSSL_FATAL_ERROR; + } + else { + result = wolfSSL_X509_STORE_add_ca( + store, x509, WOLFSSL_USER_CA); + } } } @@ -1065,7 +1301,99 @@ int wolfSSL_X509_STORE_set_default_paths(WOLFSSL_X509_STORE* store) return WOLFSSL_SUCCESS; } +int wolfSSL_X509_STORE_load_cert_buffer(WOLFSSL_X509_STORE *str, + byte *buf, word32 bufLen, int type) +{ + int ret = WOLFSSL_FAILURE; + WOLFSSL_X509 *x509 = NULL; + + if (str == NULL || buf == NULL) { + return WOLFSSL_FAILURE; + } + + /* OpenSSL X509_STORE_load_file fails on DER file, we will as well */ + x509 = wolfSSL_X509_load_certificate_buffer(buf, bufLen, type); + if (str->owned != NULL) { + wolfSSL_sk_X509_push(str->owned, x509); + } + ret = wolfSSL_X509_STORE_add_cert(str, x509); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Failed to load file"); + ret = WOLFSSL_FAILURE; + } + if (str->owned == NULL) { + wolfSSL_X509_free(x509); + } + + return ret; +} + #if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) + +static int wolfSSL_X509_STORE_read_file(const char *fname, + StaticBuffer *content, word32 *bytesRead, int *type) +{ + int ret = -1; + long sz = 0; +#ifdef HAVE_CRL + const char* header = NULL; + const char* footer = NULL; +#endif + + ret = wolfssl_read_file_static(fname, content, NULL, DYNAMIC_TYPE_FILE, + &sz); + if (ret == 0) { + *type = CERT_TYPE; + *bytesRead = (word32)sz; +#ifdef HAVE_CRL + /* Look for CRL header and footer. */ + if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && + (XSTRNSTR((char*)content->buffer, header, (word32)sz) != NULL)) { + *type = CRL_TYPE; + } +#endif + } + + return (ret == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE); +} + +static int wolfSSL_X509_STORE_load_file(WOLFSSL_X509_STORE *str, const char *fname) +{ + int ret = WOLFSSL_SUCCESS; + int type = 0; +#ifndef WOLFSSL_SMALL_STACK + byte stackBuffer[FILE_BUFFER_SIZE]; +#endif + StaticBuffer content; + word32 contentLen = 0; + +#ifdef WOLFSSL_SMALL_STACK + static_buffer_init(&content); +#else + static_buffer_init(&content, stackBuffer, FILE_BUFFER_SIZE); +#endif + + ret = wolfSSL_X509_STORE_read_file(fname, &content, &contentLen, &type); + if (ret != WOLFSSL_SUCCESS) { + WOLFSSL_MSG("Failed to load file"); + ret = WOLFSSL_FAILURE; + } + + if ((ret == WOLFSSL_SUCCESS) && (type == CERT_TYPE)) { + ret = wolfSSL_X509_STORE_load_cert_buffer(str, content.buffer, + contentLen, WOLFSSL_FILETYPE_PEM); + } +#ifdef HAVE_CRL + else if ((ret == WOLFSSL_SUCCESS) && (type == CRL_TYPE)) { + ret = BufferLoadCRL(str->cm->crl, content.buffer, contentLen, + WOLFSSL_FILETYPE_PEM, 0); + } +#endif + + static_buffer_free(&content, NULL, DYNAMIC_TYPE_FILE); + return ret; +} + /* Loads certificate(s) files in pem format into X509_STORE struct from either * a file or directory. * Returns WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE if an error occurs. @@ -1111,10 +1439,7 @@ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, /* Load individual file */ if (file) { - /* Try to process file with type DETECT_CERT_TYPE to parse the - correct certificate header and footer type */ - ret = ProcessFile(ctx, file, WOLFSSL_FILETYPE_PEM, DETECT_CERT_TYPE, - NULL, 0, str->cm->crl, 0); + ret = wolfSSL_X509_STORE_load_file(str, file); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to load file"); ret = WOLFSSL_FAILURE; @@ -1139,10 +1464,8 @@ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, ret = wc_ReadDirFirst(readCtx, dir, &name); while (ret == 0 && name) { WOLFSSL_MSG(name); - /* Try to process file with type DETECT_CERT_TYPE to parse the - correct certificate header and footer type */ - ret = ProcessFile(ctx, name, WOLFSSL_FILETYPE_PEM, DETECT_CERT_TYPE, - NULL, 0, str->cm->crl, 0); + + ret = wolfSSL_X509_STORE_load_file(str, name); /* Not failing on load errors */ if (ret != WOLFSSL_SUCCESS) WOLFSSL_MSG("Failed to load file in path, continuing"); @@ -1185,17 +1508,23 @@ int wolfSSL_X509_CA_num(WOLFSSL_X509_STORE* store) } table = store->cm->caTable; - if (table){ + if (table || (store->certs != NULL)){ if (wc_LockMutex(&store->cm->caLock) == 0){ - int i = 0; - for (i = 0; i < CA_TABLE_SIZE; i++) { - Signer* signer = table[i]; - while (signer) { - Signer* next = signer->next; - cnt_ret++; - signer = next; + if (table) { + int i = 0; + for (i = 0; i < CA_TABLE_SIZE; i++) { + Signer* signer = table[i]; + while (signer) { + Signer* next = signer->next; + cnt_ret++; + signer = next; + } } } + + if (store->certs != NULL) { + cnt_ret += wolfSSL_sk_X509_num(store->certs); + } wc_UnLockMutex(&store->cm->caLock); } } @@ -1299,6 +1628,7 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( WOLFSSL_STACK* ret = NULL; WOLFSSL_STACK* cert_stack = NULL; WOLFSSL_X509* x509 = NULL; + int i = 0; WOLFSSL_ENTER("wolfSSL_X509_STORE_get0_objects"); if (store == NULL || store->cm == NULL) { @@ -1329,6 +1659,10 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( #if defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM) cert_stack = wolfSSL_CertManagerGetCerts(store->cm); + for (i = 0; i < wolfSSL_sk_X509_num(store->certs); i++) { + wolfSSL_sk_X509_push(cert_stack, + wolfSSL_sk_X509_value(store->certs, i)); + } /* wolfSSL_sk_X509_pop checks for NULL */ while ((x509 = wolfSSL_sk_X509_pop(cert_stack)) != NULL) { WOLFSSL_X509_OBJECT* obj = wolfSSL_X509_OBJECT_new(); diff --git a/tests/api.c b/tests/api.c index 7481e24b43..f84c6c82d1 100644 --- a/tests/api.c +++ b/tests/api.c @@ -59821,11 +59821,9 @@ static int test_wolfSSL_X509_STORE_CTX(void) ExpectNotNull((ctx = X509_STORE_CTX_new())); ExpectIntEQ(X509_STORE_CTX_init(ctx, str, x5092, sk), 1); ExpectNull((sk2 = X509_STORE_CTX_get_chain(NULL))); - ExpectNotNull((sk2 = X509_STORE_CTX_get_chain(ctx))); - ExpectIntEQ(sk_num(sk2), 1); /* sanity, make sure chain has 1 cert */ + ExpectNull((sk2 = X509_STORE_CTX_get_chain(ctx))); ExpectNull((sk3 = X509_STORE_CTX_get1_chain(NULL))); - ExpectNotNull((sk3 = X509_STORE_CTX_get1_chain(ctx))); - ExpectIntEQ(sk_num(sk3), 1); /* sanity, make sure chain has 1 cert */ + ExpectNull((sk3 = X509_STORE_CTX_get1_chain(ctx))); X509_STORE_CTX_free(ctx); ctx = NULL; X509_STORE_free(str); @@ -59892,6 +59890,373 @@ static int test_wolfSSL_X509_STORE_CTX(void) return EXPECT_RESULT(); } +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ + !defined(NO_FILESYSTEM) && !defined(NO_RSA) + +typedef struct { + const char *caFile; + const char *caIntFile; + const char *caInt2File; + const char *leafFile; + X509 *x509Ca; + X509 *x509CaInt; + X509 *x509CaInt2; + X509 *x509Leaf; + STACK_OF(X509)* expectedChain; +} X509_STORE_test_data; + +static X509 * test_wolfSSL_X509_STORE_CTX_ex_helper(const char *file) +{ + XFILE fp = XBADFILE; + X509 *x = NULL; + + fp = XFOPEN(file, "rb"); + if (fp == NULL) { + return NULL; + } + x = PEM_read_X509(fp, 0, 0, 0); + XFCLOSE(fp); + + return x; +} + +static int test_wolfSSL_X509_STORE_CTX_ex1(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + int i = 0; + + /* Test case 1, add X509 certs to store and verify */ + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain)); + for (i = 0; i < sk_X509_num(chain); i++) { + ExpectIntEQ(X509_cmp(sk_X509_value(chain, i), + sk_X509_value(testData->expectedChain, i)), 0); + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex2(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + int i = 0; + + /* Test case 2, add certs by filename to store and verify */ + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_load_locations( + store, testData->caFile, NULL), 1); + ExpectIntEQ(X509_STORE_load_locations( + store, testData->caIntFile, NULL), 1); + ExpectIntEQ(X509_STORE_load_locations( + store, testData->caInt2File, NULL), 1); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain)); + for (i = 0; i < sk_X509_num(chain); i++) { + ExpectIntEQ(X509_cmp(sk_X509_value(chain, i), + sk_X509_value(testData->expectedChain, i)), 0); + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex3(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + int i = 0; + + /* Test case 3, mix and match X509 with files */ + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1); + ExpectIntEQ(X509_STORE_load_locations( + store, testData->caFile, NULL), 1); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain)); + for (i = 0; i < sk_X509_num(chain); i++) { + ExpectIntEQ(X509_cmp(sk_X509_value(chain, i), + sk_X509_value(testData->expectedChain, i)), 0); + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex4(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + STACK_OF(X509)* inter = NULL; + int i = 0; + + /* Test case 4, CA loaded by file, intermediates passed on init */ + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_load_locations( + store, testData->caFile, NULL), 1); + ExpectNotNull(inter = sk_X509_new_null()); + ExpectIntGE(sk_X509_push(inter, testData->x509CaInt), 1); + ExpectIntGE(sk_X509_push(inter, testData->x509CaInt2), 1); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, inter), 1); + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain)); + for (i = 0; i < sk_X509_num(chain); i++) { + ExpectIntEQ(X509_cmp(sk_X509_value(chain, i), + sk_X509_value(testData->expectedChain, i)), 0); + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + sk_X509_free(inter); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex5(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + STACK_OF(X509)* trusted = NULL; + int i = 0; + + /* Test case 5, manually set trusted stack */ + ExpectNotNull(store = X509_STORE_new()); + ExpectNotNull(trusted = sk_X509_new_null()); + ExpectIntGE(sk_X509_push(trusted, testData->x509Ca), 1); + ExpectIntGE(sk_X509_push(trusted, testData->x509CaInt), 1); + ExpectIntGE(sk_X509_push(trusted, testData->x509CaInt2), 1); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + X509_STORE_CTX_trusted_stack(ctx, trusted); + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain)); + for (i = 0; i < sk_X509_num(chain); i++) { + ExpectIntEQ(X509_cmp(sk_X509_value(chain, i), + sk_X509_value(testData->expectedChain, i)), 0); + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + sk_X509_free(trusted); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex6(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + STACK_OF(X509)* trusted = NULL; + STACK_OF(X509)* inter = NULL; + int i = 0; + + /* Test case 6, manually set trusted stack will be unified with + * any intermediates provided on init */ + ExpectNotNull(store = X509_STORE_new()); + ExpectNotNull(trusted = sk_X509_new_null()); + ExpectNotNull(inter = sk_X509_new_null()); + ExpectIntGE(sk_X509_push(trusted, testData->x509Ca), 1); + ExpectIntGE(sk_X509_push(inter, testData->x509CaInt), 1); + ExpectIntGE(sk_X509_push(inter, testData->x509CaInt2), 1); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, inter), 1); + X509_STORE_CTX_trusted_stack(ctx, trusted); + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain)); + for (i = 0; i < sk_X509_num(chain); i++) { + ExpectIntEQ(X509_cmp(sk_X509_value(chain, i), + sk_X509_value(testData->expectedChain, i)), 0); + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + sk_X509_free(trusted); + sk_X509_free(inter); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex7(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + int i = 0; + + /* Test case 7, certs added to store after ctx init are still used */ + ExpectNotNull(store = X509_STORE_new()); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + ExpectIntNE(X509_verify_cert(ctx), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1); + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain)); + for (i = 0; i < sk_X509_num(chain); i++) { + ExpectIntEQ(X509_cmp(sk_X509_value(chain, i), + sk_X509_value(testData->expectedChain, i)), 0); + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex8(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + int i = 0; + + /* Test case 8, Only full chain verifies */ + ExpectNotNull(store = X509_STORE_new()); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + ExpectIntNE(X509_verify_cert(ctx), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1); + ExpectIntNE(X509_verify_cert(ctx), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1); + ExpectIntNE(X509_verify_cert(ctx), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1); + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + ExpectIntEQ(sk_X509_num(chain), sk_X509_num(testData->expectedChain)); + for (i = 0; i < sk_X509_num(chain); i++) { + ExpectIntEQ(X509_cmp(sk_X509_value(chain, i), + sk_X509_value(testData->expectedChain, i)), 0); + } + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex9(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + X509_STORE_CTX* ctx2 = NULL; + STACK_OF(X509)* trusted = NULL; + + /* Test case 9, certs added to store should not be reflected in ctx that + * has been manually set with a trusted stack, but are reflected in ctx + * that has not set trusted stack */ + ExpectNotNull(store = X509_STORE_new()); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectNotNull(ctx2 = X509_STORE_CTX_new()); + ExpectNotNull(trusted = sk_X509_new_null()); + ExpectIntGE(sk_X509_push(trusted, testData->x509Ca), 1); + ExpectIntGE(sk_X509_push(trusted, testData->x509CaInt), 1); + ExpectIntGE(sk_X509_push(trusted, testData->x509CaInt2), 1); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + ExpectIntEQ(X509_STORE_CTX_init(ctx2, store, testData->x509Leaf, NULL), 1); + ExpectIntNE(X509_verify_cert(ctx), 1); + ExpectIntNE(X509_verify_cert(ctx2), 1); + X509_STORE_CTX_trusted_stack(ctx, trusted); + /* CTX1 should now verify */ + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectIntNE(X509_verify_cert(ctx2), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509Ca), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1); + /* CTX2 should now verify */ + ExpectIntEQ(X509_verify_cert(ctx2), 1); + X509_STORE_CTX_free(ctx); + X509_STORE_CTX_free(ctx2); + X509_STORE_free(store); + sk_X509_free(trusted); + return EXPECT_RESULT(); +} +#endif + +static int test_wolfSSL_X509_STORE_CTX_ex(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ + !defined(NO_FILESYSTEM) && !defined(NO_RSA) + X509_STORE_test_data testData = {0}; + testData.caFile = "./certs/ca-cert.pem"; + testData.caIntFile = "./certs/intermediate/ca-int-cert.pem"; + testData.caInt2File = "./certs/intermediate/ca-int2-cert.pem"; + testData.leafFile = "./certs/intermediate/server-chain.pem"; + + ExpectNotNull(testData.x509Ca = \ + test_wolfSSL_X509_STORE_CTX_ex_helper(testData.caFile)); + ExpectNotNull(testData.x509CaInt = \ + test_wolfSSL_X509_STORE_CTX_ex_helper(testData.caIntFile)); + ExpectNotNull(testData.x509CaInt2 = \ + test_wolfSSL_X509_STORE_CTX_ex_helper(testData.caInt2File)); + ExpectNotNull(testData.x509Leaf = \ + test_wolfSSL_X509_STORE_CTX_ex_helper(testData.leafFile)); + ExpectNotNull(testData.expectedChain = sk_X509_new_null()); + ExpectIntGE(sk_X509_push(testData.expectedChain, testData.x509Leaf), 1); + ExpectIntGE(sk_X509_push(testData.expectedChain, testData.x509CaInt2), 1); + ExpectIntGE(sk_X509_push(testData.expectedChain, testData.x509CaInt), 1); + ExpectIntGE(sk_X509_push(testData.expectedChain, testData.x509Ca), 1); + + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex1(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex2(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex3(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex4(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex5(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex6(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex7(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex8(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex9(&testData), 1); + + if(testData.x509Ca) { + X509_free(testData.x509Ca); + } + if(testData.x509CaInt) { + X509_free(testData.x509CaInt); + } + if(testData.x509CaInt2) { + X509_free(testData.x509CaInt2); + } + if(testData.x509Leaf) { + X509_free(testData.x509Leaf); + } + if (testData.expectedChain) { + sk_X509_free(testData.expectedChain); + } + +#endif /* defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ + * !defined(NO_FILESYSTEM) && !defined(NO_RSA) */ + + return EXPECT_RESULT(); +} + + #if defined(OPENSSL_EXTRA) && !defined(NO_RSA) static int test_X509_STORE_untrusted_load_cert_to_stack(const char* filename, STACK_OF(X509)* chain) @@ -59994,9 +60359,9 @@ static int test_X509_STORE_untrusted(void) /* Succeeds because path to loaded CA is available. */ ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted2, 1, 0, 1), TEST_SUCCESS); - /* Fails because root CA is in the untrusted stack */ - ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 0, - X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 0), TEST_SUCCESS); + /* Root CA in untrusted chain is OK */ + ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 1, 0, 1), + TEST_SUCCESS); /* Succeeds because path to loaded CA is available. */ ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted4, 1, 0, 1), TEST_SUCCESS); @@ -80147,7 +80512,7 @@ static int test_wolfSSL_X509_load_crl_file(void) #ifdef WC_RSA_PSS ExpectIntEQ(wolfSSL_CertManagerVerify(store->cm, "certs/rsapss/server-rsapss-cert.pem", WOLFSSL_FILETYPE_PEM), - WC_NO_ERR_TRACE(CRL_CERT_REVOKED)); + WC_NO_ERR_TRACE(ASN_NO_SIGNER_E)); #endif } /* once feeing store */ @@ -97559,6 +97924,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_TBS), TEST_DECL(test_wolfSSL_X509_STORE_CTX), + TEST_DECL(test_wolfSSL_X509_STORE_CTX_ex), TEST_DECL(test_X509_STORE_untrusted), TEST_DECL(test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup), TEST_DECL(test_wolfSSL_X509_STORE_CTX_get0_current_issuer), diff --git a/wolfssl/internal.h b/wolfssl/internal.h index 1a6c97d8fb..a6db36e500 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2756,6 +2756,8 @@ WOLFSSL_LOCAL int SetupStoreCtxCallback(WOLFSSL_X509_STORE_CTX** store_pt, WOLFSSL_LOCAL void CleanupStoreCtxCallback(WOLFSSL_X509_STORE_CTX* store, WOLFSSL* ssl, void* heap, int x509Free); #endif /* !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) */ +WOLFSSL_LOCAL int wolfSSL_X509_STORE_load_cert_buffer(WOLFSSL_X509_STORE *str, + byte *buf, word32 bufLen, int type); #endif /* !defined NO_CERTS */ /* wolfSSL Sock Addr */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 13abb0bb30..0d26abfac7 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -600,6 +600,9 @@ struct WOLFSSL_X509_STORE { WOLFSSL_X509_CRL *crl; /* points to cm->crl */ #endif wolfSSL_Ref ref; + WOLF_STACK_OF(WOLFSSL_X509)* certs; + WOLF_STACK_OF(WOLFSSL_X509)* trusted; + WOLF_STACK_OF(WOLFSSL_X509)* owned; }; #define WOLFSSL_ALWAYS_CHECK_SUBJECT 0x1 @@ -697,6 +700,11 @@ struct WOLFSSL_X509_STORE_CTX { WOLFSSL_BUFFER_INFO* certs; /* peer certs */ WOLFSSL_X509_STORE_CTX_verify_cb verify_cb; /* verify callback */ void* heap; + WOLF_STACK_OF(WOLFSSL_X509)* ctxIntermediates; /* Intermediates specified + * on store ctx init */ + WOLF_STACK_OF(WOLFSSL_X509)* setTrustedSk;/* A trusted stack override + * set with + * X509_STORE_CTX_trusted_stack*/ }; typedef char* WOLFSSL_STRING; @@ -3313,7 +3321,8 @@ enum { WOLFSSL_DTLSV1_3 = 7, WOLFSSL_USER_CA = 1, /* user added as trusted */ - WOLFSSL_CHAIN_CA = 2 /* added to cache from trusted chain */ + WOLFSSL_CHAIN_CA = 2, /* added to cache from trusted chain */ + WOLFSSL_INTER_CA = 3 /* Intermediate CA */ }; WOLFSSL_ABI WOLFSSL_API WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl); From 38c7de1707115a8c475fe84f3fc118bbce51907a Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Wed, 16 Oct 2024 16:44:15 -0700 Subject: [PATCH 02/17] Fixes for CI build errors --- src/x509.c | 4 ++-- src/x509_str.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/x509.c b/src/x509.c index c440de498d..f6ee7a64ff 100644 --- a/src/x509.c +++ b/src/x509.c @@ -7596,8 +7596,8 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, } else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) { - ret = wolfSSL_X509_STORE_load_cert_buffer(lookup->store, curr, sz, - WOLFSSL_FILETYPE_PEM); + ret = wolfSSL_X509_STORE_load_cert_buffer(lookup->store, curr, + (word32)sz, WOLFSSL_FILETYPE_PEM); if (ret != WOLFSSL_SUCCESS) goto end; curr = (byte*)XSTRNSTR((char*)curr, footer, (unsigned int)sz); diff --git a/src/x509_str.c b/src/x509_str.c index ff1e72701d..a73d9ef8cd 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -1628,7 +1628,9 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( WOLFSSL_STACK* ret = NULL; WOLFSSL_STACK* cert_stack = NULL; WOLFSSL_X509* x509 = NULL; +#if defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM) int i = 0; +#endif WOLFSSL_ENTER("wolfSSL_X509_STORE_get0_objects"); if (store == NULL || store->cm == NULL) { From 12f4f69fb44aed472f078f5a9cb0511bef297d3a Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Wed, 16 Oct 2024 21:59:48 -0700 Subject: [PATCH 03/17] Allow intermediate CA certs without keycertsign when added through X509 STORE --- src/ssl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index bfe5ad46ad..defa111903 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -5535,13 +5535,15 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) } } - if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA) { + if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA && + type != WOLFSSL_INTER_CA) { WOLFSSL_MSG("\tCan't add as CA if not actually one"); ret = NOT_CA_ERROR; } #ifndef ALLOW_INVALID_CERTSIGN else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA && - !cert->selfSigned && (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { + type != WOLFSSL_INTER_CA && !cert->selfSigned && + (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { /* Intermediate CA certs are required to have the keyCertSign * extension set. User loaded root certs are not. */ WOLFSSL_MSG("\tDoesn't have key usage certificate signing"); From f7bfa71d9f691be90d47366b2638dde10a1cfd7e Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Thu, 17 Oct 2024 22:07:52 -0700 Subject: [PATCH 04/17] Implement support for verify flag X509_V_FLAG_PARTIAL_CHAIN --- src/x509_str.c | 5 +++++ wolfssl/openssl/ssl.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/x509_str.c b/src/x509_str.c index a73d9ef8cd..3a5d870ad3 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -403,6 +403,11 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) * a trusted CA in the CM */ ret = wolfSSL_X509_verify_cert_ex(ctx); if (ret != WOLFSSL_SUCCESS) { + if ((ctx->store->param->flags & X509_V_FLAG_PARTIAL_CHAIN) && + (added == 1)) { + wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); + ret = WOLFSSL_SUCCESS; + } goto exit; } diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index a08a96db0f..1f7b640eb4 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -643,7 +643,7 @@ typedef WOLFSSL_X509_NAME_ENTRY X509_NAME_ENTRY; #define X509_V_FLAG_CRL_CHECK WOLFSSL_CRL_CHECK #define X509_V_FLAG_CRL_CHECK_ALL WOLFSSL_CRL_CHECKALL -#define X509_V_FLAG_PARTIAL_CHAIN 0 +#define X509_V_FLAG_PARTIAL_CHAIN 0x80000 #define X509_V_FLAG_TRUSTED_FIRST 0 #define X509_V_FLAG_USE_CHECK_TIME WOLFSSL_USE_CHECK_TIME From 98eb6b398c403c3c95120c87156773fa58236691 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Thu, 17 Oct 2024 22:22:35 -0700 Subject: [PATCH 05/17] Fix for windows builds --- src/x509_str.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/x509_str.c b/src/x509_str.c index 3a5d870ad3..bdffe22138 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -315,7 +315,6 @@ static int wolfSSL_X509_verify_cert_ex(WOLFSSL_X509_STORE_CTX* ctx) */ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) { - WOLFSSL_ENTER("wolfSSL_X509_verify_cert"); int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); int done = 0; int added = 0; @@ -325,6 +324,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) WOLFSSL_X509 *issuer = NULL; WOLFSSL_X509 *orig = NULL; WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL; + WOLFSSL_ENTER("wolfSSL_X509_verify_cert"); if (ctx == NULL || ctx->store == NULL || ctx->store->cm == NULL || ctx->current_cert == NULL || ctx->current_cert->derCert == NULL) { From f0fae6506f1e2e1671b9575d533928dd663e79d7 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Thu, 17 Oct 2024 22:42:11 -0700 Subject: [PATCH 06/17] Fix windows warnings --- src/ssl_certman.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ssl_certman.c b/src/ssl_certman.c index 700216c55a..cb52333173 100644 --- a/src/ssl_certman.c +++ b/src/ssl_certman.c @@ -456,7 +456,7 @@ int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm) } static int wolfSSL_CertManagerUnloadIntermediateCertsEx(WOLFSSL_CERT_MANAGER* cm, - int type) + byte type) { int ret = WOLFSSL_SUCCESS; From 6607314dc682b146603968d41e32ecd4c5fd580a Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Fri, 18 Oct 2024 15:22:25 -0700 Subject: [PATCH 07/17] Address code comments, rewrite get issuer internals, use better internal names, get rid of all lines over 80 chars --- src/x509.c | 6 +- src/x509_str.c | 229 +++++++++++++++++++++++++-------------------- tests/api.c | 25 +++-- wolfssl/internal.h | 2 +- wolfssl/ssl.h | 3 +- 5 files changed, 156 insertions(+), 109 deletions(-) diff --git a/src/x509.c b/src/x509.c index f6ee7a64ff..dd05cd4b30 100644 --- a/src/x509.c +++ b/src/x509.c @@ -7596,7 +7596,7 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, } else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) { - ret = wolfSSL_X509_STORE_load_cert_buffer(lookup->store, curr, + ret = X509StoreLoadCertBuffer(lookup->store, curr, (word32)sz, WOLFSSL_FILETYPE_PEM); if (ret != WOLFSSL_SUCCESS) goto end; @@ -14205,6 +14205,8 @@ int wolfSSL_X509_NAME_digest(const WOLFSSL_X509_NAME *name, #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) +#if defined(OPENSSL_EXTRA) && (defined(SESSION_CERTS) || \ + defined(WOLFSSL_SIGNER_DER_CERT)) /** * Find the issuing cert of the input cert. On a self-signed cert this @@ -14275,6 +14277,8 @@ static int x509GetIssuerFromCM(WOLFSSL_X509 **issuer, WOLFSSL_CERT_MANAGER* cm, return WOLFSSL_SUCCESS; } +#endif /* if defined(OPENSSL_EXTRA) && (defined(SESSION_CERTS) || \ + defined(WOLFSSL_SIGNER_DER_CERT)) */ void wolfSSL_X509_email_free(WOLF_STACK_OF(WOLFSSL_STRING) *sk) { diff --git a/src/x509_str.c b/src/x509_str.c index bdffe22138..9a022cf966 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -37,9 +37,9 @@ #ifndef NO_CERTS #ifdef OPENSSL_EXTRA -static int wolfSSL_X509_STORE_get_issuer_ex(WOLFSSL_X509 **issuer, +static int X509StoreGetIssuerEx(WOLFSSL_X509 **issuer, WOLFSSL_STACK *certs, WOLFSSL_X509 *x); -static int wolfSSL_X509_STORE_add_ca(WOLFSSL_X509_STORE* store, +static int X509StoreAddCa(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509, int type); #endif @@ -47,9 +47,9 @@ static int wolfSSL_X509_STORE_add_ca(WOLFSSL_X509_STORE* store, #define WOLFSSL_X509_STORE_DEFAULT_MAX_DEPTH 100 #endif -/******************************************************************************* +/****************************************************************************** * START OF X509_STORE_CTX APIs - ******************************************************************************/ + *****************************************************************************/ /* This API is necessary outside of OPENSSL_EXTRA because it is used in * SetupStoreCtxCallback */ @@ -90,13 +90,14 @@ void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx) XFREE(ctx->param, ctx->heap, DYNAMIC_TYPE_OPENSSL); ctx->param = NULL; - if (ctx->ctxIntermediates != NULL) { - wolfSSL_sk_X509_free(ctx->ctxIntermediates); - } - if (ctx->chain != NULL) { wolfSSL_sk_X509_free(ctx->chain); } + + if (ctx->current_issuer != NULL) { + wolfSSL_X509_free(ctx->current_issuer); + ctx->current_issuer = NULL; + } #endif XFREE(ctx, ctx->heap, DYNAMIC_TYPE_X509_CTX); @@ -115,8 +116,6 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx, WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509, WOLF_STACK_OF(WOLFSSL_X509)* sk) { - int ret = 0; - int i = 0; WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_init"); if (ctx != NULL) { @@ -135,23 +134,7 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx, ctx->current_cert = NULL; #endif - if (sk != NULL) { - if (ctx->ctxIntermediates == NULL) { - ctx->ctxIntermediates = sk_X509_new_null(); - if (ctx->ctxIntermediates == NULL) { - return WOLFSSL_FAILURE; - } - } - - for (i = 0; i < wolfSSL_sk_X509_num(sk); i++) { - ret = wolfSSL_sk_X509_push(ctx->ctxIntermediates, - wolfSSL_sk_X509_value(sk, i)); - if (ret <= 0) { - return WOLFSSL_FAILURE; - } - } - } - + ctx->ctxIntermediates = sk; if (ctx->chain != NULL) { wolfSSL_sk_X509_free(ctx->chain); ctx->chain = NULL; @@ -201,9 +184,6 @@ void wolfSSL_X509_STORE_CTX_trusted_stack(WOLFSSL_X509_STORE_CTX *ctx, WOLF_STACK_OF(WOLFSSL_X509) *sk) { if (ctx != NULL) { - if (ctx->setTrustedSk != NULL) { - wolfSSL_sk_X509_free(ctx->setTrustedSk); - } ctx->setTrustedSk = sk; } } @@ -264,7 +244,7 @@ static void SetupStoreCtxError(WOLFSSL_X509_STORE_CTX* ctx, int ret) wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth); } -static int wolfSSL_X509_verify_cert_ex(WOLFSSL_X509_STORE_CTX* ctx) +static int X509StoreVerifyCert(WOLFSSL_X509_STORE_CTX* ctx) { int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); @@ -371,7 +351,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) issuer = NULL; /* Try to find an untrusted issuer first */ - ret = wolfSSL_X509_STORE_get_issuer_ex(&issuer, certs, + ret = X509StoreGetIssuerEx(&issuer, certs, ctx->current_cert); if (ret == WOLFSSL_SUCCESS) { if (ctx->current_cert == issuer) { @@ -381,7 +361,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) /* We found our issuer in the non-trusted cert list, add it * to the CM and verify the current cert against it */ - ret = wolfSSL_X509_STORE_add_ca(ctx->store, issuer, + ret = X509StoreAddCa(ctx->store, issuer, WOLFSSL_INTER_CA); if (ret != WOLFSSL_SUCCESS) { goto exit; @@ -389,7 +369,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) added = 1; - ret = wolfSSL_X509_verify_cert_ex(ctx); + ret = X509StoreVerifyCert(ctx); if (ret != WOLFSSL_SUCCESS) { goto exit; } @@ -398,10 +378,10 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); ctx->current_cert = issuer; } - else if (ret == WOLFSSL_FAILURE) { + else if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) { /* Could not find in untrusted list, only place left is * a trusted CA in the CM */ - ret = wolfSSL_X509_verify_cert_ex(ctx); + ret = X509StoreVerifyCert(ctx); if (ret != WOLFSSL_SUCCESS) { if ((ctx->store->param->flags & X509_V_FLAG_PARTIAL_CHAIN) && (added == 1)) { @@ -420,11 +400,11 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) } #else if (ctx->setTrustedSk == NULL) { - wolfSSL_X509_STORE_get_issuer_ex(&issuer, + X509StoreGetIssuerEx(&issuer, ctx->store->trusted, ctx->current_cert); } else { - wolfSSL_X509_STORE_get_issuer_ex(&issuer, + X509StoreGetIssuerEx(&issuer, ctx->setTrustedSk, ctx->current_cert); } #endif @@ -467,7 +447,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) WOLFSSL_X509* wolfSSL_X509_STORE_CTX_get_current_cert( - WOLFSSL_X509_STORE_CTX* ctx) + WOLFSSL_X509_STORE_CTX* ctx) { WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get_current_cert"); if (ctx) @@ -611,8 +591,8 @@ int wolfSSL_X509_STORE_CTX_set_ex_data_with_cleanup( WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_ex_data_with_cleanup"); if (ctx != NULL) { - return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&ctx->ex_data, idx, data, - cleanup_routine); + return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&ctx->ex_data, idx, + data, cleanup_routine); } return WOLFSSL_FAILURE; } @@ -627,22 +607,24 @@ void wolfSSL_X509_STORE_CTX_set_depth(WOLFSSL_X509_STORE_CTX* ctx, int depth) } #endif - WOLFSSL_X509* wolfSSL_X509_STORE_CTX_get0_current_issuer( WOLFSSL_X509_STORE_CTX* ctx) { - int ret; - WOLFSSL_X509* issuer; - + WOLFSSL_STACK* node; WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get0_current_issuer"); - if (ctx == NULL) { + if (ctx == NULL) return NULL; - } - ret = wolfSSL_X509_STORE_CTX_get1_issuer(&issuer, ctx, ctx->current_cert); - if (ret == WOLFSSL_SUCCESS) { - return issuer; + /* get0 only checks currently built chain */ + if (ctx->chain != NULL) { + for (node = ctx->chain; node != NULL; node = node->next) { + if (wolfSSL_X509_check_issued(node->data.x509, + ctx->current_cert) == + WOLFSSL_X509_V_OK) { + return node->data.x509; + } + } } return NULL; @@ -662,7 +644,7 @@ void wolfSSL_X509_STORE_CTX_set_error(WOLFSSL_X509_STORE_CTX* ctx, int er) /* Set the error depth in the X509 STORE CTX */ void wolfSSL_X509_STORE_CTX_set_error_depth(WOLFSSL_X509_STORE_CTX* ctx, - int depth) + int depth) { WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_set_error_depth"); @@ -690,7 +672,8 @@ WOLFSSL_STACK* wolfSSL_X509_STORE_CTX_get_chain(WOLFSSL_X509_STORE_CTX* ctx) if (sk == NULL) return NULL; -#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || defined(OPENSSL_EXTRA) +#if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ + defined(OPENSSL_EXTRA) /* add CA used to verify top of chain to the list */ if (c->count > 0) { WOLFSSL_X509* x509 = wolfSSL_get_chain_X509(c, c->count - 1); @@ -891,30 +874,35 @@ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_STORE_get1_certs( int wolfSSL_X509_STORE_CTX_get1_issuer(WOLFSSL_X509 **issuer, WOLFSSL_X509_STORE_CTX *ctx, WOLFSSL_X509 *x) { - WOLFSSL_STACK* node; + int ret = WOLFSSL_FAILURE; + WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get1_issuer"); if (issuer == NULL || ctx == NULL || x == NULL) return WOLFSSL_FATAL_ERROR; - if (ctx->chain != NULL) { - for (node = ctx->chain; node != NULL; node = node->next) { - if (wolfSSL_X509_check_issued(node->data.x509, x) == - WOLFSSL_X509_V_OK) { - *issuer = node->data.x509; - return WOLFSSL_SUCCESS; - } - } + ret = X509StoreGetIssuerEx(issuer, ctx->store->certs, x); + if ((ret == WOLFSSL_SUCCESS) && (*issuer != NULL)) { + *issuer = wolfSSL_X509_dup(*issuer); + return (*issuer != NULL) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } - /* Result is ignored when passed to wolfSSL_OCSP_cert_to_id(). */ +#ifdef WOLFSSL_SIGNER_DER_CERT + ret = x509GetIssuerFromCM(issuer, ctx->store->cm, x); +#else + ret = X509StoreGetIssuerEx(issuer, ctx->store->trusted, x); + if ((ret == WOLFSSL_SUCCESS) && (*issuer != NULL)) { + *issuer = wolfSSL_X509_dup(*issuer); + return (*issuer != NULL) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + } +#endif - return x509GetIssuerFromCM(issuer, ctx->store->cm, x); + return ret; } #endif /* WOLFSSL_NGINX || WOLFSSL_HAPROXY || OPENSSL_EXTRA || OPENSSL_ALL */ #ifdef OPENSSL_EXTRA -static int wolfSSL_X509_STORE_get_issuer_ex(WOLFSSL_X509 **issuer, +static int X509StoreGetIssuerEx(WOLFSSL_X509 **issuer, WOLFSSL_STACK * certs, WOLFSSL_X509 *x) { int i; @@ -924,8 +912,9 @@ static int wolfSSL_X509_STORE_get_issuer_ex(WOLFSSL_X509 **issuer, if (certs != NULL) { for (i = 0; i < wolfSSL_sk_X509_num(certs); i++) { - if (wolfSSL_X509_check_issued(wolfSSL_sk_X509_value(certs, i), x) == - WOLFSSL_X509_V_OK) { + if (wolfSSL_X509_check_issued( + wolfSSL_sk_X509_value(certs, i), x) == + WOLFSSL_X509_V_OK) { *issuer = wolfSSL_sk_X509_value(certs, i); return WOLFSSL_SUCCESS; } @@ -937,13 +926,13 @@ static int wolfSSL_X509_STORE_get_issuer_ex(WOLFSSL_X509 **issuer, #endif -/******************************************************************************* +/****************************************************************************** * END OF X509_STORE_CTX APIs - ******************************************************************************/ + *****************************************************************************/ -/******************************************************************************* +/****************************************************************************** * START OF X509_STORE APIs - ******************************************************************************/ + *****************************************************************************/ #if defined(OPENSSL_EXTRA) || defined(HAVE_WEBSERVER) || \ defined(WOLFSSL_WPAS_SMALL) @@ -986,6 +975,8 @@ WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void) store->crl = store->cm->crl; #endif + store->numAdded = 0; + #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) /* Link store's new Certificate Manager to self by default */ @@ -1020,6 +1011,28 @@ WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void) return NULL; } +static void X509StoreFreeObjList(WOLFSSL_X509_STORE* store, + WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* objs) +{ + int i; + WOLFSSL_X509_OBJECT *obj = NULL; + int cnt = store->numAdded; + + i = wolfSSL_sk_X509_OBJECT_num(objs) - 1; + while (cnt > 0 && i > 0) { + /* The inner X509 is owned by somebody else, NULL out the reference */ + obj = wolfSSL_sk_X509_OBJECT_value(objs, i); + if (obj != NULL) { + obj->type = 0; + obj->data.x509 = NULL; + } + cnt--; + i--; + } + + wolfSSL_sk_X509_OBJECT_pop_free(objs, NULL); +} + void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store) { int doFree = 0; @@ -1058,7 +1071,7 @@ void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store) #endif #ifdef OPENSSL_ALL if (store->objs != NULL) { - wolfSSL_sk_X509_OBJECT_pop_free(store->objs, NULL); + X509StoreFreeObjList(store, store->objs); } #endif #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) @@ -1068,7 +1081,8 @@ void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store) if (store->lookup.dirs != NULL) { #if defined(OPENSSL_ALL) && !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) if (store->lookup.dirs->dir_entry) { - wolfSSL_sk_BY_DIR_entry_free(store->lookup.dirs->dir_entry); + wolfSSL_sk_BY_DIR_entry_free( + store->lookup.dirs->dir_entry); } #endif wc_FreeMutex(&store->lookup.dirs->lock); @@ -1130,7 +1144,7 @@ int wolfSSL_X509_STORE_up_ref(WOLFSSL_X509_STORE* store) * @return WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE on failure */ int wolfSSL_X509_STORE_set_ex_data(WOLFSSL_X509_STORE* store, int idx, - void *data) + void *data) { WOLFSSL_ENTER("wolfSSL_X509_STORE_set_ex_data"); #ifdef HAVE_EX_DATA @@ -1217,13 +1231,13 @@ WOLFSSL_X509_LOOKUP* wolfSSL_X509_STORE_add_lookup(WOLFSSL_X509_STORE* store, return &store->lookup; } -static int wolfSSL_X509_STORE_add_ca(WOLFSSL_X509_STORE* store, +static int X509StoreAddCa(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509, int type) { int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR); DerBuffer* derCert = NULL; - WOLFSSL_ENTER("wolfSSL_X509_STORE_add_ca"); + WOLFSSL_ENTER("X509StoreAddCa"); if (store != NULL && x509 != NULL && x509->derCert != NULL) { result = AllocDer(&derCert, x509->derCert->length, x509->derCert->type, NULL); @@ -1250,7 +1264,7 @@ int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509) * trusted, addCA() internals will do additional checks for * CA=TRUE */ if (wolfSSL_X509_NAME_cmp(&x509->issuer, &x509->subject) == 0) { - result = wolfSSL_X509_STORE_add_ca(store, x509, WOLFSSL_USER_CA); + result = X509StoreAddCa(store, x509, WOLFSSL_USER_CA); #if !defined(WOLFSSL_SIGNER_DER_CERT) if (result == WOLFSSL_SUCCESS && store->trusted != NULL) { result = wolfSSL_sk_X509_push(store->trusted, x509); @@ -1264,7 +1278,9 @@ int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509) result = (result > 0) ? WOLFSSL_SUCCESS : WOLFSSL_FATAL_ERROR; } else { - result = wolfSSL_X509_STORE_add_ca( + /* If store->certs is NULL, this is an X509_STORE managed by an + * SSL_CTX, preserve behavior and always add as USER_CA */ + result = X509StoreAddCa( store, x509, WOLFSSL_USER_CA); } } @@ -1306,7 +1322,7 @@ int wolfSSL_X509_STORE_set_default_paths(WOLFSSL_X509_STORE* store) return WOLFSSL_SUCCESS; } -int wolfSSL_X509_STORE_load_cert_buffer(WOLFSSL_X509_STORE *str, +int X509StoreLoadCertBuffer(WOLFSSL_X509_STORE *str, byte *buf, word32 bufLen, int type) { int ret = WOLFSSL_FAILURE; @@ -1335,7 +1351,7 @@ int wolfSSL_X509_STORE_load_cert_buffer(WOLFSSL_X509_STORE *str, #if !defined(NO_FILESYSTEM) && !defined(NO_WOLFSSL_DIR) -static int wolfSSL_X509_STORE_read_file(const char *fname, +static int X509StoreReadFile(const char *fname, StaticBuffer *content, word32 *bytesRead, int *type) { int ret = -1; @@ -1353,7 +1369,8 @@ static int wolfSSL_X509_STORE_read_file(const char *fname, #ifdef HAVE_CRL /* Look for CRL header and footer. */ if (wc_PemGetHeaderFooter(CRL_TYPE, &header, &footer) == 0 && - (XSTRNSTR((char*)content->buffer, header, (word32)sz) != NULL)) { + (XSTRNSTR((char*)content->buffer, header, (word32)sz) != + NULL)) { *type = CRL_TYPE; } #endif @@ -1362,7 +1379,8 @@ static int wolfSSL_X509_STORE_read_file(const char *fname, return (ret == 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE); } -static int wolfSSL_X509_STORE_load_file(WOLFSSL_X509_STORE *str, const char *fname) +static int X509StoreLoadFile(WOLFSSL_X509_STORE *str, + const char *fname) { int ret = WOLFSSL_SUCCESS; int type = 0; @@ -1378,14 +1396,14 @@ static int wolfSSL_X509_STORE_load_file(WOLFSSL_X509_STORE *str, const char *fna static_buffer_init(&content, stackBuffer, FILE_BUFFER_SIZE); #endif - ret = wolfSSL_X509_STORE_read_file(fname, &content, &contentLen, &type); + ret = X509StoreReadFile(fname, &content, &contentLen, &type); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to load file"); ret = WOLFSSL_FAILURE; } if ((ret == WOLFSSL_SUCCESS) && (type == CERT_TYPE)) { - ret = wolfSSL_X509_STORE_load_cert_buffer(str, content.buffer, + ret = X509StoreLoadCertBuffer(str, content.buffer, contentLen, WOLFSSL_FILETYPE_PEM); } #ifdef HAVE_CRL @@ -1404,7 +1422,7 @@ static int wolfSSL_X509_STORE_load_file(WOLFSSL_X509_STORE *str, const char *fna * Returns WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE if an error occurs. */ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, - const char *file, const char *dir) + const char *file, const char *dir) { WOLFSSL_CTX* ctx; char *name = NULL; @@ -1444,7 +1462,7 @@ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, /* Load individual file */ if (file) { - ret = wolfSSL_X509_STORE_load_file(str, file); + ret = X509StoreLoadFile(str, file); if (ret != WOLFSSL_SUCCESS) { WOLFSSL_MSG("Failed to load file"); ret = WOLFSSL_FAILURE; @@ -1457,7 +1475,7 @@ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, #ifdef WOLFSSL_SMALL_STACK readCtx = (ReadDirCtx*)XMALLOC(sizeof(ReadDirCtx), ctx->heap, - DYNAMIC_TYPE_TMP_BUFFER); + DYNAMIC_TYPE_TMP_BUFFER); if (readCtx == NULL) { WOLFSSL_MSG("Memory error"); wolfSSL_CTX_free(ctx); @@ -1470,7 +1488,7 @@ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str, while (ret == 0 && name) { WOLFSSL_MSG(name); - ret = wolfSSL_X509_STORE_load_file(str, name); + ret = X509StoreLoadFile(str, name); /* Not failing on load errors */ if (ret != WOLFSSL_SUCCESS) WOLFSSL_MSG("Failed to load file in path, continuing"); @@ -1538,7 +1556,8 @@ int wolfSSL_X509_CA_num(WOLFSSL_X509_STORE* store) } /****************************************************************************** -* wolfSSL_X509_STORE_GetCerts - retrieve stack of X509 in a certificate store ctx +* wolfSSL_X509_STORE_GetCerts - retrieve stack of X509 in a certificate +* store ctx * * This API can be used in SSL verify callback function to view cert chain * See examples/client/client.c and myVerify() function in test.h @@ -1569,7 +1588,8 @@ WOLFSSL_STACK* wolfSSL_X509_STORE_GetCerts(WOLFSSL_X509_STORE_CTX* s) /* get certificate buffer */ cert = &s->certs[certIdx]; - dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, DYNAMIC_TYPE_DCERT); + dCert = (DecodedCert*)XMALLOC(sizeof(DecodedCert), NULL, + DYNAMIC_TYPE_DCERT); if (dCert == NULL) { goto error; @@ -1632,8 +1652,8 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( { WOLFSSL_STACK* ret = NULL; WOLFSSL_STACK* cert_stack = NULL; - WOLFSSL_X509* x509 = NULL; #if defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM) + WOLFSSL_X509* x509 = NULL; int i = 0; #endif WOLFSSL_ENTER("wolfSSL_X509_STORE_get0_objects"); @@ -1646,7 +1666,7 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( if (store->objs != NULL) { #if defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM) /* want to update objs stack by cm stack again before returning it*/ - wolfSSL_sk_X509_OBJECT_pop_free(store->objs, NULL); + X509StoreFreeObjList(store, store->objs); store->objs = NULL; #else if (wolfSSL_sk_X509_OBJECT_num(store->objs) == 0) { @@ -1666,12 +1686,16 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( #if defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM) cert_stack = wolfSSL_CertManagerGetCerts(store->cm); + store->numAdded = 0; for (i = 0; i < wolfSSL_sk_X509_num(store->certs); i++) { wolfSSL_sk_X509_push(cert_stack, wolfSSL_sk_X509_value(store->certs, i)); + store->numAdded++; } - /* wolfSSL_sk_X509_pop checks for NULL */ - while ((x509 = wolfSSL_sk_X509_pop(cert_stack)) != NULL) { + /* Do not modify stack until after we guarantee success to + * simplify cleanup logic handling cert merging above */ + for (i = 0; i < wolfSSL_sk_X509_num(cert_stack); i++) { + x509 = wolfSSL_sk_value(cert_stack, i); WOLFSSL_X509_OBJECT* obj = wolfSSL_X509_OBJECT_new(); if (obj == NULL) { WOLFSSL_MSG("wolfSSL_X509_OBJECT_new error"); @@ -1686,6 +1710,10 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( obj->data.x509 = x509; x509 = NULL; } + + while(wolfSSL_sk_X509_num(cert_stack) > 0) { + wolfSSL_sk_X509_pop(cert_stack); + } #endif #ifdef HAVE_CRL @@ -1711,11 +1739,14 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( return ret; err_cleanup: if (ret != NULL) - wolfSSL_sk_X509_OBJECT_pop_free(ret, NULL); - if (cert_stack != NULL) + X509StoreFreeObjList(store, ret); + if (cert_stack != NULL) { + while(store->numAdded > 0) { + wolfSSL_sk_X509_pop(cert_stack); + store->numAdded--; + } wolfSSL_sk_X509_pop_free(cert_stack, NULL); - if (x509 != NULL) - wolfSSL_X509_free(x509); + } return NULL; } #endif /* OPENSSL_ALL */ @@ -1741,9 +1772,9 @@ int wolfSSL_X509_STORE_set1_param(WOLFSSL_X509_STORE *ctx, #endif #endif -/******************************************************************************* +/****************************************************************************** * END OF X509_STORE APIs - ******************************************************************************/ + *****************************************************************************/ #endif /* NO_CERTS */ diff --git a/tests/api.c b/tests/api.c index f84c6c82d1..806410cb3b 100644 --- a/tests/api.c +++ b/tests/api.c @@ -59555,8 +59555,12 @@ static int test_wolfSSL_X509_LOOKUP_ctrl_file(void) ExpectNull(X509_STORE_CTX_get0_current_issuer(NULL)); issuer = X509_STORE_CTX_get0_current_issuer(ctx); - ExpectNotNull(issuer); + ExpectNull(issuer); + + ExpectIntEQ(X509_verify_cert(ctx), 1); + issuer = X509_STORE_CTX_get0_current_issuer(ctx); + ExpectNotNull(issuer); caName = X509_get_subject_name(x509Ca); ExpectNotNull(caName); issuerName = X509_get_subject_name(issuer); @@ -59565,7 +59569,6 @@ static int test_wolfSSL_X509_LOOKUP_ctrl_file(void) ExpectIntEQ(cmp, 0); /* load der format */ - X509_free(issuer); issuer = NULL; X509_STORE_CTX_free(ctx); ctx = NULL; @@ -59643,7 +59646,7 @@ static int test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup(void) return res; } -static int test_wolfSSL_X509_STORE_CTX_get0_current_issuer(void) +static int test_wolfSSL_X509_STORE_CTX_get_issuer(void) { EXPECT_DECLS; #if defined(OPENSSL_EXTRA) && !defined(NO_RSA) @@ -59665,16 +59668,23 @@ static int test_wolfSSL_X509_STORE_CTX_get0_current_issuer(void) ExpectIntEQ(X509_STORE_CTX_init(ctx, str, x509Svr, NULL), SSL_SUCCESS); + /* Issuer0 is not set until chain is built for verification */ ExpectNull(X509_STORE_CTX_get0_current_issuer(NULL)); - ExpectNotNull(issuer = X509_STORE_CTX_get0_current_issuer(ctx)); + ExpectNull(issuer = X509_STORE_CTX_get0_current_issuer(ctx)); + /* Issuer1 will use the store to make a new issuer */ + ExpectIntEQ(X509_STORE_CTX_get1_issuer(&issuer, ctx, x509Svr), 1); + ExpectNotNull(issuer); + X509_free(issuer); + + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(issuer = X509_STORE_CTX_get0_current_issuer(ctx)); ExpectNotNull(caName = X509_get_subject_name(x509Ca)); ExpectNotNull(issuerName = X509_get_subject_name(issuer)); #ifdef WOLFSSL_SIGNER_DER_CERT ExpectIntEQ(X509_NAME_cmp(caName, issuerName), 0); #endif - X509_free(issuer); X509_STORE_CTX_free(ctx); X509_free(x509Svr); X509_STORE_free(str); @@ -60204,7 +60214,8 @@ static int test_wolfSSL_X509_STORE_CTX_ex(void) EXPECT_DECLS; #if defined(OPENSSL_EXTRA) && !defined(NO_CERTS) && \ !defined(NO_FILESYSTEM) && !defined(NO_RSA) - X509_STORE_test_data testData = {0}; + X509_STORE_test_data testData; + XMEMSET((void *)&testData, 0, sizeof(X509_STORE_test_data)); testData.caFile = "./certs/ca-cert.pem"; testData.caIntFile = "./certs/intermediate/ca-int-cert.pem"; testData.caInt2File = "./certs/intermediate/ca-int2-cert.pem"; @@ -97927,7 +97938,7 @@ TEST_CASE testCases[] = { TEST_DECL(test_wolfSSL_X509_STORE_CTX_ex), TEST_DECL(test_X509_STORE_untrusted), TEST_DECL(test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup), - TEST_DECL(test_wolfSSL_X509_STORE_CTX_get0_current_issuer), + TEST_DECL(test_wolfSSL_X509_STORE_CTX_get_issuer), TEST_DECL(test_wolfSSL_X509_STORE_set_flags), TEST_DECL(test_wolfSSL_X509_LOOKUP_load_file), TEST_DECL(test_wolfSSL_X509_Name_canon), diff --git a/wolfssl/internal.h b/wolfssl/internal.h index a6db36e500..c62ef351c9 100644 --- a/wolfssl/internal.h +++ b/wolfssl/internal.h @@ -2756,7 +2756,7 @@ WOLFSSL_LOCAL int SetupStoreCtxCallback(WOLFSSL_X509_STORE_CTX** store_pt, WOLFSSL_LOCAL void CleanupStoreCtxCallback(WOLFSSL_X509_STORE_CTX* store, WOLFSSL* ssl, void* heap, int x509Free); #endif /* !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) */ -WOLFSSL_LOCAL int wolfSSL_X509_STORE_load_cert_buffer(WOLFSSL_X509_STORE *str, +WOLFSSL_LOCAL int X509StoreLoadCertBuffer(WOLFSSL_X509_STORE *str, byte *buf, word32 bufLen, int type); #endif /* !defined NO_CERTS */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 0d26abfac7..411d4f82b2 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -603,6 +603,7 @@ struct WOLFSSL_X509_STORE { WOLF_STACK_OF(WOLFSSL_X509)* certs; WOLF_STACK_OF(WOLFSSL_X509)* trusted; WOLF_STACK_OF(WOLFSSL_X509)* owned; + word32 numAdded; /* Number of objs in objs that are in certs sk */ }; #define WOLFSSL_ALWAYS_CHECK_SUBJECT 0x1 @@ -677,7 +678,7 @@ typedef struct WOLFSSL_BUFFER_INFO { struct WOLFSSL_X509_STORE_CTX { WOLFSSL_X509_STORE* store; /* Store full of a CA cert chain */ WOLFSSL_X509* current_cert; /* current X509 (OPENSSL_EXTRA) */ -#ifdef WOLFSSL_ASIO +#if defined(WOLFSSL_ASIO) || defined(OPENSSL_EXTRA) WOLFSSL_X509* current_issuer; /* asio dereference */ #endif WOLFSSL_X509_CHAIN* sesChain; /* pointer to WOLFSSL_SESSION peer chain */ From 1afbf55a809bcd184ee8190dd307e2d7b81a400f Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Fri, 18 Oct 2024 15:28:03 -0700 Subject: [PATCH 08/17] Fix new build error after refactor --- src/x509_str.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/x509_str.c b/src/x509_str.c index 9a022cf966..ae988a539d 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -1011,6 +1011,7 @@ WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void) return NULL; } +#ifdef OPENSSL_ALL static void X509StoreFreeObjList(WOLFSSL_X509_STORE* store, WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* objs) { @@ -1032,6 +1033,7 @@ static void X509StoreFreeObjList(WOLFSSL_X509_STORE* store, wolfSSL_sk_X509_OBJECT_pop_free(objs, NULL); } +#endif void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store) { From 87ce96527a99d9d20ab9150d3f74772409ee7721 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Fri, 18 Oct 2024 16:34:25 -0700 Subject: [PATCH 09/17] Changes for various failing build configs --- src/ssl_certman.c | 10 ++++++---- src/x509.c | 7 ++++--- src/x509_str.c | 31 +++++++++++++++++++++++++------ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/ssl_certman.c b/src/ssl_certman.c index cb52333173..e5ecbea75c 100644 --- a/src/ssl_certman.c +++ b/src/ssl_certman.c @@ -455,8 +455,8 @@ int wolfSSL_CertManagerUnloadCAs(WOLFSSL_CERT_MANAGER* cm) return ret; } -static int wolfSSL_CertManagerUnloadIntermediateCertsEx(WOLFSSL_CERT_MANAGER* cm, - byte type) +static int wolfSSL_CertManagerUnloadIntermediateCertsEx( + WOLFSSL_CERT_MANAGER* cm, byte type) { int ret = WOLFSSL_SUCCESS; @@ -483,14 +483,16 @@ static int wolfSSL_CertManagerUnloadIntermediateCertsEx(WOLFSSL_CERT_MANAGER* cm } #if defined(OPENSSL_EXTRA) -static int wolfSSL_CertManagerUnloadTempIntermediateCerts(WOLFSSL_CERT_MANAGER* cm) +static int wolfSSL_CertManagerUnloadTempIntermediateCerts( + WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerUnloadTempIntermediateCerts"); return wolfSSL_CertManagerUnloadIntermediateCertsEx(cm, WOLFSSL_INTER_CA); } #endif -int wolfSSL_CertManagerUnloadIntermediateCerts(WOLFSSL_CERT_MANAGER* cm) +int wolfSSL_CertManagerUnloadIntermediateCerts( + WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerUnloadIntermediateCerts"); return wolfSSL_CertManagerUnloadIntermediateCertsEx(cm, WOLFSSL_CHAIN_CA); diff --git a/src/x509.c b/src/x509.c index dd05cd4b30..18feff0225 100644 --- a/src/x509.c +++ b/src/x509.c @@ -7597,7 +7597,7 @@ int wolfSSL_X509_LOOKUP_load_file(WOLFSSL_X509_LOOKUP* lookup, else if (wc_PemGetHeaderFooter(CERT_TYPE, &header, &footer) == 0 && XSTRNSTR((char*)curr, header, (unsigned int)sz) != NULL) { ret = X509StoreLoadCertBuffer(lookup->store, curr, - (word32)sz, WOLFSSL_FILETYPE_PEM); + (word32)sz, WOLFSSL_FILETYPE_PEM); if (ret != WOLFSSL_SUCCESS) goto end; curr = (byte*)XSTRNSTR((char*)curr, footer, (unsigned int)sz); @@ -14205,8 +14205,9 @@ int wolfSSL_X509_NAME_digest(const WOLFSSL_X509_NAME *name, #if defined(WOLFSSL_NGINX) || defined(WOLFSSL_HAPROXY) || \ defined(OPENSSL_EXTRA) || defined(OPENSSL_ALL) -#if defined(OPENSSL_EXTRA) && (defined(SESSION_CERTS) || \ - defined(WOLFSSL_SIGNER_DER_CERT)) +#if defined(OPENSSL_EXTRA) && \ + ((defined(SESSION_CERTS) && !defined(WOLFSSL_QT)) || \ + defined(WOLFSSL_SIGNER_DER_CERT)) /** * Find the issuing cert of the input cert. On a self-signed cert this diff --git a/src/x509_str.c b/src/x509_str.c index ae988a539d..49cd7deb67 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -247,6 +247,7 @@ static void SetupStoreCtxError(WOLFSSL_X509_STORE_CTX* ctx, int ret) static int X509StoreVerifyCert(WOLFSSL_X509_STORE_CTX* ctx) { int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); + WOLFSSL_ENTER("X509StoreVerifyCert"); if (ctx->current_cert != NULL && ctx->current_cert->derCert != NULL) { ret = wolfSSL_CertManagerVerifyBuffer(ctx->store->cm, @@ -874,7 +875,7 @@ WOLF_STACK_OF(WOLFSSL_X509)* wolfSSL_X509_STORE_get1_certs( int wolfSSL_X509_STORE_CTX_get1_issuer(WOLFSSL_X509 **issuer, WOLFSSL_X509_STORE_CTX *ctx, WOLFSSL_X509 *x) { - int ret = WOLFSSL_FAILURE; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); WOLFSSL_ENTER("wolfSSL_X509_STORE_CTX_get1_issuer"); if (issuer == NULL || ctx == NULL || x == NULL) @@ -960,6 +961,7 @@ WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void) if ((store->cm = wolfSSL_CertManagerNew()) == NULL) goto err_exit; +#ifdef OPENSSL_EXTRA if ((store->certs = wolfSSL_sk_X509_new_null()) == NULL) goto err_exit; @@ -970,6 +972,7 @@ WOLFSSL_X509_STORE* wolfSSL_X509_STORE_new(void) if ((store->trusted = wolfSSL_sk_X509_new_null()) == NULL) goto err_exit; #endif +#endif #ifdef HAVE_CRL store->crl = store->cm->crl; @@ -1057,6 +1060,7 @@ void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store) wolfSSL_CertManagerFree(store->cm); store->cm = NULL; } +#if defined(OPENSSL_EXTRA) if (store->certs != NULL) { wolfSSL_sk_X509_free(store->certs); store->certs = NULL; @@ -1071,6 +1075,7 @@ void wolfSSL_X509_STORE_free(WOLFSSL_X509_STORE* store) store->trusted = NULL; } #endif +#endif #ifdef OPENSSL_ALL if (store->objs != NULL) { X509StoreFreeObjList(store, store->objs); @@ -1270,14 +1275,24 @@ int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509) #if !defined(WOLFSSL_SIGNER_DER_CERT) if (result == WOLFSSL_SUCCESS && store->trusted != NULL) { result = wolfSSL_sk_X509_push(store->trusted, x509); - result = (result > 0) ? WOLFSSL_SUCCESS : WOLFSSL_FATAL_ERROR; + if (result > 0) { + result = WOLFSSL_SUCCESS; + } + else { + result = WOLFSSL_FATAL_ERROR; + } } #endif } else { if (store->certs != NULL) { result = wolfSSL_sk_X509_push(store->certs, x509); - result = (result > 0) ? WOLFSSL_SUCCESS : WOLFSSL_FATAL_ERROR; + if (result > 0) { + result = WOLFSSL_SUCCESS; + } + else { + result = WOLFSSL_FATAL_ERROR; + } } else { /* If store->certs is NULL, this is an X509_STORE managed by an @@ -1327,7 +1342,7 @@ int wolfSSL_X509_STORE_set_default_paths(WOLFSSL_X509_STORE* store) int X509StoreLoadCertBuffer(WOLFSSL_X509_STORE *str, byte *buf, word32 bufLen, int type) { - int ret = WOLFSSL_FAILURE; + int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE); WOLFSSL_X509 *x509 = NULL; if (str == NULL || buf == NULL) { @@ -1654,6 +1669,10 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( { WOLFSSL_STACK* ret = NULL; WOLFSSL_STACK* cert_stack = NULL; +#if ((defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM)) || \ + (defined(HAVE_CRL))) + WOLFSSL_X509_OBJECT* obj = NULL; +#endif #if defined(WOLFSSL_SIGNER_DER_CERT) && !defined(NO_FILESYSTEM) WOLFSSL_X509* x509 = NULL; int i = 0; @@ -1698,7 +1717,7 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( * simplify cleanup logic handling cert merging above */ for (i = 0; i < wolfSSL_sk_X509_num(cert_stack); i++) { x509 = wolfSSL_sk_value(cert_stack, i); - WOLFSSL_X509_OBJECT* obj = wolfSSL_X509_OBJECT_new(); + obj = wolfSSL_X509_OBJECT_new(); if (obj == NULL) { WOLFSSL_MSG("wolfSSL_X509_OBJECT_new error"); goto err_cleanup; @@ -1720,7 +1739,7 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( #ifdef HAVE_CRL if (store->cm->crl != NULL) { - WOLFSSL_X509_OBJECT* obj = wolfSSL_X509_OBJECT_new(); + obj = wolfSSL_X509_OBJECT_new(); if (obj == NULL) { WOLFSSL_MSG("wolfSSL_X509_OBJECT_new error"); goto err_cleanup; From 1ddb2ce435eb0bd85c606305e476248415c328d6 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 21 Oct 2024 16:06:20 -0700 Subject: [PATCH 10/17] Properly implement set flags for X509_V_FLAG_PARTIAL_CHAIN --- src/x509_str.c | 12 ++++++++---- tests/api.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++ wolfssl/ssl.h | 1 + 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/x509_str.c b/src/x509_str.c index 49cd7deb67..897deaf849 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -384,7 +384,8 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) * a trusted CA in the CM */ ret = X509StoreVerifyCert(ctx); if (ret != WOLFSSL_SUCCESS) { - if ((ctx->store->param->flags & X509_V_FLAG_PARTIAL_CHAIN) && + if (((ctx->flags & X509_V_FLAG_PARTIAL_CHAIN) || + (ctx->store->param->flags & X509_V_FLAG_PARTIAL_CHAIN)) && (added == 1)) { wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); ret = WOLFSSL_SUCCESS; @@ -550,9 +551,9 @@ int wolfSSL_X509_STORE_CTX_set_purpose(WOLFSSL_X509_STORE_CTX *ctx, void wolfSSL_X509_STORE_CTX_set_flags(WOLFSSL_X509_STORE_CTX *ctx, unsigned long flags) { - (void)ctx; - (void)flags; - WOLFSSL_STUB("wolfSSL_X509_STORE_CTX_set_flags (not implemented)"); + if ((ctx != NULL) && (flags & X509_V_FLAG_PARTIAL_CHAIN)){ + ctx->flags |= X509_V_FLAG_PARTIAL_CHAIN; + } } #endif /* !NO_WOLFSSL_STUB */ @@ -1329,6 +1330,9 @@ int wolfSSL_X509_STORE_set_flags(WOLFSSL_X509_STORE* store, unsigned long flag) ret = wolfSSL_CertManagerDisableCRL(store->cm); } #endif + if (flag & X509_V_FLAG_PARTIAL_CHAIN) { + store->param->flags |= X509_V_FLAG_PARTIAL_CHAIN; + } return ret; } diff --git a/tests/api.c b/tests/api.c index 806410cb3b..965aca6b1e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -225,6 +225,7 @@ #include #include #include + #include #ifdef OPENSSL_ALL #include #include @@ -60207,6 +60208,54 @@ static int test_wolfSSL_X509_STORE_CTX_ex9(X509_STORE_test_data *testData) sk_X509_free(trusted); return EXPECT_RESULT(); } + +static int test_wolfSSL_X509_STORE_CTX_ex10(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + + /* Test case 10, ensure partial chain flag works */ + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + /* Fails because chain is incomplete */ + ExpectIntNE(X509_verify_cert(ctx), 1); + ExpectIntEQ(X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN), 1); + /* Partial chain now OK */ + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + return EXPECT_RESULT(); +} + +static int test_wolfSSL_X509_STORE_CTX_ex11(X509_STORE_test_data *testData) +{ + EXPECT_DECLS; + X509_STORE* store = NULL; + X509_STORE_CTX* ctx = NULL; + STACK_OF(X509)* chain = NULL; + + /* Test case 11, test partial chain flag on ctx itself */ + ExpectNotNull(store = X509_STORE_new()); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt), 1); + ExpectIntEQ(X509_STORE_add_cert(store, testData->x509CaInt2), 1); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store, testData->x509Leaf, NULL), 1); + /* Fails because chain is incomplete */ + ExpectIntNE(X509_verify_cert(ctx), 1); + X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_PARTIAL_CHAIN); + /* Partial chain now OK */ + ExpectIntEQ(X509_verify_cert(ctx), 1); + ExpectNotNull(chain = X509_STORE_CTX_get_chain(ctx)); + X509_STORE_CTX_free(ctx); + X509_STORE_free(store); + return EXPECT_RESULT(); +} #endif static int test_wolfSSL_X509_STORE_CTX_ex(void) @@ -60244,6 +60293,8 @@ static int test_wolfSSL_X509_STORE_CTX_ex(void) ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex7(&testData), 1); ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex8(&testData), 1); ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex9(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex10(&testData), 1); + ExpectIntEQ(test_wolfSSL_X509_STORE_CTX_ex11(&testData), 1); if(testData.x509Ca) { X509_free(testData.x509Ca); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 411d4f82b2..7b28fa2287 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -701,6 +701,7 @@ struct WOLFSSL_X509_STORE_CTX { WOLFSSL_BUFFER_INFO* certs; /* peer certs */ WOLFSSL_X509_STORE_CTX_verify_cb verify_cb; /* verify callback */ void* heap; + int flags; WOLF_STACK_OF(WOLFSSL_X509)* ctxIntermediates; /* Intermediates specified * on store ctx init */ WOLF_STACK_OF(WOLFSSL_X509)* setTrustedSk;/* A trusted stack override From 3fc3a84a6b9b6d6d11145ea3b020efe8c3856ea7 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Mon, 21 Oct 2024 16:15:42 -0700 Subject: [PATCH 11/17] Move X509_STORE_CTX_set_flags under OPENSSL_EXTRA --- src/x509_str.c | 12 ++++++------ wolfssl/openssl/x509_vfy.h | 3 +++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/x509_str.c b/src/x509_str.c index 897deaf849..006eae1655 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -547,6 +547,12 @@ int wolfSSL_X509_STORE_CTX_set_purpose(WOLFSSL_X509_STORE_CTX *ctx, WOLFSSL_STUB("wolfSSL_X509_STORE_CTX_set_purpose (not implemented)"); return 0; } +#endif /* !NO_WOLFSSL_STUB */ + +#endif /* WOLFSSL_QT || OPENSSL_ALL */ +#endif /* OPENSSL_EXTRA */ + +#ifdef OPENSSL_EXTRA void wolfSSL_X509_STORE_CTX_set_flags(WOLFSSL_X509_STORE_CTX *ctx, unsigned long flags) @@ -555,12 +561,6 @@ void wolfSSL_X509_STORE_CTX_set_flags(WOLFSSL_X509_STORE_CTX *ctx, ctx->flags |= X509_V_FLAG_PARTIAL_CHAIN; } } -#endif /* !NO_WOLFSSL_STUB */ - -#endif /* WOLFSSL_QT || OPENSSL_ALL */ -#endif /* OPENSSL_EXTRA */ - -#ifdef OPENSSL_EXTRA /* set X509_STORE_CTX ex_data, max idx is MAX_EX_DATA. Return WOLFSSL_SUCCESS * on success, WOLFSSL_FAILURE on error. */ diff --git a/wolfssl/openssl/x509_vfy.h b/wolfssl/openssl/x509_vfy.h index 8666a53fee..977e0c00f8 100644 --- a/wolfssl/openssl/x509_vfy.h +++ b/wolfssl/openssl/x509_vfy.h @@ -33,10 +33,13 @@ #if defined(WOLFSSL_QT) || defined(OPENSSL_ALL) WOLFSSL_API int wolfSSL_X509_STORE_CTX_set_purpose(WOLFSSL_X509_STORE_CTX *ctx, int purpose); +#endif +#ifdef OPENSSL_EXTRA WOLFSSL_API void wolfSSL_X509_STORE_CTX_set_flags(WOLFSSL_X509_STORE_CTX *ctx, unsigned long flags); #endif + #define X509_STORE_CTX_set_purpose wolfSSL_X509_STORE_CTX_set_purpose #define X509_STORE_CTX_set_flags wolfSSL_X509_STORE_CTX_set_flags From 4c63668295d3899c26451ee8bb17f6c9e32f731e Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Tue, 22 Oct 2024 10:59:35 -0700 Subject: [PATCH 12/17] Small changes per review comments --- src/x509_str.c | 9 +++++---- tests/api.c | 2 ++ wolfssl/ssl.h | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/x509_str.c b/src/x509_str.c index 006eae1655..f85d023b18 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -43,6 +43,7 @@ static int X509StoreAddCa(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509, int type); #endif +/* Based on OpenSSL default max depth */ #ifndef WOLFSSL_X509_STORE_DEFAULT_MAX_DEPTH #define WOLFSSL_X509_STORE_DEFAULT_MAX_DEPTH 100 #endif @@ -264,9 +265,9 @@ static int X509StoreVerifyCert(WOLFSSL_X509_STORE_CTX* ctx) if (ret != WC_NO_ERR_TRACE(ASN_BEFORE_DATE_E) && ret != WC_NO_ERR_TRACE(ASN_AFTER_DATE_E)) { /* wolfSSL_CertManagerVerifyBuffer only returns ASN_AFTER_DATE_E or - ASN_BEFORE_DATE_E if there are no additional errors found in the - cert. Therefore, check if the cert is expired or not yet valid - in order to return the correct expected error. */ + * ASN_BEFORE_DATE_E if there are no additional errors found in the + * cert. Therefore, check if the cert is expired or not yet valid + * in order to return the correct expected error. */ byte *afterDate = ctx->current_cert->notAfter.data; byte *beforeDate = ctx->current_cert->notBefore.data; @@ -333,7 +334,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) ret = wolfSSL_sk_X509_push(certs, wolfSSL_sk_X509_value(ctx->ctxIntermediates, i)); if (ret <= 0) { - return WOLFSSL_FAILURE; + goto exit; } numInterAdd++; diff --git a/tests/api.c b/tests/api.c index 965aca6b1e..4123fa6408 100644 --- a/tests/api.c +++ b/tests/api.c @@ -60424,6 +60424,8 @@ static int test_X509_STORE_untrusted(void) /* Root CA in untrusted chain is OK */ ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 1, 0, 1), TEST_SUCCESS); + ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 1, 0, 0), + TEST_SUCCESS); /* Succeeds because path to loaded CA is available. */ ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted4, 1, 0, 1), TEST_SUCCESS); diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 7b28fa2287..94cafa940d 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3324,7 +3324,8 @@ enum { WOLFSSL_USER_CA = 1, /* user added as trusted */ WOLFSSL_CHAIN_CA = 2, /* added to cache from trusted chain */ - WOLFSSL_INTER_CA = 3 /* Intermediate CA */ + WOLFSSL_INTER_CA = 3 /* Intermediate CA, only for use by + * X509_STORE */ }; WOLFSSL_ABI WOLFSSL_API WC_RNG* wolfSSL_GetRNG(WOLFSSL* ssl); From 96138e70f80960fe571a17fa57a86420255f323c Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Tue, 22 Oct 2024 15:10:18 -0700 Subject: [PATCH 13/17] Restore proper error code handling for self signed CA in non-trusted intermediates --- src/x509_str.c | 20 ++++++++++++++++++++ tests/api.c | 8 ++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/x509_str.c b/src/x509_str.c index f85d023b18..44e104ba6b 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -305,6 +305,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) int depth = 0; WOLFSSL_X509 *issuer = NULL; WOLFSSL_X509 *orig = NULL; + WOLFSSL_X509 *tmp = NULL; WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL; WOLFSSL_ENTER("wolfSSL_X509_verify_cert"); @@ -355,6 +356,25 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) /* Try to find an untrusted issuer first */ ret = X509StoreGetIssuerEx(&issuer, certs, ctx->current_cert); + if (issuer != NULL && + wolfSSL_X509_NAME_cmp(&issuer->issuer, &issuer->subject) == 0) { + ret = WOLFSSL_FAILURE; + /* Self signed allowed if in set trusted stack, otherwise + * ignore it and fall back to see if its in CM */ + if ((certs == ctx->setTrustedSk) && + (wolfSSL_sk_X509_num(certs) > numInterAdd)) { + for (i = wolfSSL_sk_X509_num(certs) - 1; + i > (numInterAdd > 0 ? numInterAdd - 1 : 0); + i++) { + tmp = wolfSSL_sk_X509_value(certs, i); + if (wolfSSL_X509_NAME_cmp( + &issuer->subject, &tmp->subject) == 0) { + ret = WOLFSSL_SUCCESS; + break; + } + } + } + } if (ret == WOLFSSL_SUCCESS) { if (ctx->current_cert == issuer) { wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); diff --git a/tests/api.c b/tests/api.c index 4123fa6408..c15e431b1e 100644 --- a/tests/api.c +++ b/tests/api.c @@ -60421,10 +60421,14 @@ static int test_X509_STORE_untrusted(void) /* Succeeds because path to loaded CA is available. */ ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted2, 1, 0, 1), TEST_SUCCESS); - /* Root CA in untrusted chain is OK */ + /* Root CA in untrusted chain is OK so long as CA has been loaded + * properly */ ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 1, 0, 1), TEST_SUCCESS); - ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 1, 0, 0), + /* Still needs properly loaded CA, while including it in untrusted + * list is not an error, it also doesnt count for verify */ + ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 0, + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 0), TEST_SUCCESS); /* Succeeds because path to loaded CA is available. */ ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted4, 1, 0, 1), From 95f8d7420218470b918555841d1359139fde3ca2 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Tue, 22 Oct 2024 15:59:49 -0700 Subject: [PATCH 14/17] Fix loop to decrement --- src/x509_str.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/x509_str.c b/src/x509_str.c index 44e104ba6b..012f41d74b 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -365,13 +365,14 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) (wolfSSL_sk_X509_num(certs) > numInterAdd)) { for (i = wolfSSL_sk_X509_num(certs) - 1; i > (numInterAdd > 0 ? numInterAdd - 1 : 0); - i++) { + i--) { tmp = wolfSSL_sk_X509_value(certs, i); - if (wolfSSL_X509_NAME_cmp( + if (tmp != NULL && wolfSSL_X509_NAME_cmp( &issuer->subject, &tmp->subject) == 0) { ret = WOLFSSL_SUCCESS; break; } + tmp = NULL; } } } From ee4e1b6262f338e6c83a042543c3a8c20a7bc7c8 Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Tue, 22 Oct 2024 19:54:55 -0700 Subject: [PATCH 15/17] Properly omit self signed CA from untrusted intermediates, handle memory leak for SSL case with proper flow --- src/x509_str.c | 90 +++++++++++++++++++++++++++++--------------------- wolfssl/ssl.h | 1 + 2 files changed, 53 insertions(+), 38 deletions(-) diff --git a/src/x509_str.c b/src/x509_str.c index 012f41d74b..061e85e1b3 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -65,7 +65,12 @@ WOLFSSL_X509_STORE_CTX* wolfSSL_X509_STORE_CTX_new_ex(void* heap) XMEMSET(ctx, 0, sizeof(WOLFSSL_X509_STORE_CTX)); ctx->heap = heap; #ifdef OPENSSL_EXTRA - if (wolfSSL_X509_STORE_CTX_init(ctx, NULL, NULL, NULL) != + if ((ctx->owned = wolfSSL_sk_X509_new_null()) == NULL) { + XFREE(ctx, heap, DYNAMIC_TYPE_X509_CTX); + ctx = NULL; + } + if (ctx != NULL && + wolfSSL_X509_STORE_CTX_init(ctx, NULL, NULL, NULL) != WOLFSSL_SUCCESS) { XFREE(ctx, heap, DYNAMIC_TYPE_X509_CTX); ctx = NULL; @@ -94,6 +99,9 @@ void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx) if (ctx->chain != NULL) { wolfSSL_sk_X509_free(ctx->chain); } + if (ctx->owned != NULL) { + wolfSSL_sk_X509_pop_free(ctx->owned, NULL); + } if (ctx->current_issuer != NULL) { wolfSSL_X509_free(ctx->current_issuer); @@ -292,6 +300,32 @@ static int X509StoreVerifyCert(WOLFSSL_X509_STORE_CTX* ctx) return ret; } +static int addAllButSelfSigned(WOLF_STACK_OF(WOLFSSL_X509)*to, + WOLF_STACK_OF(WOLFSSL_X509)*from, int *numAdded) +{ + int ret = WOLFSSL_SUCCESS; + int i = 0; + int cnt = 0; + WOLFSSL_X509 *x = NULL; + + for (i = 0; i < wolfSSL_sk_X509_num(from); i++) { + x = wolfSSL_sk_X509_value(from, i); + if (wolfSSL_X509_NAME_cmp(&x->issuer, &x->subject) != 0) { + if (wolfSSL_sk_X509_push(to, x) <= 0) { + ret = WOLFSSL_FAILURE; + goto exit; + } + cnt++; + } + } + +exit: + if (numAdded != NULL) { + *numAdded = cnt; + } + return ret; +} + /* Verifies certificate chain using WOLFSSL_X509_STORE_CTX * returns 0 on success or < 0 on failure. */ @@ -305,8 +339,8 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) int depth = 0; WOLFSSL_X509 *issuer = NULL; WOLFSSL_X509 *orig = NULL; - WOLFSSL_X509 *tmp = NULL; WOLF_STACK_OF(WOLFSSL_X509)* certs = NULL; + WOLF_STACK_OF(WOLFSSL_X509)* certsToUse = NULL; WOLFSSL_ENTER("wolfSSL_X509_verify_cert"); if (ctx == NULL || ctx->store == NULL || ctx->store->cm == NULL @@ -315,32 +349,28 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) } certs = ctx->store->certs; - if (ctx->chain != NULL) { - wolfSSL_sk_X509_free(ctx->chain); - } - ctx->chain = wolfSSL_sk_X509_new_null(); - if (ctx->setTrustedSk != NULL) { certs = ctx->setTrustedSk; } if (certs == NULL && wolfSSL_sk_X509_num(ctx->ctxIntermediates) > 0) { - certs = ctx->ctxIntermediates; + certsToUse = wolfSSL_sk_X509_new_null(); + ret = addAllButSelfSigned(certsToUse, ctx->ctxIntermediates, NULL); } else { /* Add the intermediates provided on init to the list of untrusted * intermediates to be used */ - for (i = 0; i < wolfSSL_sk_X509_num(ctx->ctxIntermediates); i++) { - ret = wolfSSL_sk_X509_push(certs, - wolfSSL_sk_X509_value(ctx->ctxIntermediates, i)); - if (ret <= 0) { - goto exit; - } + ret = addAllButSelfSigned(certs, ctx->ctxIntermediates, &numInterAdd); + } + if (ret != WOLFSSL_SUCCESS) { + goto exit; + } - numInterAdd++; - } + if (ctx->chain != NULL) { + wolfSSL_sk_X509_free(ctx->chain); } + ctx->chain = wolfSSL_sk_X509_new_null(); if (ctx->depth > 0) { depth = ctx->depth + 1; @@ -356,26 +386,6 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) /* Try to find an untrusted issuer first */ ret = X509StoreGetIssuerEx(&issuer, certs, ctx->current_cert); - if (issuer != NULL && - wolfSSL_X509_NAME_cmp(&issuer->issuer, &issuer->subject) == 0) { - ret = WOLFSSL_FAILURE; - /* Self signed allowed if in set trusted stack, otherwise - * ignore it and fall back to see if its in CM */ - if ((certs == ctx->setTrustedSk) && - (wolfSSL_sk_X509_num(certs) > numInterAdd)) { - for (i = wolfSSL_sk_X509_num(certs) - 1; - i > (numInterAdd > 0 ? numInterAdd - 1 : 0); - i--) { - tmp = wolfSSL_sk_X509_value(certs, i); - if (tmp != NULL && wolfSSL_X509_NAME_cmp( - &issuer->subject, &tmp->subject) == 0) { - ret = WOLFSSL_SUCCESS; - break; - } - tmp = NULL; - } - } - } if (ret == WOLFSSL_SUCCESS) { if (ctx->current_cert == issuer) { wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); @@ -417,10 +427,11 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) /* Cert verified, finish building the chain */ wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); + issuer = NULL; #ifdef WOLFSSL_SIGNER_DER_CERT x509GetIssuerFromCM(&issuer, ctx->store->cm, ctx->current_cert); - if (issuer != NULL && ctx->store->owned != NULL) { - wolfSSL_sk_X509_push(ctx->store->owned, issuer); + if (issuer != NULL && ctx->owned != NULL) { + wolfSSL_sk_X509_push(ctx->owned, issuer); } #else if (ctx->setTrustedSk == NULL) { @@ -463,6 +474,9 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) ctx->current_cert = orig; } } + if (certsToUse != NULL) { + wolfSSL_sk_X509_free(certsToUse); + } return ret == WOLFSSL_SUCCESS ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; } diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 94cafa940d..b45a4eb188 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -702,6 +702,7 @@ struct WOLFSSL_X509_STORE_CTX { WOLFSSL_X509_STORE_CTX_verify_cb verify_cb; /* verify callback */ void* heap; int flags; + WOLF_STACK_OF(WOLFSSL_X509)* owned; /* Certs owned by this CTX */ WOLF_STACK_OF(WOLFSSL_X509)* ctxIntermediates; /* Intermediates specified * on store ctx init */ WOLF_STACK_OF(WOLFSSL_X509)* setTrustedSk;/* A trusted stack override From 6f0bcac7374fbf8c60316661b93e943deb3fc50a Mon Sep 17 00:00:00 2001 From: Colton Willey Date: Wed, 23 Oct 2024 09:34:28 -0700 Subject: [PATCH 16/17] Address review comments, rename WOLFSSL_INTER_CA, use up_ref for get issuer --- src/ssl.c | 4 ++-- src/ssl_certman.c | 2 +- src/x509_str.c | 13 +++++-------- wolfssl/ssl.h | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ssl.c b/src/ssl.c index defa111903..fe81193482 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -5536,13 +5536,13 @@ int AddCA(WOLFSSL_CERT_MANAGER* cm, DerBuffer** pDer, int type, int verify) } if (ret == 0 && cert->isCA == 0 && type != WOLFSSL_USER_CA && - type != WOLFSSL_INTER_CA) { + type != WOLFSSL_TEMP_CA) { WOLFSSL_MSG("\tCan't add as CA if not actually one"); ret = NOT_CA_ERROR; } #ifndef ALLOW_INVALID_CERTSIGN else if (ret == 0 && cert->isCA == 1 && type != WOLFSSL_USER_CA && - type != WOLFSSL_INTER_CA && !cert->selfSigned && + type != WOLFSSL_TEMP_CA && !cert->selfSigned && (cert->extKeyUsage & KEYUSE_KEY_CERT_SIGN) == 0) { /* Intermediate CA certs are required to have the keyCertSign * extension set. User loaded root certs are not. */ diff --git a/src/ssl_certman.c b/src/ssl_certman.c index e5ecbea75c..346904eef0 100644 --- a/src/ssl_certman.c +++ b/src/ssl_certman.c @@ -487,7 +487,7 @@ static int wolfSSL_CertManagerUnloadTempIntermediateCerts( WOLFSSL_CERT_MANAGER* cm) { WOLFSSL_ENTER("wolfSSL_CertManagerUnloadTempIntermediateCerts"); - return wolfSSL_CertManagerUnloadIntermediateCertsEx(cm, WOLFSSL_INTER_CA); + return wolfSSL_CertManagerUnloadIntermediateCertsEx(cm, WOLFSSL_TEMP_CA); } #endif diff --git a/src/x509_str.c b/src/x509_str.c index 061e85e1b3..072e16e167 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -72,7 +72,7 @@ WOLFSSL_X509_STORE_CTX* wolfSSL_X509_STORE_CTX_new_ex(void* heap) if (ctx != NULL && wolfSSL_X509_STORE_CTX_init(ctx, NULL, NULL, NULL) != WOLFSSL_SUCCESS) { - XFREE(ctx, heap, DYNAMIC_TYPE_X509_CTX); + wolfSSL_X509_STORE_CTX_free(ctx); ctx = NULL; } #endif @@ -105,7 +105,6 @@ void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx) if (ctx->current_issuer != NULL) { wolfSSL_X509_free(ctx->current_issuer); - ctx->current_issuer = NULL; } #endif @@ -395,7 +394,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) /* We found our issuer in the non-trusted cert list, add it * to the CM and verify the current cert against it */ ret = X509StoreAddCa(ctx->store, issuer, - WOLFSSL_INTER_CA); + WOLFSSL_TEMP_CA); if (ret != WOLFSSL_SUCCESS) { goto exit; } @@ -920,8 +919,7 @@ int wolfSSL_X509_STORE_CTX_get1_issuer(WOLFSSL_X509 **issuer, ret = X509StoreGetIssuerEx(issuer, ctx->store->certs, x); if ((ret == WOLFSSL_SUCCESS) && (*issuer != NULL)) { - *issuer = wolfSSL_X509_dup(*issuer); - return (*issuer != NULL) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + return wolfSSL_X509_up_ref(*issuer); } #ifdef WOLFSSL_SIGNER_DER_CERT @@ -929,8 +927,7 @@ int wolfSSL_X509_STORE_CTX_get1_issuer(WOLFSSL_X509 **issuer, #else ret = X509StoreGetIssuerEx(issuer, ctx->store->trusted, x); if ((ret == WOLFSSL_SUCCESS) && (*issuer != NULL)) { - *issuer = wolfSSL_X509_dup(*issuer); - return (*issuer != NULL) ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE; + return wolfSSL_X509_up_ref(*issuer); } #endif @@ -1065,7 +1062,7 @@ static void X509StoreFreeObjList(WOLFSSL_X509_STORE* store, obj = wolfSSL_sk_X509_OBJECT_value(objs, i); if (obj != NULL) { obj->type = 0; - obj->data.x509 = NULL; + obj->data.ptr = NULL; } cnt--; i--; diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index b45a4eb188..15e0e9cde5 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -3325,7 +3325,7 @@ enum { WOLFSSL_USER_CA = 1, /* user added as trusted */ WOLFSSL_CHAIN_CA = 2, /* added to cache from trusted chain */ - WOLFSSL_INTER_CA = 3 /* Intermediate CA, only for use by + WOLFSSL_TEMP_CA = 3 /* Temp intermediate CA, only for use by * X509_STORE */ }; From cab20fbdd2a0042fcdc5059477dabe9a8dce1926 Mon Sep 17 00:00:00 2001 From: Daniel Pouzzner Date: Wed, 23 Oct 2024 16:57:58 -0500 Subject: [PATCH 17/17] add and use WOLFSSL_PARTIAL_CHAIN as native bitmask macro for compat layer X509_V_FLAG_PARTIAL_CHAIN; in src/x509_str.c, fix several C++ "invalid conversion" errors in X509StoreFreeObjList() and wolfSSL_X509_STORE_get0_objects(). --- src/x509_str.c | 18 +++++++++--------- wolfssl/openssl/ssl.h | 4 ++-- wolfssl/ssl.h | 1 + 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/x509_str.c b/src/x509_str.c index 072e16e167..a659a73d46 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -415,8 +415,8 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx) * a trusted CA in the CM */ ret = X509StoreVerifyCert(ctx); if (ret != WOLFSSL_SUCCESS) { - if (((ctx->flags & X509_V_FLAG_PARTIAL_CHAIN) || - (ctx->store->param->flags & X509_V_FLAG_PARTIAL_CHAIN)) && + if (((ctx->flags & WOLFSSL_PARTIAL_CHAIN) || + (ctx->store->param->flags & WOLFSSL_PARTIAL_CHAIN)) && (added == 1)) { wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert); ret = WOLFSSL_SUCCESS; @@ -592,8 +592,8 @@ int wolfSSL_X509_STORE_CTX_set_purpose(WOLFSSL_X509_STORE_CTX *ctx, void wolfSSL_X509_STORE_CTX_set_flags(WOLFSSL_X509_STORE_CTX *ctx, unsigned long flags) { - if ((ctx != NULL) && (flags & X509_V_FLAG_PARTIAL_CHAIN)){ - ctx->flags |= X509_V_FLAG_PARTIAL_CHAIN; + if ((ctx != NULL) && (flags & WOLFSSL_PARTIAL_CHAIN)){ + ctx->flags |= WOLFSSL_PARTIAL_CHAIN; } } @@ -1059,9 +1059,9 @@ static void X509StoreFreeObjList(WOLFSSL_X509_STORE* store, i = wolfSSL_sk_X509_OBJECT_num(objs) - 1; while (cnt > 0 && i > 0) { /* The inner X509 is owned by somebody else, NULL out the reference */ - obj = wolfSSL_sk_X509_OBJECT_value(objs, i); + obj = (WOLFSSL_X509_OBJECT *)wolfSSL_sk_X509_OBJECT_value(objs, i); if (obj != NULL) { - obj->type = 0; + obj->type = (WOLFSSL_X509_LOOKUP_TYPE)0; obj->data.ptr = NULL; } cnt--; @@ -1363,8 +1363,8 @@ int wolfSSL_X509_STORE_set_flags(WOLFSSL_X509_STORE* store, unsigned long flag) ret = wolfSSL_CertManagerDisableCRL(store->cm); } #endif - if (flag & X509_V_FLAG_PARTIAL_CHAIN) { - store->param->flags |= X509_V_FLAG_PARTIAL_CHAIN; + if (flag & WOLFSSL_PARTIAL_CHAIN) { + store->param->flags |= WOLFSSL_PARTIAL_CHAIN; } return ret; } @@ -1753,7 +1753,7 @@ WOLF_STACK_OF(WOLFSSL_X509_OBJECT)* wolfSSL_X509_STORE_get0_objects( /* Do not modify stack until after we guarantee success to * simplify cleanup logic handling cert merging above */ for (i = 0; i < wolfSSL_sk_X509_num(cert_stack); i++) { - x509 = wolfSSL_sk_value(cert_stack, i); + x509 = (WOLFSSL_X509 *)wolfSSL_sk_value(cert_stack, i); obj = wolfSSL_X509_OBJECT_new(); if (obj == NULL) { WOLFSSL_MSG("wolfSSL_X509_OBJECT_new error"); diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 1f7b640eb4..f6d29f0b75 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -643,8 +643,8 @@ typedef WOLFSSL_X509_NAME_ENTRY X509_NAME_ENTRY; #define X509_V_FLAG_CRL_CHECK WOLFSSL_CRL_CHECK #define X509_V_FLAG_CRL_CHECK_ALL WOLFSSL_CRL_CHECKALL -#define X509_V_FLAG_PARTIAL_CHAIN 0x80000 -#define X509_V_FLAG_TRUSTED_FIRST 0 +#define X509_V_FLAG_PARTIAL_CHAIN WOLFSSL_PARTIAL_CHAIN +#define X509_V_FLAG_TRUSTED_FIRST 0 /* dummy value needed for gRPC port */ #define X509_V_FLAG_USE_CHECK_TIME WOLFSSL_USE_CHECK_TIME #define X509_V_FLAG_NO_CHECK_TIME WOLFSSL_NO_CHECK_TIME diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index 15e0e9cde5..4bbdf6565c 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -616,6 +616,7 @@ struct WOLFSSL_X509_STORE { #if defined(OPENSSL_EXTRA) || defined(WOLFSSL_WPAS_SMALL) #define WOLFSSL_USE_CHECK_TIME 0x2 #define WOLFSSL_NO_CHECK_TIME 0x200000 +#define WOLFSSL_PARTIAL_CHAIN 0x80000 #define WOLFSSL_HOST_NAME_MAX 256 #define WOLFSSL_VPARAM_DEFAULT 0x1