summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls/vtls.c
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2024-07-25 00:50:30 +0300
committerdartraiden <wowemuh@gmail.com>2024-07-25 02:38:23 +0300
commit67a42fc97c64c83e02f6f0d68e5a4a22c71138d3 (patch)
tree21eb2d53a9cd7e645a58662dee11588f56057eee /libs/libcurl/src/vtls/vtls.c
parent0a365886f2d06750a707037d894e1492988eb53c (diff)
libcurl: update to 8.9.0
Diffstat (limited to 'libs/libcurl/src/vtls/vtls.c')
-rw-r--r--libs/libcurl/src/vtls/vtls.c222
1 files changed, 154 insertions, 68 deletions
diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c
index f4633a5f1c..8e5f8a5491 100644
--- a/libs/libcurl/src/vtls/vtls.c
+++ b/libs/libcurl/src/vtls/vtls.c
@@ -68,6 +68,8 @@
#include "curl_base64.h"
#include "curl_printf.h"
#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
#include "strdup.h"
/* The last #include files should be: */
@@ -103,7 +105,7 @@ static CURLcode blobdup(struct curl_blob **dest,
DEBUGASSERT(dest);
DEBUGASSERT(!*dest);
if(src) {
- /* only if there's data to dupe! */
+ /* only if there is data to dupe! */
struct curl_blob *d;
d = malloc(sizeof(struct curl_blob) + src->len);
if(!d)
@@ -152,7 +154,7 @@ static const struct alpn_spec *alpn_get_spec(int httpwant, bool use_alpn)
(void)httpwant;
#endif
/* Use the ALPN protocol "http/1.1" for HTTP/1.x.
- Avoid "http/1.0" because some servers don't support it. */
+ Avoid "http/1.0" because some servers do not support it. */
return &ALPN_SPEC_H11;
}
#endif /* USE_SSL */
@@ -166,7 +168,7 @@ void Curl_ssl_easy_config_init(struct Curl_easy *data)
*/
data->set.ssl.primary.verifypeer = TRUE;
data->set.ssl.primary.verifyhost = TRUE;
- data->set.ssl.primary.sessionid = TRUE; /* session ID caching by default */
+ data->set.ssl.primary.cache_session = TRUE; /* caching by default */
#ifndef CURL_DISABLE_PROXY
data->set.proxy_ssl = data->set.ssl;
#endif
@@ -228,7 +230,7 @@ static bool clone_ssl_primary_config(struct ssl_primary_config *source,
dest->verifypeer = source->verifypeer;
dest->verifyhost = source->verifyhost;
dest->verifystatus = source->verifystatus;
- dest->sessionid = source->sessionid;
+ dest->cache_session = source->cache_session;
dest->ssl_options = source->ssl_options;
CLONE_BLOB(cert_blob);
@@ -453,7 +455,7 @@ static bool ssl_prefs_check(struct Curl_easy *data)
}
static struct ssl_connect_data *cf_ctx_new(struct Curl_easy *data,
- const struct alpn_spec *alpn)
+ const struct alpn_spec *alpn)
{
struct ssl_connect_data *ctx;
@@ -529,8 +531,8 @@ void Curl_ssl_sessionid_unlock(struct Curl_easy *data)
}
/*
- * 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.
+ * Check if there is a session ID for the given connection in the cache, and if
+ * there is one suitable, it is provided. Returns TRUE when no entry matched.
*/
bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
struct Curl_easy *data,
@@ -549,9 +551,9 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
if(!ssl_config)
return TRUE;
- DEBUGASSERT(ssl_config->primary.sessionid);
+ DEBUGASSERT(ssl_config->primary.cache_session);
- if(!ssl_config->primary.sessionid || !data->state.session)
+ if(!ssl_config->primary.cache_session || !data->state.session)
/* session ID reuse is disabled or the session cache has not been
setup */
return TRUE;
@@ -590,7 +592,7 @@ bool Curl_ssl_getsessionid(struct Curl_cfilter *cf,
}
DEBUGF(infof(data, "%s Session ID in cache for %s %s://%s:%d",
- no_match? "Didn't find": "Found",
+ no_match? "Did not find": "Found",
Curl_ssl_cf_is_proxy(cf) ? "proxy" : "host",
cf->conn->handler->scheme, peer->hostname, peer->port));
return no_match;
@@ -635,18 +637,12 @@ void Curl_ssl_delsessionid(struct Curl_easy *data, void *ssl_sessionid)
}
}
-/*
- * Store session id in the session cache. The ID passed on to this function
- * must already have been extracted and allocated the proper way for the SSL
- * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
- * later on.
- */
-CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const struct ssl_peer *peer,
- void *ssl_sessionid,
- size_t idsize,
- Curl_ssl_sessionid_dtor *sessionid_free_cb)
+CURLcode Curl_ssl_set_sessionid(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const struct ssl_peer *peer,
+ void *ssl_sessionid,
+ size_t idsize,
+ Curl_ssl_sessionid_dtor *sessionid_free_cb)
{
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
@@ -657,6 +653,8 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
char *clone_conn_to_host = NULL;
int conn_to_port;
long *general_age;
+ void *old_sessionid;
+ size_t old_size;
CURLcode result = CURLE_OUT_OF_MEMORY;
DEBUGASSERT(ssl_sessionid);
@@ -667,9 +665,20 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
return CURLE_OK;
}
+ if(!Curl_ssl_getsessionid(cf, data, peer, &old_sessionid, &old_size)) {
+ if((old_size == idsize) &&
+ ((old_sessionid == ssl_sessionid) ||
+ (idsize && !memcmp(old_sessionid, ssl_sessionid, idsize)))) {
+ /* the very same */
+ sessionid_free_cb(ssl_sessionid, idsize);
+ return CURLE_OK;
+ }
+ Curl_ssl_delsessionid(data, old_sessionid);
+ }
+
store = &data->state.session[0];
oldest_age = data->state.session[0].age; /* zero if unused */
- DEBUGASSERT(ssl_config->primary.sessionid);
+ DEBUGASSERT(ssl_config->primary.cache_session);
(void)ssl_config;
clone_host = strdup(peer->hostname);
@@ -687,7 +696,7 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
else
conn_to_port = -1;
- /* Now we should add the session ID and the host name to the cache, (remove
+ /* Now we should add the session ID and the hostname to the cache, (remove
the oldest if necessary) */
/* If using shared SSL session, lock! */
@@ -722,12 +731,12 @@ CURLcode Curl_ssl_addsessionid(struct Curl_cfilter *cf,
store->idsize = idsize;
store->sessionid_free = sessionid_free_cb;
store->age = *general_age; /* set current age */
- /* free it if there's one already present */
+ /* free it if there is one already present */
free(store->name);
free(store->conn_to_host);
- store->name = clone_host; /* clone host name */
+ store->name = clone_host; /* clone hostname */
clone_host = NULL;
- store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
+ store->conn_to_host = clone_conn_to_host; /* clone connect to hostname */
clone_conn_to_host = NULL;
store->conn_to_port = conn_to_port; /* connect to port number */
/* port number */
@@ -753,12 +762,6 @@ out:
return CURLE_OK;
}
-void Curl_free_multi_ssl_backend_data(struct multi_ssl_backend_data *mbackend)
-{
- if(Curl_ssl->free_multi_ssl_backend_data && mbackend)
- Curl_ssl->free_multi_ssl_backend_data(mbackend);
-}
-
void Curl_ssl_close_all(struct Curl_easy *data)
{
/* kill the session ID cache if not shared */
@@ -778,11 +781,12 @@ void Curl_ssl_close_all(struct Curl_easy *data)
void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps)
{
- if(!cf->connected) {
- struct ssl_connect_data *connssl = cf->ctx;
+ struct ssl_connect_data *connssl = cf->ctx;
+
+ if(connssl->io_need) {
curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
if(sock != CURL_SOCKET_BAD) {
- if(connssl->connecting_state == ssl_connect_2_writing) {
+ if(connssl->io_need & CURL_SSL_IO_NEED_SEND) {
Curl_pollset_set_out_only(data, ps, sock);
CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%"
CURL_FORMAT_SOCKET_T, sock);
@@ -1000,7 +1004,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
(void)data;
#endif
- /* if a path wasn't specified, don't pin */
+ /* if a path was not specified, do not pin */
if(!pinnedpubkey)
return CURLE_OK;
if(!pubkey || !pubkeylen)
@@ -1048,7 +1052,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
end_pos = strstr(begin_pos, ";sha256//");
/*
* if there is an end_pos, null terminate,
- * otherwise it'll go to the end of the original string
+ * otherwise it will go to the end of the original string
*/
if(end_pos)
end_pos[0] = '\0';
@@ -1094,7 +1098,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
/*
* if the size of our certificate is bigger than the file
- * size then it can't match
+ * size then it cannot match
*/
size = curlx_sotouz((curl_off_t) filesize);
if(pubkeylen > size)
@@ -1112,7 +1116,7 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
if((int) fread(buf, size, 1, fp) != 1)
break;
- /* If the sizes are the same, it can't be base64 encoded, must be der */
+ /* If the sizes are the same, it cannot be base64 encoded, must be der */
if(pubkeylen == size) {
if(!memcmp(pubkey, buf, pubkeylen))
result = CURLE_OK;
@@ -1120,18 +1124,18 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
}
/*
- * Otherwise we will assume it's PEM and try to decode it
+ * Otherwise we will assume it is PEM and try to decode it
* after placing null terminator
*/
buf[size] = '\0';
pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
- /* if it wasn't read successfully, exit */
+ /* if it was not read successfully, exit */
if(pem_read)
break;
/*
- * if the size of our certificate doesn't match the size of
- * the decoded file, they can't be the same, otherwise compare
+ * if the size of our certificate does not match the size of
+ * the decoded file, they cannot be the same, otherwise compare
*/
if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
result = CURLE_OK;
@@ -1173,12 +1177,18 @@ int Curl_none_init(void)
void Curl_none_cleanup(void)
{ }
-int Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
- struct Curl_easy *data UNUSED_PARAM)
+CURLcode Curl_none_shutdown(struct Curl_cfilter *cf UNUSED_PARAM,
+ struct Curl_easy *data UNUSED_PARAM,
+ bool send_shutdown UNUSED_PARAM,
+ bool *done)
{
(void)data;
(void)cf;
- return 0;
+ (void)send_shutdown;
+ /* Every SSL backend should have a shutdown implementation. Until we
+ * have implemented that, we put this fake in place. */
+ *done = TRUE;
+ return CURLE_OK;
}
int Curl_none_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1339,7 +1349,6 @@ static const struct Curl_ssl Curl_ssl_multi = {
NULL, /* sha256sum */
NULL, /* associate_connection */
NULL, /* disassociate_connection */
- NULL, /* free_multi_ssl_backend_data */
multissl_recv_plain, /* recv decrypted data */
multissl_send_plain, /* send data to encrypt */
};
@@ -1349,8 +1358,6 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_multi;
#elif defined(USE_WOLFSSL)
&Curl_ssl_wolfssl;
-#elif defined(USE_SECTRANSP)
- &Curl_ssl_sectransp;
#elif defined(USE_GNUTLS)
&Curl_ssl_gnutls;
#elif defined(USE_MBEDTLS)
@@ -1359,6 +1366,8 @@ const struct Curl_ssl *Curl_ssl =
&Curl_ssl_rustls;
#elif defined(USE_OPENSSL)
&Curl_ssl_openssl;
+#elif defined(USE_SECTRANSP)
+ &Curl_ssl_sectransp;
#elif defined(USE_SCHANNEL)
&Curl_ssl_schannel;
#elif defined(USE_BEARSSL)
@@ -1371,9 +1380,6 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_WOLFSSL)
&Curl_ssl_wolfssl,
#endif
-#if defined(USE_SECTRANSP)
- &Curl_ssl_sectransp,
-#endif
#if defined(USE_GNUTLS)
&Curl_ssl_gnutls,
#endif
@@ -1383,6 +1389,9 @@ static const struct Curl_ssl *available_backends[] = {
#if defined(USE_OPENSSL)
&Curl_ssl_openssl,
#endif
+#if defined(USE_SECTRANSP)
+ &Curl_ssl_sectransp,
+#endif
#if defined(USE_SCHANNEL)
&Curl_ssl_schannel,
#endif
@@ -1564,10 +1573,10 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf,
const char *ehostname, *edispname;
int eport;
- /* We need the hostname for SNI negotiation. Once handshaked, this
- * remains the SNI hostname for the TLS connection. But when the
- * connection is reused, the settings in cf->conn might change.
- * So we keep a copy of the hostname we use for SNI.
+ /* We need the hostname for SNI negotiation. Once handshaked, this remains
+ * the SNI hostname for the TLS connection. When the connection is reused,
+ * the settings in cf->conn might change. We keep a copy of the hostname we
+ * use for SNI.
*/
#ifndef CURL_DISABLE_PROXY
if(Curl_ssl_cf_is_proxy(cf)) {
@@ -1751,17 +1760,34 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
return nread;
}
-static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct easy_pollset *ps)
+static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- struct cf_call_data save;
+ CURLcode result = CURLE_OK;
+
+ *done = TRUE;
+ if(!cf->shutdown) {
+ struct cf_call_data save;
- if(!cf->connected) {
CF_DATA_SAVE(save, cf, data);
- Curl_ssl->adjust_pollset(cf, data, ps);
+ result = Curl_ssl->shut_down(cf, data, TRUE, done);
+ CURL_TRC_CF(data, cf, "cf_shutdown -> %d, done=%d", result, *done);
CF_DATA_RESTORE(cf, save);
+ cf->shutdown = (result || *done);
}
+ return result;
+}
+
+static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct easy_pollset *ps)
+{
+ struct cf_call_data save;
+
+ CF_DATA_SAVE(save, cf, data);
+ Curl_ssl->adjust_pollset(cf, data, ps);
+ CF_DATA_RESTORE(cf, save);
}
static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
@@ -1851,6 +1877,7 @@ struct Curl_cftype Curl_cft_ssl = {
ssl_cf_destroy,
ssl_cf_connect,
ssl_cf_close,
+ ssl_cf_shutdown,
Curl_cf_def_get_host,
ssl_cf_adjust_pollset,
ssl_cf_data_pending,
@@ -1871,6 +1898,7 @@ struct Curl_cftype Curl_cft_ssl_proxy = {
ssl_cf_destroy,
ssl_cf_connect,
ssl_cf_close,
+ ssl_cf_shutdown,
Curl_cf_def_get_host,
ssl_cf_adjust_pollset,
ssl_cf_data_pending,
@@ -1982,10 +2010,10 @@ CURLcode Curl_cf_ssl_proxy_insert_after(struct Curl_cfilter *cf_at,
#endif /* !CURL_DISABLE_PROXY */
-bool Curl_ssl_supports(struct Curl_easy *data, int option)
+bool Curl_ssl_supports(struct Curl_easy *data, unsigned int ssl_option)
{
(void)data;
- return (Curl_ssl->supports & option)? TRUE : FALSE;
+ return (Curl_ssl->supports & ssl_option)? TRUE : FALSE;
}
static struct Curl_cfilter *get_ssl_filter(struct Curl_cfilter *cf)
@@ -2021,19 +2049,77 @@ void *Curl_ssl_get_internals(struct Curl_easy *data, int sockindex,
return result;
}
+static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct cf_call_data save;
+ CURLcode result = CURLE_OK;
+ timediff_t timeout_ms;
+ int what, loop = 10;
+
+ if(cf->shutdown) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ CF_DATA_SAVE(save, cf, data);
+
+ *done = FALSE;
+ while(!result && !*done && loop--) {
+ timeout_ms = Curl_shutdown_timeleft(cf->conn, cf->sockindex, NULL);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time is already up */
+ failf(data, "SSL shutdown timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ result = Curl_ssl->shut_down(cf, data, send_shutdown, done);
+ if(result ||*done)
+ goto out;
+
+ if(connssl->io_need) {
+ what = Curl_conn_cf_poll(cf, data, timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ result = CURLE_RECV_ERROR;
+ goto out;
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto out;
+ }
+ /* socket is readable or writable */
+ }
+ }
+out:
+ CF_DATA_RESTORE(cf, save);
+ cf->shutdown = (result || *done);
+ return result;
+}
+
CURLcode Curl_ssl_cfilter_remove(struct Curl_easy *data,
- int sockindex)
+ int sockindex, bool send_shutdown)
{
struct Curl_cfilter *cf, *head;
CURLcode result = CURLE_OK;
- (void)data;
head = data->conn? data->conn->cfilter[sockindex] : NULL;
for(cf = head; cf; cf = cf->next) {
if(cf->cft == &Curl_cft_ssl) {
- if(Curl_ssl->shut_down(cf, data))
+ bool done;
+ CURL_TRC_CF(data, cf, "shutdown and remove SSL, start");
+ Curl_shutdown_start(data, sockindex, NULL);
+ result = vtls_shutdown_blocking(cf, data, send_shutdown, &done);
+ Curl_shutdown_clear(data, sockindex);
+ if(!result && !done) /* blocking failed? */
result = CURLE_SSL_SHUTDOWN_FAILED;
Curl_conn_cf_discard_sub(head, cf, data, FALSE);
+ CURL_TRC_CF(data, cf, "shutdown and remove SSL, done -> %d", result);
break;
}
}