Skip to content

Commit fa9f24f

Browse files
authored
Merge pull request #10223 from rlm2002/zd21611
CN constraints fix
2 parents d577ea3 + 797ba3f commit fa9f24f

3 files changed

Lines changed: 132 additions & 2 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);
@@ -55,6 +56,7 @@ int test_wolfSSL_CertManagerRejectMD5Cert(void);
5556
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint3), \
5657
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint4), \
5758
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint5), \
59+
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerNameConstraint_DNS_CN), \
5860
TEST_DECL_GROUP("certman", test_wolfSSL_CertManagerCRL), \
5961
TEST_DECL_GROUP("certman", test_wolfSSL_CRL_reason_extensions_cleanup), \
6062
TEST_DECL_GROUP("certman", test_wolfSSL_CRL_static_revoked_list), \

wolfcrypt/src/asn.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17717,9 +17717,16 @@ static int ConfirmNameConstraints(Signer* signer, DecodedCert* cert)
1771717717
XMEMSET(&subjectDnsName, 0, sizeof(DNS_entry));
1771817718
switch (nameType) {
1771917719
case ASN_DNS_TYPE:
17720-
/* Should it also consider CN in subject? It could use
17721-
* subjectDnsName too */
1772217720
name = cert->altNames;
17721+
17722+
/* When no SAN is present, apply DNS name constraints to the
17723+
* Subject CN. */
17724+
if (cert->subjectCN != NULL && cert->altNames == NULL) {
17725+
subjectDnsName.next = NULL;
17726+
subjectDnsName.type = ASN_DNS_TYPE;
17727+
subjectDnsName.len = cert->subjectCNLen;
17728+
subjectDnsName.name = cert->subjectCN;
17729+
}
1772317730
break;
1772417731
case ASN_IP_TYPE:
1772517732
/* IP addresses are stored in altNames with type ASN_IP_TYPE */

0 commit comments

Comments
 (0)