mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
Gisle's "SSL patch" from June 16th 2004, modified by me as discussed on the
mailing list.
This commit is contained in:
parent
d4b577114b
commit
bd3d5a17b4
10
CHANGES
10
CHANGES
@ -6,6 +6,16 @@
|
|||||||
|
|
||||||
Changelog
|
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)
|
Daniel (16 June 2004)
|
||||||
- Modified to keep the upload byte counter in an curl_off_t, not an int as
|
- 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
|
before. 32bits is not enough. This is most likely the bug Jean-Louis Lemaire
|
||||||
|
@ -173,6 +173,8 @@ typedef enum {
|
|||||||
CURLINFO_HEADER_OUT, /* 2 */
|
CURLINFO_HEADER_OUT, /* 2 */
|
||||||
CURLINFO_DATA_IN, /* 3 */
|
CURLINFO_DATA_IN, /* 3 */
|
||||||
CURLINFO_DATA_OUT, /* 4 */
|
CURLINFO_DATA_OUT, /* 4 */
|
||||||
|
CURLINFO_SSL_DATA_IN, /* 5 */
|
||||||
|
CURLINFO_SSL_DATA_OUT, /* 6 */
|
||||||
CURLINFO_END
|
CURLINFO_END
|
||||||
} curl_infotype;
|
} curl_infotype;
|
||||||
|
|
||||||
|
@ -204,7 +204,8 @@ CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if(data->set.verbose)
|
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((size_t)bytes_written != write_len) {
|
||||||
/* if not all was written at once, we must advance the pointer, decrease
|
/* 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)
|
char *ptr, size_t size)
|
||||||
{
|
{
|
||||||
static const char * const s_infotype[CURLINFO_END] = {
|
static const char * const s_infotype[CURLINFO_END] = {
|
||||||
"* ", "< ", "> ", "{ ", "} " };
|
"* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
|
||||||
|
|
||||||
if(data->set.fdebug)
|
if(data->set.fdebug)
|
||||||
return (*data->set.fdebug)(data, type, ptr, size,
|
return (*data->set.fdebug)(data, type, ptr, size,
|
||||||
|
181
lib/ssluse.c
181
lib/ssluse.c
@ -47,6 +47,9 @@
|
|||||||
#include "connect.h" /* Curl_ourerrno() proto */
|
#include "connect.h" /* Curl_ourerrno() proto */
|
||||||
#include "strequal.h"
|
#include "strequal.h"
|
||||||
|
|
||||||
|
#define _MPRINTF_REPLACE /* use the internal *printf() functions */
|
||||||
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
#ifdef USE_SSLEAY
|
#ifdef USE_SSLEAY
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
@ -56,6 +59,10 @@
|
|||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
#ifndef min
|
||||||
|
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#endif
|
||||||
|
|
||||||
#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
|
#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
|
||||||
#define HAVE_SSL_GET1_SESSION 1
|
#define HAVE_SSL_GET1_SESSION 1
|
||||||
#else
|
#else
|
||||||
@ -859,6 +866,7 @@ static CURLcode verifyhost(struct connectdata *conn,
|
|||||||
/* Is this a wildcard match? */
|
/* Is this a wildcard match? */
|
||||||
else if((altptr[0] == '*') &&
|
else if((altptr[0] == '*') &&
|
||||||
(domainlen == altlen-1) &&
|
(domainlen == altlen-1) &&
|
||||||
|
domain &&
|
||||||
curl_strnequal(domain, altptr+1, domainlen))
|
curl_strnequal(domain, altptr+1, domainlen))
|
||||||
matched = TRUE;
|
matched = TRUE;
|
||||||
break;
|
break;
|
||||||
@ -938,6 +946,115 @@ static CURLcode verifyhost(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
CURLcode
|
||||||
Curl_SSLConnect(struct connectdata *conn,
|
Curl_SSLConnect(struct connectdata *conn,
|
||||||
@ -991,6 +1108,14 @@ Curl_SSLConnect(struct connectdata *conn,
|
|||||||
return CURLE_OUT_OF_MEMORY;
|
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
|
/* OpenSSL contains code to work-around lots of bugs and flaws in various
|
||||||
SSL-implementations. SSL_CTX_set_options() is used to enabled those
|
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
|
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);
|
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(data->set.cert) {
|
||||||
if(!cert_stuff(conn,
|
if(!cert_stuff(conn,
|
||||||
connssl->ctx,
|
connssl->ctx,
|
||||||
@ -1105,10 +1240,6 @@ Curl_SSLConnect(struct connectdata *conn,
|
|||||||
/* Evaluate in milliseconds how much time that has passed */
|
/* Evaluate in milliseconds how much time that has passed */
|
||||||
has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
|
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 */
|
/* get the most strict timeout of the ones converted to milliseconds */
|
||||||
if(data->set.timeout &&
|
if(data->set.timeout &&
|
||||||
(data->set.timeout>data->set.connecttimeout))
|
(data->set.timeout>data->set.connecttimeout))
|
||||||
@ -1150,6 +1281,8 @@ Curl_SSLConnect(struct connectdata *conn,
|
|||||||
unsigned long errdetail;
|
unsigned long errdetail;
|
||||||
char error_buffer[120]; /* OpenSSL documents that this must be at least
|
char error_buffer[120]; /* OpenSSL documents that this must be at least
|
||||||
120 bytes long. */
|
120 bytes long. */
|
||||||
|
CURLcode rc;
|
||||||
|
const char *cert_problem = NULL;
|
||||||
|
|
||||||
errdetail = ERR_get_error(); /* Gets the earliest error code from the
|
errdetail = ERR_get_error(); /* Gets the earliest error code from the
|
||||||
thread's error queue and removes the
|
thread's error queue and removes the
|
||||||
@ -1161,16 +1294,34 @@ Curl_SSLConnect(struct connectdata *conn,
|
|||||||
SSL routines:
|
SSL routines:
|
||||||
SSL2_SET_CERTIFICATE:
|
SSL2_SET_CERTIFICATE:
|
||||||
certificate verify failed */
|
certificate verify failed */
|
||||||
|
/* fall-through */
|
||||||
case 0x14090086:
|
case 0x14090086:
|
||||||
/* 14090086:
|
/* 14090086:
|
||||||
SSL routines:
|
SSL routines:
|
||||||
SSL3_GET_SERVER_CERTIFICATE:
|
SSL3_GET_SERVER_CERTIFICATE:
|
||||||
certificate verify failed */
|
certificate verify failed */
|
||||||
failf(data,
|
cert_problem = "SSL certificate problem, verify that the CA cert is"
|
||||||
"SSL certificate problem, verify that the CA cert is OK");
|
" OK. Details:\n";
|
||||||
return CURLE_SSL_CACERT;
|
rc = CURLE_SSL_CACERT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
rc = CURLE_SSL_CONNECT_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* detail is already set to the SSL error above */
|
/* 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
|
#ifdef HAVE_ERR_ERROR_STRING_N
|
||||||
/* OpenSSL 0.9.6 and later has a function named
|
/* OpenSSL 0.9.6 and later has a function named
|
||||||
ERRO_error_string_n() that takes the size of the buffer as a
|
ERRO_error_string_n() that takes the size of the buffer as a
|
||||||
@ -1179,10 +1330,8 @@ Curl_SSLConnect(struct connectdata *conn,
|
|||||||
#else
|
#else
|
||||||
ERR_error_string(errdetail, error_buffer);
|
ERR_error_string(errdetail, error_buffer);
|
||||||
#endif
|
#endif
|
||||||
|
failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
|
||||||
failf(data, "SSL: %s", error_buffer);
|
return rc;
|
||||||
return CURLE_SSL_CONNECT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1278,18 +1427,18 @@ Curl_SSLConnect(struct connectdata *conn,
|
|||||||
/* We could do all sorts of certificate verification stuff here before
|
/* We could do all sorts of certificate verification stuff here before
|
||||||
deallocating the certificate. */
|
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.certverifyresult != X509_V_OK) {
|
||||||
if(data->set.ssl.verifypeer) {
|
if(data->set.ssl.verifypeer) {
|
||||||
/* We probably never reach this, because SSL_connect() will fail
|
/* We probably never reach this, because SSL_connect() will fail
|
||||||
and we return earlyer if verifypeer is set? */
|
and we return earlyer if verifypeer is set? */
|
||||||
failf(data, "SSL certificate verify result: %d",
|
failf(data, "SSL certificate verify result: %s (%d)",
|
||||||
data->set.ssl.certverifyresult);
|
X509_verify_cert_error_string(err), err);
|
||||||
retcode = CURLE_SSL_PEER_CERTIFICATE;
|
retcode = CURLE_SSL_PEER_CERTIFICATE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
infof(data, "SSL certificate verify result: %d, continuing anyway.\n",
|
infof(data, "SSL certificate verify result: %s (%d), continuing anyway.\n",
|
||||||
data->set.ssl.certverifyresult);
|
X509_verify_cert_error_string(err), err);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
infof(data, "SSL certificate verify ok.\n");
|
infof(data, "SSL certificate verify ok.\n");
|
||||||
|
@ -1892,7 +1892,7 @@ static int handleSock5Proxy(const char *proxy_name,
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
failf(conn->data,
|
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__);
|
__FILE__, __LINE__);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -2572,7 +2572,6 @@ int my_trace(CURL *handle, curl_infotype type,
|
|||||||
struct Configurable *config = (struct Configurable *)userp;
|
struct Configurable *config = (struct Configurable *)userp;
|
||||||
FILE *output=config->errors;
|
FILE *output=config->errors;
|
||||||
const char *text;
|
const char *text;
|
||||||
|
|
||||||
(void)handle; /* prevent compiler warning */
|
(void)handle; /* prevent compiler warning */
|
||||||
|
|
||||||
if(!config->trace_stream) {
|
if(!config->trace_stream) {
|
||||||
@ -2606,6 +2605,12 @@ int my_trace(CURL *handle, curl_infotype type,
|
|||||||
case CURLINFO_DATA_IN:
|
case CURLINFO_DATA_IN:
|
||||||
text = "<= Recv data";
|
text = "<= Recv data";
|
||||||
break;
|
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);
|
dump(text, output, data, size, config->trace_ascii);
|
||||||
|
Loading…
Reference in New Issue
Block a user