From: Henrik Holst Date: Thu, 10 Feb 2022 20:04:52 +0000 (+0100) Subject: hostcheck: reduce strlen calls on chained certificates X-Git-Tag: curl-7_82_0~85 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=65c6e37fe3f53db13501f7586b1b4ba9bfe1d6d5;p=thirdparty%2Fcurl.git hostcheck: reduce strlen calls on chained certificates Closes #8428 --- diff --git a/lib/vtls/hostcheck.c b/lib/vtls/hostcheck.c index 08a3470383..8dc97a27d0 100644 --- a/lib/vtls/hostcheck.c +++ b/lib/vtls/hostcheck.c @@ -72,14 +72,15 @@ static bool pmatch(const char *hostname, size_t hostlen, * Return TRUE on a match. FALSE if not. */ -static bool hostmatch(const char *hostname, const char *pattern, +static bool hostmatch(const char *hostname, + size_t hostlen, + const char *pattern, size_t patternlen) { const char *pattern_label_end, *wildcard, *hostname_label_end; size_t prefixlen, suffixlen; /* normalize pattern and hostname by stripping off trailing dots */ - size_t hostlen = strlen(hostname); DEBUGASSERT(patternlen); if(hostname[hostlen-1]=='.') hostlen--; @@ -129,10 +130,10 @@ static bool hostmatch(const char *hostname, const char *pattern, * Curl_cert_hostcheck() returns TRUE if a match and FALSE if not. */ bool Curl_cert_hostcheck(const char *match, size_t matchlen, - const char *hostname) + const char *hostname, size_t hostlen) { if(match && *match && hostname && *hostname) - return hostmatch(hostname, match, matchlen); + return hostmatch(hostname, hostlen, match, matchlen); return FALSE; } diff --git a/lib/vtls/hostcheck.h b/lib/vtls/hostcheck.h index c8d0507ddc..aa966403dd 100644 --- a/lib/vtls/hostcheck.h +++ b/lib/vtls/hostcheck.h @@ -26,6 +26,6 @@ /* returns TRUE if there's a match */ bool Curl_cert_hostcheck(const char *match_pattern, size_t matchlen, - const char *hostname); + const char *hostname, size_t hostlen); #endif /* HEADER_CURL_HOSTCHECK_H */ diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index a0a6730c12..fe9a6860d9 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1615,13 +1615,14 @@ static bool subj_alt_hostcheck(struct Curl_easy *data, const char *match_pattern, size_t matchlen, const char *hostname, + size_t hostlen, const char *dispname) { #ifdef CURL_DISABLE_VERBOSE_STRINGS (void)dispname; (void)data; #endif - if(Curl_cert_hostcheck(match_pattern, matchlen, hostname)) { + if(Curl_cert_hostcheck(match_pattern, matchlen, hostname, hostlen)) { infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"", dispname, match_pattern); return TRUE; @@ -1668,6 +1669,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */ const char * const hostname = SSL_HOST_NAME(); const char * const dispname = SSL_HOST_DISPNAME(); + size_t hostlen = strlen(hostname); #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1730,7 +1732,9 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, if((altlen == strlen(altptr)) && /* if this isn't true, there was an embedded zero in the name string and we cannot match it. */ - subj_alt_hostcheck(data, altptr, altlen, hostname, dispname)) { + subj_alt_hostcheck(data, + altptr, + altlen, hostname, hostlen, dispname)) { dnsmatched = TRUE; } break; @@ -1822,7 +1826,8 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, "SSL: unable to obtain common name from peer certificate"); result = CURLE_PEER_FAILED_VERIFICATION; } - else if(!Curl_cert_hostcheck((const char *)peer_CN, peerlen, hostname)) { + else if(!Curl_cert_hostcheck((const char *)peer_CN, + peerlen, hostname, hostlen)) { failf(data, "SSL: certificate subject name '%s' does not match " "target host name '%s'", peer_CN, dispname); result = CURLE_PEER_FAILED_VERIFICATION; diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index d2d3bf9233..01de3fc732 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -465,6 +465,7 @@ static CURLcode verify_host(struct Curl_easy *data, CURLcode result = CURLE_PEER_FAILED_VERIFICATION; TCHAR *cert_hostname_buff = NULL; size_t cert_hostname_buff_index = 0; + size_t hostlen = strlen(conn_hostname); DWORD len = 0; DWORD actual_len = 0; @@ -521,7 +522,7 @@ static CURLcode verify_host(struct Curl_easy *data, } else { if(Curl_cert_hostcheck(cert_hostname, strlen(cert_hostname), - conn_hostname)) { + conn_hostname, hostlen)) { infof(data, "schannel: connection hostname (%s) validated " "against certificate name (%s)", diff --git a/lib/vtls/x509asn1.c b/lib/vtls/x509asn1.c index 13fa694f2a..f64acb83c9 100644 --- a/lib/vtls/x509asn1.c +++ b/lib/vtls/x509asn1.c @@ -1275,6 +1275,7 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn, ssize_t len; const char * const hostname = SSL_HOST_NAME(); const char * const dispname = SSL_HOST_DISPNAME(); + size_t hostlen = strlen(hostname); #ifdef ENABLE_IPV6 struct in6_addr addr; #else @@ -1330,7 +1331,8 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn, len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING, name.beg, name.end); if(len > 0 && (size_t)len == strlen(dnsname)) - matched = Curl_cert_hostcheck(dnsname, (size_t)len, hostname); + matched = Curl_cert_hostcheck(dnsname, + (size_t)len, hostname, hostlen); else matched = 0; free(dnsname); @@ -1389,7 +1391,8 @@ CURLcode Curl_verifyhost(struct Curl_easy *data, struct connectdata *conn, } if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */ failf(data, "SSL: illegal cert name field"); - else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) { + else if(Curl_cert_hostcheck((const char *) dnsname, + len, hostname, hostlen)) { infof(data, " common name: %s (matched)", dnsname); free(dnsname); return CURLE_OK; diff --git a/tests/unit/unit1397.c b/tests/unit/unit1397.c index 1b47b286a0..71ea4cfac2 100644 --- a/tests/unit/unit1397.c +++ b/tests/unit/unit1397.c @@ -41,39 +41,48 @@ UNITTEST_START /* here you start doing things and checking that the results are good */ fail_unless(Curl_cert_hostcheck(STRCONST("www.example.com"), - "www.example.com"), "good 1"); -fail_unless(Curl_cert_hostcheck(STRCONST("*.example.com"), "www.example.com"), + STRCONST("www.example.com")), "good 1"); +fail_unless(Curl_cert_hostcheck(STRCONST("*.example.com"), + STRCONST("www.example.com")), "good 2"); fail_unless(Curl_cert_hostcheck(STRCONST("xxx*.example.com"), - "xxxwww.example.com"), "good 3"); -fail_unless(Curl_cert_hostcheck(STRCONST("f*.example.com"), "foo.example.com"), - "good 4"); -fail_unless(Curl_cert_hostcheck(STRCONST("192.168.0.0"), "192.168.0.0"), - "good 5"); + STRCONST("xxxwww.example.com")), "good 3"); +fail_unless(Curl_cert_hostcheck(STRCONST("f*.example.com"), + STRCONST("foo.example.com")), "good 4"); +fail_unless(Curl_cert_hostcheck(STRCONST("192.168.0.0"), + STRCONST("192.168.0.0")), "good 5"); fail_if(Curl_cert_hostcheck(STRCONST("xxx.example.com"), - "www.example.com"), "bad 1"); -fail_if(Curl_cert_hostcheck(STRCONST("*"), "www.example.com"), "bad 2"); -fail_if(Curl_cert_hostcheck(STRCONST("*.*.com"), "www.example.com"), "bad 3"); + STRCONST("www.example.com")), "bad 1"); +fail_if(Curl_cert_hostcheck(STRCONST("*"), + STRCONST("www.example.com")),"bad 2"); +fail_if(Curl_cert_hostcheck(STRCONST("*.*.com"), + STRCONST("www.example.com")), "bad 3"); fail_if(Curl_cert_hostcheck(STRCONST("*.example.com"), - "baa.foo.example.com"), "bad 4"); + STRCONST("baa.foo.example.com")), "bad 4"); fail_if(Curl_cert_hostcheck(STRCONST("f*.example.com"), - "baa.example.com"), "bad 5"); -fail_if(Curl_cert_hostcheck(STRCONST("*.com"), "example.com"), "bad 6"); -fail_if(Curl_cert_hostcheck(STRCONST("*fail.com"), "example.com"), "bad 7"); -fail_if(Curl_cert_hostcheck(STRCONST("*.example."), "www.example."), "bad 8"); -fail_if(Curl_cert_hostcheck(STRCONST("*.example."), "www.example"), "bad 9"); -fail_if(Curl_cert_hostcheck(STRCONST(""), "www"), "bad 10"); -fail_if(Curl_cert_hostcheck(STRCONST("*"), "www"), "bad 11"); -fail_if(Curl_cert_hostcheck(STRCONST("*.168.0.0"), "192.168.0.0"), "bad 12"); + STRCONST("baa.example.com")), "bad 5"); +fail_if(Curl_cert_hostcheck(STRCONST("*.com"), + STRCONST("example.com")), "bad 6"); +fail_if(Curl_cert_hostcheck(STRCONST("*fail.com"), + STRCONST("example.com")), "bad 7"); +fail_if(Curl_cert_hostcheck(STRCONST("*.example."), + STRCONST("www.example.")), "bad 8"); +fail_if(Curl_cert_hostcheck(STRCONST("*.example."), + STRCONST("www.example")), "bad 9"); +fail_if(Curl_cert_hostcheck(STRCONST(""), STRCONST("www")), "bad 10"); +fail_if(Curl_cert_hostcheck(STRCONST("*"), STRCONST("www")), "bad 11"); +fail_if(Curl_cert_hostcheck(STRCONST("*.168.0.0"), + STRCONST("192.168.0.0")), "bad 12"); fail_if(Curl_cert_hostcheck(STRCONST("www.example.com"), - "192.168.0.0"), "bad 13"); + STRCONST("192.168.0.0")), "bad 13"); #ifdef ENABLE_IPV6 fail_if(Curl_cert_hostcheck(STRCONST("*::3285:a9ff:fe46:b619"), - "fe80::3285:a9ff:fe46:b619"), "bad 14"); + STRCONST("fe80::3285:a9ff:fe46:b619")), "bad 14"); fail_unless(Curl_cert_hostcheck(STRCONST("fe80::3285:a9ff:fe46:b619"), - "fe80::3285:a9ff:fe46:b619"), "good 6"); + STRCONST("fe80::3285:a9ff:fe46:b619")), + "good 6"); #endif #endif