summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vtls')
-rw-r--r--libs/libcurl/src/vtls/bearssl.c2
-rw-r--r--libs/libcurl/src/vtls/gtls.c4
-rw-r--r--libs/libcurl/src/vtls/mbedtls.c77
-rw-r--r--libs/libcurl/src/vtls/mbedtls_threadlock.c12
-rw-r--r--libs/libcurl/src/vtls/mbedtls_threadlock.h4
-rw-r--r--libs/libcurl/src/vtls/openssl.c74
-rw-r--r--libs/libcurl/src/vtls/rustls.c73
-rw-r--r--libs/libcurl/src/vtls/schannel.c14
-rw-r--r--libs/libcurl/src/vtls/sectransp.c2
-rw-r--r--libs/libcurl/src/vtls/vtls.c55
-rw-r--r--libs/libcurl/src/vtls/vtls_int.h1
-rw-r--r--libs/libcurl/src/vtls/wolfssl.c6
12 files changed, 218 insertions, 106 deletions
diff --git a/libs/libcurl/src/vtls/bearssl.c b/libs/libcurl/src/vtls/bearssl.c
index 924802c61f..9ccfd8f473 100644
--- a/libs/libcurl/src/vtls/bearssl.c
+++ b/libs/libcurl/src/vtls/bearssl.c
@@ -707,7 +707,7 @@ static CURLcode bearssl_connect_step1(struct Curl_cfilter *cf,
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
}
- if(connssl->peer.is_ip_address) {
+ if(connssl->peer.type != CURL_SSL_PEER_DNS) {
if(verifyhost) {
failf(data, "BearSSL: "
"host verification of IP address is not supported");
diff --git a/libs/libcurl/src/vtls/gtls.c b/libs/libcurl/src/vtls/gtls.c
index dd40380738..1184ceb5c6 100644
--- a/libs/libcurl/src/vtls/gtls.c
+++ b/libs/libcurl/src/vtls/gtls.c
@@ -117,6 +117,8 @@ static ssize_t gtls_pull(void *s, void *buf, size_t blen)
(CURLE_AGAIN == result)? EAGAIN : EINVAL);
nread = -1;
}
+ else if(nread == 0)
+ connssl->peer_closed = TRUE;
return nread;
}
@@ -1489,7 +1491,7 @@ static int gtls_shutdown(struct Curl_cfilter *cf,
bool done = FALSE;
char buf[120];
- while(!done) {
+ while(!done && !connssl->peer_closed) {
int what = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data),
SSL_SHUTDOWN_TIMEOUT);
if(what > 0) {
diff --git a/libs/libcurl/src/vtls/mbedtls.c b/libs/libcurl/src/vtls/mbedtls.c
index c008eace9b..22a6a8cba2 100644
--- a/libs/libcurl/src/vtls/mbedtls.c
+++ b/libs/libcurl/src/vtls/mbedtls.c
@@ -110,7 +110,8 @@ struct mbed_ssl_backend_data {
};
/* apply threading? */
-#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
+ defined(_WIN32)
#define THREADING_SUPPORT
#endif
@@ -123,7 +124,6 @@ static mbedtls_entropy_context ts_entropy;
static int entropy_init_initialized = 0;
-/* start of entropy_init_mutex() */
static void entropy_init_mutex(mbedtls_entropy_context *ctx)
{
/* lock 0 = entropy_init_mutex() */
@@ -134,9 +134,18 @@ static void entropy_init_mutex(mbedtls_entropy_context *ctx)
}
Curl_mbedtlsthreadlock_unlock_function(0);
}
-/* end of entropy_init_mutex() */
-/* start of entropy_func_mutex() */
+static void entropy_cleanup_mutex(mbedtls_entropy_context *ctx)
+{
+ /* lock 0 = use same lock as init */
+ Curl_mbedtlsthreadlock_lock_function(0);
+ if(entropy_init_initialized == 1) {
+ mbedtls_entropy_free(ctx);
+ entropy_init_initialized = 0;
+ }
+ Curl_mbedtlsthreadlock_unlock_function(0);
+}
+
static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
{
int ret;
@@ -147,7 +156,6 @@ static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
return ret;
}
-/* end of entropy_func_mutex() */
#endif /* THREADING_SUPPORT */
@@ -237,6 +245,23 @@ static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+static CURLcode mbedtls_version_from_curl(
+ mbedtls_ssl_protocol_version* mbedver, long version)
+{
+ switch(version) {
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ *mbedver = MBEDTLS_SSL_VERSION_TLS1_2;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_3:
+ break;
+ }
+
+ return CURLE_SSL_CONNECT_ERROR;
+}
+#else
static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
{
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
@@ -267,6 +292,7 @@ static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
return CURLE_SSL_CONNECT_ERROR;
}
+#endif
static CURLcode
set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -275,7 +301,10 @@ set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
struct mbed_ssl_backend_data *backend =
(struct mbed_ssl_backend_data *)connssl->backend;
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
-#if MBEDTLS_VERSION_NUMBER >= 0x03000000
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+ mbedtls_ssl_protocol_version mbedtls_ver_min = MBEDTLS_SSL_VERSION_TLS1_2;
+ mbedtls_ssl_protocol_version mbedtls_ver_max = MBEDTLS_SSL_VERSION_TLS1_2;
+#elif MBEDTLS_VERSION_NUMBER >= 0x03000000
int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_3;
int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_3;
#else
@@ -313,10 +342,15 @@ set_ssl_version_min_max(struct Curl_cfilter *cf, struct Curl_easy *data)
return result;
}
+#if MBEDTLS_VERSION_NUMBER >= 0x03020000
+ mbedtls_ssl_conf_min_tls_version(&backend->config, mbedtls_ver_min);
+ mbedtls_ssl_conf_max_tls_version(&backend->config, mbedtls_ver_max);
+#else
mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
mbedtls_ver_min);
mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3,
mbedtls_ver_max);
+#endif
return result;
}
@@ -351,7 +385,6 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
#ifdef THREADING_SUPPORT
- entropy_init_mutex(&ts_entropy);
mbedtls_ctr_drbg_init(&backend->ctr_drbg);
ret = mbedtls_ctr_drbg_seed(&backend->ctr_drbg, entropy_func_mutex,
@@ -654,14 +687,13 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
&backend->clicert, &backend->pk);
}
- if(connssl->peer.sni) {
- if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni)) {
- /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
- the name to set in the SNI extension. So even if curl connects to a
- host specified as an IP address, this function must be used. */
- failf(data, "Failed to set SNI");
- return CURLE_SSL_CONNECT_ERROR;
- }
+ if(mbedtls_ssl_set_hostname(&backend->ssl, connssl->peer.sni?
+ connssl->peer.sni : connssl->peer.hostname)) {
+ /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks and
+ the name to set in the SNI extension. So even if curl connects to a
+ host specified as an IP address, this function must be used. */
+ failf(data, "Failed to set SNI");
+ return CURLE_SSL_CONNECT_ERROR;
}
#ifdef HAS_ALPN
@@ -775,6 +807,7 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
peercert = mbedtls_ssl_get_peer_cert(&backend->ssl);
if(peercert && data->set.verbose) {
+#ifndef MBEDTLS_X509_REMOVE_INFO
const size_t bufsize = 16384;
char *buffer = malloc(bufsize);
@@ -787,6 +820,9 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
infof(data, "Unable to dump certificate information");
free(buffer);
+#else
+ infof(data, "Unable to dump certificate information");
+#endif
}
if(pinnedpubkey) {
@@ -1216,14 +1252,19 @@ static CURLcode mbedtls_connect(struct Curl_cfilter *cf,
*/
static int mbedtls_init(void)
{
- return Curl_mbedtlsthreadlock_thread_setup();
+ if(!Curl_mbedtlsthreadlock_thread_setup())
+ return 0;
+#ifdef THREADING_SUPPORT
+ entropy_init_mutex(&ts_entropy);
+#endif
+ return 1;
}
static void mbedtls_cleanup(void)
{
#ifdef THREADING_SUPPORT
- mbedtls_entropy_free(&ts_entropy);
-#endif /* THREADING_SUPPORT */
+ entropy_cleanup_mutex(&ts_entropy);
+#endif
(void)Curl_mbedtlsthreadlock_thread_cleanup();
}
diff --git a/libs/libcurl/src/vtls/mbedtls_threadlock.c b/libs/libcurl/src/vtls/mbedtls_threadlock.c
index 757d19f003..d6d20328a7 100644
--- a/libs/libcurl/src/vtls/mbedtls_threadlock.c
+++ b/libs/libcurl/src/vtls/mbedtls_threadlock.c
@@ -26,12 +26,12 @@
#if defined(USE_MBEDTLS) && \
((defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
- defined(USE_THREADS_WIN32))
+ defined(_WIN32))
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
# include <pthread.h>
# define MBEDTLS_MUTEX_T pthread_mutex_t
-#elif defined(USE_THREADS_WIN32)
+#elif defined(_WIN32)
# define MBEDTLS_MUTEX_T HANDLE
#endif
@@ -59,7 +59,7 @@ int Curl_mbedtlsthreadlock_thread_setup(void)
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
if(pthread_mutex_init(&mutex_buf[i], NULL))
return 0; /* pthread_mutex_init failed */
-#elif defined(USE_THREADS_WIN32)
+#elif defined(_WIN32)
mutex_buf[i] = CreateMutex(0, FALSE, 0);
if(mutex_buf[i] == 0)
return 0; /* CreateMutex failed */
@@ -80,7 +80,7 @@ int Curl_mbedtlsthreadlock_thread_cleanup(void)
#if defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)
if(pthread_mutex_destroy(&mutex_buf[i]))
return 0; /* pthread_mutex_destroy failed */
-#elif defined(USE_THREADS_WIN32)
+#elif defined(_WIN32)
if(!CloseHandle(mutex_buf[i]))
return 0; /* CloseHandle failed */
#endif /* USE_THREADS_POSIX && HAVE_PTHREAD_H */
@@ -100,7 +100,7 @@ int Curl_mbedtlsthreadlock_lock_function(int n)
"Error: mbedtlsthreadlock_lock_function failed\n"));
return 0; /* pthread_mutex_lock failed */
}
-#elif defined(USE_THREADS_WIN32)
+#elif defined(_WIN32)
if(WaitForSingleObject(mutex_buf[n], INFINITE) == WAIT_FAILED) {
DEBUGF(fprintf(stderr,
"Error: mbedtlsthreadlock_lock_function failed\n"));
@@ -120,7 +120,7 @@ int Curl_mbedtlsthreadlock_unlock_function(int n)
"Error: mbedtlsthreadlock_unlock_function failed\n"));
return 0; /* pthread_mutex_unlock failed */
}
-#elif defined(USE_THREADS_WIN32)
+#elif defined(_WIN32)
if(!ReleaseMutex(mutex_buf[n])) {
DEBUGF(fprintf(stderr,
"Error: mbedtlsthreadlock_unlock_function failed\n"));
diff --git a/libs/libcurl/src/vtls/mbedtls_threadlock.h b/libs/libcurl/src/vtls/mbedtls_threadlock.h
index 96f4bb8d43..ae651c3866 100644
--- a/libs/libcurl/src/vtls/mbedtls_threadlock.h
+++ b/libs/libcurl/src/vtls/mbedtls_threadlock.h
@@ -29,7 +29,7 @@
#ifdef USE_MBEDTLS
#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \
- defined(USE_THREADS_WIN32)
+ defined(_WIN32)
int Curl_mbedtlsthreadlock_thread_setup(void);
int Curl_mbedtlsthreadlock_thread_cleanup(void);
@@ -43,7 +43,7 @@ int Curl_mbedtlsthreadlock_unlock_function(int n);
#define Curl_mbedtlsthreadlock_lock_function(x) 1
#define Curl_mbedtlsthreadlock_unlock_function(x) 1
-#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
+#endif /* (USE_THREADS_POSIX && HAVE_PTHREAD_H) || _WIN32 */
#endif /* USE_MBEDTLS */
diff --git a/libs/libcurl/src/vtls/openssl.c b/libs/libcurl/src/vtls/openssl.c
index be6780b7ed..b22ec269ac 100644
--- a/libs/libcurl/src/vtls/openssl.c
+++ b/libs/libcurl/src/vtls/openssl.c
@@ -769,6 +769,9 @@ static int ossl_bio_cf_in_read(BIO *bio, char *buf, int blen)
if(CURLE_AGAIN == result)
BIO_set_retry_read(bio);
}
+ else if(nread == 0) {
+ connssl->peer_closed = TRUE;
+ }
/* Before returning server replies to the SSL instance, we need
* to have setup the x509 store or verification will fail. */
@@ -1887,16 +1890,41 @@ static void ossl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
if(backend->handle) {
- if(cf->next && cf->next->connected) {
+ /* Send the TLS shutdown if we are still connected *and* if
+ * the peer did not already close the connection. */
+ if(cf->next && cf->next->connected && !connssl->peer_closed) {
char buf[1024];
int nread, err;
long sslerr;
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
- (void)SSL_read(backend->handle, buf, (int)sizeof(buf));
ERR_clear_error();
- if(SSL_shutdown(backend->handle) == 1) {
+ nread = SSL_read(backend->handle, buf, (int)sizeof(buf));
+ err = SSL_get_error(backend->handle, nread);
+ if(!nread && err == SSL_ERROR_ZERO_RETURN) {
+ CURLcode result;
+ ssize_t n;
+ size_t blen = sizeof(buf);
+ CURL_TRC_CF(data, cf, "peer has shutdown TLS");
+ /* SSL_read() will not longer touch the socket, let's receive
+ * directly from the next filter to see if the underlying
+ * connection has also been closed. */
+ n = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+ if(!n) {
+ connssl->peer_closed = TRUE;
+ CURL_TRC_CF(data, cf, "peer closed connection");
+ }
+ }
+ ERR_clear_error();
+ if(connssl->peer_closed) {
+ /* As the peer closed, we do not expect it to read anything more we
+ * may send. It may be harmful, leading to TCP RST and delaying
+ * a lingering close. Just leave. */
+ CURL_TRC_CF(data, cf, "not from sending TLS shutdown on "
+ "connection closed by peer");
+ }
+ else if(SSL_shutdown(backend->handle) == 1) {
CURL_TRC_CF(data, cf, "SSL shutdown finished");
}
else {
@@ -2134,7 +2162,7 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
struct ssl_peer *peer, X509 *server_cert)
{
bool matched = FALSE;
- int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
+ int target; /* target type, GEN_DNS or GEN_IPADD */
size_t addrlen = 0;
STACK_OF(GENERAL_NAME) *altnames;
#ifdef ENABLE_IPV6
@@ -2149,19 +2177,28 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
(void)conn;
hostlen = strlen(peer->hostname);
- if(peer->is_ip_address) {
+ switch(peer->type) {
+ case CURL_SSL_PEER_IPV4:
+ if(!Curl_inet_pton(AF_INET, peer->hostname, &addr))
+ return CURLE_PEER_FAILED_VERIFICATION;
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in_addr);
+ break;
#ifdef ENABLE_IPV6
- if(conn->bits.ipv6_ip &&
- Curl_inet_pton(AF_INET6, peer->hostname, &addr)) {
- target = GEN_IPADD;
- addrlen = sizeof(struct in6_addr);
- }
- else
+ case CURL_SSL_PEER_IPV6:
+ if(!Curl_inet_pton(AF_INET6, peer->hostname, &addr))
+ return CURLE_PEER_FAILED_VERIFICATION;
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in6_addr);
+ break;
#endif
- if(Curl_inet_pton(AF_INET, peer->hostname, &addr)) {
- target = GEN_IPADD;
- addrlen = sizeof(struct in_addr);
- }
+ case CURL_SSL_PEER_DNS:
+ target = GEN_DNS;
+ break;
+ default:
+ DEBUGASSERT(0);
+ failf(data, "unexpected ssl peer type: %d", peer->type);
+ return CURLE_PEER_FAILED_VERIFICATION;
}
/* get a "list" of alternative names */
@@ -2242,9 +2279,12 @@ CURLcode Curl_ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn,
/* an alternative name matched */
;
else if(dNSName || iPAddress) {
- infof(data, " subjectAltName does not match %s", peer->dispname);
+ const char *tname = (peer->type == CURL_SSL_PEER_DNS) ? "host name" :
+ (peer->type == CURL_SSL_PEER_IPV4) ?
+ "ipv4 address" : "ipv6 address";
+ infof(data, " subjectAltName does not match %s %s", tname, peer->dispname);
failf(data, "SSL: no alternative certificate subject name matches "
- "target host name '%s'", peer->dispname);
+ "target %s '%s'", tname, peer->dispname);
result = CURLE_PEER_FAILED_VERIFICATION;
}
else {
diff --git a/libs/libcurl/src/vtls/rustls.c b/libs/libcurl/src/vtls/rustls.c
index f0eb1443e6..0688df13ef 100644
--- a/libs/libcurl/src/vtls/rustls.c
+++ b/libs/libcurl/src/vtls/rustls.c
@@ -7,6 +7,7 @@
*
* Copyright (C) Jacob Hoffman-Andrews,
* <github@hoffman-andrews.com>
+ * Copyright (C) kpcyrd, <kpcyrd@archlinux.org>
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -85,6 +86,7 @@ static int
read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
{
struct io_ctx *io_ctx = userdata;
+ struct ssl_connect_data *const connssl = io_ctx->cf->ctx;
CURLcode result;
int ret = 0;
ssize_t nread = Curl_conn_cf_recv(io_ctx->cf->next, io_ctx->data,
@@ -96,6 +98,8 @@ read_cb(void *userdata, uint8_t *buf, uintptr_t len, uintptr_t *out_n)
else
ret = EINVAL;
}
+ else if(nread == 0)
+ connssl->peer_closed = TRUE;
*out_n = (int)nread;
return ret;
}
@@ -291,7 +295,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
DEBUGASSERT(backend);
rconn = backend->conn;
- CURL_TRC_CF(data, cf, "cf_send: %ld plain bytes", plainlen);
+ CURL_TRC_CF(data, cf, "cf_send: %zu plain bytes", plainlen);
io_ctx.cf = cf;
io_ctx.data = data;
@@ -342,7 +346,7 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data,
/* A server certificate verify callback for rustls that always returns
RUSTLS_RESULT_OK, or in other words disable certificate verification. */
-static enum rustls_result
+static uint32_t
cr_verify_none(void *userdata UNUSED_PARAM,
const rustls_verify_server_cert_params *params UNUSED_PARAM)
{
@@ -373,7 +377,10 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct rustls_connection *rconn = NULL;
struct rustls_client_config_builder *config_builder = NULL;
- struct rustls_root_cert_store *roots = NULL;
+ const struct rustls_root_cert_store *roots = NULL;
+ struct rustls_root_cert_store_builder *roots_builder = NULL;
+ struct rustls_web_pki_server_cert_verifier_builder *verifier_builder = NULL;
+ struct rustls_server_cert_verifier *server_cert_verifier = NULL;
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
const char * const ssl_cafile =
/* CURLOPT_CAINFO_BLOB overrides CURLOPT_CAINFO */
@@ -414,38 +421,60 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data,
hostname = "example.invalid";
}
}
- else if(ca_info_blob) {
- roots = rustls_root_cert_store_new();
-
- /* Enable strict parsing only if verification isn't disabled. */
- result = rustls_root_cert_store_add_pem(roots, ca_info_blob->data,
- ca_info_blob->len, verifypeer);
- if(result != RUSTLS_RESULT_OK) {
- failf(data, "rustls: failed to parse trusted certificates from blob");
- rustls_root_cert_store_free(roots);
- rustls_client_config_free(
- rustls_client_config_builder_build(config_builder));
- return CURLE_SSL_CACERT_BADFILE;
+ else if(ca_info_blob || ssl_cafile) {
+ roots_builder = rustls_root_cert_store_builder_new();
+
+ if(ca_info_blob) {
+ /* Enable strict parsing only if verification isn't disabled. */
+ result = rustls_root_cert_store_builder_add_pem(roots_builder,
+ ca_info_blob->data,
+ ca_info_blob->len,
+ verifypeer);
+ if(result != RUSTLS_RESULT_OK) {
+ failf(data, "rustls: failed to parse trusted certificates from blob");
+ rustls_root_cert_store_builder_free(roots_builder);
+ rustls_client_config_free(
+ rustls_client_config_builder_build(config_builder));
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ else if(ssl_cafile) {
+ /* Enable strict parsing only if verification isn't disabled. */
+ result = rustls_root_cert_store_builder_load_roots_from_file(
+ roots_builder, ssl_cafile, verifypeer);
+ if(result != RUSTLS_RESULT_OK) {
+ failf(data, "rustls: failed to load trusted certificates");
+ rustls_root_cert_store_builder_free(roots_builder);
+ rustls_client_config_free(
+ rustls_client_config_builder_build(config_builder));
+ return CURLE_SSL_CACERT_BADFILE;
+ }
}
- result = rustls_client_config_builder_use_roots(config_builder, roots);
- rustls_root_cert_store_free(roots);
+ result = rustls_root_cert_store_builder_build(roots_builder, &roots);
+ rustls_root_cert_store_builder_free(roots_builder);
if(result != RUSTLS_RESULT_OK) {
failf(data, "rustls: failed to load trusted certificates");
rustls_client_config_free(
rustls_client_config_builder_build(config_builder));
return CURLE_SSL_CACERT_BADFILE;
}
- }
- else if(ssl_cafile) {
- result = rustls_client_config_builder_load_roots_from_file(
- config_builder, ssl_cafile);
+
+ verifier_builder = rustls_web_pki_server_cert_verifier_builder_new(roots);
+
+ result = rustls_web_pki_server_cert_verifier_builder_build(
+ verifier_builder, &server_cert_verifier);
+ rustls_web_pki_server_cert_verifier_builder_free(verifier_builder);
if(result != RUSTLS_RESULT_OK) {
failf(data, "rustls: failed to load trusted certificates");
+ rustls_server_cert_verifier_free(server_cert_verifier);
rustls_client_config_free(
rustls_client_config_builder_build(config_builder));
return CURLE_SSL_CACERT_BADFILE;
}
+
+ rustls_client_config_builder_set_server_verifier(config_builder,
+ server_cert_verifier);
}
backend->config = rustls_client_config_builder_build(config_builder);
@@ -671,7 +700,7 @@ cr_close(struct Curl_cfilter *cf, struct Curl_easy *data)
DEBUGASSERT(backend);
- if(backend->conn) {
+ if(backend->conn && !connssl->peer_closed) {
rustls_connection_send_close_notify(backend->conn);
n = cr_send(cf, data, NULL, 0, &tmperr);
if(n < 0) {
diff --git a/libs/libcurl/src/vtls/schannel.c b/libs/libcurl/src/vtls/schannel.c
index 64a31f155d..d63d321bf3 100644
--- a/libs/libcurl/src/vtls/schannel.c
+++ b/libs/libcurl/src/vtls/schannel.c
@@ -1159,7 +1159,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
/* Warn if SNI is disabled due to use of an IP address */
- if(connssl->peer.is_ip_address) {
+ if(connssl->peer.type != CURL_SSL_PEER_DNS) {
infof(data, "schannel: using IP address, SNI is not supported by OS.");
}
@@ -2133,7 +2133,6 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
infof(data, "schannel: server indicated shutdown in a prior call");
goto cleanup;
}
-
/* It's debatable what to return when !len. Regardless we can't return
immediately because there may be data to decrypt (in the case we want to
decrypt all encrypted cached data) so handle !len later in cleanup.
@@ -2317,10 +2316,10 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
/* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
returned so we have to work around that in cleanup. */
backend->recv_sspi_close_notify = true;
- if(!backend->recv_connection_closed) {
+ if(!backend->recv_connection_closed)
backend->recv_connection_closed = true;
- infof(data, "schannel: server closed the connection");
- }
+ infof(data,
+ "schannel: server close notification received (close_notify)");
goto cleanup;
}
}
@@ -2443,7 +2442,10 @@ static bool schannel_data_pending(struct Curl_cfilter *cf,
if(backend->ctxt) /* SSL/TLS is in use */
return (backend->decdata_offset > 0 ||
- (backend->encdata_offset > 0 && !backend->encdata_is_incomplete));
+ (backend->encdata_offset > 0 && !backend->encdata_is_incomplete) ||
+ backend->recv_connection_closed ||
+ backend->recv_sspi_close_notify ||
+ backend->recv_unrecoverable_err);
else
return FALSE;
}
diff --git a/libs/libcurl/src/vtls/sectransp.c b/libs/libcurl/src/vtls/sectransp.c
index eb43d08c5b..f62c034e55 100644
--- a/libs/libcurl/src/vtls/sectransp.c
+++ b/libs/libcurl/src/vtls/sectransp.c
@@ -2008,7 +2008,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
return CURLE_SSL_CONNECT_ERROR;
}
- if(connssl->peer.is_ip_address) {
+ if(connssl->peer.type != CURL_SSL_PEER_DNS) {
infof(data, "WARNING: using IP address, SNI is being disabled by "
"the OS.");
}
diff --git a/libs/libcurl/src/vtls/vtls.c b/libs/libcurl/src/vtls/vtls.c
index 6deb512879..e4fcb0dd83 100644
--- a/libs/libcurl/src/vtls/vtls.c
+++ b/libs/libcurl/src/vtls/vtls.c
@@ -774,9 +774,13 @@ void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
if(sock != CURL_SOCKET_BAD) {
if(connssl->connecting_state == ssl_connect_2_writing) {
Curl_pollset_set_out_only(data, ps, sock);
+ CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%"
+ CURL_FORMAT_SOCKET_T, sock);
}
else {
Curl_pollset_set_in_only(data, ps, sock);
+ CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%"
+ CURL_FORMAT_SOCKET_T, sock);
}
}
}
@@ -1512,7 +1516,7 @@ void Curl_ssl_peer_cleanup(struct ssl_peer *peer)
free(peer->sni);
free(peer->hostname);
peer->hostname = peer->sni = peer->dispname = NULL;
- peer->is_ip_address = FALSE;
+ peer->type = CURL_SSL_PEER_DNS;
}
static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1526,18 +1530,23 @@ static void cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
cf->connected = FALSE;
}
-static int is_ip_address(const char *hostname)
+static ssl_peer_type get_peer_type(const char *hostname)
{
+ if(hostname && hostname[0]) {
#ifdef ENABLE_IPV6
- struct in6_addr addr;
+ struct in6_addr addr;
#else
- struct in_addr addr;
+ struct in_addr addr;
#endif
- return (hostname && hostname[0] && (Curl_inet_pton(AF_INET, hostname, &addr)
+ if(Curl_inet_pton(AF_INET, hostname, &addr))
+ return CURL_SSL_PEER_IPV4;
#ifdef ENABLE_IPV6
- || Curl_inet_pton(AF_INET6, hostname, &addr)
+ else if(Curl_inet_pton(AF_INET6, hostname, &addr)) {
+ return CURL_SSL_PEER_IPV6;
+ }
#endif
- ));
+ }
+ return CURL_SSL_PEER_DNS;
}
CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
@@ -1566,6 +1575,7 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
}
/* change if ehostname changed */
+ DEBUGASSERT(!ehostname || ehostname[0]);
if(ehostname && (!peer->hostname
|| strcmp(ehostname, peer->hostname))) {
Curl_ssl_peer_cleanup(peer);
@@ -1585,8 +1595,8 @@ CURLcode Curl_ssl_peer_init(struct ssl_peer *peer, struct Curl_cfilter *cf)
}
peer->sni = NULL;
- peer->is_ip_address = is_ip_address(peer->hostname)? TRUE : FALSE;
- if(peer->hostname[0] && !peer->is_ip_address) {
+ peer->type = get_peer_type(peer->hostname);
+ if(peer->type == CURL_SSL_PEER_DNS && peer->hostname[0]) {
/* not an IP address, normalize according to RCC 6066 ch. 3,
* max len of SNI is 2^16-1, no trailing dot */
size_t len = strlen(peer->hostname);
@@ -1715,32 +1725,17 @@ static ssize_t ssl_cf_recv(struct Curl_cfilter *cf,
{
struct cf_call_data save;
ssize_t nread;
- size_t ntotal = 0;
CF_DATA_SAVE(save, cf, data);
*err = CURLE_OK;
- /* Do receive until we fill the buffer somehwhat or EGAIN, error or EOF */
- while(!ntotal || (len - ntotal) > (4*1024)) {
+ nread = Curl_ssl->recv_plain(cf, data, buf, len, err);
+ if(nread > 0) {
+ DEBUGASSERT((size_t)nread <= len);
+ }
+ else if(nread == 0) {
+ /* eof */
*err = CURLE_OK;
- nread = Curl_ssl->recv_plain(cf, data, buf + ntotal, len - ntotal, err);
- if(nread < 0) {
- if(*err == CURLE_AGAIN && ntotal > 0) {
- /* we EAGAINed after having reed data, return the success amount */
- *err = CURLE_OK;
- break;
- }
- /* we have a an error to report */
- goto out;
- }
- else if(nread == 0) {
- /* eof */
- break;
- }
- ntotal += (size_t)nread;
- DEBUGASSERT((size_t)ntotal <= len);
}
- nread = (ssize_t)ntotal;
-out:
CURL_TRC_CF(data, cf, "cf_recv(len=%zu) -> %zd, %d", len,
nread, *err);
CF_DATA_RESTORE(cf, save);
diff --git a/libs/libcurl/src/vtls/vtls_int.h b/libs/libcurl/src/vtls/vtls_int.h
index 858a0de8e7..563a5d11a9 100644
--- a/libs/libcurl/src/vtls/vtls_int.h
+++ b/libs/libcurl/src/vtls/vtls_int.h
@@ -76,6 +76,7 @@ struct ssl_connect_data {
int port; /* remote port at origin */
BIT(use_alpn); /* if ALPN shall be used in handshake */
BIT(reused_session); /* session-ID was reused for this */
+ BIT(peer_closed); /* peer has closed connection */
};
diff --git a/libs/libcurl/src/vtls/wolfssl.c b/libs/libcurl/src/vtls/wolfssl.c
index 349d077ec4..fe845c5752 100644
--- a/libs/libcurl/src/vtls/wolfssl.c
+++ b/libs/libcurl/src/vtls/wolfssl.c
@@ -232,7 +232,6 @@ static const struct group_name_map gnm[] = {
static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
{
wolfSSL_BIO_set_shutdown(bio, 1);
- wolfSSL_BIO_set_init(bio, 1);
wolfSSL_BIO_set_data(bio, NULL);
return 1;
}
@@ -321,6 +320,8 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
wolfSSL_BIO_clear_retry_flags(bio);
if(nread < 0 && CURLE_AGAIN == result)
BIO_set_retry_read(bio);
+ else if(nread == 0)
+ connssl->peer_closed = TRUE;
return (int)nread;
}
@@ -1059,7 +1060,8 @@ static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
/* Maybe the server has already sent a close notify alert.
Read it to avoid an RST on the TCP connection. */
(void)wolfSSL_read(backend->handle, buf, (int)sizeof(buf));
- (void)wolfSSL_shutdown(backend->handle);
+ if(!connssl->peer_closed)
+ (void)wolfSSL_shutdown(backend->handle);
wolfSSL_free(backend->handle);
backend->handle = NULL;
}