mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-01-27 07:12:19 +01:00
Merge pull request #9626 from rizlik/name_contraints_fixes
asn: MatchBaseName fixes
This commit is contained in:
@@ -23,6 +23,8 @@
|
||||
|
||||
#include <tests/api/test_asn.h>
|
||||
|
||||
#include <wolfssl/wolfcrypt/asn.h>
|
||||
|
||||
#if defined(WC_ENABLE_ASYM_KEY_EXPORT) && defined(HAVE_ED25519)
|
||||
static int test_SetAsymKeyDer_once(byte* privKey, word32 privKeySz, byte* pubKey,
|
||||
word32 pubKeySz, byte* trueDer, word32 trueDerSz)
|
||||
@@ -638,3 +640,150 @@ int test_wc_IndexSequenceOf(void)
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
int test_wolfssl_local_MatchBaseName(void)
|
||||
{
|
||||
EXPECT_DECLS;
|
||||
|
||||
#if !defined(NO_CERTS) && !defined(NO_ASN) && !defined(IGNORE_NAME_CONSTRAINTS)
|
||||
/*
|
||||
* Tests for DNS type (ASN_DNS_TYPE = 0x02)
|
||||
*/
|
||||
|
||||
/* Positive tests - should match */
|
||||
/* Exact match */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"domain.com", 10, "domain.com", 10), 1);
|
||||
/* Case insensitive match */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"DOMAIN.COM", 10, "domain.com", 10), 1);
|
||||
/* Subdomain match (RFC 5280: adding labels to the left) */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"sub.domain.com", 14, "domain.com", 10), 1);
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"a.b.domain.com", 14, "domain.com", 10), 1);
|
||||
/* Leading dot constraint with subdomain (not RFC 5280 compliant for DNS,
|
||||
* but kept for backwards compatibility) */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"sub.domain.com", 14, ".domain.com", 11), 1);
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"a.b.domain.com", 14, ".domain.com", 11), 1);
|
||||
|
||||
/* Negative tests - should NOT match */
|
||||
/* Bug #3: fakedomain.com should NOT match domain.com (no dot boundary) */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"fakedomain.com", 14, "domain.com", 10), 0);
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"notdomain.com", 13, "domain.com", 10), 0);
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"xexample.com", 12, "example.com", 11), 0);
|
||||
/* Bug #3: fakedomain.com should NOT match .domain.com */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"fakedomain.com", 14, ".domain.com", 11), 0);
|
||||
/* domain.com should NOT match .domain.com (leading dot requires subdomain) */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"domain.com", 10, ".domain.com", 11), 0);
|
||||
/* Different domain */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"other.com", 9, "domain.com", 10), 0);
|
||||
/* Name starting with dot */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
".domain.com", 11, "domain.com", 10), 0);
|
||||
|
||||
/*
|
||||
* Tests for email type (ASN_RFC822_TYPE = 0x01)
|
||||
*/
|
||||
|
||||
/* Positive tests - should match */
|
||||
/* Exact email match */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@domain.com", 15, "user@domain.com", 15), 1);
|
||||
/* Email with domain constraint (leading dot) - subdomain present */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@sub.domain.com", 19, ".domain.com", 11), 1);
|
||||
/* Email with domain constraint (no leading dot) - exact domain */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@domain.com", 15, "domain.com", 10), 1);
|
||||
|
||||
/* Negative tests - should NOT match */
|
||||
/* user@domain.com should NOT match .domain.com (subdomain required) */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@domain.com", 15, ".domain.com", 11), 0);
|
||||
/* user@sub.domain.com should NOT match domain.com (exact domain only) */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@sub.domain.com", 19, "domain.com", 10), 0);
|
||||
/* @ at start is invalid */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"@domain.com", 11, ".domain.com", 11), 0);
|
||||
/* @ at end is invalid */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@", 5, ".domain.com", 11), 0);
|
||||
/* double @ is invalid */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@@domain.com", 16, ".domain.com", 11), 0);
|
||||
/* multiple @ is invalid */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@domain@extra.com", 21, ".domain.com", 11), 0);
|
||||
/* No @ in email name */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"userdomain.com", 14, ".domain.com", 11), 0);
|
||||
/* Email domain doesn't match constraint */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@other.com", 14, ".domain.com", 11), 0);
|
||||
/* Email suffix without dot boundary (fakedomain) */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@fakedomain.com", 19, ".domain.com", 11), 0);
|
||||
/* Base constraint with invalid @ position */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@domain.com", 15, "@domain.com", 11), 0);
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_RFC822_TYPE,
|
||||
"user@domain.com", 15, "user@", 5), 0);
|
||||
|
||||
/*
|
||||
* Tests for directory type (ASN_DIR_TYPE = 0x04)
|
||||
*/
|
||||
|
||||
/* Positive tests - should match */
|
||||
/* Exact match */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DIR_TYPE,
|
||||
"CN=test", 7, "CN=test", 7), 1);
|
||||
/* Prefix match (name longer than base) */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DIR_TYPE,
|
||||
"CN=test,O=org", 13, "CN=test", 7), 1);
|
||||
|
||||
/* Negative tests - should NOT match */
|
||||
/* Different content */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DIR_TYPE,
|
||||
"CN=other", 8, "CN=test", 7), 0);
|
||||
/* Case sensitive for directory */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DIR_TYPE,
|
||||
"CN=TEST", 7, "CN=test", 7), 0);
|
||||
|
||||
/*
|
||||
* Edge cases and error handling
|
||||
*/
|
||||
|
||||
/* NULL pointers */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
NULL, 10, "domain.com", 10), 0);
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"domain.com", 10, NULL, 10), 0);
|
||||
/* Empty/zero size */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"", 0, "domain.com", 10), 0);
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"domain.com", 10, "", 0), 0);
|
||||
/* Invalid type */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(0xFF,
|
||||
"domain.com", 10, "domain.com", 10), 0);
|
||||
/* Name starting with dot */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
".", 1, ".", 1), 0);
|
||||
/* Name shorter than base */
|
||||
ExpectIntEQ(wolfssl_local_MatchBaseName(ASN_DNS_TYPE,
|
||||
"a.com", 5, "domain.com", 10), 0);
|
||||
|
||||
#endif /* !NO_CERTS && !NO_ASN && !IGNORE_NAME_CONSTRAINTS */
|
||||
|
||||
return EXPECT_RESULT();
|
||||
}
|
||||
|
||||
@@ -27,10 +27,12 @@
|
||||
int test_SetAsymKeyDer(void);
|
||||
int test_GetSetShortInt(void);
|
||||
int test_wc_IndexSequenceOf(void);
|
||||
int test_wolfssl_local_MatchBaseName(void);
|
||||
|
||||
#define TEST_ASN_DECLS \
|
||||
TEST_DECL_GROUP("asn", test_SetAsymKeyDer), \
|
||||
TEST_DECL_GROUP("asn", test_GetSetShortInt), \
|
||||
TEST_DECL_GROUP("asn", test_wc_IndexSequenceOf)
|
||||
TEST_DECL_GROUP("asn", test_wc_IndexSequenceOf), \
|
||||
TEST_DECL_GROUP("asn", test_wolfssl_local_MatchBaseName)
|
||||
|
||||
#endif /* WOLFCRYPT_TEST_ASN_H */
|
||||
|
||||
@@ -19315,8 +19315,8 @@ exit_cs:
|
||||
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
|
||||
static int MatchBaseName(int type, const char* name, int nameSz,
|
||||
const char* base, int baseSz)
|
||||
int wolfssl_local_MatchBaseName(int type, const char* name, int nameSz,
|
||||
const char* base, int baseSz)
|
||||
{
|
||||
if (base == NULL || baseSz <= 0 || name == NULL || nameSz <= 0 ||
|
||||
name[0] == '.' || nameSz < baseSz ||
|
||||
@@ -19333,6 +19333,8 @@ static int MatchBaseName(int type, const char* name, int nameSz,
|
||||
if (type == ASN_RFC822_TYPE) {
|
||||
const char* p = NULL;
|
||||
int count = 0;
|
||||
int baseIsEmail = 0;
|
||||
int atPos = -1;
|
||||
|
||||
if (base[0] != '.') {
|
||||
p = base;
|
||||
@@ -19344,25 +19346,36 @@ static int MatchBaseName(int type, const char* name, int nameSz,
|
||||
p++;
|
||||
}
|
||||
|
||||
/* No '@' in base, reset p to NULL */
|
||||
if (count >= baseSz)
|
||||
p = NULL;
|
||||
if (count < baseSz) {
|
||||
/* '@' found in base - validate it's not at start/end and only one */
|
||||
if (count == 0 || count == baseSz - 1)
|
||||
return 0; /* '@' at start or end of base is invalid */
|
||||
baseIsEmail = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
/* Base isn't an email address, it is a domain name,
|
||||
* wind the name forward one character past its '@'. */
|
||||
p = name;
|
||||
count = 0;
|
||||
while (*p != '@' && count < baseSz) {
|
||||
count++;
|
||||
p++;
|
||||
/* verify that name is a valid email address, store @ position */
|
||||
p = name;
|
||||
count = 0;
|
||||
while (count < nameSz) {
|
||||
if (*p == '@') {
|
||||
if (atPos >= 0)
|
||||
return 0; /* Multiple '@' in name is invalid */
|
||||
atPos = count;
|
||||
}
|
||||
count++;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (count < baseSz && *p == '@') {
|
||||
name = p + 1;
|
||||
nameSz -= count + 1;
|
||||
}
|
||||
/* Validate '@' exists and is not at start or end */
|
||||
if (atPos < 0 || atPos == 0 || atPos == nameSz - 1)
|
||||
return 0;
|
||||
|
||||
if (!baseIsEmail) {
|
||||
/* Base isn't an email address but a domain or host.
|
||||
* wind the name forward one character past its '@'. */
|
||||
name = name + atPos + 1;
|
||||
nameSz -= atPos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19370,13 +19383,24 @@ static int MatchBaseName(int type, const char* name, int nameSz,
|
||||
* "...Any DNS name that can be constructed by simply adding zero or more
|
||||
* labels to the left-hand side of the name satisfies the name constraint."
|
||||
* i.e www.host.example.com works for host.example.com name constraint and
|
||||
* host1.example.com does not. */
|
||||
* host1.example.com does not.
|
||||
*
|
||||
* Note: For DNS type, RFC 5280 does not allow leading dot in constraint.
|
||||
* However, we accept it here for backwards compatibility. */
|
||||
if (type == ASN_DNS_TYPE || (type == ASN_RFC822_TYPE && base[0] == '.')) {
|
||||
int szAdjust = nameSz - baseSz;
|
||||
/* Check dot boundary: if there's a prefix and base doesn't start with
|
||||
* '.', the character before the matched suffix must be '.'.
|
||||
* When base starts with '.', the dot is included in the comparison. */
|
||||
if (szAdjust > 0 && base[0] != '.' && name[szAdjust - 1] != '.')
|
||||
return 0;
|
||||
name += szAdjust;
|
||||
nameSz -= szAdjust;
|
||||
}
|
||||
|
||||
if (nameSz != baseSz)
|
||||
return 0;
|
||||
|
||||
while (nameSz > 0) {
|
||||
if (XTOLOWER((unsigned char)*name) !=
|
||||
XTOLOWER((unsigned char)*base))
|
||||
@@ -19408,8 +19432,8 @@ static int PermittedListOk(DNS_entry* name, Base_entry* dnsList, byte nameType)
|
||||
if (current->type == nameType) {
|
||||
need = 1; /* restriction on permitted names is set for this type */
|
||||
if (name->len >= current->nameSz &&
|
||||
MatchBaseName(nameType, name->name, name->len,
|
||||
current->name, current->nameSz)) {
|
||||
wolfssl_local_MatchBaseName(nameType, name->name, name->len,
|
||||
current->name, current->nameSz)) {
|
||||
match = 1; /* found the current name in the permitted list*/
|
||||
break;
|
||||
}
|
||||
@@ -19439,8 +19463,8 @@ static int IsInExcludedList(DNS_entry* name, Base_entry* dnsList, byte nameType)
|
||||
while (current != NULL) {
|
||||
if (current->type == nameType) {
|
||||
if (name->len >= current->nameSz &&
|
||||
MatchBaseName(nameType, name->name, name->len,
|
||||
current->name, current->nameSz)) {
|
||||
wolfssl_local_MatchBaseName(nameType, name->name, name->len,
|
||||
current->name, current->nameSz)) {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2789,6 +2789,12 @@ WOLFSSL_LOCAL int VerifyX509Acert(const byte* cert, word32 certSz,
|
||||
#endif /* WOLFSSL_ACERT */
|
||||
|
||||
|
||||
#ifndef IGNORE_NAME_CONSTRAINTS
|
||||
WOLFSSL_TEST_VIS int wolfssl_local_MatchBaseName(int type, const char* name,
|
||||
int nameSz, const char* base,
|
||||
int baseSz);
|
||||
#endif
|
||||
|
||||
#if ((defined(HAVE_ED25519) && defined(HAVE_ED25519_KEY_IMPORT)) \
|
||||
|| (defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_KEY_IMPORT)) \
|
||||
|| (defined(HAVE_ED448) && defined(HAVE_ED448_KEY_IMPORT)) \
|
||||
|
||||
Reference in New Issue
Block a user