diff options
-rw-r--r-- | lib/ssluse.c | 64 |
1 files changed, 37 insertions, 27 deletions
diff --git a/lib/ssluse.c b/lib/ssluse.c index 74563c7ee..8652cbd7c 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -1048,40 +1048,50 @@ static int asn1_output(const ASN1_UTCTIME *tm, * E.g. * "foo.host.com" matches "*.host.com". * - * We are a bit more liberal than RFC2818 describes in that we - * accept multiple "*" in pattern (similar to what some other browsers do). - * E.g. - * "abc.def.domain.com" should strickly not match "*.domain.com", but we - * don't consider "." to be important in CERT checking. + * We use the matching rule described in RFC6125, section 6.4.3. + * http://tools.ietf.org/html/rfc6125#section-6.4.3 */ #define HOST_NOMATCH 0 #define HOST_MATCH 1 static int hostmatch(const char *hostname, const char *pattern) { - for(;;) { - char c = *pattern++; - - if(c == '\0') - return (*hostname ? HOST_NOMATCH : HOST_MATCH); - - if(c == '*') { - c = *pattern; - if(c == '\0') /* "*\0" matches anything remaining */ - return HOST_MATCH; - - while(*hostname) { - /* The only recursive function in libcurl! */ - if(hostmatch(hostname++,pattern) == HOST_MATCH) - return HOST_MATCH; - } - break; - } - - if(Curl_raw_toupper(c) != Curl_raw_toupper(*hostname++)) - break; + const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; + int wildcard_enabled; + size_t prefixlen, suffixlen; + pattern_wildcard = strchr(pattern, '*'); + if(pattern_wildcard == NULL) { + return Curl_raw_equal(pattern, hostname) ? HOST_MATCH : HOST_NOMATCH; + } + /* We require at least 2 dots in pattern to avoid too wide wildcard + match. */ + wildcard_enabled = 1; + pattern_label_end = strchr(pattern, '.'); + if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL || + pattern_wildcard > pattern_label_end || + Curl_raw_nequal(pattern, "xn--", 4)) { + wildcard_enabled = 0; + } + if(!wildcard_enabled) { + return Curl_raw_equal(pattern, hostname) ? HOST_MATCH : HOST_NOMATCH; + } + hostname_label_end = strchr(hostname, '.'); + if(hostname_label_end == NULL || + !Curl_raw_equal(pattern_label_end, hostname_label_end)) { + return HOST_NOMATCH; + } + /* The wildcard must match at least one character, so the left-most + label of the hostname is at least as large as the left-most label + of the pattern. */ + if(hostname_label_end - hostname < pattern_label_end - pattern) { + return HOST_NOMATCH; } - return HOST_NOMATCH; + prefixlen = pattern_wildcard - pattern; + suffixlen = pattern_label_end - (pattern_wildcard+1); + return Curl_raw_nequal(pattern, hostname, prefixlen) && + Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen, + suffixlen) ? + HOST_MATCH : HOST_NOMATCH; } static int |