aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2004-06-18 06:20:43 +0000
committerDaniel Stenberg <daniel@haxx.se>2004-06-18 06:20:43 +0000
commitbd3d5a17b49dfdb9029376961f429a21dd045af4 (patch)
tree30328541870aafd03e3533ba52c8005af883dc5c
parentd4b577114bcc1c0ddde3174a82177188d76c4b71 (diff)
Gisle's "SSL patch" from June 16th 2004, modified by me as discussed on the
mailing list.
-rw-r--r--CHANGES10
-rw-r--r--include/curl/curl.h2
-rw-r--r--lib/sendf.c5
-rw-r--r--lib/ssluse.c181
-rw-r--r--lib/url.c2
-rw-r--r--src/main.c7
6 files changed, 187 insertions, 20 deletions
diff --git a/CHANGES b/CHANGES
index 4d6fc8c9d..0a9c12d47 100644
--- 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
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 409256246..ef7129856 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -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;
diff --git a/lib/sendf.c b/lib/sendf.c
index a4fbb5182..b1b33a8fc 100644
--- a/lib/sendf.c
+++ b/lib/sendf.c
@@ -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,
diff --git a/lib/ssluse.c b/lib/ssluse.c
index abe299811..544385305 100644
--- a/lib/ssluse.c
+++ b/lib/ssluse.c
@@ -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");
diff --git a/lib/url.c b/lib/url.c
index f83e49435..e165b3730 100644
--- 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
}
diff --git a/src/main.c b/src/main.c
index 9551cfe26..c759fcc63 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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);