Skip to content

Commit 797ba3f

Browse files
committed
test DNS name constraints on CA are applied against Subject CN name when SAN name is unavailable
test correct CN with no SAN available is accepted
1 parent e7b7fdd commit 797ba3f

2 files changed

Lines changed: 123 additions & 0 deletions

File tree

tests/api/test_certman.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
15871708
int test_wolfSSL_CertManagerCRL(void)
15881709
{
15891710
EXPECT_DECLS;

tests/api/test_certman.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ int test_wolfSSL_CertManagerNameConstraint2(void);
3535
int test_wolfSSL_CertManagerNameConstraint3(void);
3636
int test_wolfSSL_CertManagerNameConstraint4(void);
3737
int test_wolfSSL_CertManagerNameConstraint5(void);
38+
int test_wolfSSL_CertManagerNameConstraint_DNS_CN(void);
3839
int test_wolfSSL_CertManagerCRL(void);
3940
int test_wolfSSL_CRL_reason_extensions_cleanup(void);
4041
int test_wolfSSL_CRL_static_revoked_list(void);
@@ -54,6 +55,7 @@ int test_various_pathlen_chains(void);
5455
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint3), \
5556
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint4), \
5657
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint5), \
58+
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint_DNS_CN), \
5759
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerCRL), \
5860
TEST_DECL_GROUP("certman", test_wolfSSL_CRL_reason_extensions_cleanup), \
5961
TEST_DECL_GROUP("certman", test_wolfSSL_CRL_static_revoked_list), \

0 commit comments

Comments
 (0)