From 2be50baf975ffaad77e7356d217af209431916f8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 3 Dec 2007 11:39:27 +0000 Subject: Now libcurl (built with OpenSSL) doesn't return error anymore if the remote SSL-based server doesn't present a certificate when the request is told to ignore certificate verification anyway. --- CHANGES | 4 ++ lib/ssluse.c | 137 ++++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 88 insertions(+), 53 deletions(-) diff --git a/CHANGES b/CHANGES index f9c3b7131..bcacca5b2 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,10 @@ Daniel S (3 Dec 2007) +- Now libcurl (built with OpenSSL) doesn't return error anymore if the remote + SSL-based server doesn't present a certificate when the request is told to + ignore certificate verification anyway. + - Michal Marek introduced CURLOPT_PROXY_TRANSFER_MODE which is used to control the appending of the "type=" thing on FTP URLs when they are passed to a HTTP proxy. Some proxies just don't like that appending (which is done diff --git a/lib/ssluse.c b/lib/ssluse.c index 8aa78f367..6b1835e5b 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -1569,61 +1569,27 @@ Curl_ossl_connect_step2(struct connectdata *conn, } } -static CURLcode -Curl_ossl_connect_step3(struct connectdata *conn, - int sockindex) +/* + * Get the server cert, verify it and show it etc, only call failf() if the + * 'strict' argument is TRUE as otherwise all this is for informational + * purposes only! + * + * We check certificates to authenticate the server; otherwise we risk + * man-in-the-middle attack. + */ +static CURLcode servercert(struct connectdata *conn, + struct ssl_connect_data *connssl, + bool strict) { - CURLcode retcode = CURLE_OK; - char * str; + CURLcode retcode; + char *str; long lerr; ASN1_TIME *certdate; - void *ssl_sessionid=NULL; struct SessionHandle *data = conn->data; - struct ssl_connect_data *connssl = &conn->ssl[sockindex]; - - DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); - - if(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { - /* Since this is not a cached session ID, then we want to stach this one - in the cache! */ - SSL_SESSION *our_ssl_sessionid; -#ifdef HAVE_SSL_GET1_SESSION - our_ssl_sessionid = SSL_get1_session(connssl->handle); - - /* SSL_get1_session() will increment the reference - count and the session will stay in memory until explicitly freed with - SSL_SESSION_free(3), regardless of its state. - This function was introduced in openssl 0.9.5a. */ -#else - our_ssl_sessionid = SSL_get_session(connssl->handle); - - /* if SSL_get1_session() is unavailable, use SSL_get_session(). - This is an inferior option because the session can be flushed - at any time by openssl. It is included only so curl compiles - under versions of openssl < 0.9.5a. - - WARNING: How curl behaves if it's session is flushed is - untested. - */ -#endif - retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, - 0 /* unknown size */); - if(retcode) { - failf(data, "failed to store ssl session"); - return retcode; - } - } - - - /* Get server's certificate (note: beware of dynamic allocation) - opt */ - /* major serious hack alert -- we should check certificates - * to authenticate the server; otherwise we risk man-in-the-middle - * attack - */ - connssl->server_cert = SSL_get_peer_certificate(connssl->handle); if(!connssl->server_cert) { - failf(data, "SSL: couldn't get peer certificate!"); + if(strict) + failf(data, "SSL: couldn't get peer certificate!"); return CURLE_PEER_FAILED_VERIFICATION; } infof (data, "Server certificate:\n"); @@ -1631,7 +1597,8 @@ Curl_ossl_connect_step3(struct connectdata *conn, str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert), NULL, 0); if(!str) { - failf(data, "SSL: couldn't get X509-subject!"); + if(strict) + failf(data, "SSL: couldn't get X509-subject!"); X509_free(connssl->server_cert); connssl->server_cert = NULL; return CURLE_SSL_CONNECT_ERROR; @@ -1657,7 +1624,8 @@ Curl_ossl_connect_step3(struct connectdata *conn, str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert), NULL, 0); if(!str) { - failf(data, "SSL: couldn't get X509-issuer name!"); + if(strict) + failf(data, "SSL: couldn't get X509-issuer name!"); retcode = CURLE_SSL_CONNECT_ERROR; } else { @@ -1673,8 +1641,9 @@ Curl_ossl_connect_step3(struct connectdata *conn, if(data->set.ssl.verifypeer) { /* We probably never reach this, because SSL_connect() will fail and we return earlyer if verifypeer is set? */ - failf(data, "SSL certificate verify result: %s (%ld)", - X509_verify_cert_error_string(lerr), lerr); + if(strict) + failf(data, "SSL certificate verify result: %s (%ld)", + X509_verify_cert_error_string(lerr), lerr); retcode = CURLE_PEER_FAILED_VERIFICATION; } else @@ -1689,6 +1658,68 @@ Curl_ossl_connect_step3(struct connectdata *conn, X509_free(connssl->server_cert); connssl->server_cert = NULL; connssl->connecting_state = ssl_connect_done; + + return retcode; +} + + +static CURLcode +Curl_ossl_connect_step3(struct connectdata *conn, + int sockindex) +{ + CURLcode retcode = CURLE_OK; + void *ssl_sessionid=NULL; + struct SessionHandle *data = conn->data; + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; + + DEBUGASSERT(ssl_connect_3 == connssl->connecting_state); + + if(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) { + /* Since this is not a cached session ID, then we want to stach this one + in the cache! */ + SSL_SESSION *our_ssl_sessionid; +#ifdef HAVE_SSL_GET1_SESSION + our_ssl_sessionid = SSL_get1_session(connssl->handle); + + /* SSL_get1_session() will increment the reference + count and the session will stay in memory until explicitly freed with + SSL_SESSION_free(3), regardless of its state. + This function was introduced in openssl 0.9.5a. */ +#else + our_ssl_sessionid = SSL_get_session(connssl->handle); + + /* if SSL_get1_session() is unavailable, use SSL_get_session(). + This is an inferior option because the session can be flushed + at any time by openssl. It is included only so curl compiles + under versions of openssl < 0.9.5a. + + WARNING: How curl behaves if it's session is flushed is + untested. + */ +#endif + retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, + 0 /* unknown size */); + if(retcode) { + failf(data, "failed to store ssl session"); + return retcode; + } + } + + + /* + * We check certificates to authenticate the server; otherwise we risk + * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to + * verify the peer ignore faults and failures from the server cert + * operations. + */ + + if(!data->set.ssl.verifypeer) + (void)servercert(conn, connssl, FALSE); + else + retcode = servercert(conn, connssl, TRUE); + + if(CURLE_OK == retcode) + connssl->connecting_state = ssl_connect_done; return retcode; } -- cgit v1.2.3