diff options
author | Daniel Stenberg <daniel@haxx.se> | 2016-06-15 15:36:40 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2016-06-16 10:33:15 +0200 |
commit | d4643d6e799b088e0a7e9b768facc0d1e1e86257 (patch) | |
tree | bcb479230a2ec2593d1a55905f38562ca7a41724 /lib/vtls | |
parent | b1839f6ed8bc8d9324c1fcf334955ddabf47b936 (diff) |
openssl: fix cert check with non-DNS name fields present
Regression introduced in 5f5b62635 (released in 7.48.0)
Reported-by: Fabian Ruff
Fixes #875
Diffstat (limited to 'lib/vtls')
-rw-r--r-- | lib/vtls/openssl.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index f702653cd..2f69790e9 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -1082,6 +1082,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) struct in_addr addr; #endif CURLcode result = CURLE_OK; + bool dNSName = FALSE; /* if a dNSName field exists in the cert */ #ifdef ENABLE_IPV6 if(conn->bits.ipv6_ip && @@ -1102,16 +1103,23 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) if(altnames) { int numalts; int i; + bool dnsmatched = FALSE; + bool ipmatched = FALSE; /* get amount of alternatives, RFC2459 claims there MUST be at least one, but we don't depend on it... */ numalts = sk_GENERAL_NAME_num(altnames); - /* loop through all alternatives while none has matched */ - for(i=0; (i<numalts) && !matched; i++) { + /* loop through all alternatives - until a dnsmatch */ + for(i=0; (i < numalts) && !dnsmatched; i++) { /* get a handle to alternative name number i */ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); + /* If a subjectAltName extension of type dNSName is present, that MUST + be used as the identity. / RFC2818 section 3.1 */ + if(check->type == GEN_DNS) + dNSName = TRUE; + /* only check alternatives of the same type the target is */ if(check->type == target) { /* get data and length */ @@ -1134,7 +1142,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) /* if this isn't true, there was an embedded zero in the name string and we cannot match it. */ Curl_cert_hostcheck(altptr, conn->host.name)) { - matched = TRUE; + dnsmatched = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"\n", conn->host.dispname, altptr); @@ -1145,7 +1153,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) /* compare alternative IP address if the data chunk is the same size our server IP address is */ if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { - matched = TRUE; + ipmatched = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's IP address!\n", conn->host.dispname); @@ -1155,14 +1163,19 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert) } } GENERAL_NAMES_free(altnames); + + if(dnsmatched || (!dNSName && ipmatched)) { + /* count as a match if the dnsname matched or if there was no dnsname + fields at all AND there was an IP field match */ + matched = TRUE; + } } if(matched) /* an alternative name matched */ ; - else if(altnames) { - /* an alternative name field existed, but didn't match and then we MUST - fail */ + else if(dNSName) { + /* an dNSName field existed, but didn't match and then we MUST fail */ infof(data, " subjectAltName does not match %s\n", conn->host.dispname); failf(data, "SSL: no alternative certificate subject name matches " "target host name '%s'", conn->host.dispname); |