Skip to content

Commit 5b0f3ff

Browse files
committed
src/internal.c: add IsValidFQDN(), and in MatchDomainName(), do pattern matching and case folding only if target string IsValidFQDN().
1 parent 1d363f3 commit 5b0f3ff

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

src/internal.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13272,6 +13272,78 @@ static int MatchIPv6(const char* pattern, int patternLen,
1327213272
}
1327313273
#endif /* WOLFSSL_IP_ALT_NAME && !WOLFSSL_USER_IO */
1327413274

13275+
/* Returns 1 if name is a syntactically valid DNS FQDN per RFC 952/1123.
13276+
*
13277+
* Rules enforced:
13278+
* - Total effective length (excluding optional trailing dot) in [1, 253]
13279+
* - Each label is 1-63 octets of [a-zA-Z0-9-]
13280+
* - No label starts or ends with '-'
13281+
* - At least two labels (single-label names are not "fully qualified")
13282+
* - Final label (TLD) contains at least one letter (rejects all-numeric
13283+
* strings that could be confused with IPv4 literals, and matches the
13284+
* ICANN constraint that TLDs are alphabetic)
13285+
* - Optional trailing dot is accepted (absolute FQDN form)
13286+
* - Internationalized names are valid in their ACE/punycode (xn--) form
13287+
*/
13288+
static int IsValidFQDN(const char* name, word32 nameSz)
13289+
{
13290+
word32 i;
13291+
int labelLen = 0;
13292+
int labelCount = 0;
13293+
int tldHasAlpha = 0; /* tracks alpha presence in the *current* label */
13294+
13295+
if (name == NULL || nameSz <= 0)
13296+
return 0;
13297+
13298+
/* Strip a single optional trailing dot before measuring. "example.com."
13299+
* is the absolute form of the same FQDN.
13300+
*/
13301+
if (name[nameSz - 1] == '.')
13302+
--nameSz;
13303+
13304+
if (nameSz < 1 || nameSz > 253)
13305+
return 0;
13306+
13307+
for (i = 0; i < nameSz; i++) {
13308+
byte c = (byte)name[i];
13309+
13310+
if (c == '.') {
13311+
if (labelLen == 0 || name[i - 1] == '-')
13312+
return 0; /* empty label or label ending in '-' */
13313+
++labelCount;
13314+
labelLen = 0;
13315+
tldHasAlpha = 0; /* reset for next label */
13316+
continue;
13317+
}
13318+
13319+
if (++labelLen > 63)
13320+
return 0;
13321+
13322+
if (c == '-') {
13323+
if (labelLen == 1) /* label starts with '-' */
13324+
return 0;
13325+
}
13326+
else if (((c | 0x20) >= 'a') && ((c | 0x20) <= 'z')) {
13327+
tldHasAlpha = 1;
13328+
}
13329+
else if ((c < '0') || (c > '9')) {
13330+
return 0; /* character outside [a-zA-Z0-9-] */
13331+
}
13332+
}
13333+
13334+
/* Final label (no trailing dot in the effective range to close it) */
13335+
if ((labelLen == 0) || (name[nameSz - 1] == '-'))
13336+
return 0;
13337+
++labelCount;
13338+
13339+
/* Technically, "Fully qualified" requires at least two labels, and the TLD
13340+
* must not be purely numeric (no such TLD exists; also rejects bare IPv4).
13341+
* We enforce the not-purely-numeric rule, but we allow single labels, so
13342+
* that ad hoc "localhost" CN is allowed.
13343+
*/
13344+
return ((labelCount > 0) && tldHasAlpha);
13345+
}
13346+
1327513347
/* Match names with wildcards, each wildcard can represent a single name
1327613348
component or fragment but not multiple names, i.e.,
1327713349
*.z.com matches y.z.com but not x.y.z.com
@@ -13296,6 +13368,19 @@ int MatchDomainName(const char* pattern, int patternLen, const char* str,
1329613368
return 1;
1329713369
#endif
1329813370

13371+
if (! IsValidFQDN(str, strLen)) {
13372+
/* Not a valid FQDN or IPv6 address -- require byte-exact match, no case
13373+
* folding, no wildcard interpretation. This is appropriate for an IPv4
13374+
* match, for example.
13375+
*/
13376+
return (((word32)patternLen == strLen) &&
13377+
(XMEMCMP(pattern, str, patternLen) == 0));
13378+
}
13379+
13380+
/* strip trailing dot if necessary (FQDN designator). */
13381+
if (str[strLen-1] == '.')
13382+
--strLen;
13383+
1329913384
while (patternLen > 0) {
1330013385
/* Get the next pattern char to evaluate */
1330113386
char p = (char)XTOLOWER((unsigned char)*pattern);

0 commit comments

Comments
 (0)