diff options
Diffstat (limited to 'Utilities/cmcurl/lib/vtls/vtls.c')
-rw-r--r-- | Utilities/cmcurl/lib/vtls/vtls.c | 300 |
1 files changed, 134 insertions, 166 deletions
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c index 56a8823..b808e1c 100644 --- a/Utilities/cmcurl/lib/vtls/vtls.c +++ b/Utilities/cmcurl/lib/vtls/vtls.c @@ -65,6 +65,7 @@ #include "url.h" #include "progress.h" #include "share.h" +#include "multiif.h" #include "timeval.h" #include "curl_md5.h" #include "warnless.h" @@ -80,94 +81,49 @@ (data->share->specifier & \ (1<<CURL_LOCK_DATA_SSL_SESSION))) -static bool safe_strequal(char* str1, char* str2) -{ - if(str1 && str2) - /* both pointers point to something then compare them */ - return (0 != strcasecompare(str1, str2)) ? TRUE : FALSE; - else - /* if both pointers are NULL then treat them as equal */ - return (!str1 && !str2) ? TRUE : FALSE; -} +#define CLONE_STRING(var) \ + if(source->var) { \ + dest->var = strdup(source->var); \ + if(!dest->var) \ + return FALSE; \ + } \ + else \ + dest->var = NULL; bool -Curl_ssl_config_matches(struct ssl_config_data* data, - struct ssl_config_data* needle) +Curl_ssl_config_matches(struct ssl_primary_config* data, + struct ssl_primary_config* needle) { if((data->version == needle->version) && (data->verifypeer == needle->verifypeer) && (data->verifyhost == needle->verifyhost) && - safe_strequal(data->CApath, needle->CApath) && - safe_strequal(data->CAfile, needle->CAfile) && - safe_strequal(data->clientcert, needle->clientcert) && - safe_strequal(data->cipher_list, needle->cipher_list)) + Curl_safe_strcasecompare(data->CApath, needle->CApath) && + Curl_safe_strcasecompare(data->CAfile, needle->CAfile) && + Curl_safe_strcasecompare(data->clientcert, needle->clientcert) && + Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list)) return TRUE; return FALSE; } bool -Curl_clone_ssl_config(struct ssl_config_data *source, - struct ssl_config_data *dest) +Curl_clone_primary_ssl_config(struct ssl_primary_config *source, + struct ssl_primary_config *dest) { - dest->sessionid = source->sessionid; dest->verifyhost = source->verifyhost; dest->verifypeer = source->verifypeer; dest->version = source->version; - if(source->CAfile) { - dest->CAfile = strdup(source->CAfile); - if(!dest->CAfile) - return FALSE; - } - else - dest->CAfile = NULL; - - if(source->CApath) { - dest->CApath = strdup(source->CApath); - if(!dest->CApath) - return FALSE; - } - else - dest->CApath = NULL; - - if(source->cipher_list) { - dest->cipher_list = strdup(source->cipher_list); - if(!dest->cipher_list) - return FALSE; - } - else - dest->cipher_list = NULL; - - if(source->egdsocket) { - dest->egdsocket = strdup(source->egdsocket); - if(!dest->egdsocket) - return FALSE; - } - else - dest->egdsocket = NULL; - - if(source->random_file) { - dest->random_file = strdup(source->random_file); - if(!dest->random_file) - return FALSE; - } - else - dest->random_file = NULL; - - if(source->clientcert) { - dest->clientcert = strdup(source->clientcert); - if(!dest->clientcert) - return FALSE; - dest->sessionid = FALSE; - } - else - dest->clientcert = NULL; - + CLONE_STRING(CAfile); + CLONE_STRING(CApath); + CLONE_STRING(cipher_list); + CLONE_STRING(egdsocket); + CLONE_STRING(random_file); + CLONE_STRING(clientcert); return TRUE; } -void Curl_free_ssl_config(struct ssl_config_data* sslc) +void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc) { Curl_safefree(sslc->CAfile); Curl_safefree(sslc->CApath); @@ -177,77 +133,6 @@ void Curl_free_ssl_config(struct ssl_config_data* sslc) Curl_safefree(sslc->clientcert); } - -/* - * Curl_rand() returns a random unsigned integer, 32bit. - * - * This non-SSL function is put here only because this file is the only one - * with knowledge of what the underlying SSL libraries provide in terms of - * randomizers. - * - * NOTE: 'data' may be passed in as NULL when coming from external API without - * easy handle! - * - */ - -unsigned int Curl_rand(struct Curl_easy *data) -{ - unsigned int r = 0; - static unsigned int randseed; - static bool seeded = FALSE; - -#ifdef CURLDEBUG - char *force_entropy = getenv("CURL_ENTROPY"); - if(force_entropy) { - if(!seeded) { - size_t elen = strlen(force_entropy); - size_t clen = sizeof(randseed); - size_t min = elen < clen ? elen : clen; - memcpy((char *)&randseed, force_entropy, min); - seeded = TRUE; - } - else - randseed++; - return randseed; - } -#endif - - /* data may be NULL! */ - if(!Curl_ssl_random(data, (unsigned char *)&r, sizeof(r))) - return r; - - /* If Curl_ssl_random() returns non-zero it couldn't offer randomness and we - instead perform a "best effort" */ - -#ifdef RANDOM_FILE - if(!seeded) { - /* if there's a random file to read a seed from, use it */ - int fd = open(RANDOM_FILE, O_RDONLY); - if(fd > -1) { - /* read random data into the randseed variable */ - ssize_t nread = read(fd, &randseed, sizeof(randseed)); - if(nread == sizeof(randseed)) - seeded = TRUE; - close(fd); - } - } -#endif - - if(!seeded) { - struct timeval now = curlx_tvnow(); - infof(data, "WARNING: Using weak random seed\n"); - randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec; - randseed = randseed * 1103515245 + 12345; - randseed = randseed * 1103515245 + 12345; - randseed = randseed * 1103515245 + 12345; - seeded = TRUE; - } - - /* Return an unsigned 32-bit pseudo-random number. */ - r = randseed = randseed * 1103515245 + 12345; - return (r << 16) | ((r >> 16) & 0xFFFF); -} - int Curl_ssl_backend(void) { return (int)CURL_SSL_BACKEND; @@ -288,19 +173,41 @@ void Curl_ssl_cleanup(void) static bool ssl_prefs_check(struct Curl_easy *data) { /* check for CURLOPT_SSLVERSION invalid parameter value */ - if((data->set.ssl.version < 0) - || (data->set.ssl.version >= CURL_SSLVERSION_LAST)) { + if((data->set.ssl.primary.version < 0) + || (data->set.ssl.primary.version >= CURL_SSLVERSION_LAST)) { failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION"); return FALSE; } return TRUE; } +static CURLcode +ssl_connect_init_proxy(struct connectdata *conn, int sockindex) +{ + DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]); + if(ssl_connection_complete == conn->ssl[sockindex].state && + !conn->proxy_ssl[sockindex].use) { +#if defined(HTTPS_PROXY_SUPPORT) + conn->proxy_ssl[sockindex] = conn->ssl[sockindex]; + memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex])); +#else + return CURLE_NOT_BUILT_IN; +#endif + } + return CURLE_OK; +} + CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex) { CURLcode result; + if(conn->bits.proxy_ssl_connected[sockindex]) { + result = ssl_connect_init_proxy(conn, sockindex); + if(result) + return result; + } + if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; @@ -321,6 +228,11 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done) { CURLcode result; + if(conn->bits.proxy_ssl_connected[sockindex]) { + result = ssl_connect_init_proxy(conn, sockindex); + if(result) + return result; + } if(!ssl_prefs_check(conn->data)) return CURLE_SSL_CONNECT_ERROR; @@ -363,7 +275,8 @@ void Curl_ssl_sessionid_unlock(struct connectdata *conn) */ bool Curl_ssl_getsessionid(struct connectdata *conn, void **ssl_sessionid, - size_t *idsize) /* set 0 if unknown */ + size_t *idsize, /* set 0 if unknown */ + int sockindex) { struct curl_ssl_session *check; struct Curl_easy *data = conn->data; @@ -371,11 +284,18 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, long *general_age; bool no_match = TRUE; + const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; + const char * const name = isProxy ? conn->http_proxy.host.name : + conn->host.name; + int port = isProxy ? (int)conn->port : conn->remote_port; *ssl_sessionid = NULL; - DEBUGASSERT(conn->ssl_config.sessionid); + DEBUGASSERT(data->set.general_ssl.sessionid); - if(!conn->ssl_config.sessionid) + if(!data->set.general_ssl.sessionid) /* session ID re-use is disabled */ return TRUE; @@ -385,21 +305,21 @@ bool Curl_ssl_getsessionid(struct connectdata *conn, else general_age = &data->state.sessionage; - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { check = &data->state.session[i]; if(!check->sessionid) /* not session ID means blank entry */ continue; - if(strcasecompare(conn->host.name, check->name) && + if(strcasecompare(name, check->name) && ((!conn->bits.conn_to_host && !check->conn_to_host) || (conn->bits.conn_to_host && check->conn_to_host && strcasecompare(conn->conn_to_host.name, check->conn_to_host))) && ((!conn->bits.conn_to_port && check->conn_to_port == -1) || (conn->bits.conn_to_port && check->conn_to_port != -1 && conn->conn_to_port == check->conn_to_port)) && - (conn->remote_port == check->remote_port) && + (port == check->remote_port) && strcasecompare(conn->handler->scheme, check->scheme) && - Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) { + Curl_ssl_config_matches(ssl_config, &check->ssl_config)) { /* yes, we have a session ID! */ (*general_age)++; /* increase general age */ check->age = *general_age; /* set this as used in this age */ @@ -428,7 +348,7 @@ void Curl_ssl_kill_session(struct curl_ssl_session *session) session->sessionid = NULL; session->age = 0; /* fresh */ - Curl_free_ssl_config(&session->ssl_config); + Curl_free_primary_ssl_config(&session->ssl_config); Curl_safefree(session->name); Curl_safefree(session->conn_to_host); @@ -443,7 +363,7 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) size_t i; struct Curl_easy *data=conn->data; - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) { + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) { struct curl_ssl_session *check = &data->state.session[i]; if(check->sessionid == ssl_sessionid) { @@ -461,7 +381,8 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) */ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, - size_t idsize) + size_t idsize, + int sockindex) { size_t i; struct Curl_easy *data=conn->data; /* the mother of all structs */ @@ -471,10 +392,14 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, char *clone_conn_to_host; int conn_to_port; long *general_age; + const bool isProxy = CONNECT_PROXY_SSL(); + struct ssl_primary_config * const ssl_config = isProxy ? + &conn->proxy_ssl_config : + &conn->ssl_config; - DEBUGASSERT(conn->ssl_config.sessionid); + DEBUGASSERT(data->set.general_ssl.sessionid); - clone_host = strdup(conn->host.name); + clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name); if(!clone_host) return CURLE_OUT_OF_MEMORY; /* bail out */ @@ -505,14 +430,14 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, } /* find an empty slot for us, or find the oldest */ - for(i = 1; (i < data->set.ssl.max_ssl_sessions) && + for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) && data->state.session[i].sessionid; i++) { if(data->state.session[i].age < oldest_age) { oldest_age = data->state.session[i].age; store = &data->state.session[i]; } } - if(i == data->set.ssl.max_ssl_sessions) + if(i == data->set.general_ssl.max_ssl_sessions) /* cache is full, we must "kill" the oldest entry! */ Curl_ssl_kill_session(store); else @@ -528,10 +453,11 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->name = clone_host; /* clone host name */ store->conn_to_host = clone_conn_to_host; /* clone connect to host name */ store->conn_to_port = conn_to_port; /* connect to port number */ - store->remote_port = conn->remote_port; /* port number */ + /* port number */ + store->remote_port = isProxy ? (int)conn->port : conn->remote_port; store->scheme = conn->handler->scheme; - if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { + if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); free(clone_conn_to_host); @@ -547,7 +473,7 @@ void Curl_ssl_close_all(struct Curl_easy *data) size_t i; /* kill the session ID cache if not shared */ if(data->state.session && !SSLSESSION_SHARED(data)) { - for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) + for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) /* the single-killer function handles empty table slots */ Curl_ssl_kill_session(&data->state.session[i]); @@ -558,6 +484,43 @@ void Curl_ssl_close_all(struct Curl_easy *data) curlssl_close_all(data); } +#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \ + defined(USE_DARWINSSL) || defined(USE_NSS) +/* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only. */ +int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET]; + + if(!numsocks) + return GETSOCK_BLANK; + + if(connssl->connecting_state == ssl_connect_2_writing) { + /* write mode */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_WRITESOCK(0); + } + else if(connssl->connecting_state == ssl_connect_2_reading) { + /* read mode */ + socks[0] = conn->sock[FIRSTSOCKET]; + return GETSOCK_READSOCK(0); + } + + return GETSOCK_BLANK; +} +#else +int Curl_ssl_getsock(struct connectdata *conn, + curl_socket_t *socks, + int numsocks) +{ + (void)conn; + (void)socks; + (void)numsocks; + return GETSOCK_BLANK; +} +/* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */ +#endif + void Curl_ssl_close(struct connectdata *conn, int sockindex) { DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); @@ -615,7 +578,7 @@ CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount) return CURLE_OUT_OF_MEMORY; /* store the info in the SSL section */ - data->set.ssl.max_ssl_sessions = amount; + data->set.general_ssl.max_ssl_sessions = amount; data->state.session = session; data->state.sessionage = 1; /* this is brand new */ return CURLE_OK; @@ -691,9 +654,9 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, const char *value, size_t valuelen) { - struct curl_certinfo * ci = &data->info.certs; - char * output; - struct curl_slist * nl; + struct curl_certinfo *ci = &data->info.certs; + char *output; + struct curl_slist *nl; CURLcode result = CURLE_OK; size_t labellen = strlen(label); size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */ @@ -736,11 +699,16 @@ CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen); } -int Curl_ssl_random(struct Curl_easy *data, - unsigned char *entropy, - size_t length) +CURLcode Curl_ssl_random(struct Curl_easy *data, + unsigned char *entropy, + size_t length) { - return curlssl_random(data, entropy, length); + int rc = curlssl_random(data, entropy, length); + if(rc) { + failf(data, "PRNG seeding failed"); + return CURLE_FAILED_INIT; /* possibly weird return code */ + } + return CURLE_OK; } /* |