summaryrefslogtreecommitdiff
path: root/lib/vtls/vtls.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vtls/vtls.c')
-rw-r--r--lib/vtls/vtls.c209
1 files changed, 121 insertions, 88 deletions
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index ed65b46b9..07d64ab9d 100644
--- a/lib/vtls/vtls.c
+++ b/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,48 @@
(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);
@@ -217,19 +172,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(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_NSS) || \
+ defined(USE_GSKIT)
+ 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;
@@ -250,6 +227,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;
@@ -292,7 +274,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;
@@ -300,11 +283,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;
@@ -314,21 +304,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 */
@@ -357,7 +347,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);
@@ -372,7 +362,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) {
@@ -390,7 +380,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 */
@@ -400,10 +391,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 */
@@ -434,14 +429,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
@@ -457,10 +452,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);
@@ -476,7 +472,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]);
@@ -487,6 +483,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));
@@ -544,7 +577,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;