6 /** A picky certificate name check:
7 * check if the pattern or string in s1 (from a certificate) matches the
8 * hostname (in s2), returns true if matched.
10 * The only place where a wildcard is allowed is in the leftmost
12 int name_match(const char *p1, const char *p2) {
13 const char *const dom = "0123456789.";
16 /* blank patterns never match */
20 /* disallow wildcards in certificates for domain literals
22 if (strspn(p1+(*p1 == '*' ? 1 : 0), dom) == strlen(p1))
25 /* disallow wildcards for domain literals */
26 if (strspn(p2, dom) == strlen(p2))
29 /* If we decided above that wildcarding is still OK,
30 * try a wildcard match first - providing that
31 * the wildcard is for a full component,
32 * i. e. starts with "*." */
33 if (wildcard_ok && p1[0] == '*' && p1[1] == '.') {
38 /* skip over the asterisk */
41 /* make sure CAs don't wildcard top-level domains by requiring there
42 * are at least two dots in wildcarded X.509 CN/SANs */
43 for(tmp = p1; *tmp; tmp += strcspn(tmp, ".")) {
50 /* If there are at least 2 dots, do the wildcard match.
51 * Match from the end by incrementing the p2 pointer by the
52 * length difference between remainder of pattern and string to
54 if (number_dots >= 2) {
63 /* Now to the match. Either wildcards are forbidden or not found,
64 * then it's a case-insensitive full-string match, or wildcards are
65 * permitted and found and we've bumped the start-string pointers
67 return (0 == strcasecmp(p1, p2));
69 /* XXX open issue: do we need to deal with trailing dots in patterns
70 * or domains? A trailing dot is an anchor that prevents resolver
71 * "search"es to DNS, so might cause false mismatches. */
80 /* print test and return true on failure */
81 static int test(const char *p1, const char *p2, int expect) {
82 int match = name_match(p1, p2);
84 printf("name_match(\"%s\", \"%s\") == %d (%d expected)\n", p1, p2, match, expect);
85 return expect != match;
88 int main(int argc, const char **argv) {
91 if (argc > 1 && 0 == strcmp(argv[1], "-v"))
94 rc |= test("example.org", "example.org", 1);
95 rc |= test("*example.org", "foo.example.org", 0);
96 rc |= test("*.example.org", "foo.example.org", 1);
97 rc |= test("*.168.23.23", "192.168.23.23", 0);
98 rc |= test("*.com", "example.com", 0);
100 printf("x509_name_match: ");
101 puts(rc ? "FAIL" : "PASS");