Now libcurl (built with OpenSSL) doesn't return error anymore if the remote
authorDaniel Stenberg <daniel@haxx.se>
Mon, 3 Dec 2007 11:39:27 +0000 (11:39 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 3 Dec 2007 11:39:27 +0000 (11:39 +0000)
SSL-based server doesn't present a certificate when the request is told to
ignore certificate verification anyway.

CHANGES
lib/ssluse.c

diff --git a/CHANGES b/CHANGES
index f9c3b71..bcacca5 100644 (file)
--- 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
index 8aa78f3..6b1835e 100644 (file)
@@ -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;
 }