Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/x509.c
Original file line number Diff line number Diff line change
Expand Up @@ -6070,7 +6070,8 @@ static int MatchIpName(const char* name, int nameSz, WOLFSSL_GENERAL_NAME* gn)
/* Helper to check if name string matches a single GENERAL_NAME constraint.
* permitted selects subtree semantics for wildcard DNS names: containment
* for permitted subtrees, intersection for excluded subtrees.
* Returns 1 if matches, 0 if not. */
* Returns 1 if matches, 0 if not, and a negative error if the name cannot be
* compared, which the caller must treat as failing the constraint. */
static int MatchNameConstraint(int type, const char* name, int nameSz,
WOLFSSL_GENERAL_NAME* gn, int permitted)
{
Expand All @@ -6093,6 +6094,11 @@ static int MatchNameConstraint(int type, const char* name, int nameSz,
}
baseStr = (const char*)wolfSSL_ASN1_STRING_get0_data(gn->d.ia5);
baseLen = wolfSSL_ASN1_STRING_length(gn->d.ia5);
if (type == WOLFSSL_GEN_DNS && baseLen == 0) {
/* RFC 5280 4.2.1.10: an empty dNSName base covers every DNS
* name. */
return 1;
}
if (baseStr == NULL || baseLen <= 0) {
return 0;
}
Expand Down Expand Up @@ -6194,7 +6200,8 @@ int wolfSSL_NAME_CONSTRAINTS_check_name(WOLFSSL_NAME_CONSTRAINTS* nc,
}
hasPermittedType = 1;

if (MatchNameConstraint(type, name, nameSz, gn, 1)) {
/* A name that cannot be compared is not shown to be permitted. */
if (MatchNameConstraint(type, name, nameSz, gn, 1) == 1) {
matchedPermitted = 1;
break;
}
Expand All @@ -6221,7 +6228,8 @@ int wolfSSL_NAME_CONSTRAINTS_check_name(WOLFSSL_NAME_CONSTRAINTS* nc,
continue;
}

if (MatchNameConstraint(type, name, nameSz, gn, 0)) {
/* A name that cannot be compared is not shown to be outside. */
if (MatchNameConstraint(type, name, nameSz, gn, 0) != 0) {
WOLFSSL_MSG("Name in excluded subtrees");
return 0;
}
Expand Down
56 changes: 47 additions & 9 deletions tests/api/test_asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
#include <wolfssl/wolfcrypt/asn_public.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/rsa.h>

/* A lone "." dNSName constraint base covers every DNS name, except with
* OPENSSL_COMPATIBLE_DEFAULTS where it matches no name. */
#ifdef OPENSSL_COMPATIBLE_DEFAULTS
#define NC_DNS_DOT_BASE_MATCH 0
#else
#define NC_DNS_DOT_BASE_MATCH 1
#endif
#ifdef HAVE_ED25519
#include <wolfssl/wolfcrypt/ed25519.h>
#endif
Expand Down Expand Up @@ -1054,12 +1062,24 @@ int test_wolfssl_local_MatchBaseName(void)
/* @ at end is invalid */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"user@", 5, ".domain.com", 11), 0);
/* double @ is invalid */
/* An '@' outside a quoted local-part cannot be compared */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"user@@domain.com", 16, ".domain.com", 11),
WC_NO_ERR_TRACE(ASN_PARSE_E));
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"user@domain@extra.com", 21, ".domain.com", 11),
WC_NO_ERR_TRACE(ASN_PARSE_E));
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"user@@domain.com", 16, ".domain.com", 11), 0);
/* multiple @ is invalid */
"user@domain@extra.com", 21, "extra.com", 9),
WC_NO_ERR_TRACE(ASN_PARSE_E));
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"user@domain@extra.com", 21, ".domain.com", 11), 0);
"x@evil.com@good.com", 19, "good.com", 8),
WC_NO_ERR_TRACE(ASN_PARSE_E));
/* RFC 5322 quoted local-part containing @ */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"\"x@y\"@evil.com", 14, "evil.com", 8), 1);
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"\"x@y\"@good.com", 14, "evil.com", 8), 0);
/* No @ in email name */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"userdomain.com", 14, ".domain.com", 11), 0);
Expand Down Expand Up @@ -1725,14 +1745,26 @@ int test_wolfssl_local_MatchBaseName(void)
/* Empty/zero size */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
"", 0, "domain.com", 10), 0);
/* RFC 5280 4.2.1.10: an empty dNSName base covers every DNS name. */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
"domain.com", 10, "", 0), 1);
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
"domain.com", 10, "", 0), 0);
"domain.com", 10, ".", 1), NC_DNS_DOT_BASE_MATCH);
ExpectIntEQ(wolfssl_local_MatchDnsConstraintWildcard(
"*.domain.com", 12, "", 0, 0), 1);
ExpectIntEQ(wolfssl_local_MatchDnsConstraintWildcard(
"*.domain.com", 12, ".", 1, 1), NC_DNS_DOT_BASE_MATCH);
/* An empty rfc822Name base names no host. */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
"user@domain.com", 15, "", 0), 0);
/* Invalid type */
ExpectIntEQ(wolfssl_local_MatchBaseName(0xFF,
"domain.com", 10, "domain.com", 10), 0);
/* Name starting with dot */
/* Name starting with dot, whatever the base */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
".", 1, ".", 1), 0);
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
".domain.com", 11, "", 0), 0);
/* Name shorter than base */
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
"a.com", 5, "domain.com", 10), 0);
Expand Down Expand Up @@ -1858,13 +1890,16 @@ int test_wolfssl_local_MatchDnsConstraintWildcard(void)
NULL, 3, 1), 0);
ExpectIntEQ(wolfssl_local_MatchDnsConstraintWildcard("*.com", 0,
"com", 3, 1), 0);
/* A zero-length base covers every DNS name (RFC 5280 4.2.1.10). */
ExpectIntEQ(wolfssl_local_MatchDnsConstraintWildcard("*.com", 5,
"com", 0, 1), 0);
"com", 0, 1), 1);
/* Name beginning with a dot is invalid. */
ExpectIntEQ(dnsWildPermitted(".x.com", "com"), 0);
ExpectIntEQ(dnsWildExcluded(".x.com", "com"), 0);
/* Base that is only dots collapses to nothing. */
ExpectIntEQ(dnsWildExcluded("*.example.com", "."), 0);
/* A lone dot is the empty base unless OpenSSL compatible. */
ExpectIntEQ(dnsWildExcluded("*.example.com", "."),
NC_DNS_DOT_BASE_MATCH);
/* A base of more than one dot has an empty label. */
ExpectIntEQ(dnsWildExcluded("*.example.com", ".."), 0);
/* SAN has an empty interior label ("*..com"), but only the right-most
* "com" label overlaps the base "com" -- the empty label sits outside the
Expand Down Expand Up @@ -1892,6 +1927,9 @@ int test_wolfssl_local_MatchUriNameConstraint(void)
* Exact host match (no leading dot in the constraint).
*/
ExpectIntEQ(uriNC("https://host.com/path", "host.com"), 1);
/* A lone "." base is a leading-dot base with no labels. */
ExpectIntEQ(uriNC("https://host.com/path", "."),
NC_DNS_DOT_BASE_MATCH);
ExpectIntEQ(uriNC("https://host.com", "host.com"), 1);
ExpectIntEQ(uriNC("https://host.com:8443/x", "host.com"), 1);
ExpectIntEQ(uriNC("ftp://user@host.com/x", "host.com"), 1);
Expand Down
51 changes: 51 additions & 0 deletions tests/api/test_ossl_x509_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@
#include <tests/api/api.h>
#include <tests/api/test_ossl_x509_ext.h>

/* A lone "." dNSName constraint base covers every DNS name, except with
* OPENSSL_COMPATIBLE_DEFAULTS where it matches no name. */
#ifdef OPENSSL_COMPATIBLE_DEFAULTS
#define NC_DNS_DOT_BASE_MATCH 0
#else
#define NC_DNS_DOT_BASE_MATCH 1
#endif

int test_wolfSSL_X509_get_extension_flags(void)
{
Expand Down Expand Up @@ -2367,6 +2374,12 @@ int test_wolfSSL_NAME_CONSTRAINTS_check_name(void)
/* @ at end */
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
"user@", 5), 0);
/* An '@' outside a quoted local-part is not permitted */
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
"x@evil.com@sub.wolfssl.com", 26), 0);
/* A quoted local-part may hold an '@' */
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_EMAIL,
"\"x@y\"@sub.wolfssl.com", 21), 1);
}

NAME_CONSTRAINTS_free(nc);
Expand Down Expand Up @@ -2436,6 +2449,44 @@ int test_wolfSSL_NAME_CONSTRAINTS_check_name(void)
"bar.example.com", 15), 1);
}

if (EXPECT_SUCCESS()) {
/* An empty excluded dNSName covers every DNS name (RFC 5280
* 4.2.1.10), as does a lone trailing dot unless OpenSSL
* compatible. */
GENERAL_SUBTREE* subtree = NULL;

ExpectNotNull(subtree =
wolfSSL_sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, 0));
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wolfSSL_ASN1_STRING_set(subtree->base->d.ia5,
"", 0), WOLFSSL_SUCCESS);
}
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
"evil.com", 8), 0);
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
"*.evil.com", 10), 0);
if (EXPECT_SUCCESS()) {
ExpectIntEQ(wolfSSL_ASN1_STRING_set(subtree->base->d.ia5,
".", 1), WOLFSSL_SUCCESS);
}
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
"evil.com", 8), !NC_DNS_DOT_BASE_MATCH);
}

if (EXPECT_SUCCESS()) {
/* Moved to the permitted side, an empty dNSName permits every DNS
* name. */
nc->permittedSubtrees = nc->excludedSubtrees;
nc->excludedSubtrees = NULL;
ExpectIntEQ(wolfSSL_ASN1_STRING_set(
wolfSSL_sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, 0)->
base->d.ia5, "", 0), WOLFSSL_SUCCESS);
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
"any.example.org", 15), 1);
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_DNS,
"*.example.org", 13), 1);
}

NAME_CONSTRAINTS_free(nc);
nc = NULL;

Expand Down
Loading
Loading