diff -rup curl-7.10.6.orig/lib/ssluse.c curl-7.10.6/lib/ssluse.c --- curl-7.10.6.orig/lib/ssluse.c 2009-08-08 10:41:32.442607231 +0200 +++ curl-7.10.6/lib/ssluse.c 2009-08-08 10:53:52.459515245 +0200 @@ -736,6 +736,95 @@ cert_hostcheck(const char *certname, con } #endif +static CURLcode verifyhost(struct connectdata *conn, + X509 *server_cert) +{ + struct SessionHandle *data = conn->data; + + /* we have to look to the last occurence of a commonName in the + distinguished one to get the most significant one. */ + int j,i=-1 ; + +/* The following is done because of a bug in 0.9.6b */ + + unsigned char *nulstr = (unsigned char *)""; + unsigned char *peer_CN = nulstr; + + X509_NAME *name = X509_get_subject_name(server_cert) ; + if (name) + while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0) + i=j; + + /* we have the name entry and we will now convert this to a string + that we can use for comparison. Doing this we support BMPstring, + UTF8 etc. */ + + if (i>=0) { + ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i)); + + /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input + is already UTF-8 encoded. We check for this case and copy the raw + string manually to avoid the problem. This code can be made + conditional in the future when OpenSSL has been fixed. Work-around + brought by Alexis S. L. Carvalho. */ + if(tmp) { + if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) { + j = ASN1_STRING_length(tmp); + if(j >= 0) { + peer_CN = OPENSSL_malloc(j+1); + if(peer_CN) { + memcpy(peer_CN, ASN1_STRING_data(tmp), j); + peer_CN[j] = '\0'; + } + } + } + else /* not a UTF8 name */ + j = ASN1_STRING_to_UTF8(&peer_CN, tmp); + + if(peer_CN && ((int)strlen((char *)peer_CN) != j)) { + /* there was a terminating zero before the end of string, this + cannot match and we return failure! */ + failf(data, "SSL: illegal cert name field"); + if (peer_CN != nulstr) + OPENSSL_free(peer_CN); + return CURLE_SSL_PEER_CERTIFICATE; + } + } + } + + if (peer_CN == nulstr) + peer_CN = NULL; + + if (!peer_CN) { + if(data->set.ssl.verifyhost > 1) { + failf(data, + "SSL: unable to obtain common name from peer certificate"); + 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 if(!cert_hostcheck((const char *)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); + OPENSSL_free(peer_CN); + 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); + OPENSSL_free(peer_CN); + } + return CURLE_OK; +} + /* ====================================================== */ CURLcode Curl_SSLConnect(struct connectdata *conn) @@ -1013,32 +1102,12 @@ 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) { - failf(data, "SSL: unable to obtain common name from peer certificate"); - X509_free(conn->ssl.server_cert); - return CURLE_SSL_PEER_CERTIFICATE; - } - - 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); + if(data->set.ssl.verifyhost) { + retcode = verifyhost(conn, conn->ssl.server_cert); + if(retcode) { + X509_free(conn->ssl.server_cert); + return retcode; } - else - infof(data, "\t common name: %s (matched)\n", peer_CN); } str = X509_NAME_oneline (X509_get_issuer_name (conn->ssl.server_cert),