aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2016-06-15 15:36:40 +0200
committerDaniel Stenberg <daniel@haxx.se>2016-06-16 10:33:15 +0200
commitd4643d6e799b088e0a7e9b768facc0d1e1e86257 (patch)
treebcb479230a2ec2593d1a55905f38562ca7a41724 /lib
parentb1839f6ed8bc8d9324c1fcf334955ddabf47b936 (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')
-rw-r--r--lib/vtls/openssl.c27
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);