diff --git a/src/x509_str.c b/src/x509_str.c index 38b22a6f85..9dea8a3c40 100644 --- a/src/x509_str.c +++ b/src/x509_str.c @@ -206,6 +206,7 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx, #endif ctx->ctxIntermediates = sk; + ctx->setTrustedSk = NULL; #ifdef HAVE_CRL ctx->crls = NULL; #endif diff --git a/tests/api/test_ossl_x509_str.c b/tests/api/test_ossl_x509_str.c index bbe5775b20..97c923087f 100644 --- a/tests/api/test_ossl_x509_str.c +++ b/tests/api/test_ossl_x509_str.c @@ -2903,6 +2903,64 @@ int test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup(void) return res; } +/* The trusted stack set with X509_STORE_CTX_trusted_stack() is borrowed from + * the caller and must not survive a cleanup/re-init into a different store. */ +int test_wolfSSL_X509_STORE_CTX_trusted_stack_reinit(void) +{ + EXPECT_DECLS; +#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) + X509_STORE_CTX* ctx = NULL; + X509_STORE* store1 = NULL; + X509_STORE* store2 = NULL; + X509* x509Ca = NULL; + X509* x509Svr = NULL; + STACK_OF(X509)* trusted = NULL; +#ifdef WOLFSSL_TEST_STALE_TRUSTED_STACK_UAF + int verifyRet = 0; +#endif + + ExpectNotNull(x509Ca = wolfSSL_X509_load_certificate_file(caCertFile, + SSL_FILETYPE_PEM)); + ExpectNotNull(x509Svr = wolfSSL_X509_load_certificate_file(svrCertFile, + SSL_FILETYPE_PEM)); + ExpectNotNull(trusted = sk_X509_new_null()); + ExpectIntGE(sk_X509_push(trusted, x509Ca), 1); + + /* Both stores are empty, so the caller's stack is the only trust source. */ + ExpectNotNull(store1 = X509_STORE_new()); + ExpectNotNull(store2 = X509_STORE_new()); + ExpectNotNull(ctx = X509_STORE_CTX_new()); + + ExpectIntEQ(X509_STORE_CTX_init(ctx, store1, x509Svr, NULL), 1); + ExpectIntNE(X509_verify_cert(ctx), 1); + X509_STORE_CTX_trusted_stack(ctx, trusted); + ExpectIntEQ(X509_verify_cert(ctx), 1); + + /* Re-init against a different store: the previous trust domain must be + * gone, so this must fail. */ + X509_STORE_CTX_cleanup(ctx); + ExpectIntEQ(X509_STORE_CTX_init(ctx, store2, x509Svr, NULL), 1); + ExpectIntNE(X509_verify_cert(ctx), 1); + +#ifdef WOLFSSL_TEST_STALE_TRUSTED_STACK_UAF + /* Opt-in ASAN repro: the ctx must hold no reference left to free. Call + * verify outside the Expect macro, which stops running after a failure. */ + sk_X509_free(trusted); + trusted = NULL; + verifyRet = X509_verify_cert(ctx); + ExpectIntNE(verifyRet, 1); +#endif + + X509_STORE_CTX_free(ctx); + X509_STORE_free(store1); + X509_STORE_free(store2); + sk_X509_free(trusted); + X509_free(x509Svr); + X509_free(x509Ca); +#endif + return EXPECT_RESULT(); +} + int test_wolfSSL_X509_STORE_CTX_get_issuer(void) { EXPECT_DECLS; diff --git a/tests/api/test_ossl_x509_str.h b/tests/api/test_ossl_x509_str.h index b1d4d4cbb1..688fd7df94 100644 --- a/tests/api/test_ossl_x509_str.h +++ b/tests/api/test_ossl_x509_str.h @@ -43,6 +43,7 @@ int test_X509_STORE_InvalidCa(void); int test_X509_STORE_InvalidCa_CtxCallback(void); int test_X509_STORE_InvalidCa_NoCallback(void); int test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup(void); +int test_wolfSSL_X509_STORE_CTX_trusted_stack_reinit(void); int test_wolfSSL_X509_STORE_CTX_get_issuer(void); int test_wolfSSL_X509_STORE_set_flags(void); int test_wolfSSL_X509_STORE(void); @@ -87,6 +88,8 @@ int test_wolfSSL_CTX_set_cert_store(void); TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_InvalidCa_NoCallback), \ TEST_DECL_GROUP("ossl_x509_store", \ test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup), \ + TEST_DECL_GROUP("ossl_x509_store", \ + test_wolfSSL_X509_STORE_CTX_trusted_stack_reinit), \ TEST_DECL_GROUP("ossl_x509_store", \ test_wolfSSL_X509_STORE_CTX_get_issuer), \ TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_set_flags), \