]> granicus.if.org Git - curl/commitdiff
Gisle's "SSL patch" from June 16th 2004, modified by me as discussed on the
authorDaniel Stenberg <daniel@haxx.se>
Fri, 18 Jun 2004 06:20:43 +0000 (06:20 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Fri, 18 Jun 2004 06:20:43 +0000 (06:20 +0000)
mailing list.

CHANGES
include/curl/curl.h
lib/sendf.c
lib/ssluse.c
lib/url.c
src/main.c

diff --git a/CHANGES b/CHANGES
index 4d6fc8c9db419e638e7d2295dfc9d34981f0bef1..0a9c12d47982a6a895cd58435fe76d17ac53e73f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,16 @@
 
                                   Changelog
 
+Daniel (18 June 2004)
+- Gisle Vanem's patch that provides more details from the SSL layers (if you
+  use an OpenSSL version that supports it). It also introduces two new types
+  of data that can be sent to the debug callback: CURLINFO_SSL_DATA_IN and
+  CURLINFO_SSL_DATA_OUT.
+
+- With David Byron's test server I could repeat his problem and make sure that
+  POSTing over HTTPS:// with NTLM works fine now. There was a general problem
+  with multi-pass authentication with non-GET operations with CONNECT.
+
 Daniel (16 June 2004)
 - Modified to keep the upload byte counter in an curl_off_t, not an int as
   before. 32bits is not enough. This is most likely the bug Jean-Louis Lemaire
index 40925624661e6b7901337ee8bdadd83d6cd358ac..ef7129856c3f6f05e9943c7a5c5b61c721df0da0 100644 (file)
@@ -173,6 +173,8 @@ typedef enum {
   CURLINFO_HEADER_OUT,   /* 2 */
   CURLINFO_DATA_IN,      /* 3 */
   CURLINFO_DATA_OUT,     /* 4 */
+  CURLINFO_SSL_DATA_IN,  /* 5 */
+  CURLINFO_SSL_DATA_OUT, /* 6 */
   CURLINFO_END
 } curl_infotype;
 
index a4fbb51829abf962e33148ea7734248609affaec..b1b33a8fc313cc8e4f65f4fa39c5c3f4232d29f1 100644 (file)
@@ -204,7 +204,8 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
       break;
 
     if(data->set.verbose)
-      Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written, conn->host.dispname);
+      Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written,
+                 conn->host.dispname);
 
     if((size_t)bytes_written != write_len) {
       /* if not all was written at once, we must advance the pointer, decrease
@@ -444,7 +445,7 @@ static int showit(struct SessionHandle *data, curl_infotype type,
                   char *ptr, size_t size)
 {
   static const char * const s_infotype[CURLINFO_END] = {
-    "* ", "< ", "> ", "{ ", "} " };
+    "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
 
   if(data->set.fdebug)
     return (*data->set.fdebug)(data, type, ptr, size,
index abe29981101350a8d1b2a3bc4534b8e39f0b1ab3..54438530546c79fcbe6377e0ac745b39b298b232 100644 (file)
@@ -47,6 +47,9 @@
 #include "connect.h" /* Curl_ourerrno() proto */
 #include "strequal.h"
 
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
 #ifdef USE_SSLEAY
 #include <openssl/rand.h>
 #include <openssl/x509v3.h>
 /* The last #include file should be: */
 #include "memdebug.h"
 
+#ifndef min
+#define min(a, b)   ((a) < (b) ? (a) : (b))
+#endif
+
 #if OPENSSL_VERSION_NUMBER >= 0x0090581fL
 #define HAVE_SSL_GET1_SESSION 1
 #else
@@ -859,6 +866,7 @@ static CURLcode verifyhost(struct connectdata *conn,
           /* Is this a wildcard match? */
           else if((altptr[0] == '*') &&
                   (domainlen == altlen-1) &&
+                  domain &&
                   curl_strnequal(domain, altptr+1, domainlen))
             matched = TRUE;
           break;
@@ -938,6 +946,115 @@ static CURLcode verifyhost(struct connectdata *conn,
 }
 #endif
 
+/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
+   and thus this cannot be done there. */
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+
+static const char *ssl_msg_type(int ssl_ver, int msg)
+{
+  if (ssl_ver == SSL2_VERSION_MAJOR) {
+    switch (msg) {
+      case SSL2_MT_ERROR:
+        return "Error";
+      case SSL2_MT_CLIENT_HELLO:
+        return "Client hello";
+      case SSL2_MT_CLIENT_MASTER_KEY:
+        return "Client key";
+      case SSL2_MT_CLIENT_FINISHED:
+        return "Client finished";
+      case SSL2_MT_SERVER_HELLO:
+        return "Server hello";
+      case SSL2_MT_SERVER_VERIFY:
+        return "Server verify";
+      case SSL2_MT_SERVER_FINISHED:
+        return "Server finished";
+      case SSL2_MT_REQUEST_CERTIFICATE:
+        return "Request CERT";
+      case SSL2_MT_CLIENT_CERTIFICATE:
+        return "Client CERT";
+    }
+  }
+  else if (ssl_ver == SSL3_VERSION_MAJOR) {
+    switch (msg) {
+      case SSL3_MT_HELLO_REQUEST:
+        return "Hello request";
+      case SSL3_MT_CLIENT_HELLO:
+        return "Client hello";
+      case SSL3_MT_SERVER_HELLO:
+        return "Server hello";
+      case SSL3_MT_CERTIFICATE:
+        return "CERT";
+      case SSL3_MT_SERVER_KEY_EXCHANGE:
+        return "Server key exchange";
+      case SSL3_MT_CLIENT_KEY_EXCHANGE:
+        return "Client key exchange";
+      case SSL3_MT_CERTIFICATE_REQUEST:
+        return "Request CERT";
+      case SSL3_MT_SERVER_DONE:
+        return "Server finished";
+      case SSL3_MT_CERTIFICATE_VERIFY:
+        return "CERT verify";
+      case SSL3_MT_FINISHED:
+        return "Finished";
+    }
+  }
+  return "Unknown";
+}
+
+static const char *tls_rt_type(int type)
+{
+  return (
+    type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " :
+    type == SSL3_RT_ALERT              ? "TLS alert, "         :
+    type == SSL3_RT_HANDSHAKE          ? "TLS handshake, "     :
+    type == SSL3_RT_APPLICATION_DATA   ? "TLS app data, "      :
+                                         "TLS Unknown, ");
+}
+
+
+/*
+ * Our callback from the SSL/TLS layers.
+ */
+static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
+                          const void *buf, size_t len, const SSL *ssl,
+                          struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  const char *msg_name, *tls_rt_name;
+  char ssl_buf[1024];
+  int  ver, msg_type, txt_len;
+
+  if (!conn || !conn->data || !conn->data->set.fdebug ||
+      (direction != 0 && direction != 1))
+    return;
+
+  data = conn->data;
+  ssl_ver >>= 8;
+  ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' :
+         ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?');
+
+  /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
+   * always pass-up content-type as 0. But the interesting message-tupe
+   * is at 'buf[0]'.
+   */
+  if (ssl_ver == SSL3_VERSION_MAJOR && content_type != 0)
+    tls_rt_name = tls_rt_type(content_type);
+  else
+    tls_rt_name = "";
+
+  msg_type = *(char*)buf;
+  msg_name = ssl_msg_type(ssl_ver, msg_type);
+
+  txt_len = 1 + sprintf(ssl_buf, "SSLv%c, %s%s (%d):\n",
+                        ver, tls_rt_name, msg_name, msg_type);
+  Curl_debug(data, CURLINFO_TEXT, ssl_buf, txt_len, NULL);
+
+  Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
+             CURLINFO_SSL_DATA_IN, buf, len, NULL);
+  (void) ssl;
+}
+#endif
+
 /* ====================================================== */
 CURLcode
 Curl_SSLConnect(struct connectdata *conn,
@@ -991,6 +1108,14 @@ Curl_SSLConnect(struct connectdata *conn,
     return CURLE_OUT_OF_MEMORY;
   }
 
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+  if (data->set.fdebug) {
+    SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK,
+                          ssl_tls_trace);
+    SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, conn);
+  }
+#endif
+
   /* OpenSSL contains code to work-around lots of bugs and flaws in various
      SSL-implementations. SSL_CTX_set_options() is used to enabled those
      work-arounds. The man page for this option states that SSL_OP_ALL enables
@@ -1001,6 +1126,16 @@ Curl_SSLConnect(struct connectdata *conn,
   */
   SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL);
 
+#if 0
+  /*
+   * Not sure it's needed to tell SSL_connect() that socket is
+   * non-blocking. It doesn't seem to care, but just return with
+   * SSL_ERROR_WANT_x.
+   */
+  if (data->state.used_interface == Curl_if_multi)
+    SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL);
+#endif
+
   if(data->set.cert) {
     if(!cert_stuff(conn,
                    connssl->ctx,
@@ -1105,10 +1240,6 @@ Curl_SSLConnect(struct connectdata *conn,
       /* Evaluate in milliseconds how much time that has passed */
       has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
 
-#ifndef min
-#define min(a, b)   ((a) < (b) ? (a) : (b))
-#endif
-
       /* get the most strict timeout of the ones converted to milliseconds */
       if(data->set.timeout &&
          (data->set.timeout>data->set.connecttimeout))
@@ -1150,6 +1281,8 @@ Curl_SSLConnect(struct connectdata *conn,
         unsigned long errdetail;
         char error_buffer[120]; /* OpenSSL documents that this must be at least
                                    120 bytes long. */
+        CURLcode rc;
+        const char *cert_problem = NULL;
 
         errdetail = ERR_get_error(); /* Gets the earliest error code from the
                                         thread's error queue and removes the
@@ -1161,16 +1294,34 @@ Curl_SSLConnect(struct connectdata *conn,
              SSL routines:
              SSL2_SET_CERTIFICATE:
              certificate verify failed */
+          /* fall-through */
         case 0x14090086:
           /* 14090086:
              SSL routines:
              SSL3_GET_SERVER_CERTIFICATE:
              certificate verify failed */
-          failf(data,
-                "SSL certificate problem, verify that the CA cert is OK");
-          return CURLE_SSL_CACERT;
+          cert_problem = "SSL certificate problem, verify that the CA cert is"
+                         " OK. Details:\n";
+          rc = CURLE_SSL_CACERT;
+          break;
         default:
+          rc = CURLE_SSL_CONNECT_ERROR;
+          break;
+        }
+
           /* detail is already set to the SSL error above */
+
+        /* If we e.g. use SSLv2 request-method and the server doesn't like us
+         * (RST connection etc.), OpenSSL gives no explanation whatsoever and
+         * the SO_ERROR is also lost.
+         */
+        if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
+         failf(data, "Unknown SSL protocol error in connection to %s:%d ",
+                conn->host.name, conn->port);
+          return rc;
+        }
+        /* Could be a CERT problem */
+
 #ifdef HAVE_ERR_ERROR_STRING_N
           /* OpenSSL 0.9.6 and later has a function named
              ERRO_error_string_n() that takes the size of the buffer as a
@@ -1179,10 +1330,8 @@ Curl_SSLConnect(struct connectdata *conn,
 #else
           ERR_error_string(errdetail, error_buffer);
 #endif
-
-          failf(data, "SSL: %s", error_buffer);
-          return CURLE_SSL_CONNECT_ERROR;
-        }
+        failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
+        return rc;
       }
     }
     else
@@ -1278,18 +1427,18 @@ Curl_SSLConnect(struct connectdata *conn,
     /* We could do all sorts of certificate verification stuff here before
        deallocating the certificate. */
 
-    data->set.ssl.certverifyresult=SSL_get_verify_result(connssl->handle);
+    err = data->set.ssl.certverifyresult=SSL_get_verify_result(connssl->handle);
     if(data->set.ssl.certverifyresult != X509_V_OK) {
       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: %d",
-              data->set.ssl.certverifyresult);
+        failf(data, "SSL certificate verify result: %s (%d)",
+              X509_verify_cert_error_string(err), err);
         retcode = CURLE_SSL_PEER_CERTIFICATE;
       }
       else
-        infof(data, "SSL certificate verify result: %d, continuing anyway.\n",
-              data->set.ssl.certverifyresult);
+        infof(data, "SSL certificate verify result: %s (%d), continuing anyway.\n",
+              X509_verify_cert_error_string(err), err);
     }
     else
       infof(data, "SSL certificate verify ok.\n");
index f83e4943538f0015e44f4b222eda47af1741e51a..e165b373019aa52f090ebbcd0fdf170eb0949d27 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -1892,7 +1892,7 @@ static int handleSock5Proxy(const char *proxy_name,
     }
 #else
     failf(conn->data,
-          "%s:%d has an internal error an needs to be fixed to work",
+          "%s:%d has an internal error and needs to be fixed to work",
           __FILE__, __LINE__);
 #endif
   }
index 9551cfe2684d36f7476742185b6823a88a9364da..c759fcc630572fa3ee03c6edb31092a939c46257 100644 (file)
@@ -2572,7 +2572,6 @@ int my_trace(CURL *handle, curl_infotype type,
   struct Configurable *config = (struct Configurable *)userp;
   FILE *output=config->errors;
   const char *text;
-
   (void)handle; /* prevent compiler warning */
 
   if(!config->trace_stream) {
@@ -2606,6 +2605,12 @@ int my_trace(CURL *handle, curl_infotype type,
   case CURLINFO_DATA_IN:
     text = "<= Recv data";
     break;
+  case CURLINFO_SSL_DATA_IN:
+    text = "<= Recv SSL data";
+    break;
+  case CURLINFO_SSL_DATA_OUT:
+    text = "<= Send SSL data";
+    break;
   }
 
   dump(text, output, data, size, config->trace_ascii);