Commit bd3d5a17 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Gisle's "SSL patch" from June 16th 2004, modified by me as discussed on the

mailing list.
parent d4b57711
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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
+2 −0
Original line number Diff line number Diff line
@@ -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;

+3 −2
Original line number Diff line number Diff line
@@ -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,
+165 −16
Original line number Diff line number Diff line
@@ -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>
@@ -56,6 +59,10 @@
/* 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");
+1 −1
Original line number Diff line number Diff line
@@ -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
  }
Loading