From: Daniel Stenberg Date: Mon, 24 Jan 2022 10:02:55 +0000 (+0100) Subject: hostcheck: fixed to not touch used input strings X-Git-Tag: curl-7_82_0~182 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=955cb99130f7ca33b0ded3242e9f494f4d0988dc;p=thirdparty%2Fcurl.git hostcheck: fixed to not touch used input strings Avoids the need to clone the strings before check, thus avoiding mallocs, which for cases where there are many SAN names in a cert could end up numerous. Closes #8321 --- diff --git a/lib/hostcheck.c b/lib/hostcheck.c index 59e34c52e7..eb3dfa3dc0 100644 --- a/lib/hostcheck.c +++ b/lib/hostcheck.c @@ -33,6 +33,7 @@ #ifdef HAVE_NETINET_IN6_H #include #endif +#include "curl_memrchr.h" #include "hostcheck.h" #include "strcase.h" @@ -42,6 +43,16 @@ /* The last #include file should be: */ #include "memdebug.h" +/* check the two input strings with given length, but do not + assume they end in nul-bytes */ +static bool pmatch(const char *hostname, size_t hostlen, + const char *pattern, size_t patternlen) +{ + if(hostlen != patternlen) + return FALSE; + return strncasecompare(hostname, pattern, hostlen); +} + /* * Match a hostname against a wildcard pattern. * E.g. @@ -58,85 +69,70 @@ * apparent distinction between a name and an IP. We need to detect the use of * an IP address and not wildcard match on such names. * - * NOTE: hostmatch() gets called with copied buffers so that it can modify the - * contents at will. + * Return TRUE on a match. FALSE if not. */ -static int hostmatch(char *hostname, char *pattern) +static bool hostmatch(const char *hostname, const char *pattern) { - const char *pattern_label_end, *pattern_wildcard, *hostname_label_end; - int wildcard_enabled; + const char *pattern_label_end, *wildcard, *hostname_label_end; size_t prefixlen, suffixlen; /* normalize pattern and hostname by stripping off trailing dots */ - size_t len = strlen(hostname); - if(hostname[len-1]=='.') - hostname[len-1] = 0; - len = strlen(pattern); - if(pattern[len-1]=='.') - pattern[len-1] = 0; - - pattern_wildcard = strchr(pattern, '*'); - if(!pattern_wildcard) - return strcasecompare(pattern, hostname) ? - CURL_HOST_MATCH : CURL_HOST_NOMATCH; + size_t patternlen; + size_t hostlen = strlen(hostname); + if(hostname[hostlen-1]=='.') + hostlen--; + patternlen = strlen(pattern); + if(pattern[patternlen-1]=='.') + patternlen--; + + wildcard = memchr(pattern, '*', patternlen); + if(!wildcard) + return pmatch(hostname, hostlen, pattern, patternlen); /* detect IP address as hostname and fail the match if so */ if(Curl_host_is_ipnum(hostname)) - return CURL_HOST_NOMATCH; + return FALSE; - /* We require at least 2 dots in pattern to avoid too wide wildcard + /* We require at least 2 dots in the pattern to avoid too wide wildcard match. */ - wildcard_enabled = 1; - pattern_label_end = strchr(pattern, '.'); - if(!pattern_label_end || !strchr(pattern_label_end + 1, '.') || - pattern_wildcard > pattern_label_end || - strncasecompare(pattern, "xn--", 4)) { - wildcard_enabled = 0; + pattern_label_end = memchr(pattern, '.', patternlen); + if(!pattern_label_end || + (memrchr(pattern, '.', patternlen) == pattern_label_end) || + strncasecompare(pattern, "xn--", 4)) + return pmatch(hostname, hostlen, pattern, patternlen); + + hostname_label_end = memchr(hostname, '.', hostlen); + if(!hostname_label_end) + return FALSE; + else { + size_t skiphost = hostname_label_end - hostname; + size_t skiplen = pattern_label_end - pattern; + if(!pmatch(hostname_label_end, hostlen - skiphost, + pattern_label_end, patternlen - skiplen)) + return FALSE; } - if(!wildcard_enabled) - return strcasecompare(pattern, hostname) ? - CURL_HOST_MATCH : CURL_HOST_NOMATCH; - - hostname_label_end = strchr(hostname, '.'); - if(!hostname_label_end || - !strcasecompare(pattern_label_end, hostname_label_end)) - return CURL_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 CURL_HOST_NOMATCH; + return FALSE; - prefixlen = pattern_wildcard - pattern; - suffixlen = pattern_label_end - (pattern_wildcard + 1); + prefixlen = wildcard - pattern; + suffixlen = pattern_label_end - (wildcard + 1); return strncasecompare(pattern, hostname, prefixlen) && - strncasecompare(pattern_wildcard + 1, hostname_label_end - suffixlen, - suffixlen) ? - CURL_HOST_MATCH : CURL_HOST_NOMATCH; + strncasecompare(wildcard + 1, hostname_label_end - suffixlen, + suffixlen) ? TRUE : FALSE; } -int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) +/* + * Curl_cert_hostcheck() returns TRUE if a match and FALSE if not. + */ +bool Curl_cert_hostcheck(const char *match, const char *hostname) { - int res = 0; - if(!match_pattern || !*match_pattern || - !hostname || !*hostname) /* sanity check */ - ; - else { - char *matchp = strdup(match_pattern); - if(matchp) { - char *hostp = strdup(hostname); - if(hostp) { - if(hostmatch(hostp, matchp) == CURL_HOST_MATCH) - res = 1; - free(hostp); - } - free(matchp); - } - } - - return res; + if(match && *match && hostname && *hostname) + return hostmatch(hostname, match); + return FALSE; } #endif /* OPENSSL, GSKIT or schannel+wince */ diff --git a/lib/hostcheck.h b/lib/hostcheck.h index 52155f43b4..b8bbb8a991 100644 --- a/lib/hostcheck.h +++ b/lib/hostcheck.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2020, Daniel Stenberg, , et al. + * Copyright (C) 1998 - 2022, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -24,8 +24,7 @@ #include -#define CURL_HOST_NOMATCH 0 -#define CURL_HOST_MATCH 1 -int Curl_cert_hostcheck(const char *match_pattern, const char *hostname); +/* returns TRUE if there's a match */ +bool Curl_cert_hostcheck(const char *match_pattern, const char *hostname); #endif /* HEADER_CURL_HOSTCHECK_H */ diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index 4966cd4945..f496a59cad 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -7,7 +7,7 @@ * * Copyright (C) 2012 - 2016, Marc Hoersken, * Copyright (C) 2012, Mark Salisbury, - * Copyright (C) 2012 - 2021, Daniel Stenberg, , et al. + * Copyright (C) 2012 - 2022, Daniel Stenberg, , et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -520,10 +520,7 @@ static CURLcode verify_host(struct Curl_easy *data, result = CURLE_OUT_OF_MEMORY; } else { - int match_result; - - match_result = Curl_cert_hostcheck(cert_hostname, conn_hostname); - if(match_result == CURL_HOST_MATCH) { + if(Curl_cert_hostcheck(cert_hostname, conn_hostname)) { infof(data, "schannel: connection hostname (%s) validated " "against certificate name (%s)",