@@ -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+
0 commit comments