Skip to content

Commit 5bdb96c

Browse files
committed
wip
1 parent 2746f1c commit 5bdb96c

6 files changed

Lines changed: 186 additions & 106 deletions

File tree

src/x509.c

Lines changed: 32 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -5666,91 +5666,6 @@ static int MatchIpName(const char* name, int nameSz, WOLFSSL_GENERAL_NAME* gn)
56665666
constraintData, constraintLen);
56675667
}
56685668

5669-
/* Extract host from URI for name constraint matching.
5670-
* URI format: scheme://[userinfo@]host[:port][/path][?query][#fragment]
5671-
* IPv6 literals are enclosed in brackets: scheme://[ipv6addr]:port/path
5672-
* Returns pointer to host start and sets hostLen, or NULL on failure. */
5673-
static const char* ExtractHostFromUri(const char* uri, int uriLen, int* hostLen)
5674-
{
5675-
const char* hostStart;
5676-
const char* hostEnd;
5677-
const char* p;
5678-
const char* uriEnd;
5679-
5680-
if (uri == NULL || uriLen <= 0 || hostLen == NULL) {
5681-
return NULL;
5682-
}
5683-
5684-
uriEnd = uri + uriLen;
5685-
5686-
/* Find "://" to skip scheme */
5687-
hostStart = NULL;
5688-
for (p = uri; p < uriEnd - 2; p++) {
5689-
if (p[0] == ':' && p[1] == '/' && p[2] == '/') {
5690-
hostStart = p + 3;
5691-
break;
5692-
}
5693-
}
5694-
if (hostStart == NULL || hostStart >= uriEnd) {
5695-
return NULL;
5696-
}
5697-
5698-
/* Skip userinfo if present (look for @ before any /, ?, #)
5699-
* userinfo can contain ':' (ex: user:pass@host), don't stop at ':'
5700-
* For IPv6, also don't stop at '[' in userinfo */
5701-
for (p = hostStart; p < uriEnd; p++) {
5702-
if (*p == '@') {
5703-
hostStart = p + 1;
5704-
break;
5705-
}
5706-
if (*p == '/' || *p == '?' || *p == '#') {
5707-
/* No userinfo found */
5708-
break;
5709-
}
5710-
/* If '[' before '@', found IPv6 literal, not userinfo */
5711-
if (*p == '[') {
5712-
break;
5713-
}
5714-
}
5715-
if (hostStart >= uriEnd) {
5716-
return NULL;
5717-
}
5718-
5719-
/* Check for IPv6 literal */
5720-
if (*hostStart == '[') {
5721-
/* Find closing bracket, skip opening one */
5722-
hostStart++;
5723-
hostEnd = hostStart;
5724-
while (hostEnd < uriEnd && *hostEnd != ']') {
5725-
hostEnd++;
5726-
}
5727-
if (hostEnd >= uriEnd) {
5728-
/* No closing bracket found, malformed */
5729-
return NULL;
5730-
}
5731-
/* hostEnd points to closing bracket, extract content between */
5732-
*hostLen = (int)(hostEnd - hostStart);
5733-
if (*hostLen <= 0) {
5734-
return NULL;
5735-
}
5736-
return hostStart;
5737-
}
5738-
5739-
/* Regular hostname, find end */
5740-
hostEnd = hostStart;
5741-
while (hostEnd < uriEnd && *hostEnd != ':' && *hostEnd != '/' &&
5742-
*hostEnd != '?' && *hostEnd != '#') {
5743-
hostEnd++;
5744-
}
5745-
5746-
*hostLen = (int)(hostEnd - hostStart);
5747-
if (*hostLen <= 0) {
5748-
return NULL;
5749-
}
5750-
5751-
return hostStart;
5752-
}
5753-
57545669
/* Helper to check if name string matches a single GENERAL_NAME constraint.
57555670
* Returns 1 if matches, 0 if not. */
57565671
static int MatchNameConstraint(int type, const char* name, int nameSz,
@@ -5784,15 +5699,7 @@ static int MatchNameConstraint(int type, const char* name, int nameSz,
57845699
nameSz, baseStr, baseLen);
57855700
}
57865701
else if (type == WOLFSSL_GEN_URI) {
5787-
const char* host;
5788-
int hostLen;
5789-
5790-
/* For URI, extract host and match against DNS-style */
5791-
host = ExtractHostFromUri(name, nameSz, &hostLen);
5792-
if (host == NULL) {
5793-
return 0;
5794-
}
5795-
return wolfssl_local_MatchBaseName(ASN_DNS_TYPE, host, hostLen,
5702+
return wolfssl_local_MatchUriNameConstraint(name, nameSz,
57965703
baseStr, baseLen);
57975704
}
57985705
else {
@@ -5807,6 +5714,29 @@ static int MatchNameConstraint(int type, const char* name, int nameSz,
58075714
}
58085715
}
58095716

5717+
static int NameConstraintsHasType(const WOLFSSL_STACK* sk, int type)
5718+
{
5719+
int i;
5720+
int num;
5721+
5722+
if (sk == NULL) {
5723+
return 0;
5724+
}
5725+
5726+
num = wolfSSL_sk_GENERAL_SUBTREE_num(sk);
5727+
for (i = 0; i < num; i++) {
5728+
WOLFSSL_GENERAL_SUBTREE* subtree;
5729+
5730+
subtree = wolfSSL_sk_GENERAL_SUBTREE_value(sk, i);
5731+
if (subtree != NULL && subtree->base != NULL &&
5732+
subtree->base->type == type) {
5733+
return 1;
5734+
}
5735+
}
5736+
5737+
return 0;
5738+
}
5739+
58105740
/*
58115741
* Check if a name string satisfies given name constraints.
58125742
*
@@ -5837,6 +5767,14 @@ int wolfSSL_NAME_CONSTRAINTS_check_name(WOLFSSL_NAME_CONSTRAINTS* nc,
58375767
return 0;
58385768
}
58395769

5770+
if (type == WOLFSSL_GEN_URI &&
5771+
(NameConstraintsHasType(nc->permittedSubtrees, type) ||
5772+
NameConstraintsHasType(nc->excludedSubtrees, type)) &&
5773+
!wolfssl_local_UriNameHasDnsHost(name, nameSz)) {
5774+
WOLFSSL_MSG("URI name constraint applied to URI without DNS host");
5775+
return 0;
5776+
}
5777+
58405778
/* Check permitted subtrees */
58415779
if (nc->permittedSubtrees != NULL) {
58425780
num = wolfSSL_sk_GENERAL_SUBTREE_num(nc->permittedSubtrees);

tests/api.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23046,6 +23046,22 @@ static int test_NameConstraints_DnsUriWildcard(void)
2304623046
sanSz = build_simple_san(san, sizeof(san), URI, "https://www.host.com/");
2304723047
ExpectIntGT((int)sanSz, 0);
2304823048
ExpectIntEQ(verify_with_otherName_chain(nc, ncSz, 1, san, sanSz), 0);
23049+
23050+
/* (11) RFC 5280 requires a DNS host when URI constraints are applied.
23051+
* Fail closed even for excluded-only constraints where a boolean
23052+
* non-match would otherwise pass. */
23053+
ncSz = build_simple_nameConstraints(nc, sizeof(nc), 1, URI,
23054+
"blocked.com");
23055+
sanSz = build_simple_san(san, sizeof(san), URI, "https://12.31.2.3/");
23056+
ExpectIntGT((int)ncSz, 0);
23057+
ExpectIntGT((int)sanSz, 0);
23058+
ExpectIntEQ(verify_with_otherName_chain(nc, ncSz, 1, san, sanSz),
23059+
WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));
23060+
23061+
sanSz = build_simple_san(san, sizeof(san), URI, "https://[v1.addr.]/");
23062+
ExpectIntGT((int)sanSz, 0);
23063+
ExpectIntEQ(verify_with_otherName_chain(nc, ncSz, 1, san, sanSz),
23064+
WC_NO_ERR_TRACE(ASN_NAME_INVALID_E));
2304923065
#endif
2305023066
return EXPECT_RESULT();
2305123067
}

tests/api/test_asn.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,8 @@ int test_wolfssl_local_MatchUriNameConstraint(void)
11601160
ExpectIntEQ(uriNC("https://host.com.:8443/x", "host.com"), 1);
11611161
ExpectIntEQ(uriNC("https://host.com", "host.com."), 1);
11621162
ExpectIntEQ(uriNC("https://host.com./", "host.com."), 1);
1163+
ExpectIntEQ(uriNC("https://v1.addr./", "v1.addr"), 1);
1164+
ExpectIntEQ(uriNC("https://v1.addr/", "v1.addr."), 1);
11631165
/* Only ONE trailing dot is the marker; an empty last label is not. */
11641166
ExpectIntEQ(uriNC("https://host.com../", "host.com"), 0);
11651167

@@ -1174,10 +1176,14 @@ int test_wolfssl_local_MatchUriNameConstraint(void)
11741176
ExpectIntEQ(uriNC("https://evilhost.com", ".host.com"), 0);
11751177

11761178
/*
1177-
* IPv6 literal host extraction ([..]) then exact match.
1179+
* RFC 5280 URI constraints require a DNS host. IP-literals / IPvFuture
1180+
* hosts in brackets and IPv4address hosts are not DNS reg-names.
11781181
*/
1179-
ExpectIntEQ(uriNC("https://[2001:db8::1]:443/x", "2001:db8::1"), 1);
1182+
ExpectIntEQ(uriNC("https://[2001:db8::1]:443/x", "2001:db8::1"), 0);
11801183
ExpectIntEQ(uriNC("https://[2001:db8::1]", "2001:db8::2"), 0);
1184+
ExpectIntEQ(uriNC("https://[v1.addr.]/", "v1.addr"), 0);
1185+
ExpectIntEQ(uriNC("https://[v1.addr.]/", "v1.addr."), 0);
1186+
ExpectIntEQ(uriNC("https://12.31.2.3/", "12.31.2.3"), 0);
11811187

11821188
/*
11831189
* Malformed / degenerate URIs and inputs (reject).

tests/api/test_ossl_x509_ext.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ int test_wolfSSL_X509_get_extension_flags(void)
9898
return EXPECT_RESULT();
9999
}
100100

101+
101102
int test_wolfSSL_X509_get_ext(void)
102103
{
103104
EXPECT_DECLS;
@@ -2037,8 +2038,8 @@ int test_wolfSSL_NAME_CONSTRAINTS_uri(void)
20372038
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
20382039
"https://user:pass@www.wolfssl.com/path", 38), 1);
20392040

2040-
/* IPv6 literal URIs, host extracted without brackets.
2041-
* These don't match .wolfssl.com constraint (different host type) */
2041+
/* URI constraints require a DNS reg-name host, so IP-literals do not
2042+
* match the .wolfssl.com constraint. */
20422043
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
20432044
"https://[::1]:8080/path", 23), 0);
20442045
ExpectIntEQ(wolfSSL_NAME_CONSTRAINTS_check_name(nc, GEN_URI,
@@ -2431,4 +2432,3 @@ int test_wolfSSL_NAME_CONSTRAINTS_excluded(void)
24312432
* !IGNORE_NAME_CONSTRAINTS */
24322433
return EXPECT_RESULT();
24332434
}
2434-

0 commit comments

Comments
 (0)