From a39e8ae976e64ced8753ba887ba0e9652050525a Mon Sep 17 00:00:00 2001 From: Marco Oliverio Date: Fri, 12 Jun 2026 08:16:44 +0200 Subject: [PATCH] Route DNS name-constraint checks through one helper Add wolfssl_local_MatchDnsNameConstraint() dispatching wildcard names to the subtree matcher and literal names to plain base-name matching, and use it for the ASN_DNS_TYPE branches of PermittedListOk() and IsInExcludedList(). This also drops the outer name->len >= base len byte-length guard for literal DNS names. That guard ran before MatchBaseName() could strip the absolute-FQDN trailing dot, so a constraint base like DNS:example.com. never matched the SAN example.com it denotes. --- tests/api.c | 17 +++++++++++++++++ wolfcrypt/src/asn.c | 37 +++++++++++++++++++++++++------------ wolfssl/wolfcrypt/asn.h | 3 +++ 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/tests/api.c b/tests/api.c index d0a820219d..197946eb2a 100644 --- a/tests/api.c +++ b/tests/api.c @@ -23114,6 +23114,23 @@ static int test_NameConstraints_DnsUriWildcard(void) ExpectIntGT((int)sanSz, 0); ExpectIntEQ(verify_with_otherName_chain(nc, ncSz, 1, san, sanSz), WC_NO_ERR_TRACE(ASN_NAME_INVALID_E)); + + /* (12) One trailing dot on the constraint base is the absolute-FQDN + * marker: DNS:example.com. denotes the same subtree as + * DNS:example.com, so the permitted form accepts the bare SAN and + * the excluded form rejects it. */ + ncSz = build_simple_nameConstraints(nc, sizeof(nc), 0, DNS, + "example.com."); + sanSz = build_simple_san(san, sizeof(san), DNS, "example.com"); + ExpectIntGT((int)ncSz, 0); + ExpectIntGT((int)sanSz, 0); + ExpectIntEQ(verify_with_otherName_chain(nc, ncSz, 1, san, sanSz), 0); + + ncSz = build_simple_nameConstraints(nc, sizeof(nc), 1, DNS, + "example.com."); + ExpectIntGT((int)ncSz, 0); + ExpectIntEQ(verify_with_otherName_chain(nc, ncSz, 1, san, sanSz), + WC_NO_ERR_TRACE(ASN_NAME_INVALID_E)); #endif return EXPECT_RESULT(); } diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index 2aa867a729..dadb48d4a8 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -18551,6 +18551,23 @@ static int DnsNameHasWildcard(const char* name, int nameSz) return 0; } +/* Match a DNS name against a DNS name-constraint base. A wildcard name + * denotes a set of names: permitted subtrees require containment, excluded + * subtrees intersection (selected by `permitted`). Literal names use plain + * base-name matching, which normalizes the absolute-FQDN trailing dot + * before its own length check. + * Returns 1 on match, 0 otherwise. */ +int wolfssl_local_MatchDnsNameConstraint(const char* name, int nameSz, + const char* base, int baseSz, int permitted) +{ + if (DnsNameHasWildcard(name, nameSz)) { + return wolfssl_local_MatchDnsConstraintWildcard(name, nameSz, + base, baseSz, permitted); + } + return wolfssl_local_MatchBaseName(ASN_DNS_TYPE, name, nameSz, base, + baseSz); +} + /* Search through the list to find if the name is permitted. * name The DNS name to search for * dnsList The list to search through @@ -18601,12 +18618,10 @@ static int PermittedListOk(DNS_entry* name, Base_entry* dnsList, byte nameType) break; } } - else if (nameType == ASN_DNS_TYPE && - DnsNameHasWildcard(name->name, name->len)) { - /* Wildcard DNS SAN: a '*' can expand to a longer label, so the - * byte-length guard used for literal names below is invalid. - * Permit only if every expansion stays inside the subtree. */ - if (wolfssl_local_MatchDnsConstraintWildcard(name->name, + else if (nameType == ASN_DNS_TYPE) { + /* Permit only if every expansion of a wildcard stays inside + * the subtree. */ + if (wolfssl_local_MatchDnsNameConstraint(name->name, name->len, current->name, current->nameSz, 1)) { match = 1; break; @@ -18675,12 +18690,10 @@ static int IsInExcludedList(DNS_entry* name, Base_entry* dnsList, byte nameType) break; } } - else if (nameType == ASN_DNS_TYPE && - DnsNameHasWildcard(name->name, name->len)) { - /* Wildcard DNS SAN: a '*' can expand to a longer label, so the - * byte-length guard used for literal names below is invalid. - * Exclude if any expansion can fall inside the subtree. */ - if (wolfssl_local_MatchDnsConstraintWildcard(name->name, + else if (nameType == ASN_DNS_TYPE) { + /* Exclude if any expansion of a wildcard can fall inside the + * subtree. */ + if (wolfssl_local_MatchDnsNameConstraint(name->name, name->len, current->name, current->nameSz, 0)) { ret = 1; break; diff --git a/wolfssl/wolfcrypt/asn.h b/wolfssl/wolfcrypt/asn.h index 0090b8ab46..e1f13a292b 100644 --- a/wolfssl/wolfcrypt/asn.h +++ b/wolfssl/wolfcrypt/asn.h @@ -3227,6 +3227,9 @@ WOLFSSL_TEST_VIS int wolfssl_local_MatchDnsConstraintWildcard( const char* name, int nameSz, const char* base, int baseSz, int permitted); +WOLFSSL_LOCAL int wolfssl_local_MatchDnsNameConstraint(const char* name, + int nameSz, const char* base, + int baseSz, int permitted); #endif #if ((defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)) \