Skip to content

Commit 1f684e6

Browse files
authored
Merge pull request #7604 from ColtonWilley/explicit_len_pattern_match
Rewrite pattern matching to use explicit length
2 parents 43f4ba9 + 0c00693 commit 1f684e6

4 files changed

Lines changed: 464 additions & 40 deletions

File tree

src/internal.c

Lines changed: 76 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12393,55 +12393,77 @@ int CipherRequires(byte first, byte second, int requirement)
1239312393
*.z.com matches y.z.com but not x.y.z.com
1239412394

1239512395
return 1 on success */
12396-
int MatchDomainName(const char* pattern, int len, const char* str)
12396+
int MatchDomainName(const char* pattern, int patternLen, const char* str,
12397+
word32 strLen)
1239712398
{
1239812399
int ret = 0;
1239912400

12400-
if (pattern == NULL || str == NULL || len <= 0)
12401+
if (pattern == NULL || str == NULL || patternLen <= 0 || strLen == 0)
1240112402
return 0;
1240212403

12403-
while (len > 0) {
12404-
12405-
char p = (char)XTOLOWER((unsigned char)*pattern++);
12404+
while (patternLen > 0) {
12405+
/* Get the next pattern char to evaluate */
12406+
char p = (char)XTOLOWER((unsigned char)*pattern);
1240612407
if (p == '\0')
1240712408
break;
1240812409

12410+
pattern++;
12411+
1240912412
if (p == '*') {
1241012413
char s;
12414+
/* We will always match '*' */
12415+
patternLen--;
1241112416

12412-
while (--len > 0) {
12417+
/* Consume any extra '*' chars until the next non '*' char. */
12418+
while (patternLen > 0) {
1241312419
p = (char)XTOLOWER((unsigned char)*pattern);
1241412420
pattern++;
12415-
if (p == '\0' && len > 0)
12421+
if (p == '\0' && patternLen > 0)
1241612422
return 0;
1241712423
if (p != '*')
1241812424
break;
12425+
12426+
patternLen--;
1241912427
}
1242012428

12421-
if (len == 0)
12422-
p = '\0';
12429+
/* Consume str until we reach next char in pattern after '*' or
12430+
* end of string */
12431+
while (strLen > 0) {
12432+
s = (char)XTOLOWER((unsigned char) *str);
12433+
str++;
12434+
strLen--;
12435+
12436+
/* p is next char in pattern after '*', or '*' if '*' is the
12437+
* last char in the pattern (in which case patternLen is 1) */
12438+
if ( ((s == p) && (patternLen > 0))) {
12439+
/* We had already counted the '*' as matched, this means
12440+
* we also matched the next non '*' char in pattern */
12441+
patternLen--;
12442+
break;
12443+
}
1242312444

12424-
while ( (s = (char)XTOLOWER((unsigned char) *str)) != '\0') {
12425-
if (s == p)
12445+
/* If strlen is 0, we have consumed the entire string. Count that
12446+
* as a match of '*' */
12447+
if (strLen == 0) {
1242612448
break;
12449+
}
12450+
1242712451
if (s == '.')
1242812452
return 0;
12429-
str++;
1243012453
}
1243112454
}
1243212455
else {
12456+
/* Simple case, pattern match exactly */
1243312457
if (p != (char)XTOLOWER((unsigned char) *str))
1243412458
return 0;
12435-
}
12436-
1243712459

12438-
if (len > 0) {
1243912460
str++;
12440-
len--;
12461+
strLen--;
12462+
patternLen--;
1244112463
}
1244212464
}
1244312465

12444-
if (*str == '\0' && len == 0) {
12466+
if (strLen == 0 && patternLen == 0) {
1244512467
ret = 1; /* success */
1244612468
}
1244712469

@@ -12453,14 +12475,16 @@ int MatchDomainName(const char* pattern, int len, const char* str)
1245312475
* Fail if there are wild patterns and they didn't match.
1245412476
* Check the common name if no alternative names matched.
1245512477
*
12456-
* dCert Decoded cert to get the alternative names from.
12457-
* domain Domain name to compare against.
12458-
* checkCN Whether to check the common name.
12459-
* returns 1 : match was found.
12460-
* 0 : no match found.
12461-
* -1 : No matches and wild pattern match failed.
12478+
* dCert Decoded cert to get the alternative names from.
12479+
* domain Domain name to compare against.
12480+
* domainLen Length of the domain name.
12481+
* checkCN Whether to check the common name.
12482+
* returns 1 : match was found.
12483+
* 0 : no match found.
12484+
* -1 : No matches and wild pattern match failed.
1246212485
*/
12463-
int CheckForAltNames(DecodedCert* dCert, const char* domain, int* checkCN)
12486+
int CheckForAltNames(DecodedCert* dCert, const char* domain, word32 domainLen,
12487+
int* checkCN)
1246412488
{
1246512489
int match = 0;
1246612490
DNS_entry* altName = NULL;
@@ -12491,7 +12515,7 @@ int CheckForAltNames(DecodedCert* dCert, const char* domain, int* checkCN)
1249112515
len = (word32)altName->len;
1249212516
}
1249312517

12494-
if (MatchDomainName(buf, (int)len, domain)) {
12518+
if (MatchDomainName(buf, (int)len, domain, domainLen)) {
1249512519
match = 1;
1249612520
if (checkCN != NULL) {
1249712521
*checkCN = 0;
@@ -12525,10 +12549,8 @@ int CheckHostName(DecodedCert* dCert, const char *domainName, size_t domainNameL
1252512549
int checkCN;
1252612550
int ret = DOMAIN_NAME_MISMATCH;
1252712551

12528-
/* Assume name is NUL terminated. */
12529-
(void)domainNameLen;
12530-
12531-
if (CheckForAltNames(dCert, domainName, &checkCN) != 1) {
12552+
if (CheckForAltNames(dCert, domainName, (word32)domainNameLen,
12553+
&checkCN) != 1) {
1253212554
WOLFSSL_MSG("DomainName match on alt names failed");
1253312555
}
1253412556
else {
@@ -12538,7 +12560,7 @@ int CheckHostName(DecodedCert* dCert, const char *domainName, size_t domainNameL
1253812560
#ifndef WOLFSSL_HOSTNAME_VERIFY_ALT_NAME_ONLY
1253912561
if (checkCN == 1) {
1254012562
if (MatchDomainName(dCert->subjectCN, dCert->subjectCNLen,
12541-
domainName) == 1) {
12563+
domainName, (word32)domainNameLen) == 1) {
1254212564
ret = 0;
1254312565
}
1254412566
else {
@@ -13576,7 +13598,8 @@ int DoVerifyCallback(WOLFSSL_CERT_MANAGER* cm, WOLFSSL* ssl, int cert_err,
1357613598
ssl->param && ssl->param->hostName[0]) {
1357713599
/* If altNames names is present, then subject common name is ignored */
1357813600
if (args->dCert->altNames != NULL) {
13579-
if (CheckForAltNames(args->dCert, ssl->param->hostName, NULL) != 1) {
13601+
if (CheckForAltNames(args->dCert, ssl->param->hostName,
13602+
(word32)XSTRLEN(ssl->param->hostName), NULL) != 1) {
1358013603
if (cert_err == 0) {
1358113604
ret = DOMAIN_NAME_MISMATCH;
1358213605
WOLFSSL_ERROR_VERBOSE(ret);
@@ -13586,9 +13609,11 @@ int DoVerifyCallback(WOLFSSL_CERT_MANAGER* cm, WOLFSSL* ssl, int cert_err,
1358613609
#ifndef WOLFSSL_HOSTNAME_VERIFY_ALT_NAME_ONLY
1358713610
else {
1358813611
if (args->dCert->subjectCN) {
13589-
if (MatchDomainName(args->dCert->subjectCN,
13590-
args->dCert->subjectCNLen,
13591-
ssl->param->hostName) == 0) {
13612+
if (MatchDomainName(
13613+
args->dCert->subjectCN,
13614+
args->dCert->subjectCNLen,
13615+
ssl->param->hostName,
13616+
(word32)XSTRLEN(ssl->param->hostName)) == 0) {
1359213617
if (cert_err == 0) {
1359313618
ret = DOMAIN_NAME_MISMATCH;
1359413619
WOLFSSL_ERROR_VERBOSE(ret);
@@ -15401,6 +15426,9 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1540115426
if (args->dCert->altNames) {
1540215427
if (CheckForAltNames(args->dCert,
1540315428
(char*)ssl->buffers.domainName.buffer,
15429+
(ssl->buffers.domainName.buffer == NULL ? 0 :
15430+
(word32)XSTRLEN(
15431+
(const char *)ssl->buffers.domainName.buffer)),
1540415432
NULL) != 1) {
1540515433
WOLFSSL_MSG("DomainName match on alt names failed");
1540615434
/* try to get peer key still */
@@ -15410,9 +15438,14 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1541015438
}
1541115439
else {
1541215440
if (MatchDomainName(
15413-
args->dCert->subjectCN,
15414-
args->dCert->subjectCNLen,
15415-
(char*)ssl->buffers.domainName.buffer) == 0) {
15441+
args->dCert->subjectCN,
15442+
args->dCert->subjectCNLen,
15443+
(char*)ssl->buffers.domainName.buffer,
15444+
(ssl->buffers.domainName.buffer == NULL ? 0 :
15445+
(word32)XSTRLEN(
15446+
(const char *)ssl->buffers.domainName.buffer)
15447+
)) == 0)
15448+
{
1541615449
WOLFSSL_MSG("DomainName match on common name failed");
1541715450
ret = DOMAIN_NAME_MISMATCH;
1541815451
WOLFSSL_ERROR_VERBOSE(ret);
@@ -15422,10 +15455,15 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
1542215455
/* Old behavior. */
1542315456
if (MatchDomainName(args->dCert->subjectCN,
1542415457
args->dCert->subjectCNLen,
15425-
(char*)ssl->buffers.domainName.buffer) == 0) {
15458+
(char*)ssl->buffers.domainName.buffer,
15459+
(ssl->buffers.domainName.buffer == NULL ? 0 :
15460+
(word32)XSTRLEN(ssl->buffers.domainName.buffer))) == 0)
15461+
{
1542615462
WOLFSSL_MSG("DomainName match on common name failed");
1542715463
if (CheckForAltNames(args->dCert,
1542815464
(char*)ssl->buffers.domainName.buffer,
15465+
(ssl->buffers.domainName.buffer == NULL ? 0 :
15466+
(word32)XSTRLEN(ssl->buffers.domainName.buffer)),
1542915467
NULL) != 1) {
1543015468
WOLFSSL_MSG(
1543115469
"DomainName match on alt names failed too");

src/x509.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13343,6 +13343,7 @@ int wolfSSL_X509_check_host(WOLFSSL_X509 *x, const char *chk, size_t chklen,
1334313343
unsigned int flags, char **peername)
1334413344
{
1334513345
int ret;
13346+
size_t i;
1334613347
#ifdef WOLFSSL_SMALL_STACK
1334713348
DecodedCert *dCert;
1334813349
#else
@@ -13384,6 +13385,22 @@ int wolfSSL_X509_check_host(WOLFSSL_X509 *x, const char *chk, size_t chklen,
1338413385
goto out;
1338513386
}
1338613387

13388+
/* Replicate openssl behavior for checklen */
13389+
if (chklen == 0) {
13390+
chklen = (size_t)(XSTRLEN(chk));
13391+
}
13392+
else {
13393+
for (i = 0; i < (chklen > 1 ? chklen - 1 : chklen); i++) {
13394+
if (chk[i] == '\0') {
13395+
ret = -1;
13396+
goto out;
13397+
}
13398+
}
13399+
}
13400+
if (chklen > 1 && (chk[chklen - 1] == '\0')) {
13401+
chklen--;
13402+
}
13403+
1338713404
ret = CheckHostName(dCert, (char *)chk, chklen);
1338813405

1338913406
out:

0 commit comments

Comments
 (0)