mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 13:20:52 +02:00
x509: fix CA:FALSE bypass in wolfSSL_X509_verify_cert
When an untrusted issuer has CA:FALSE and no verify_cb is registered, the !isCa branch now fails closed (ret=WOLFSSL_FAILURE, goto exit) instead of falling through and skipping X509StoreVerifyCert for the leaf. SetupStoreCtxError_ex is also hardened to never overwrite a previously recorded error with success, preventing a later valid chain link from clobbering ctx->error back to X509_V_OK. Tests added for both the no-callback rejection and the error-preservation cases. Reported by: Nicholas Carlini (Anthropic) & Thai Duong (Calif.io)
This commit is contained in:
committed by
JacobBarthelmeh
parent
a88dd07c70
commit
e5ab7fa745
+10
-1
@@ -318,6 +318,11 @@ static void SetupStoreCtxError_ex(WOLFSSL_X509_STORE_CTX* ctx, int ret,
|
||||
{
|
||||
int error = GetX509Error(ret);
|
||||
|
||||
/* Do not overwrite a previously recorded error with success; preserve
|
||||
* the worst-seen error across the chain walk. */
|
||||
if (error == 0 && ctx->error != 0)
|
||||
return;
|
||||
|
||||
wolfSSL_X509_STORE_CTX_set_error(ctx, error);
|
||||
wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth);
|
||||
}
|
||||
@@ -635,9 +640,14 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
|
||||
if (ctx->store->verify_cb) {
|
||||
ret = ctx->store->verify_cb(0, ctx);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
ret = WOLFSSL_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = WOLFSSL_FAILURE;
|
||||
goto exit;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -2174,4 +2184,3 @@ int wolfSSL_X509_STORE_set1_param(WOLFSSL_X509_STORE *ctx,
|
||||
#endif /* !WOLFCRYPT_ONLY */
|
||||
|
||||
#endif /* !WOLFSSL_X509_STORE_INCLUDED */
|
||||
|
||||
|
||||
@@ -1074,6 +1074,56 @@ int test_X509_STORE_InvalidCa(void)
|
||||
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1);
|
||||
ExpectIntEQ(X509_verify_cert(ctx), 1);
|
||||
ExpectIntEQ(last_errcode, X509_V_ERR_INVALID_CA);
|
||||
/* Defense in depth: ctx->error must not be clobbered back to X509_V_OK
|
||||
* by the later successful verification of the intermediate against the
|
||||
* trusted root. The worst-seen error must persist. */
|
||||
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA);
|
||||
|
||||
X509_free(cert);
|
||||
X509_STORE_free(str);
|
||||
X509_STORE_CTX_free(ctx);
|
||||
sk_X509_pop_free(untrusted, NULL);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_X509_STORE_InvalidCa_NoCallback(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
|
||||
const char* filename = "./certs/intermediate/ca_false_intermediate/"
|
||||
"test_int_not_cacert.pem";
|
||||
const char* srvfile = "./certs/intermediate/ca_false_intermediate/"
|
||||
"test_sign_bynoca_srv.pem";
|
||||
X509_STORE_CTX* ctx = NULL;
|
||||
X509_STORE* str = NULL;
|
||||
XFILE fp = XBADFILE;
|
||||
X509* cert = NULL;
|
||||
STACK_OF(X509)* untrusted = NULL;
|
||||
|
||||
ExpectTrue((fp = XFOPEN(srvfile, "rb"))
|
||||
!= XBADFILE);
|
||||
ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 ));
|
||||
if (fp != XBADFILE) {
|
||||
XFCLOSE(fp);
|
||||
fp = XBADFILE;
|
||||
}
|
||||
|
||||
ExpectNotNull(str = X509_STORE_new());
|
||||
ExpectNotNull(ctx = X509_STORE_CTX_new());
|
||||
ExpectNotNull(untrusted = sk_X509_new_null());
|
||||
|
||||
/* Create cert chain stack with an intermediate that is CA:FALSE. */
|
||||
ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(filename,
|
||||
untrusted), TEST_SUCCESS);
|
||||
|
||||
ExpectIntEQ(X509_STORE_load_locations(str,
|
||||
"./certs/intermediate/ca_false_intermediate/test_ca.pem",
|
||||
NULL), 1);
|
||||
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1);
|
||||
/* No verify callback: verification must fail on CA:FALSE issuer. */
|
||||
ExpectIntNE(X509_verify_cert(ctx), 1);
|
||||
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA);
|
||||
|
||||
X509_free(cert);
|
||||
X509_STORE_free(str);
|
||||
@@ -1793,4 +1843,3 @@ int test_X509_STORE_No_SSL_CTX(void)
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ int test_wolfSSL_X509_STORE_CTX(void);
|
||||
int test_wolfSSL_X509_STORE_CTX_ex(void);
|
||||
int test_X509_STORE_untrusted(void);
|
||||
int test_X509_STORE_InvalidCa(void);
|
||||
int test_X509_STORE_InvalidCa_NoCallback(void);
|
||||
int test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup(void);
|
||||
int test_wolfSSL_X509_STORE_CTX_get_issuer(void);
|
||||
int test_wolfSSL_X509_STORE_set_flags(void);
|
||||
@@ -51,6 +52,7 @@ int test_X509_STORE_No_SSL_CTX(void);
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX_ex), \
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_untrusted), \
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_InvalidCa), \
|
||||
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", \
|
||||
|
||||
Reference in New Issue
Block a user