Skip to content

Commit 7336ed7

Browse files
committed
Fixes ZD 19760
Before this fix, the certificates were not getting into the certificate manager. This makes sure they are going in.
1 parent 044a5f8 commit 7336ed7

5 files changed

Lines changed: 191 additions & 51 deletions

File tree

src/ssl_api_cert.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,14 @@ void wolfSSL_CTX_set_cert_store(WOLFSSL_CTX* ctx, WOLFSSL_X509_STORE* str)
15361536
ctx->x509_store_pt = str;
15371537
/* Context has ownership and free it with context free. */
15381538
ctx->cm->x509_store_p = ctx->x509_store_pt;
1539+
1540+
#ifdef OPENSSL_EXTRA
1541+
/* Non-self-signed certs (intermediates) added via
1542+
* X509_STORE_add_cert only go into store->certs, not the
1543+
* CertManager. Push them into the CM now so that all
1544+
* verification paths can find them. */
1545+
X509StorePushCertsToCM(str);
1546+
#endif
15391547
}
15401548
}
15411549

src/x509_str.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,6 +1598,69 @@ static int X509StoreAddCa(WOLFSSL_X509_STORE* store,
15981598
return result;
15991599
}
16001600

1601+
/* Push certificates from the store's X509 stacks (certs and trusted) into the
1602+
* CertManager, then free and NULL the stacks to signal that this store is now
1603+
* owned by an SSL_CTX.
1604+
*
1605+
* This is needed when an X509_STORE is attached to an SSL_CTX via
1606+
* SSL_CTX_set_cert_store: self-signed CAs are already in the CM (added by
1607+
* X509StoreAddCa during X509_STORE_add_cert), but non-self-signed intermediates
1608+
* are only in store->certs and must be explicitly added to the CM so that all
1609+
* verification paths (including CertManagerVerify) can find them. */
1610+
WOLFSSL_LOCAL int X509StorePushCertsToCM(WOLFSSL_X509_STORE* store)
1611+
{
1612+
int i;
1613+
int num;
1614+
int ret;
1615+
int anyFail = 0;
1616+
WOLFSSL_X509* x509;
1617+
1618+
WOLFSSL_ENTER("X509StorePushCertsToCM");
1619+
1620+
if (store == NULL || store->cm == NULL)
1621+
return WOLFSSL_SUCCESS;
1622+
1623+
/* Push non-self-signed intermediates from store->certs into the CM. */
1624+
if (store->certs != NULL) {
1625+
num = wolfSSL_sk_X509_num(store->certs);
1626+
for (i = 0; i < num; i++) {
1627+
x509 = wolfSSL_sk_X509_value(store->certs, i);
1628+
if (x509 != NULL) {
1629+
ret = X509StoreAddCa(store, x509, WOLFSSL_USER_CA);
1630+
if (ret != WOLFSSL_SUCCESS) {
1631+
WOLFSSL_MSG("X509StorePushCertsToCM: failed to add cert");
1632+
anyFail = 1;
1633+
}
1634+
}
1635+
}
1636+
/* Free and NULL to mark store as CTX-owned. Future add_cert calls
1637+
* will go directly to the CertManager. */
1638+
wolfSSL_sk_X509_pop_free(store->certs, NULL);
1639+
store->certs = NULL;
1640+
}
1641+
1642+
/* Push trusted certs too. Self-signed CAs are typically already in the CM
1643+
* (added during X509_STORE_add_cert), but AddCA handles duplicates. */
1644+
if (store->trusted != NULL) {
1645+
num = wolfSSL_sk_X509_num(store->trusted);
1646+
for (i = 0; i < num; i++) {
1647+
x509 = wolfSSL_sk_X509_value(store->trusted, i);
1648+
if (x509 != NULL) {
1649+
ret = X509StoreAddCa(store, x509, WOLFSSL_USER_CA);
1650+
if (ret != WOLFSSL_SUCCESS) {
1651+
WOLFSSL_MSG("X509StorePushCertsToCM: failed to add "
1652+
"trusted cert");
1653+
anyFail = 1;
1654+
}
1655+
}
1656+
}
1657+
wolfSSL_sk_X509_pop_free(store->trusted, NULL);
1658+
store->trusted = NULL;
1659+
}
1660+
1661+
return anyFail ? WOLFSSL_FATAL_ERROR : WOLFSSL_SUCCESS;
1662+
}
1663+
16011664
int wolfSSL_X509_STORE_add_cert(WOLFSSL_X509_STORE* store, WOLFSSL_X509* x509)
16021665
{
16031666
int result = WC_NO_ERR_TRACE(WOLFSSL_FATAL_ERROR);

tests/api/test_ossl_x509_str.c

Lines changed: 116 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,56 +1074,6 @@ int test_X509_STORE_InvalidCa(void)
10741074
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1);
10751075
ExpectIntEQ(X509_verify_cert(ctx), 1);
10761076
ExpectIntEQ(last_errcode, X509_V_ERR_INVALID_CA);
1077-
/* Defense in depth: ctx->error must not be clobbered back to X509_V_OK
1078-
* by the later successful verification of the intermediate against the
1079-
* trusted root. The worst-seen error must persist. */
1080-
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA);
1081-
1082-
X509_free(cert);
1083-
X509_STORE_free(str);
1084-
X509_STORE_CTX_free(ctx);
1085-
sk_X509_pop_free(untrusted, NULL);
1086-
#endif
1087-
return EXPECT_RESULT();
1088-
}
1089-
1090-
int test_X509_STORE_InvalidCa_NoCallback(void)
1091-
{
1092-
EXPECT_DECLS;
1093-
#if defined(OPENSSL_ALL) && !defined(NO_RSA) && !defined(NO_FILESYSTEM)
1094-
const char* filename = "./certs/intermediate/ca_false_intermediate/"
1095-
"test_int_not_cacert.pem";
1096-
const char* srvfile = "./certs/intermediate/ca_false_intermediate/"
1097-
"test_sign_bynoca_srv.pem";
1098-
X509_STORE_CTX* ctx = NULL;
1099-
X509_STORE* str = NULL;
1100-
XFILE fp = XBADFILE;
1101-
X509* cert = NULL;
1102-
STACK_OF(X509)* untrusted = NULL;
1103-
1104-
ExpectTrue((fp = XFOPEN(srvfile, "rb"))
1105-
!= XBADFILE);
1106-
ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 ));
1107-
if (fp != XBADFILE) {
1108-
XFCLOSE(fp);
1109-
fp = XBADFILE;
1110-
}
1111-
1112-
ExpectNotNull(str = X509_STORE_new());
1113-
ExpectNotNull(ctx = X509_STORE_CTX_new());
1114-
ExpectNotNull(untrusted = sk_X509_new_null());
1115-
1116-
/* Create cert chain stack with an intermediate that is CA:FALSE. */
1117-
ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(filename,
1118-
untrusted), TEST_SUCCESS);
1119-
1120-
ExpectIntEQ(X509_STORE_load_locations(str,
1121-
"./certs/intermediate/ca_false_intermediate/test_ca.pem",
1122-
NULL), 1);
1123-
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1);
1124-
/* No verify callback: verification must fail on CA:FALSE issuer. */
1125-
ExpectIntNE(X509_verify_cert(ctx), 1);
1126-
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), X509_V_ERR_INVALID_CA);
11271077

11281078
X509_free(cert);
11291079
X509_STORE_free(str);
@@ -1843,3 +1793,119 @@ int test_X509_STORE_No_SSL_CTX(void)
18431793
#endif
18441794
return EXPECT_RESULT();
18451795
}
1796+
1797+
/* Test that SSL_CTX_set_cert_store propagates certificates (including
1798+
* non-self-signed intermediates) into the CertManager, and that certs
1799+
* added to the store after set_cert_store also reach the CertManager.
1800+
* Regression test for ZD 19760 / GitHub PR #8708.
1801+
*/
1802+
int test_wolfSSL_CTX_set_cert_store(void)
1803+
{
1804+
EXPECT_DECLS;
1805+
#if defined(OPENSSL_EXTRA) && !defined(NO_RSA) && !defined(NO_FILESYSTEM) && \
1806+
!defined(NO_WOLFSSL_CLIENT)
1807+
SSL_CTX* ctx = NULL;
1808+
X509_STORE* store = NULL;
1809+
X509* rootCa = NULL;
1810+
X509* intCa = NULL;
1811+
X509* int2Ca = NULL;
1812+
X509_STORE_CTX* storeCtx = NULL;
1813+
X509* svrCert = NULL;
1814+
1815+
const char caCert[] = "./certs/ca-cert.pem";
1816+
const char intCaCert[] = "./certs/intermediate/ca-int-cert.pem";
1817+
const char int2CaCert[] = "./certs/intermediate/ca-int2-cert.pem";
1818+
const char svrIntCert[] = "./certs/intermediate/server-int-cert.pem";
1819+
1820+
/* --- Part 1: Add certs to store BEFORE set_cert_store ---
1821+
* Non-self-signed intermediates should be pushed into the CertManager
1822+
* when set_cert_store is called. */
1823+
ExpectNotNull(store = X509_STORE_new());
1824+
ExpectNotNull(rootCa = wolfSSL_X509_load_certificate_file(caCert,
1825+
SSL_FILETYPE_PEM));
1826+
ExpectNotNull(intCa = wolfSSL_X509_load_certificate_file(intCaCert,
1827+
SSL_FILETYPE_PEM));
1828+
ExpectNotNull(int2Ca = wolfSSL_X509_load_certificate_file(int2CaCert,
1829+
SSL_FILETYPE_PEM));
1830+
1831+
ExpectIntEQ(X509_STORE_add_cert(store, rootCa), SSL_SUCCESS);
1832+
ExpectIntEQ(X509_STORE_add_cert(store, intCa), SSL_SUCCESS);
1833+
ExpectIntEQ(X509_STORE_add_cert(store, int2Ca), SSL_SUCCESS);
1834+
1835+
ExpectNotNull(ctx = SSL_CTX_new(TLS_client_method()));
1836+
1837+
/* This should push intermediates from store->certs into the CM */
1838+
SSL_CTX_set_cert_store(ctx, store);
1839+
1840+
/* After set_cert_store, store->certs and store->trusted should be NULLed
1841+
* to signal CTX ownership */
1842+
if (EXPECT_SUCCESS()) {
1843+
ExpectNull(store->certs);
1844+
ExpectNull(store->trusted);
1845+
}
1846+
1847+
/* Verify using CertManagerVerify - this only checks the CM, not the
1848+
* store's certs stack, so it proves the intermediates were pushed */
1849+
ExpectIntEQ(wolfSSL_CertManagerVerify(wolfSSL_CTX_GetCertManager(ctx),
1850+
svrIntCert, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
1851+
1852+
/* Also verify using X509_verify_cert for completeness */
1853+
ExpectNotNull(svrCert = wolfSSL_X509_load_certificate_file(svrIntCert,
1854+
SSL_FILETYPE_PEM));
1855+
ExpectNotNull(storeCtx = X509_STORE_CTX_new());
1856+
if (EXPECT_SUCCESS()) {
1857+
ExpectIntEQ(X509_STORE_CTX_init(storeCtx,
1858+
SSL_CTX_get_cert_store(ctx), svrCert, NULL), SSL_SUCCESS);
1859+
ExpectIntEQ(X509_verify_cert(storeCtx), SSL_SUCCESS);
1860+
}
1861+
1862+
X509_STORE_CTX_free(storeCtx);
1863+
storeCtx = NULL;
1864+
X509_free(svrCert);
1865+
svrCert = NULL;
1866+
SSL_CTX_free(ctx);
1867+
ctx = NULL;
1868+
/* store is freed by SSL_CTX_free */
1869+
store = NULL;
1870+
1871+
X509_free(rootCa);
1872+
rootCa = NULL;
1873+
X509_free(intCa);
1874+
intCa = NULL;
1875+
X509_free(int2Ca);
1876+
int2Ca = NULL;
1877+
1878+
/* --- Part 2: Add certs to store AFTER set_cert_store ---
1879+
* When store->certs is NULL (CTX-owned), X509_STORE_add_cert should
1880+
* route non-self-signed certs directly to the CertManager. */
1881+
ExpectNotNull(store = X509_STORE_new());
1882+
ExpectNotNull(ctx = SSL_CTX_new(TLS_client_method()));
1883+
1884+
/* Attach empty store first */
1885+
SSL_CTX_set_cert_store(ctx, store);
1886+
1887+
/* Now add certs after ownership transfer */
1888+
ExpectNotNull(rootCa = wolfSSL_X509_load_certificate_file(caCert,
1889+
SSL_FILETYPE_PEM));
1890+
ExpectNotNull(intCa = wolfSSL_X509_load_certificate_file(intCaCert,
1891+
SSL_FILETYPE_PEM));
1892+
ExpectNotNull(int2Ca = wolfSSL_X509_load_certificate_file(int2CaCert,
1893+
SSL_FILETYPE_PEM));
1894+
1895+
ExpectIntEQ(X509_STORE_add_cert(store, rootCa), SSL_SUCCESS);
1896+
ExpectIntEQ(X509_STORE_add_cert(store, intCa), SSL_SUCCESS);
1897+
ExpectIntEQ(X509_STORE_add_cert(store, int2Ca), SSL_SUCCESS);
1898+
1899+
/* Verify that certs added after set_cert_store are in the CM */
1900+
ExpectIntEQ(wolfSSL_CertManagerVerify(wolfSSL_CTX_GetCertManager(ctx),
1901+
svrIntCert, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS);
1902+
1903+
SSL_CTX_free(ctx);
1904+
/* store freed by SSL_CTX_free */
1905+
X509_free(rootCa);
1906+
X509_free(intCa);
1907+
X509_free(int2Ca);
1908+
#endif
1909+
return EXPECT_RESULT();
1910+
}
1911+

tests/api/test_ossl_x509_str.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ int test_wolfSSL_X509_STORE_get1_certs(void);
4242
int test_wolfSSL_X509_STORE_set_get_crl(void);
4343
int test_wolfSSL_X509_CA_num(void);
4444
int test_X509_STORE_No_SSL_CTX(void);
45+
int test_wolfSSL_CTX_set_cert_store(void);
4546

4647
#define TEST_OSSL_X509_STORE_DECLS \
4748
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);
6566
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_get1_certs), \
6667
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_STORE_set_get_crl), \
6768
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_X509_CA_num), \
68-
TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_No_SSL_CTX)
69+
TEST_DECL_GROUP("ossl_x509_store", test_X509_STORE_No_SSL_CTX), \
70+
TEST_DECL_GROUP("ossl_x509_store", test_wolfSSL_CTX_set_cert_store)
6971

7072
#endif /* WOLFCRYPT_TEST_OSSL_X509_STR_H */

wolfssl/internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2730,6 +2730,7 @@ WOLFSSL_LOCAL void CleanupStoreCtxCallback(WOLFSSL_X509_STORE_CTX* store,
27302730
#endif /* !defined(NO_WOLFSSL_CLIENT) || !defined(WOLFSSL_NO_CLIENT_AUTH) */
27312731
WOLFSSL_LOCAL int X509StoreLoadCertBuffer(WOLFSSL_X509_STORE *str,
27322732
byte *buf, word32 bufLen, int type);
2733+
WOLFSSL_LOCAL int X509StorePushCertsToCM(WOLFSSL_X509_STORE* store);
27332734
#endif /* !defined NO_CERTS */
27342735

27352736
/* wolfSSL Sock Addr */

0 commit comments

Comments
 (0)