Skip to content

Commit e43eb4e

Browse files
committed
X509_STORE_CTX: chain owns references to its certs
Fixes a heap-use-after-free found by ASAN in the sanitize-asan CI config. wolfSSL_X509_verify_cert filled ctx->chain with borrowed pointers while CleanupStoreCtxCallback frees the chain members it expects from X509_STORE_CTX_get_chain. Calling X509_verify_cert from a cert verify callback, like OpenVPN does, freed the certs twice. Take a reference for each cert pushed onto the chain and free the members whenever the chain is freed, like OpenSSL. Also address review comments: - Pass a cert verify callback failure on to the following verify callbacks as preverify_ok = 0. - Only define X509_STORE_CTX_set0_crls with HAVE_CRL.
1 parent bb28b73 commit e43eb4e

3 files changed

Lines changed: 32 additions & 8 deletions

File tree

src/internal.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15573,6 +15573,9 @@ int DoVerifyCallback(WOLFSSL_CERT_MANAGER* cm, WOLFSSL* ssl, int cert_err,
1557315573
}
1557415574
else {
1557515575
verifyFail = 1;
15576+
/* Pass the failure on to the following verify
15577+
* callbacks. */
15578+
verify_ok = 0;
1557615579
}
1557715580
}
1557815581
#endif

src/x509_str.c

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx)
9292
ctx->param = NULL;
9393

9494
if (ctx->chain != NULL) {
95-
wolfSSL_sk_X509_free(ctx->chain);
95+
wolfSSL_sk_X509_pop_free(ctx->chain, NULL);
9696
}
9797
if (ctx->owned != NULL) {
9898
wolfSSL_sk_X509_pop_free(ctx->owned, NULL);
@@ -207,7 +207,7 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx,
207207
ctx->crls = NULL;
208208
#endif
209209
if (ctx->chain != NULL) {
210-
wolfSSL_sk_X509_free(ctx->chain);
210+
wolfSSL_sk_X509_pop_free(ctx->chain, NULL);
211211
ctx->chain = NULL;
212212
}
213213
#ifdef SESSION_CERTS
@@ -663,6 +663,22 @@ static int X509StoreRemoveCert(WOLFSSL_STACK *stack, WOLFSSL_X509 *cert) {
663663
}
664664

665665

666+
/* Push x509 onto the ctx chain with its own reference, like OpenSSL.
667+
* The chain owns a reference to each of its certs. */
668+
static int X509StoreChainPush(WOLF_STACK_OF(WOLFSSL_X509)* chain,
669+
WOLFSSL_X509* x509)
670+
{
671+
int ret = WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
672+
673+
if (x509 == NULL || wolfSSL_X509_up_ref(x509) != WOLFSSL_SUCCESS)
674+
return ret;
675+
ret = wolfSSL_sk_X509_push(chain, x509) > 0 ? WOLFSSL_SUCCESS :
676+
WC_NO_ERR_TRACE(WOLFSSL_FAILURE);
677+
if (ret != WOLFSSL_SUCCESS)
678+
wolfSSL_X509_free(x509);
679+
return ret;
680+
}
681+
666682
/* Current certificate failed, but it is possible there is an
667683
* alternative cert with the same subject key which will work.
668684
* Retry until all possible candidate certs are exhausted. */
@@ -677,6 +693,9 @@ static int X509VerifyCertSetupRetry(WOLFSSL_X509_STORE_CTX* ctx,
677693
WOLFSSL_TEMP_CA);
678694
X509StoreMoveCert(certs, failed, ctx->current_cert);
679695
ctx->current_cert = wolfSSL_sk_X509_pop(ctx->chain);
696+
/* Release the chain's reference. The cert stays valid through its
697+
* original owner. */
698+
wolfSSL_X509_free(ctx->current_cert);
680699
if (*depth < origDepth)
681700
*depth += 1;
682701

@@ -907,7 +926,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
907926
}
908927

909928
if (ctx->chain != NULL) {
910-
wolfSSL_sk_X509_free(ctx->chain);
929+
wolfSSL_sk_X509_pop_free(ctx->chain, NULL);
911930
}
912931
ctx->chain = wolfSSL_sk_X509_new_null();
913932
if (ctx->chain == NULL) {
@@ -941,7 +960,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
941960
ctx->current_cert);
942961
if (ret == WOLFSSL_SUCCESS) {
943962
if (ctx->current_cert == issuer) {
944-
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
963+
X509StoreChainPush(ctx->chain, ctx->current_cert);
945964
break;
946965
}
947966

@@ -988,7 +1007,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
9881007
continue;
9891008
}
9901009
/* Add it to the current chain and look at the issuer cert next */
991-
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
1010+
X509StoreChainPush(ctx->chain, ctx->current_cert);
9921011
ctx->current_cert = issuer;
9931012
}
9941013
else if (ret == WC_NO_ERR_TRACE(WOLFSSL_FAILURE)) {
@@ -1025,7 +1044,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
10251044
(ctx->store->param->flags & WOLFSSL_PARTIAL_CHAIN))) &&
10261045
X509StoreCertIsTrusted(ctx->store, ctx->current_cert,
10271046
origTrustedSk)) {
1028-
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
1047+
X509StoreChainPush(ctx->chain, ctx->current_cert);
10291048
/* Clear error set by the failed X509StoreVerifyCert
10301049
* attempt; the partial-chain fallback accepted the
10311050
* chain at a caller-trusted certificate. */
@@ -1046,7 +1065,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
10461065
}
10471066

10481067
/* Cert verified, finish building the chain */
1049-
wolfSSL_sk_X509_push(ctx->chain, ctx->current_cert);
1068+
X509StoreChainPush(ctx->chain, ctx->current_cert);
10501069
issuer = NULL;
10511070
#ifdef WOLFSSL_SIGNER_DER_CERT
10521071
x509GetIssuerFromCM(&issuer, ctx->store->cm, ctx->current_cert);
@@ -1064,7 +1083,7 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
10641083
}
10651084
#endif
10661085
if (issuer != NULL) {
1067-
wolfSSL_sk_X509_push(ctx->chain, issuer);
1086+
X509StoreChainPush(ctx->chain, issuer);
10681087
}
10691088

10701089
done = 1;

wolfssl/openssl/ssl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,9 @@ typedef WOLFSSL_X509_NAME_ENTRY X509_NAME_ENTRY;
771771
#define X509_STORE_CTX_get0_store wolfSSL_X509_STORE_CTX_get0_store
772772
#define X509_STORE_CTX_get0_cert wolfSSL_X509_STORE_CTX_get0_cert
773773
#define X509_STORE_CTX_trusted_stack wolfSSL_X509_STORE_CTX_trusted_stack
774+
#ifdef HAVE_CRL
774775
#define X509_STORE_CTX_set0_crls wolfSSL_X509_STORE_CTX_set0_crls
776+
#endif
775777

776778
#define X509_STORE_set_verify_cb(s, c) \
777779
wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_CTX_verify_cb)(c))

0 commit comments

Comments
 (0)