@@ -1584,6 +1584,127 @@ int test_wolfSSL_CertManagerNameConstraint5(void)
15841584 return EXPECT_RESULT ();
15851585}
15861586
1587+ int test_wolfSSL_CertManagerNameConstraint_DNS_CN (void )
1588+ {
1589+ EXPECT_DECLS ;
1590+ #if !defined(NO_FILESYSTEM ) && !defined(NO_CERTS ) && \
1591+ !defined(NO_WOLFSSL_CM_VERIFY ) && !defined(NO_RSA ) && \
1592+ defined(OPENSSL_EXTRA ) && defined(WOLFSSL_CERT_GEN ) && \
1593+ defined(WOLFSSL_CERT_EXT ) && defined(WOLFSSL_ALT_NAMES ) && \
1594+ !defined(NO_SHA256 )
1595+ /* Test that DNS name constraints are enforced against the Subject CN
1596+ * when no SAN extension is present. The CA cert (cert-ext-ncdns.der)
1597+ * permits only DNS:wolfssl.com and DNS:example.com. A leaf cert with
1598+ * CN=evil.attacker.com and no SAN should be REJECTED. */
1599+ WOLFSSL_CERT_MANAGER * cm = NULL ;
1600+ WOLFSSL_EVP_PKEY * priv = NULL ;
1601+ WOLFSSL_X509_NAME * name = NULL ;
1602+ const char * ca_cert = "./certs/test/cert-ext-ncdns.der" ;
1603+ const char * server_cert = "./certs/test/server-goodcn.pem" ;
1604+
1605+ byte * der = NULL ;
1606+ int derSz ;
1607+ byte * pt ;
1608+ WOLFSSL_X509 * x509 = NULL ;
1609+ WOLFSSL_X509 * ca = NULL ;
1610+
1611+ pt = (byte * )server_key_der_2048 ;
1612+ ExpectNotNull (priv = wolfSSL_d2i_PrivateKey (EVP_PKEY_RSA , NULL ,
1613+ (const unsigned char * * )& pt , sizeof_server_key_der_2048 ));
1614+
1615+ ExpectNotNull (cm = wolfSSL_CertManagerNew ());
1616+ ExpectNotNull (ca = wolfSSL_X509_load_certificate_file (ca_cert ,
1617+ WOLFSSL_FILETYPE_ASN1 ));
1618+ ExpectNotNull ((der = (byte * )wolfSSL_X509_get_der (ca , & derSz )));
1619+ ExpectIntEQ (wolfSSL_CertManagerLoadCABuffer (cm , der , derSz ,
1620+ WOLFSSL_FILETYPE_ASN1 ), WOLFSSL_SUCCESS );
1621+
1622+ /* Sanity check: cert with SAN=evil.attacker.com is correctly rejected */
1623+ ExpectNotNull (x509 = wolfSSL_X509_load_certificate_file (server_cert ,
1624+ WOLFSSL_FILETYPE_PEM ));
1625+ ExpectNotNull (name = wolfSSL_X509_get_subject_name (ca ));
1626+ ExpectIntEQ (wolfSSL_X509_set_issuer_name (x509 , name ), WOLFSSL_SUCCESS );
1627+ name = NULL ;
1628+
1629+ ExpectNotNull (name = X509_NAME_new ());
1630+ ExpectIntEQ (X509_NAME_add_entry_by_txt (name , "countryName" , MBSTRING_UTF8 ,
1631+ (byte * )"US" , 2 , -1 , 0 ), SSL_SUCCESS );
1632+ ExpectIntEQ (X509_NAME_add_entry_by_txt (name , "commonName" , MBSTRING_UTF8 ,
1633+ (byte * )"evil.attacker.com" , 17 , -1 , 0 ),
1634+ SSL_SUCCESS );
1635+ ExpectIntEQ (wolfSSL_X509_set_subject_name (x509 , name ), WOLFSSL_SUCCESS );
1636+ X509_NAME_free (name );
1637+ name = NULL ;
1638+
1639+ ExpectIntEQ (wolfSSL_X509_add_altname (x509 , "evil.attacker.com" ,
1640+ ASN_DNS_TYPE ), WOLFSSL_SUCCESS );
1641+ ExpectIntGT (wolfSSL_X509_sign (x509 , priv , EVP_sha256 ()), 0 );
1642+ ExpectNotNull ((der = (byte * )wolfSSL_X509_get_der (x509 , & derSz )));
1643+ ExpectIntEQ (wolfSSL_CertManagerVerifyBuffer (cm , der , derSz ,
1644+ WOLFSSL_FILETYPE_ASN1 ), WC_NO_ERR_TRACE (ASN_NAME_INVALID_E ));
1645+ wolfSSL_X509_free (x509 );
1646+ x509 = NULL ;
1647+
1648+ /* NOW the actual vulnerability test: cert with CN=evil.attacker.com
1649+ * but NO SAN. The DNS name constraint should still reject this, since
1650+ * wolfSSL's hostname verification falls back to CN when no SAN exists. */
1651+ ExpectNotNull (x509 = wolfSSL_X509_load_certificate_file (server_cert ,
1652+ WOLFSSL_FILETYPE_PEM ));
1653+ ExpectNotNull (name = wolfSSL_X509_get_subject_name (ca ));
1654+ ExpectIntEQ (wolfSSL_X509_set_issuer_name (x509 , name ), WOLFSSL_SUCCESS );
1655+ name = NULL ;
1656+
1657+ ExpectNotNull (name = X509_NAME_new ());
1658+ ExpectIntEQ (X509_NAME_add_entry_by_txt (name , "countryName" , MBSTRING_UTF8 ,
1659+ (byte * )"US" , 2 , -1 , 0 ), SSL_SUCCESS );
1660+ ExpectIntEQ (X509_NAME_add_entry_by_txt (name , "commonName" , MBSTRING_UTF8 ,
1661+ (byte * )"evil.attacker.com" , 17 , -1 , 0 ),
1662+ SSL_SUCCESS );
1663+ ExpectIntEQ (wolfSSL_X509_set_subject_name (x509 , name ), WOLFSSL_SUCCESS );
1664+ X509_NAME_free (name );
1665+ name = NULL ;
1666+
1667+ /* Do NOT add any SAN this is the bypass vector */
1668+ ExpectIntGT (wolfSSL_X509_sign (x509 , priv , EVP_sha256 ()), 0 );
1669+ ExpectNotNull ((der = (byte * )wolfSSL_X509_get_der (x509 , & derSz )));
1670+ /* Should be ASN_NAME_INVALID_E because CN violates the constraint */
1671+ ExpectIntEQ (wolfSSL_CertManagerVerifyBuffer (cm , der , derSz ,
1672+ WOLFSSL_FILETYPE_ASN1 ), WC_NO_ERR_TRACE (ASN_NAME_INVALID_E ));
1673+ wolfSSL_X509_free (x509 );
1674+ x509 = NULL ;
1675+
1676+ /* Positive test: CN matches a permitted name (wolfssl.com) and no SAN is
1677+ * present. The CN fallback should accept this cert. */
1678+ ExpectNotNull (x509 = wolfSSL_X509_load_certificate_file (server_cert ,
1679+ WOLFSSL_FILETYPE_PEM ));
1680+ ExpectNotNull (name = wolfSSL_X509_get_subject_name (ca ));
1681+ ExpectIntEQ (wolfSSL_X509_set_issuer_name (x509 , name ), WOLFSSL_SUCCESS );
1682+ name = NULL ;
1683+
1684+ ExpectNotNull (name = X509_NAME_new ());
1685+ ExpectIntEQ (X509_NAME_add_entry_by_txt (name , "countryName" , MBSTRING_UTF8 ,
1686+ (byte * )"US" , 2 , -1 , 0 ), SSL_SUCCESS );
1687+ ExpectIntEQ (X509_NAME_add_entry_by_txt (name , "commonName" , MBSTRING_UTF8 ,
1688+ (byte * )"wolfssl.com" , 11 , -1 , 0 ),
1689+ SSL_SUCCESS );
1690+ ExpectIntEQ (wolfSSL_X509_set_subject_name (x509 , name ), WOLFSSL_SUCCESS );
1691+ X509_NAME_free (name );
1692+ name = NULL ;
1693+
1694+ /* No SAN added; CN=wolfssl.com matches the permitted DNS constraint. */
1695+ ExpectIntGT (wolfSSL_X509_sign (x509 , priv , EVP_sha256 ()), 0 );
1696+ ExpectNotNull ((der = (byte * )wolfSSL_X509_get_der (x509 , & derSz )));
1697+ ExpectIntEQ (wolfSSL_CertManagerVerifyBuffer (cm , der , derSz ,
1698+ WOLFSSL_FILETYPE_ASN1 ), WOLFSSL_SUCCESS );
1699+
1700+ wolfSSL_CertManagerFree (cm );
1701+ wolfSSL_X509_free (x509 );
1702+ wolfSSL_X509_free (ca );
1703+ wolfSSL_EVP_PKEY_free (priv );
1704+ #endif
1705+ return EXPECT_RESULT ();
1706+ }
1707+
15871708int test_wolfSSL_CertManagerCRL (void )
15881709{
15891710 EXPECT_DECLS ;
0 commit comments