From 6494889e3ba6b1432258f0a8ed402723607cff21 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 7 Oct 2003 21:46:47 +0000 Subject: [PATCH] Neil Dunbar provided a patch that now makes libcurl check SSL subjectAltNames when matching certs. This is apparently detailed in RFC2818 as the right thing to do. I had to add configure checks for inet_pton() and our own (strictly speaking, code from BIND written by Paul Vixie) provided code for the function for platforms that miss it. --- lib/Makefile.am | 2 +- lib/inet_pton.c | 226 ++++++++++++++++++++++++++++++++++++++++ lib/inet_pton.h | 34 ++++++ lib/ssluse.c | 272 ++++++++++++++++++++++++++++++++++-------------- 4 files changed, 454 insertions(+), 80 deletions(-) create mode 100644 lib/inet_pton.c create mode 100644 lib/inet_pton.h diff --git a/lib/Makefile.am b/lib/Makefile.am index 691d7b741..f1bd00823 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -78,7 +78,7 @@ memdebug.h inet_ntoa_r.h http_chunks.c http_chunks.h strtok.c strtok.h \ connect.c connect.h llist.c llist.h hash.c hash.h multi.c \ content_encoding.c content_encoding.h share.c share.h http_digest.c \ md5.c md5.h http_digest.h http_negotiate.c http_negotiate.h \ -http_ntlm.c http_ntlm.h ca-bundle.h +http_ntlm.c http_ntlm.h ca-bundle.h inet_pton.c inet_pton.h noinst_HEADERS = setup.h transfer.h diff --git a/lib/inet_pton.c b/lib/inet_pton.c new file mode 100644 index 000000000..0945bdcb4 --- /dev/null +++ b/lib/inet_pton.c @@ -0,0 +1,226 @@ +/* This is from the BIND 4.9.4 release, modified to compile by itself */ + +/* Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +#include "setup.h" + +#ifndef HAVE_INET_PTON + +#include +#include +#include +#include +#include +#include +#include + +#define IN6ADDRSZ 16 +#define INADDRSZ 4 +#define INT16SZ 2 + +#ifndef AF_INET6 +#define AF_INET6 AF_MAX+1 /* just to let this compile */ +#endif + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4(const char *src, u_char *dst); +static int inet_pton6(const char *src, u_char *dst); + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +Curl_inet_pton(af, src, dst) + int af; + const char *src; + void *dst; +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); + case AF_INET6: + return (inet_pton6(src, dst)); + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(src, dst) + const char *src; + u_char *dst; +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + u_char tmp[INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + u_int new = *tp * 10 + (pch - digits); + + if (new > 255) + return (0); + *tp = new; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + /* bcopy(tmp, dst, INADDRSZ); */ + memcpy(dst, tmp, INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton6(src, dst) + const char *src; + u_char *dst; +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + + memset((tp = tmp), 0, IN6ADDRSZ); + endp = tp + IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + /* bcopy(tmp, dst, IN6ADDRSZ); */ + memcpy(dst, tmp, IN6ADDRSZ); + return (1); +} + +#endif /* HAVE_INET_PTON */ diff --git a/lib/inet_pton.h b/lib/inet_pton.h new file mode 100644 index 000000000..d758e06d2 --- /dev/null +++ b/lib/inet_pton.h @@ -0,0 +1,34 @@ +#ifndef __INET_PTON_H +#define __INET_PTON_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2003, 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 + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * $Id$ + ***************************************************************************/ + +#include "setup.h" + +#ifdef HAVE_INET_PTON +#define Curl_inet_pton(x,y,z) inet_pton(x,y,z) +#else +int Curl_inet_pton(int, const char *, void *); +#endif + +#endif /* __INET_PTON_H */ diff --git a/lib/ssluse.c b/lib/ssluse.c index 14142822b..8b04ccf1f 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -30,6 +30,7 @@ #include #include +#include #ifdef HAVE_SYS_TYPES_H #include #endif @@ -41,9 +42,11 @@ #include "sendf.h" #include "formdata.h" /* for the boundary function */ #include "url.h" /* for the ssl config check function */ +#include "inet_pton.h" #ifdef USE_SSLEAY #include +#include /* The last #include file should be: */ #ifdef CURLDEBUG @@ -191,7 +194,7 @@ int random_the_seed(struct SessionHandle *data) /* generates a default path for the random seed file */ buf[0]=0; /* blank it first */ RAND_file_name(buf, BUFSIZE); - if ( buf[0] ) { + if(buf[0]) { /* we got a file name to try */ nread += RAND_load_file(buf, 16384); if(seed_enough(nread)) @@ -207,13 +210,13 @@ int random_the_seed(struct SessionHandle *data) #endif static int do_file_type(const char *type) { - if (!type || !type[0]) + if(!type || !type[0]) return SSL_FILETYPE_PEM; - if (curl_strequal(type, "PEM")) + if(curl_strequal(type, "PEM")) return SSL_FILETYPE_PEM; - if (curl_strequal(type, "DER")) + if(curl_strequal(type, "DER")) return SSL_FILETYPE_ASN1; - if (curl_strequal(type, "ENG")) + if(curl_strequal(type, "ENG")) return SSL_FILETYPE_ENGINE; return -1; } @@ -228,7 +231,7 @@ int cert_stuff(struct connectdata *conn, struct SessionHandle *data = conn->data; int file_type; - if (cert_file != NULL) { + if(cert_file != NULL) { SSL *ssl; X509 *x509; @@ -255,7 +258,7 @@ int cert_stuff(struct connectdata *conn, switch(file_type) { case SSL_FILETYPE_PEM: /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ - if (SSL_CTX_use_certificate_chain_file(conn->ssl.ctx, + if(SSL_CTX_use_certificate_chain_file(conn->ssl.ctx, cert_file) != 1) { failf(data, "unable to set certificate file (wrong password?)"); return 0; @@ -266,7 +269,7 @@ int cert_stuff(struct connectdata *conn, /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but we use the case above for PEM so this can only be performed with ASN1 files. */ - if (SSL_CTX_use_certificate_file(conn->ssl.ctx, + if(SSL_CTX_use_certificate_file(conn->ssl.ctx, cert_file, file_type) != 1) { failf(data, "unable to set certificate file (wrong password?)"); @@ -286,11 +289,11 @@ int cert_stuff(struct connectdata *conn, switch(file_type) { case SSL_FILETYPE_PEM: - if (key_file == NULL) + if(key_file == NULL) /* cert & key can only be in PEM case in the same file */ key_file=cert_file; case SSL_FILETYPE_ASN1: - if (SSL_CTX_use_PrivateKey_file(conn->ssl.ctx, + if(SSL_CTX_use_PrivateKey_file(conn->ssl.ctx, key_file, file_type) != 1) { failf(data, "unable to set private key file: '%s' type %s\n", @@ -302,11 +305,11 @@ int cert_stuff(struct connectdata *conn, #ifdef HAVE_OPENSSL_ENGINE_H { /* XXXX still needs some work */ EVP_PKEY *priv_key = NULL; - if (conn && conn->data && conn->data->engine) { + if(conn && conn->data && conn->data->engine) { #ifdef HAVE_ENGINE_LOAD_FOUR_ARGS UI_METHOD *ui_method = UI_OpenSSL(); #endif - if (!key_file || !key_file[0]) { + if(!key_file || !key_file[0]) { failf(data, "no key set to load from crypto engine\n"); return 0; } @@ -315,11 +318,11 @@ int cert_stuff(struct connectdata *conn, ui_method, #endif data->set.key_passwd); - if (!priv_key) { + if(!priv_key) { failf(data, "failed to load private key from crypto engine\n"); return 0; } - if (SSL_CTX_use_PrivateKey(conn->ssl.ctx, priv_key) != 1) { + if(SSL_CTX_use_PrivateKey(conn->ssl.ctx, priv_key) != 1) { failf(data, "unable to set private key\n"); EVP_PKEY_free(priv_key); return 0; @@ -346,7 +349,7 @@ int cert_stuff(struct connectdata *conn, /* This version was provided by Evan Jordan and is supposed to not leak memory as the previous version: */ - if (x509 != NULL) { + if(x509 != NULL) { EVP_PKEY *pktmp = X509_get_pubkey(x509); EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl)); EVP_PKEY_free(pktmp); @@ -360,7 +363,7 @@ int cert_stuff(struct connectdata *conn, /* Now we know that a key and cert have been set against * the SSL context */ - if (!SSL_CTX_check_private_key(conn->ssl.ctx)) { + if(!SSL_CTX_check_private_key(conn->ssl.ctx)) { failf(data, "Private key does not match the certificate public key"); return(0); } @@ -457,7 +460,7 @@ void Curl_SSL_cleanup(void) */ void Curl_SSL_Close(struct connectdata *conn) { - if (conn->ssl.use) { + if(conn->ssl.use) { /* ERR_remove_state() frees the error queue associated with thread pid. If pid == 0, the current thread will have its @@ -583,7 +586,7 @@ int Curl_SSL_Close_All(struct SessionHandle *data) free(data->state.session); } #ifdef HAVE_OPENSSL_ENGINE_H - if (data->engine) + if(data->engine) { ENGINE_free(data->engine); data->engine = NULL; @@ -669,28 +672,28 @@ static int Curl_ASN1_UTCTIME_output(struct connectdata *conn, i=tm->length; asn1_string=(char *)tm->data; - if (i < 10) + if(i < 10) return 1; - if (asn1_string[i-1] == 'Z') + if(asn1_string[i-1] == 'Z') gmt=TRUE; for (i=0; i<10; i++) - if ((asn1_string[i] > '9') || (asn1_string[i] < '0')) + if((asn1_string[i] > '9') || (asn1_string[i] < '0')) return 2; year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0'); - if (year < 50) + if(year < 50) year+=100; month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0'); - if ((month > 12) || (month < 1)) + if((month > 12) || (month < 1)) return 3; day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0'); hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0'); minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0'); - if ( (asn1_string[10] >= '0') && (asn1_string[10] <= '9') && - (asn1_string[11] >= '0') && (asn1_string[11] <= '9')) + if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') && + (asn1_string[11] >= '0') && (asn1_string[11] <= '9')) second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0'); infof(data, @@ -742,6 +745,148 @@ cert_hostcheck(const char *certname, const char *hostname) } #endif +static CURLcode verifyhost(struct connectdata *conn) +{ + char peer_CN[257]; + int ntype = 3; /* 1 = IPv6, 2 = IPv4, 3=DNS */ + int i; + int altmatch = 0; +#ifdef ENABLE_IPV6 + struct in6_addr addr; +#else + struct in_addr addr; +#endif + char *ptr; + struct SessionHandle *data = conn->data; + +#ifdef ENABLE_IPV6 + if(conn->hostname[0] == '[' && strchr(conn->hostname, ']')) { + char *n2 = strdup(conn->hostname+1); + *strchr(n2, ']') = '\0'; + if(Curl_inet_pton(AF_INET6, n2, &addr)) + ntype = 1; + free(n2); + } + else +#endif + { + if((ptr = strrchr(conn->hostname, '.')) && + isdigit((unsigned char)ptr[1])) { + if(Curl_inet_pton(AF_INET, conn->hostname, &addr)) + ntype = 2; + } + } + + i = X509_get_ext_by_NID(conn->ssl.server_cert, NID_subject_alt_name, -1); + if(i >= 0) { + X509_EXTENSION *ex; + STACK_OF(GENERAL_NAME) *alt; + + ex = X509_get_ext(conn->ssl.server_cert, i); + alt = X509V3_EXT_d2i(ex); + if(alt) { + int n, len1 = 0, len2 = 0; + char *domain = NULL; + GENERAL_NAME *gn; + + if(ntype == 3) { + len1 = strlen(conn->hostname); + domain = strchr(conn->hostname, '.'); + if(domain) { + len2 = len1 - (domain-conn->hostname); + } + } + n = sk_GENERAL_NAME_num(alt); + for (i=0; itype == GEN_DNS) { + if(ntype != 3) + continue; + + sn = (char *) ASN1_STRING_data(gn->d.ia5); + sl = ASN1_STRING_length(gn->d.ia5); + + /* Is this an exact match? */ + if((len1 == sl) && curl_strnequal(conn->hostname, sn, len1)) + break; + + /* Is this a wildcard match? */ + if((*sn == '*') && domain && (len2 == sl-1) && + curl_strnequal(domain, sn+1, len2)) + break; + + } + else if(gn->type == GEN_IPADD) { + if(ntype == 3) + continue; + + sn = (char *) ASN1_STRING_data(gn->d.ia5); + sl = ASN1_STRING_length(gn->d.ia5); + +#ifdef ENABLE_IPv6 + if(ntype == 1 && sl != sizeof(struct in6_addr)) + continue; + else +#endif + if(ntype == 2 && sl != sizeof(struct in_addr)) + continue; + + if(!memcmp(sn, &addr, sl)) + break; + } + } + + GENERAL_NAMES_free(alt); + if(i < n) { /* got a match in altnames */ + altmatch = 1; + infof(data, "\t subjectAltName: %s matched\n", conn->hostname); + } + } + } + + if(!altmatch) { + bool obtain=FALSE; + if(X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert), + NID_commonName, + peer_CN, + sizeof(peer_CN)) < 0) { + if(data->set.ssl.verifyhost > 1) { + failf(data, + "SSL: unable to obtain common name from peer certificate"); + X509_free(conn->ssl.server_cert); + return CURLE_SSL_PEER_CERTIFICATE; + } + else { + /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we + output a note about the situation */ + infof(data, "\t common name: WARNING couldn't obtain\n"); + } + } + else + obtain = TRUE; + + if(obtain) { + if(!cert_hostcheck(peer_CN, conn->hostname)) { + if(data->set.ssl.verifyhost > 1) { + failf(data, "SSL: certificate subject name '%s' does not match " + "target host name '%s'", peer_CN, conn->hostname); + X509_free(conn->ssl.server_cert); + return CURLE_SSL_PEER_CERTIFICATE; + } + else + infof(data, "\t common name: %s (does not match '%s')\n", + peer_CN, conn->hostname); + } + else + infof(data, "\t common name: %s (matched)\n", peer_CN); + } + } + + return CURLE_OK; +} + /* ====================================================== */ CURLcode Curl_SSLConnect(struct connectdata *conn) @@ -803,19 +948,19 @@ Curl_SSLConnect(struct connectdata *conn) SSL_CTX_set_options(conn->ssl.ctx, SSL_OP_ALL); if(data->set.cert) { - if (!cert_stuff(conn, - data->set.cert, - data->set.cert_type, - data->set.key, - data->set.key_type)) { + if(!cert_stuff(conn, + data->set.cert, + data->set.cert_type, + data->set.key, + data->set.key_type)) { /* failf() is already done in cert_stuff() */ return CURLE_SSL_CERTPROBLEM; } } if(data->set.ssl.cipher_list) { - if (!SSL_CTX_set_cipher_list(conn->ssl.ctx, - data->set.ssl.cipher_list)) { + if(!SSL_CTX_set_cipher_list(conn->ssl.ctx, + data->set.ssl.cipher_list)) { failf(data, "failed setting cipher list"); return CURLE_SSL_CIPHER; } @@ -826,10 +971,10 @@ Curl_SSLConnect(struct connectdata *conn) SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT| SSL_VERIFY_CLIENT_ONCE, cert_verify_callback); - if ((data->set.ssl.CAfile || data->set.ssl.CApath) && - !SSL_CTX_load_verify_locations(conn->ssl.ctx, - data->set.ssl.CAfile, - data->set.ssl.CApath)) { + if((data->set.ssl.CAfile || data->set.ssl.CApath) && + !SSL_CTX_load_verify_locations(conn->ssl.ctx, + data->set.ssl.CAfile, + data->set.ssl.CApath)) { failf(data,"error setting certificate verify locations"); return CURLE_SSL_CACERT; } @@ -838,10 +983,10 @@ Curl_SSLConnect(struct connectdata *conn) SSL_CTX_set_verify(conn->ssl.ctx, SSL_VERIFY_NONE, cert_verify_callback); /* give application a chance to interfere with SSL set up. */ - if (data->set.ssl.fsslctx) { + if(data->set.ssl.fsslctx) { retcode = (*data->set.ssl.fsslctx)(data, conn->ssl.ctx, data->set.ssl.fsslctxp); - if (retcode) { + if(retcode) { failf(data,"error signaled by ssl ctx callback"); return retcode; } @@ -996,15 +1141,15 @@ Curl_SSLConnect(struct connectdata *conn) * attack */ - conn->ssl.server_cert = SSL_get_peer_certificate (conn->ssl.handle); + conn->ssl.server_cert = SSL_get_peer_certificate(conn->ssl.handle); if(!conn->ssl.server_cert) { failf(data, "SSL: couldn't get peer certificate!"); return CURLE_SSL_PEER_CERTIFICATE; } infof (data, "Server certificate:\n"); - str = X509_NAME_oneline (X509_get_subject_name (conn->ssl.server_cert), - NULL, 0); + str = X509_NAME_oneline(X509_get_subject_name(conn->ssl.server_cert), + NULL, 0); if(!str) { failf(data, "SSL: couldn't get X509-subject!"); X509_free(conn->ssl.server_cert); @@ -1019,45 +1164,14 @@ Curl_SSLConnect(struct connectdata *conn) certdate = X509_get_notAfter(conn->ssl.server_cert); Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate); - if (data->set.ssl.verifyhost) { - char peer_CN[257]; - if (X509_NAME_get_text_by_NID(X509_get_subject_name(conn->ssl.server_cert), - NID_commonName, - peer_CN, - sizeof(peer_CN)) < 0) { - /* Failed to get the CN field from the server's certificate */ - if (data->set.ssl.verifyhost > 1) { - failf(data, "SSL: unable to obtain common name from peer certificate"); - X509_free(conn->ssl.server_cert); - return CURLE_SSL_PEER_CERTIFICATE; - } - else - /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we - output a note about the situation */ - infof(data, "\t common name: WARNING couldn't obtain\n"); - } - else { - /* Compare the CN field with the remote host name */ - if (!cert_hostcheck(peer_CN, conn->hostname)) { - if (data->set.ssl.verifyhost > 1) { - failf(data, "SSL: certificate subject name '%s' does not match " - "target host name '%s'", - peer_CN, conn->hostname); - X509_free(conn->ssl.server_cert); - return CURLE_SSL_PEER_CERTIFICATE; - } - else - infof(data, - "\t common name: %s (does not match '%s')\n", - peer_CN, conn->hostname); - } - else - infof(data, "\t common name: %s (matched)\n", peer_CN); - } + if(data->set.ssl.verifyhost) { + retcode = verifyhost(conn); + if(retcode) + return retcode; } - str = X509_NAME_oneline (X509_get_issuer_name (conn->ssl.server_cert), - NULL, 0); + str = X509_NAME_oneline(X509_get_issuer_name(conn->ssl.server_cert), + NULL, 0); if(!str) { failf(data, "SSL: couldn't get X509-issuer name!"); X509_free(conn->ssl.server_cert); @@ -1071,7 +1185,7 @@ Curl_SSLConnect(struct connectdata *conn) if(data->set.ssl.verifypeer) { data->set.ssl.certverifyresult=SSL_get_verify_result(conn->ssl.handle); - if (data->set.ssl.certverifyresult != X509_V_OK) { + if(data->set.ssl.certverifyresult != X509_V_OK) { failf(data, "SSL certificate verify result: %d", data->set.ssl.certverifyresult); retcode = CURLE_SSL_PEER_CERTIFICATE;