summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/urldata.h1
-rw-r--r--lib/vtls/axtls.c8
-rw-r--r--lib/vtls/cyassl.c6
-rw-r--r--lib/vtls/darwinssl.c4
-rw-r--r--lib/vtls/gtls.c4
-rw-r--r--lib/vtls/mbedtls.c5
-rw-r--r--lib/vtls/openssl.c6
-rw-r--r--lib/vtls/polarssl.c4
-rw-r--r--lib/vtls/schannel.c55
-rw-r--r--lib/vtls/vtls.c38
-rw-r--r--lib/vtls/vtls.h39
11 files changed, 117 insertions, 53 deletions
diff --git a/lib/urldata.h b/lib/urldata.h
index 25594d3b5..bb32b1751 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -242,7 +242,6 @@ struct curl_schannel_cred {
CredHandle cred_handle;
TimeStamp time_stamp;
int refcount;
- bool cached;
};
struct curl_schannel_ctxt {
diff --git a/lib/vtls/axtls.c b/lib/vtls/axtls.c
index 0afcfaa58..df6ae9562 100644
--- a/lib/vtls/axtls.c
+++ b/lib/vtls/axtls.c
@@ -259,14 +259,18 @@ static CURLcode connect_prep(struct connectdata *conn, int sockindex)
*/
/* In axTLS, handshaking happens inside ssl_client_new. */
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
/* we got a session id, use it! */
infof (data, "SSL re-using session ID\n");
ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
ssl_sessionid, (uint8_t)ssl_idsize);
+ Curl_ssl_sessionid_unlock();
}
- else
+ else {
+ Curl_ssl_sessionid_unlock();
ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
+ }
conn->ssl[sockindex].ssl = ssl;
return CURLE_OK;
@@ -381,9 +385,11 @@ static CURLcode connect_finish(struct connectdata *conn, int sockindex)
/* Put our freshly minted SSL session in cache */
ssl_idsize = ssl_get_session_id_size(ssl);
ssl_sessionid = ssl_get_session_id(ssl);
+ Curl_ssl_sessionid_lock(conn);
if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
!= CURLE_OK)
infof (data, "failed to add session to cache\n");
+ Curl_ssl_sessionid_unlock(conn);
return CURLE_OK;
}
diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c
index da737c727..c189af772 100644
--- a/lib/vtls/cyassl.c
+++ b/lib/vtls/cyassl.c
@@ -378,9 +378,11 @@ cyassl_connect_step1(struct connectdata *conn,
#endif /* HAVE_ALPN */
/* Check if there's a cached ID we can/should use here! */
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
+ Curl_ssl_sessionid_unlock(conn);
failf(data, "SSL: SSL_set_session failed: %s",
ERR_error_string(SSL_get_error(conssl->handle, 0), error_buffer));
return CURLE_SSL_CONNECT_ERROR;
@@ -388,6 +390,7 @@ cyassl_connect_step1(struct connectdata *conn,
/* Informational message */
infof (data, "SSL re-using session ID\n");
}
+ Curl_ssl_sessionid_unlock(conn);
/* pass the raw socket into the SSL layer */
if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
@@ -581,6 +584,7 @@ cyassl_connect_step3(struct connectdata *conn,
our_ssl_sessionid = SSL_get_session(connssl->handle);
+ Curl_ssl_sessionid_lock(conn);
incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
if(incache) {
if(old_ssl_sessionid != our_ssl_sessionid) {
@@ -594,10 +598,12 @@ cyassl_connect_step3(struct connectdata *conn,
result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
0 /* unknown size */);
if(result) {
+ Curl_ssl_sessionid_unlock(conn);
failf(data, "failed to store ssl session");
return result;
}
}
+ Curl_ssl_sessionid_unlock(conn);
connssl->connecting_state = ssl_connect_done;
diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c
index 71d379b90..d873e193b 100644
--- a/lib/vtls/darwinssl.c
+++ b/lib/vtls/darwinssl.c
@@ -1474,10 +1474,12 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
/* Check if there's a cached ID we can/should use here! */
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
&ssl_sessionid_len)) {
/* we got a session id, use it! */
err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+ Curl_ssl_sessionid_unlock(conn);
if(err != noErr) {
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
@@ -1497,11 +1499,13 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
if(err != noErr) {
+ Curl_ssl_sessionid_unlock(conn);
failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
return CURLE_SSL_CONNECT_ERROR;
}
result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len);
+ Curl_ssl_sessionid_unlock(conn);
if(result) {
failf(data, "failed to store ssl session");
return result;
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index 1b5a6a4d5..d8b92e348 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -750,6 +750,7 @@ gtls_connect_step1(struct connectdata *conn,
/* This might be a reconnect, so we check for a session ID in the cache
to speed up things */
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
/* we got a session id, use it! */
gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
@@ -757,6 +758,7 @@ gtls_connect_step1(struct connectdata *conn,
/* Informational message */
infof (data, "SSL re-using session ID\n");
}
+ Curl_ssl_sessionid_unlock(conn);
return CURLE_OK;
}
@@ -1284,6 +1286,7 @@ gtls_connect_step3(struct connectdata *conn,
/* extract session ID to the allocated buffer */
gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+ Curl_ssl_sessionid_lock(conn);
incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
if(incache) {
/* there was one before in the cache, so instead of risking that the
@@ -1293,6 +1296,7 @@ gtls_connect_step3(struct connectdata *conn,
/* store this session id */
result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
+ Curl_ssl_sessionid_unlock(conn);
if(result) {
free(connect_sessionid);
result = CURLE_OUT_OF_MEMORY;
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
index fafaef675..2992d8834 100644
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
@@ -365,14 +365,17 @@ mbed_connect_step1(struct connectdata *conn,
mbedtls_ssl_conf_ciphersuites(&connssl->config,
mbedtls_ssl_list_ciphersuites());
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) {
ret = mbedtls_ssl_set_session(&connssl->ssl, old_session);
if(ret) {
+ Curl_ssl_sessionid_unlock(conn);
failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
}
infof(data, "mbedTLS re-using session\n");
}
+ Curl_ssl_sessionid_unlock(conn);
mbedtls_ssl_conf_ca_chain(&connssl->config,
&connssl->cacert,
@@ -607,10 +610,12 @@ mbed_connect_step3(struct connectdata *conn,
}
/* If there's already a matching session in the cache, delete it */
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(conn, old_ssl_sessionid);
retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
+ Curl_ssl_sessionid_unlock(conn);
if(retcode) {
free(our_ssl_sessionid);
failf(data, "failed to store ssl session");
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 776ebe5de..f702653cd 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -2082,9 +2082,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
#endif
/* Check if there's a cached ID we can/should use here! */
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
/* we got a session id, use it! */
if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
+ Curl_ssl_sessionid_unlock(conn);
failf(data, "SSL: SSL_set_session failed: %s",
ERR_error_string(ERR_get_error(), NULL));
return CURLE_SSL_CONNECT_ERROR;
@@ -2092,6 +2094,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
/* Informational message */
infof (data, "SSL re-using session ID\n");
}
+ Curl_ssl_sessionid_unlock(conn);
/* pass the raw socket into the SSL layers */
if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
@@ -2818,6 +2821,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
will stay in memory until explicitly freed with SSL_SESSION_free(3),
regardless of its state. */
+ Curl_ssl_sessionid_lock(conn);
incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
if(incache) {
if(old_ssl_sessionid != our_ssl_sessionid) {
@@ -2831,6 +2835,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
0 /* unknown size */);
if(result) {
+ Curl_ssl_sessionid_unlock(conn);
failf(data, "failed to store ssl session");
return result;
}
@@ -2842,6 +2847,7 @@ static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
*/
SSL_SESSION_free(our_ssl_sessionid);
}
+ Curl_ssl_sessionid_unlock(conn);
/*
* We check certificates to authenticate the server; otherwise we risk
diff --git a/lib/vtls/polarssl.c b/lib/vtls/polarssl.c
index 0e8b0f500..14a098b39 100644
--- a/lib/vtls/polarssl.c
+++ b/lib/vtls/polarssl.c
@@ -337,8 +337,10 @@ polarssl_connect_step1(struct connectdata *conn,
net_send, &conn->sock[sockindex]);
ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites());
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &old_session, NULL)) {
ret = ssl_set_session(&connssl->ssl, old_session);
+ Curl_ssl_sessionid_unlock(conn);
if(ret) {
failf(data, "ssl_set_session returned -0x%x", -ret);
return CURLE_SSL_CONNECT_ERROR;
@@ -572,10 +574,12 @@ polarssl_connect_step3(struct connectdata *conn,
}
/* If there's already a matching session in the cache, delete it */
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL))
Curl_ssl_delsessionid(conn, old_ssl_sessionid);
retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0);
+ Curl_ssl_sessionid_unlock(conn);
if(retcode) {
free(our_ssl_sessionid);
failf(data, "failed to store ssl session");
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 3db5c362c..38a2aa33e 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -123,11 +123,21 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
conn->host.name, conn->remote_port);
/* check for an existing re-usable credential handle */
+ Curl_ssl_sessionid_lock(conn);
if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL)) {
connssl->cred = old_cred;
infof(data, "schannel: re-using existing credential handle\n");
+
+ /* increment the reference counter of the credential/session handle */
+ connssl->cred->refcount++;
+ infof(data, "schannel: incremented credential handle refcount = %d\n",
+ connssl->cred->refcount);
+
+ Curl_ssl_sessionid_unlock(conn);
}
else {
+ Curl_ssl_sessionid_unlock(conn);
+
/* setup Schannel API options */
memset(&schannel_cred, 0, sizeof(schannel_cred));
schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
@@ -200,6 +210,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_OUT_OF_MEMORY;
}
memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
+ connssl->cred->refcount = 1;
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
*/
@@ -666,18 +677,13 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
}
#endif
- /* increment the reference counter of the credential/session handle */
- if(connssl->cred && connssl->ctxt) {
- connssl->cred->refcount++;
- infof(data, "schannel: incremented credential handle refcount = %d\n",
- connssl->cred->refcount);
- }
-
/* save the current session data for possible re-use */
+ Curl_ssl_sessionid_lock(conn);
incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL));
if(incache) {
if(old_cred != connssl->cred) {
infof(data, "schannel: old credential handle is stale, removing\n");
+ /* we're not taking old_cred ownership here, no refcount++ is needed */
Curl_ssl_delsessionid(conn, (void *)old_cred);
incache = FALSE;
}
@@ -687,14 +693,17 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
sizeof(struct curl_schannel_cred));
if(result) {
+ Curl_ssl_sessionid_unlock(conn);
failf(data, "schannel: failed to store credential handle");
return result;
}
else {
- connssl->cred->cached = TRUE;
+ /* this cred session is now also referenced by sessionid cache */
+ connssl->cred->refcount++;
infof(data, "schannel: stored credential handle in session cache\n");
}
}
+ Curl_ssl_sessionid_unlock(conn);
if(data->set.ssl.certinfo) {
sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
@@ -1442,19 +1451,10 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
/* free SSPI Schannel API credential handle */
if(connssl->cred) {
- /* decrement the reference counter of the credential/session handle */
- if(connssl->cred->refcount > 0) {
- connssl->cred->refcount--;
- infof(data, "schannel: decremented credential handle refcount = %d\n",
- connssl->cred->refcount);
- }
-
- /* if the handle was not cached and the refcount is zero */
- if(!connssl->cred->cached && connssl->cred->refcount == 0) {
- infof(data, "schannel: clear credential handle\n");
- s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle);
- Curl_safefree(connssl->cred);
- }
+ Curl_ssl_sessionid_lock(conn);
+ Curl_schannel_session_free(connssl->cred);
+ Curl_ssl_sessionid_unlock(conn);
+ connssl->cred = NULL;
}
/* free internal buffer for received encrypted data */
@@ -1476,16 +1476,13 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
void Curl_schannel_session_free(void *ptr)
{
+ /* this is expected to be called under sessionid lock */
struct curl_schannel_cred *cred = ptr;
- if(cred && cred->cached) {
- if(cred->refcount == 0) {
- s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
- Curl_safefree(cred);
- }
- else {
- cred->cached = FALSE;
- }
+ cred->refcount--;
+ if(cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ Curl_safefree(cred);
}
}
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index ca505a71c..6a7c1ace6 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -330,6 +330,25 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
}
/*
+ * Lock shared SSL session data
+ */
+void Curl_ssl_sessionid_lock(struct connectdata *conn)
+{
+ if(SSLSESSION_SHARED(conn->data))
+ Curl_share_lock(conn->data,
+ CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+}
+
+/*
+ * Unlock shared SSL session data
+ */
+void Curl_ssl_sessionid_unlock(struct connectdata *conn)
+{
+ if(SSLSESSION_SHARED(conn->data))
+ Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION);
+}
+
+/*
* Check if there's a session ID for the given connection in the cache, and if
* there's one suitable, it is provided. Returns TRUE when no entry matched.
*/
@@ -350,10 +369,8 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
return TRUE;
/* Lock if shared */
- if(SSLSESSION_SHARED(data)) {
- Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+ if(SSLSESSION_SHARED(data))
general_age = &data->share->sessionage;
- }
else
general_age = &data->state.sessionage;
@@ -382,10 +399,6 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
}
}
- /* Unlock */
- if(SSLSESSION_SHARED(data))
- Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
-
return no_match;
}
@@ -418,9 +431,6 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
size_t i;
struct SessionHandle *data=conn->data;
- if(SSLSESSION_SHARED(data))
- Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
-
for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) {
struct curl_ssl_session *check = &data->state.session[i];
@@ -429,9 +439,6 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
break;
}
}
-
- if(SSLSESSION_SHARED(data))
- Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
}
/*
@@ -481,7 +488,6 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
/* If using shared SSL session, lock! */
if(SSLSESSION_SHARED(data)) {
- Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
general_age = &data->share->sessionage;
}
else {
@@ -514,10 +520,6 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
store->conn_to_port = conn_to_port; /* connect to port number */
store->remote_port = conn->remote_port; /* port number */
- /* Unlock */
- if(SSLSESSION_SHARED(data))
- Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
-
if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) {
store->sessionid = NULL; /* let caller free sessionid */
free(clone_host);
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index 31ba9fc50..f7031561a 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -96,17 +96,48 @@ CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum,
/* Functions to be used by SSL library adaptation functions */
-/* extract a session ID */
+/* Lock session cache mutex.
+ * Call this before calling other Curl_ssl_*session* functions
+ * Caller should unlock this mutex as soon as possible, as it may block
+ * other SSL connection from making progress.
+ * The purpose of explicitly locking SSL session cache data is to allow
+ * individual SSL engines to manage session lifetime in their specific way.
+ */
+void Curl_ssl_sessionid_lock(struct connectdata *conn);
+
+/* Unlock session cache mutex */
+void Curl_ssl_sessionid_unlock(struct connectdata *conn);
+
+/* extract a session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must make sure that the ownership of returned sessionid object
+ * is properly taken (e.g. its refcount is incremented
+ * under sessionid mutex).
+ */
bool Curl_ssl_getsessionid(struct connectdata *conn,
void **ssl_sessionid,
size_t *idsize); /* set 0 if unknown */
-/* add a new session ID */
+/* add a new session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must ensure that it has properly shared ownership of this sessionid
+ * object with cache (e.g. incrementing refcount on success)
+ */
CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
void *ssl_sessionid,
size_t idsize);
-/* Kill a single session ID entry in the cache */
+/* Kill a single session ID entry in the cache
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * This will call engine-specific curlssl_session_free function, which must
+ * take sessionid object ownership from sessionid cache
+ * (e.g. decrement refcount).
+ */
void Curl_ssl_kill_session(struct curl_ssl_session *session);
-/* delete a session from the cache */
+/* delete a session from the cache
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * This will call engine-specific curlssl_session_free function, which must
+ * take sessionid object ownership from sessionid cache
+ * (e.g. decrement refcount).
+ */
void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
/* get N random bytes into the buffer, return 0 if a find random is filled