mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-07-05 14:00:48 +02:00
Fixes ZD 19760
Before this fix, the certificates were not getting into the certificate manager. This makes sure they are going in.
This commit is contained in:
@@ -1536,6 +1536,14 @@ void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str)
|
||||
ctx->x509_store_pt = str;
|
||||
/* Context has ownership and free it with context free. */
|
||||
ctx->cm->x509_store_p = ctx->x509_store_pt;
|
||||
|
||||
#ifdef OPENSSL_EXTRA
|
||||
/* Non-self-signed certs (intermediates) added via
|
||||
* X509_STORE_add_cert only go into store->certs, not the
|
||||
* CertManager. Push them into the CM now so that all
|
||||
* verification paths can find them. */
|
||||
X509StorePushCertsToCM(str);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1598,6 +1598,69 @@ static int X509StoreAddCa(WOLFSSL_X509_STORE* store,
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Push certificates from the store's X509 stacks (certs and trusted) into the
|
||||
* CertManager, then free and NULL the stacks to signal that this store is now
|
||||
* owned by an SSL_CTX.
|
||||
*
|
||||
* This is needed when an X509_STORE is attached to an SSL_CTX via
|
||||
* SSL_CTX_set_cert_store: self-signed CAs are already in the CM (added by
|
||||
* X509StoreAddCa during X509_STORE_add_cert), but non-self-signed intermediates
|
||||
* are only in store->certs and must be explicitly added to the CM so that all
|
||||
* verification paths (including CertManagerVerify) can find them. */
|
||||
WOLFSSL_LOCAL int X509StorePushCertsToCM(WOLFSSL_X509_STORE* store)
|
||||
{
|
||||
int i;
|
||||
int num;
|
||||
int ret;
|
||||
int anyFail = 0;
|
||||
WOLFSSL_X509* x509;
|
||||
|
||||
WOLFSSL_ENTER("X509StorePushCertsToCM");
|
||||
|
||||
if (store == NULL || store->cm == NULL)
|
||||
return WOLFSSL_SUCCESS;
|
||||
|
||||
/* Push non-self-signed intermediates from store->certs into the CM. */
|
||||
if (store->certs != NULL) {
|
||||
num = wolfSSL_sk_X509_num(store->certs);
|
||||
for (i = 0; i < num; i++) {
|
||||
x509 = wolfSSL_sk_X509_value(store->certs, i);
|
||||
if (x509 != NULL) {
|
||||
ret = X509StoreAddCa(store, x509, WOLFSSL_USER_CA);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
WOLFSSL_MSG("X509StorePushCertsToCM: failed to add cert");
|
||||
anyFail = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Free and NULL to mark store as CTX-owned. Future add_cert calls
|
||||
* will go directly to the CertManager. */
|
||||
wolfSSL_sk_X509_pop_free(store->certs, NULL);
|
||||
store->certs = NULL;
|
||||
}
|
||||
|
||||
/* Push trusted certs too. Self-signed CAs are typically already in the CM
|
||||
* (added during X509_STORE_add_cert), but AddCA handles duplicates. */
|
||||
if (store->trusted != NULL) {
|
||||
num = wolfSSL_sk_X509_num(store->trusted);
|
||||
for (i = 0; i < num; i++) {
|
||||
x509 = wolfSSL_sk_X509_value(store->trusted, i);
|
||||
if (x509 != NULL) {
|
||||
ret = X509StoreAddCa(store, x509, WOLFSSL_USER_CA);
|
||||
if (ret != WOLFSSL_SUCCESS) {
|
||||
WOLFSSL_MSG("X509StorePushCertsToCM: failed to add "
|
||||
"trusted cert");
|
||||
anyFail = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
wolfSSL_sk_X509_pop_free(store->trusted, NULL);
|
||||
store->trusted = NULL;
|
||||
}
|
||||
|
||||
return anyFail ? WOLFSSL_FATAL_ERROR : WOLFSSL_SUCCESS;
|
||||
}
|
||||
|
||||
int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509)
|
||||
{
|
||||
int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR);
|
||||
|
||||
+116
-50
@@ -1074,56 +1074,6 @@ 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);
|
||||
@@ -1843,3 +1793,119 @@ int test_X509_STORE_No_SSL_CTX(void)
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
/* Test that SSL_CTX_set_cert_store propagates certificates (including
|
||||
* non-self-signed intermediates) into the CertManager, and that certs
|
||||
* added to the store after set_cert_store also reach the CertManager.
|
||||
* Regression test for ZD 19760 / GitHub PR #8708.
|
||||
*/
|
||||
int test_wolfSSL_CTX_set_cert_store(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
|
||||
!defined(NO_WOLFSSL_CLIENT)
|
||||
SSL_CTX* ctx = NULL;
|
||||
X509_STORE* store = NULL;
|
||||
X509* rootCa = NULL;
|
||||
X509* intCa = NULL;
|
||||
X509* int2Ca = NULL;
|
||||
X509_STORE_CTX* storeCtx = NULL;
|
||||
X509* svrCert = NULL;
|
||||
|
||||
const char caCert[] = "./certs/ca-cert.pem";
|
||||
const char intCaCert[] = "./certs/intermediate/ca-int-cert.pem";
|
||||
const char int2CaCert[] = "./certs/intermediate/ca-int2-cert.pem";
|
||||
const char svrIntCert[] = "./certs/intermediate/server-int-cert.pem";
|
||||
|
||||
/* --- Part 1: Add certs to store BEFORE set_cert_store ---
|
||||
* Non-self-signed intermediates should be pushed into the CertManager
|
||||
* when set_cert_store is called. */
|
||||
ExpectNotNull(store = X509_STORE_new());
|
||||
ExpectNotNull(rootCa = wolfSSL_X509_load_certificate_file(caCert,
|
||||
SSL_FILETYPE_PEM));
|
||||
ExpectNotNull(intCa = wolfSSL_X509_load_certificate_file(intCaCert,
|
||||
SSL_FILETYPE_PEM));
|
||||
ExpectNotNull(int2Ca = wolfSSL_X509_load_certificate_file(int2CaCert,
|
||||
SSL_FILETYPE_PEM));
|
||||
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, rootCa), SSL_SUCCESS);
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, intCa), SSL_SUCCESS);
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, int2Ca), SSL_SUCCESS);
|
||||
|
||||
ExpectNotNull(ctx = SSL_CTX_new(TLS_client_method()));
|
||||
|
||||
/* This should push intermediates from store->certs into the CM */
|
||||
SSL_CTX_set_cert_store(ctx, store);
|
||||
|
||||
/* After set_cert_store, store->certs and store->trusted should be NULLed
|
||||
* to signal CTX ownership */
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectNull(store->certs);
|
||||
ExpectNull(store->trusted);
|
||||
}
|
||||
|
||||
/* Verify using CertManagerVerify - this only checks the CM, not the
|
||||
* store's certs stack, so it proves the intermediates were pushed */
|
||||
ExpectIntEQ(wolfSSL_CertManagerVerify(wolfSSL_CTX_GetCertManager(ctx),
|
||||
svrIntCert, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
||||
|
||||
/* Also verify using X509_verify_cert for completeness */
|
||||
ExpectNotNull(svrCert = wolfSSL_X509_load_certificate_file(svrIntCert,
|
||||
SSL_FILETYPE_PEM));
|
||||
ExpectNotNull(storeCtx = X509_STORE_CTX_new());
|
||||
if (EXPECT_SUCCESS()) {
|
||||
ExpectIntEQ(X509_STORE_CTX_init(storeCtx,
|
||||
SSL_CTX_get_cert_store(ctx), svrCert, NULL), SSL_SUCCESS);
|
||||
ExpectIntEQ(X509_verify_cert(storeCtx), SSL_SUCCESS);
|
||||
}
|
||||
|
||||
X509_STORE_CTX_free(storeCtx);
|
||||
storeCtx = NULL;
|
||||
X509_free(svrCert);
|
||||
svrCert = NULL;
|
||||
SSL_CTX_free(ctx);
|
||||
ctx = NULL;
|
||||
/* store is freed by SSL_CTX_free */
|
||||
store = NULL;
|
||||
|
||||
X509_free(rootCa);
|
||||
rootCa = NULL;
|
||||
X509_free(intCa);
|
||||
intCa = NULL;
|
||||
X509_free(int2Ca);
|
||||
int2Ca = NULL;
|
||||
|
||||
/* --- Part 2: Add certs to store AFTER set_cert_store ---
|
||||
* When store->certs is NULL (CTX-owned), X509_STORE_add_cert should
|
||||
* route non-self-signed certs directly to the CertManager. */
|
||||
ExpectNotNull(store = X509_STORE_new());
|
||||
ExpectNotNull(ctx = SSL_CTX_new(TLS_client_method()));
|
||||
|
||||
/* Attach empty store first */
|
||||
SSL_CTX_set_cert_store(ctx, store);
|
||||
|
||||
/* Now add certs after ownership transfer */
|
||||
ExpectNotNull(rootCa = wolfSSL_X509_load_certificate_file(caCert,
|
||||
SSL_FILETYPE_PEM));
|
||||
ExpectNotNull(intCa = wolfSSL_X509_load_certificate_file(intCaCert,
|
||||
SSL_FILETYPE_PEM));
|
||||
ExpectNotNull(int2Ca = wolfSSL_X509_load_certificate_file(int2CaCert,
|
||||
SSL_FILETYPE_PEM));
|
||||
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, rootCa), SSL_SUCCESS);
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, intCa), SSL_SUCCESS);
|
||||
ExpectIntEQ(X509_STORE_add_cert(store, int2Ca), SSL_SUCCESS);
|
||||
|
||||
/* Verify that certs added after set_cert_store are in the CM */
|
||||
ExpectIntEQ(wolfSSL_CertManagerVerify(wolfSSL_CTX_GetCertManager(ctx),
|
||||
svrIntCert, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
|
||||
|
||||
SSL_CTX_free(ctx);
|
||||
/* store freed by SSL_CTX_free */
|
||||
X509_free(rootCa);
|
||||
X509_free(intCa);
|
||||
X509_free(int2Ca);
|
||||
#endif
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ int test_wolfSSL_X509_STORE_get1_certs(void);
|
||||
int test_wolfSSL_X509_STORE_set_get_crl(void);
|
||||
int test_wolfSSL_X509_CA_num(void);
|
||||
int test_X509_STORE_No_SSL_CTX(void);
|
||||
int test_wolfSSL_CTX_set_cert_store(void);
|
||||
|
||||
#define TEST_OSSL_X509_STORE_DECLS \
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_CTX_set_time), \
|
||||
@@ -65,6 +66,7 @@ int test_X509_STORE_No_SSL_CTX(void);
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_get1_certs), \
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_set_get_crl), \
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_CA_num), \
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_No_SSL_CTX)
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_No_SSL_CTX), \
|
||||
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_CTX_set_cert_store)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_OSSL_X509_STR_H */
|
||||
|
||||
@@ -2730,6 +2730,7 @@ WOLFSSL_LOCAL void CleanupStoreCtxCallback(WOLFSSL_X509_STORE_CTX* store,
|
||||
#endif /* !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) */
|
||||
WOLFSSL_LOCAL int X509StoreLoadCertBuffer(WOLFSSL_X509_STORE *str,
|
||||
byte *buf, word32 bufLen, int type);
|
||||
WOLFSSL_LOCAL int X509StorePushCertsToCM(WOLFSSL_X509_STORE* store);
|
||||
#endif /* !defined NO_CERTS */
|
||||
|
||||
/* wolfSSL Sock Addr */
|
||||
|
||||
Reference in New Issue
Block a user