summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/vtls/wolfssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/vtls/wolfssl.c')
-rw-r--r--libs/libcurl/src/vtls/wolfssl.c1605
1 files changed, 920 insertions, 685 deletions
diff --git a/libs/libcurl/src/vtls/wolfssl.c b/libs/libcurl/src/vtls/wolfssl.c
index 9a05f82946..0971895859 100644
--- a/libs/libcurl/src/vtls/wolfssl.c
+++ b/libs/libcurl/src/vtls/wolfssl.c
@@ -28,13 +28,14 @@
*
*/
-#include "curl_setup.h"
+#include "../curl_setup.h"
#ifdef USE_WOLFSSL
#define WOLFSSL_OPTIONS_IGNORE_SYS
-#include <wolfssl/version.h>
#include <wolfssl/options.h>
+#include <wolfssl/version.h>
+
#if LIBWOLFSSL_VERSION_HEX < 0x03004006 /* wolfSSL 3.4.6 (2015) */
#error "wolfSSL version should be at least 3.4.6"
@@ -55,36 +56,34 @@
#include <limits.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "inet_pton.h"
+#include "../urldata.h"
+#include "../sendf.h"
+#include "../curlx/inet_pton.h"
#include "vtls.h"
#include "vtls_int.h"
+#include "vtls_scache.h"
#include "keylog.h"
-#include "parsedate.h"
-#include "connect.h" /* for the connect timeout */
-#include "select.h"
-#include "strcase.h"
+#include "../parsedate.h"
+#include "../connect.h" /* for the connect timeout */
+#include "../progress.h"
+#include "../select.h"
+#include "../strcase.h"
+#include "../strdup.h"
#include "x509asn1.h"
-#include "curl_printf.h"
-#include "multiif.h"
+#include "../curl_printf.h"
+#include "../multiif.h"
-#include <wolfssl/openssl/ssl.h>
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>
#include "wolfssl.h"
/* The last #include files should be: */
-#include "curl_memory.h"
-#include "memdebug.h"
+#include "../curl_memory.h"
+#include "../memdebug.h"
-#ifdef USE_ECH
-# include "curl_base64.h"
-# define ECH_ENABLED(__data__) \
- (__data__->set.tls_ech && \
- !(__data__->set.tls_ech & CURLECH_DISABLE)\
- )
-#endif /* USE_ECH */
+#ifdef HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
+#define USE_ECH_WOLFSSL
+#endif
/* KEEP_PEER_CERT is a product of the presence of build time symbol
OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
@@ -97,11 +96,11 @@
#endif
#endif
-#ifdef HAVE_WOLFSSL_BIO
+#ifdef HAVE_WOLFSSL_BIO_NEW
#define USE_BIO_CHAIN
-#ifdef HAVE_WOLFSSL_FULL_BIO
+#ifdef HAVE_WOLFSSL_BIO_SET_SHUTDOWN
#define USE_FULL_BIO
-#else /* HAVE_WOLFSSL_FULL_BIO */
+#else /* HAVE_WOLFSSL_BIO_SET_SHUTDOWN */
#undef USE_FULL_BIO
#endif
/* wolfSSL 5.7.4 and older do not have these symbols, but only the
@@ -115,10 +114,14 @@
#define wolfSSL_BIO_set_retry_read BIO_set_retry_read
#endif /* !WOLFSSL_BIO_CTRL_GET_CLOSE */
-#else /* HAVE_WOLFSSL_BIO */
+#else /* HAVE_WOLFSSL_BIO_NEW */
#undef USE_BIO_CHAIN
#endif
+static CURLcode wssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done);
+
#ifdef OPENSSL_EXTRA
/*
* Availability note:
@@ -126,13 +129,13 @@
* wolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
* option is not set, then TLS 1.3 will not be logged.
* For TLS 1.2 and before, we use wolfSSL_get_keys().
- * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
+ * wolfSSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
* (--enable-opensslextra or --enable-all).
*/
#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
static int
-wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
- int secretSz, void *ctx)
+wssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
+ int secretSz, void *ctx)
{
const char *label;
unsigned char client_random[SSL3_RANDOM_SIZE];
@@ -168,7 +171,7 @@ wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
return 0;
}
- if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
+ if(wolfSSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
/* Should never happen as wolfSSL_KeepArrays() was called before. */
return 0;
}
@@ -178,8 +181,7 @@ wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
}
#endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
-static void
-wolfssl_log_tls12_secret(WOLFSSL *ssl)
+static void wssl_log_tls12_secret(WOLFSSL *ssl)
{
unsigned char *ms, *sr, *cr;
unsigned int msLen, srLen, crLen, i, x = 0;
@@ -221,7 +223,7 @@ wolfssl_log_tls12_secret(WOLFSSL *ssl)
}
#endif /* OPENSSL_EXTRA */
-static int wolfssl_do_file_type(const char *type)
+static int wssl_do_file_type(const char *type)
{
if(!type || !type[0])
return WOLFSSL_FILETYPE_PEM;
@@ -239,19 +241,19 @@ struct group_name_map {
};
static const struct group_name_map gnm[] = {
- { WOLFSSL_KYBER_LEVEL1, "KYBER_LEVEL1" },
- { WOLFSSL_KYBER_LEVEL3, "KYBER_LEVEL3" },
- { WOLFSSL_KYBER_LEVEL5, "KYBER_LEVEL5" },
- { WOLFSSL_P256_KYBER_LEVEL1, "P256_KYBER_LEVEL1" },
- { WOLFSSL_P384_KYBER_LEVEL3, "P384_KYBER_LEVEL3" },
- { WOLFSSL_P521_KYBER_LEVEL5, "P521_KYBER_LEVEL5" },
+ { WOLFSSL_ML_KEM_512, "ML_KEM_512" },
+ { WOLFSSL_ML_KEM_768, "ML_KEM_768" },
+ { WOLFSSL_ML_KEM_1024, "ML_KEM_1024" },
+ { WOLFSSL_P256_ML_KEM_512, "P256_ML_KEM_512" },
+ { WOLFSSL_P384_ML_KEM_768, "P384_ML_KEM_768" },
+ { WOLFSSL_P521_ML_KEM_1024, "P521_ML_KEM_1024" },
{ 0, NULL }
};
#endif
#ifdef USE_BIO_CHAIN
-static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
+static int wssl_bio_cf_create(WOLFSSL_BIO *bio)
{
#ifdef USE_FULL_BIO
wolfSSL_BIO_set_shutdown(bio, 1);
@@ -260,14 +262,14 @@ static int wolfssl_bio_cf_create(WOLFSSL_BIO *bio)
return 1;
}
-static int wolfssl_bio_cf_destroy(WOLFSSL_BIO *bio)
+static int wssl_bio_cf_destroy(WOLFSSL_BIO *bio)
{
if(!bio)
return 0;
return 1;
}
-static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
+static long wssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
long ret = 1;
@@ -297,9 +299,11 @@ static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
ret = 1;
break;
#ifdef WOLFSSL_BIO_CTRL_EOF
- case WOLFSSL_BIO_CTRL_EOF:
+ case WOLFSSL_BIO_CTRL_EOF: {
/* EOF has been reached on input? */
- return (!cf->next || !cf->next->connected);
+ struct ssl_connect_data *connssl = cf->ctx;
+ return connssl->peer_closed;
+ }
#endif
default:
ret = 0;
@@ -308,30 +312,29 @@ static long wolfssl_bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
return ret;
}
-static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
- const char *buf, int blen)
+static int wssl_bio_cf_out_write(WOLFSSL_BIO *bio,
+ const char *buf, int blen)
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nwritten, skiplen = 0;
CURLcode result = CURLE_OK;
DEBUGASSERT(data);
- if(backend->shutting_down && backend->io_send_blocked_len &&
- (backend->io_send_blocked_len < blen)) {
+ if(wssl->shutting_down && wssl->io_send_blocked_len &&
+ (wssl->io_send_blocked_len < blen)) {
/* bug in wolfSSL: <https://github.com/wolfSSL/wolfssl/issues/7784>
* It adds the close notify message again every time we retry
* sending during shutdown. */
CURL_TRC_CF(data, cf, "bio_write, shutdown restrict send of %d"
- " to %d bytes", blen, backend->io_send_blocked_len);
- skiplen = (ssize_t)(blen - backend->io_send_blocked_len);
- blen = backend->io_send_blocked_len;
+ " to %d bytes", blen, wssl->io_send_blocked_len);
+ skiplen = (ssize_t)(blen - wssl->io_send_blocked_len);
+ blen = wssl->io_send_blocked_len;
}
nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, FALSE, &result);
- backend->io_result = result;
+ wssl->io_result = result;
CURL_TRC_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
blen, nwritten, result);
#ifdef USE_FULL_BIO
@@ -339,20 +342,19 @@ static int wolfssl_bio_cf_out_write(WOLFSSL_BIO *bio,
#endif
if(nwritten < 0 && CURLE_AGAIN == result) {
wolfSSL_BIO_set_retry_write(bio);
- if(backend->shutting_down && !backend->io_send_blocked_len)
- backend->io_send_blocked_len = blen;
+ if(wssl->shutting_down && !wssl->io_send_blocked_len)
+ wssl->io_send_blocked_len = blen;
}
else if(!result && skiplen)
nwritten += skiplen;
return (int)nwritten;
}
-static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
+static int wssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
{
struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
struct Curl_easy *data = CF_DATA_CURRENT(cf);
ssize_t nread;
CURLcode result = CURLE_OK;
@@ -362,8 +364,20 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
if(!buf)
return 0;
+ if((connssl->connecting_state == ssl_connect_2) &&
+ !wssl->x509_store_setup) {
+ /* During handshake, init the x509 store before receiving the
+ * server response. This allows sending of ClientHello without delay. */
+ result = Curl_wssl_setup_x509_store(cf, data, wssl);
+ if(result) {
+ CURL_TRC_CF(data, cf, "Curl_wssl_setup_x509_store() -> %d", result);
+ wssl->io_result = result;
+ return -1;
+ }
+ }
+
nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
- backend->io_result = result;
+ wssl->io_result = result;
CURL_TRC_CF(data, cf, "bio_read(len=%d) -> %zd, %d", blen, nread, result);
#ifdef USE_FULL_BIO
wolfSSL_BIO_clear_retry_flags(bio);
@@ -375,82 +389,93 @@ static int wolfssl_bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
return (int)nread;
}
-static WOLFSSL_BIO_METHOD *wolfssl_bio_cf_method = NULL;
+static WOLFSSL_BIO_METHOD *wssl_bio_cf_method = NULL;
-static void wolfssl_bio_cf_init_methods(void)
+static void wssl_bio_cf_init_methods(void)
{
- wolfssl_bio_cf_method = wolfSSL_BIO_meth_new(WOLFSSL_BIO_MEMORY,
+ wssl_bio_cf_method = wolfSSL_BIO_meth_new(WOLFSSL_BIO_MEMORY,
"wolfSSL CF BIO");
- wolfSSL_BIO_meth_set_write(wolfssl_bio_cf_method, &wolfssl_bio_cf_out_write);
- wolfSSL_BIO_meth_set_read(wolfssl_bio_cf_method, &wolfssl_bio_cf_in_read);
- wolfSSL_BIO_meth_set_ctrl(wolfssl_bio_cf_method, &wolfssl_bio_cf_ctrl);
- wolfSSL_BIO_meth_set_create(wolfssl_bio_cf_method, &wolfssl_bio_cf_create);
- wolfSSL_BIO_meth_set_destroy(wolfssl_bio_cf_method, &wolfssl_bio_cf_destroy);
+ wolfSSL_BIO_meth_set_write(wssl_bio_cf_method, &wssl_bio_cf_out_write);
+ wolfSSL_BIO_meth_set_read(wssl_bio_cf_method, &wssl_bio_cf_in_read);
+ wolfSSL_BIO_meth_set_ctrl(wssl_bio_cf_method, &wssl_bio_cf_ctrl);
+ wolfSSL_BIO_meth_set_create(wssl_bio_cf_method, &wssl_bio_cf_create);
+ wolfSSL_BIO_meth_set_destroy(wssl_bio_cf_method, &wssl_bio_cf_destroy);
}
-static void wolfssl_bio_cf_free_methods(void)
+static void wssl_bio_cf_free_methods(void)
{
- wolfSSL_BIO_meth_free(wolfssl_bio_cf_method);
+ wolfSSL_BIO_meth_free(wssl_bio_cf_method);
}
#else /* USE_BIO_CHAIN */
-#define wolfssl_bio_cf_init_methods() Curl_nop_stmt
-#define wolfssl_bio_cf_free_methods() Curl_nop_stmt
+#define wssl_bio_cf_init_methods() Curl_nop_stmt
+#define wssl_bio_cf_free_methods() Curl_nop_stmt
#endif /* !USE_BIO_CHAIN */
-static void wolfssl_session_free(void *sdata, size_t slen)
-{
- (void)slen;
- free(sdata);
-}
-
-CURLcode wssl_cache_session(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct ssl_peer *peer,
- WOLFSSL_SESSION *session)
+CURLcode Curl_wssl_cache_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const char *ssl_peer_key,
+ WOLFSSL_SESSION *session,
+ int ietf_tls_id,
+ const char *alpn,
+ unsigned char *quic_tp,
+ size_t quic_tp_len)
{
CURLcode result = CURLE_OK;
- unsigned char *sdata = NULL;
- unsigned int slen;
+ struct Curl_ssl_session *sc_session = NULL;
+ unsigned char *sdata = NULL, *qtp_clone = NULL;
+ unsigned int sdata_len;
+ unsigned int earlydata_max = 0;
if(!session)
goto out;
- slen = wolfSSL_i2d_SSL_SESSION(session, NULL);
- if(slen <= 0) {
- CURL_TRC_CF(data, cf, "fail to assess session length: %u", slen);
+ sdata_len = wolfSSL_i2d_SSL_SESSION(session, NULL);
+ if(sdata_len <= 0) {
+ CURL_TRC_CF(data, cf, "fail to assess session length: %u", sdata_len);
result = CURLE_FAILED_INIT;
goto out;
}
- sdata = calloc(1, slen);
+ sdata = calloc(1, sdata_len);
if(!sdata) {
- failf(data, "unable to allocate session buffer of %u bytes", slen);
+ failf(data, "unable to allocate session buffer of %u bytes", sdata_len);
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- slen = wolfSSL_i2d_SSL_SESSION(session, &sdata);
- if(slen <= 0) {
- CURL_TRC_CF(data, cf, "fail to serialize session: %u", slen);
+ sdata_len = wolfSSL_i2d_SSL_SESSION(session, &sdata);
+ if(sdata_len <= 0) {
+ CURL_TRC_CF(data, cf, "fail to serialize session: %u", sdata_len);
result = CURLE_FAILED_INIT;
goto out;
}
+ if(quic_tp && quic_tp_len) {
+ qtp_clone = Curl_memdup0((char *)quic_tp, quic_tp_len);
+ if(!qtp_clone) {
+ free(sdata);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+#ifdef WOLFSSL_EARLY_DATA
+ earlydata_max = wolfSSL_SESSION_get_max_early_data(session);
+#endif
- Curl_ssl_sessionid_lock(data);
- result = Curl_ssl_set_sessionid(cf, data, peer, NULL,
- sdata, slen, wolfssl_session_free);
- Curl_ssl_sessionid_unlock(data);
- if(result)
- failf(data, "failed to add new ssl session to cache (%d)", result);
- else {
- CURL_TRC_CF(data, cf, "added new session to cache");
- sdata = NULL;
+ result = Curl_ssl_session_create2(sdata, sdata_len,
+ ietf_tls_id, alpn,
+ (curl_off_t)time(NULL) +
+ wolfSSL_SESSION_get_timeout(session),
+ earlydata_max, qtp_clone, quic_tp_len,
+ &sc_session);
+ sdata = NULL; /* took ownership of sdata */
+ if(!result) {
+ result = Curl_ssl_scache_put(cf, data, ssl_peer_key, sc_session);
+ /* took ownership of `sc_session` */
}
out:
free(sdata);
- return 0;
+ return result;
}
static int wssl_vtls_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
@@ -465,50 +490,122 @@ static int wssl_vtls_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
DEBUGASSERT(connssl);
DEBUGASSERT(data);
if(connssl && data) {
- (void)wssl_cache_session(cf, data, &connssl->peer, session);
+ (void)Curl_wssl_cache_session(cf, data, connssl->peer.scache_key,
+ session, wolfSSL_version(ssl),
+ connssl->negotiated.alpn, NULL, 0);
}
}
return 0;
}
-CURLcode wssl_setup_session(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- struct wolfssl_ctx *wss,
- struct ssl_peer *peer)
+static CURLcode wssl_on_session_reuse(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct alpn_spec *alpns,
+ struct Curl_ssl_session *scs,
+ bool *do_early_data)
{
- void *psdata;
- const unsigned char *sdata = NULL;
- size_t slen = 0;
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
CURLcode result = CURLE_OK;
- Curl_ssl_sessionid_lock(data);
- if(!Curl_ssl_getsessionid(cf, data, peer, &psdata, &slen, NULL)) {
+ *do_early_data = FALSE;
+#ifdef WOLFSSL_EARLY_DATA
+ connssl->earlydata_max = wolfSSL_SESSION_get_max_early_data(
+ wolfSSL_get_session(wssl->ssl));
+#else
+ (void)wssl;
+ connssl->earlydata_max = 0;
+#endif
+
+ if(!connssl->earlydata_max) {
+ /* Seems to be GnuTLS way to signal no EarlyData in session */
+ CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
+ }
+ else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
+ CURL_TRC_CF(data, cf, "SSL session has different ALPN, no early data");
+ }
+ else {
+ infof(data, "SSL session allows %zu bytes of early data, "
+ "reusing ALPN '%s'", connssl->earlydata_max, scs->alpn);
+ connssl->earlydata_state = ssl_earlydata_await;
+ connssl->state = ssl_connection_deferred;
+ result = Curl_alpn_set_negotiated(cf, data, connssl,
+ (const unsigned char *)scs->alpn,
+ scs->alpn ? strlen(scs->alpn) : 0);
+ *do_early_data = !result;
+ }
+ return result;
+}
+
+static CURLcode
+wssl_setup_session(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct wssl_ctx *wss,
+ struct alpn_spec *alpns,
+ const char *ssl_peer_key,
+ Curl_wssl_init_session_reuse_cb *sess_reuse_cb)
+{
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct Curl_ssl_session *scs = NULL;
+ CURLcode result;
+
+ result = Curl_ssl_scache_take(cf, data, ssl_peer_key, &scs);
+ if(!result && scs && scs->sdata && scs->sdata_len &&
+ (!scs->alpn || Curl_alpn_contains_proto(alpns, scs->alpn))) {
WOLFSSL_SESSION *session;
- sdata = psdata;
- session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata, (long)slen);
+ /* wolfSSL changes the passed pointer for whatever reasons, yikes */
+ const unsigned char *sdata = scs->sdata;
+ session = wolfSSL_d2i_SSL_SESSION(NULL, &sdata, (long)scs->sdata_len);
if(session) {
- int ret = wolfSSL_set_session(wss->handle, session);
+ int ret = wolfSSL_set_session(wss->ssl, session);
if(ret != WOLFSSL_SUCCESS) {
- Curl_ssl_delsessionid(data, psdata);
- infof(data, "previous session not accepted (%d), "
+ Curl_ssl_session_destroy(scs);
+ scs = NULL;
+ infof(data, "cached session not accepted (%d), "
"removing from cache", ret);
}
- else
- infof(data, "SSL reusing session ID");
+ else {
+ infof(data, "SSL reusing session with ALPN '%s'",
+ scs->alpn ? scs->alpn : "-");
+ if(ssl_config->earlydata &&
+ !cf->conn->connect_only &&
+ !strcmp("TLSv1.3", wolfSSL_get_version(wss->ssl))) {
+ bool do_early_data = FALSE;
+ if(sess_reuse_cb) {
+ result = sess_reuse_cb(cf, data, alpns, scs, &do_early_data);
+ if(result)
+ goto out;
+ }
+#ifdef WOLFSSL_EARLY_DATA
+ if(do_early_data) {
+ unsigned int edmax = (scs->earlydata_max < UINT_MAX) ?
+ (unsigned int)scs->earlydata_max : UINT_MAX;
+ /* We only try the ALPN protocol the session used before,
+ * otherwise we might send early data for the wrong protocol */
+ Curl_alpn_restrict_to(alpns, scs->alpn);
+ wolfSSL_set_max_early_data(wss->ssl, edmax);
+ }
+#else
+ /* Should never enable when not supported */
+ DEBUGASSERT(!do_early_data);
+#endif
+ }
+ }
wolfSSL_SESSION_free(session);
}
else {
failf(data, "could not decode previous session");
}
}
- Curl_ssl_sessionid_unlock(data);
+out:
+ Curl_ssl_scache_return(cf, data, ssl_peer_key, scs);
return result;
}
-static CURLcode populate_x509_store(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- WOLFSSL_X509_STORE *store,
- struct wolfssl_ctx *wssl)
+static CURLcode wssl_populate_x509_store(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ WOLFSSL_X509_STORE *store,
+ struct wssl_ctx *wssl)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
const struct curl_blob *ca_info_blob = conn_config->ca_info_blob;
@@ -518,57 +615,61 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
const char * const ssl_capath = conn_config->CApath;
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
bool imported_native_ca = FALSE;
+ bool imported_ca_info_blob = FALSE;
+
+ /* We do not want to do this again, no matter the outcome */
+ wssl->x509_store_setup = TRUE;
-#if !defined(NO_FILESYSTEM) && defined(WOLFSSL_SYS_CA_CERTS)
+#ifndef NO_FILESYSTEM
/* load native CA certificates */
if(ssl_config->native_ca_store) {
- if(wolfSSL_CTX_load_system_CA_certs(wssl->ctx) != WOLFSSL_SUCCESS) {
+#ifdef WOLFSSL_SYS_CA_CERTS
+ if(wolfSSL_CTX_load_system_CA_certs(wssl->ssl_ctx) != WOLFSSL_SUCCESS) {
infof(data, "error importing native CA store, continuing anyway");
}
else {
imported_native_ca = TRUE;
infof(data, "successfully imported native CA store");
- wssl->x509_store_setup = TRUE;
}
+#else
+ infof(data, "ignoring native CA option because wolfSSL was built without "
+ "native CA support");
+#endif
}
#endif /* !NO_FILESYSTEM */
/* load certificate blob */
if(ca_info_blob) {
- if(wolfSSL_CTX_load_verify_buffer(wssl->ctx, ca_info_blob->data,
+ if(wolfSSL_CTX_load_verify_buffer(wssl->ssl_ctx, ca_info_blob->data,
(long)ca_info_blob->len,
WOLFSSL_FILETYPE_PEM) !=
WOLFSSL_SUCCESS) {
- if(imported_native_ca) {
- infof(data, "error importing CA certificate blob, continuing anyway");
- }
- else {
- failf(data, "error importing CA certificate blob");
- return CURLE_SSL_CACERT_BADFILE;
- }
+ failf(data, "error importing CA certificate blob");
+ return CURLE_SSL_CACERT_BADFILE;
}
else {
+ imported_ca_info_blob = TRUE;
infof(data, "successfully imported CA certificate blob");
- wssl->x509_store_setup = TRUE;
}
}
#ifndef NO_FILESYSTEM
/* load trusted cacert from file if not blob */
- CURL_TRC_CF(data, cf, "populate_x509_store, path=%s, blob=%d",
+ CURL_TRC_CF(data, cf, "wssl_populate_x509_store, path=%s, blob=%d",
ssl_cafile ? ssl_cafile : "none", !!ca_info_blob);
if(!store)
return CURLE_OUT_OF_MEMORY;
- if((ssl_cafile || ssl_capath) && (!wssl->x509_store_setup)) {
+ if(ssl_cafile || ssl_capath) {
int rc =
- wolfSSL_CTX_load_verify_locations_ex(wssl->ctx,
+ wolfSSL_CTX_load_verify_locations_ex(wssl->ssl_ctx,
ssl_cafile,
ssl_capath,
WOLFSSL_LOAD_FLAG_IGNORE_ERR);
if(WOLFSSL_SUCCESS != rc) {
- if(conn_config->verifypeer) {
+ if(conn_config->verifypeer &&
+ !imported_native_ca && !imported_ca_info_blob) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:"
" CAfile: %s CApath: %s",
@@ -592,7 +693,6 @@ static CURLcode populate_x509_store(struct Curl_cfilter *cf,
}
#endif
(void)store;
- wssl->x509_store_setup = TRUE;
return CURLE_OK;
}
@@ -620,12 +720,12 @@ static void wssl_x509_share_free(void *key, size_t key_len, void *p)
}
static bool
-cached_x509_store_expired(const struct Curl_easy *data,
- const struct wssl_x509_share *mb)
+wssl_cached_x509_store_expired(const struct Curl_easy *data,
+ const struct wssl_x509_share *mb)
{
const struct ssl_general_config *cfg = &data->set.general_ssl;
- struct curltime now = Curl_now();
- timediff_t elapsed_ms = Curl_timediff(now, mb->time);
+ struct curltime now = curlx_now();
+ timediff_t elapsed_ms = curlx_timediff(now, mb->time);
timediff_t timeout_ms = cfg->ca_cache_timeout * (timediff_t)1000;
if(timeout_ms < 0)
@@ -635,8 +735,8 @@ cached_x509_store_expired(const struct Curl_easy *data,
}
static bool
-cached_x509_store_different(struct Curl_cfilter *cf,
- const struct wssl_x509_share *mb)
+wssl_cached_x509_store_different(struct Curl_cfilter *cf,
+ const struct wssl_x509_share *mb)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
if(!mb->CAfile || !conn_config->CAfile)
@@ -645,8 +745,8 @@ cached_x509_store_different(struct Curl_cfilter *cf,
return strcmp(mb->CAfile, conn_config->CAfile);
}
-static WOLFSSL_X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
- const struct Curl_easy *data)
+static WOLFSSL_X509_STORE *wssl_get_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
struct Curl_multi *multi = data->multi;
struct wssl_x509_share *share;
@@ -654,20 +754,20 @@ static WOLFSSL_X509_STORE *get_cached_x509_store(struct Curl_cfilter *cf,
DEBUGASSERT(multi);
share = multi ? Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_WSSL_X509_KEY),
sizeof(MPROTO_WSSL_X509_KEY)-1) : NULL;
if(share && share->store &&
- !cached_x509_store_expired(data, share) &&
- !cached_x509_store_different(cf, share)) {
+ !wssl_cached_x509_store_expired(data, share) &&
+ !wssl_cached_x509_store_different(cf, share)) {
store = share->store;
}
return store;
}
-static void set_cached_x509_store(struct Curl_cfilter *cf,
- const struct Curl_easy *data,
- WOLFSSL_X509_STORE *store)
+static void wssl_set_cached_x509_store(struct Curl_cfilter *cf,
+ const struct Curl_easy *data,
+ WOLFSSL_X509_STORE *store)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct Curl_multi *multi = data->multi;
@@ -677,7 +777,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
if(!multi)
return;
share = Curl_hash_pick(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_WSSL_X509_KEY),
sizeof(MPROTO_WSSL_X509_KEY)-1);
if(!share) {
@@ -685,7 +785,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
if(!share)
return;
if(!Curl_hash_add2(&multi->proto_hash,
- (void *)MPROTO_WSSL_X509_KEY,
+ CURL_UNCONST(MPROTO_WSSL_X509_KEY),
sizeof(MPROTO_WSSL_X509_KEY)-1,
share, wssl_x509_share_free)) {
free(share);
@@ -709,7 +809,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
free(share->CAfile);
}
- share->time = Curl_now();
+ share->time = curlx_now();
share->store = store;
share->CAfile = CAfile;
}
@@ -717,7 +817,7 @@ static void set_cached_x509_store(struct Curl_cfilter *cf,
CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
struct Curl_easy *data,
- struct wolfssl_ctx *wssl)
+ struct wssl_ctx *wssl)
{
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
@@ -735,12 +835,14 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
!ssl_config->primary.CRLfile &&
!ssl_config->native_ca_store;
- cached_store = cache_criteria_met ? get_cached_x509_store(cf, data) : NULL;
- if(cached_store && wolfSSL_CTX_get_cert_store(wssl->ctx) == cached_store) {
+ cached_store = cache_criteria_met ? wssl_get_cached_x509_store(cf, data)
+ : NULL;
+ if(cached_store &&
+ wolfSSL_CTX_get_cert_store(wssl->ssl_ctx) == cached_store) {
/* The cached store is already in use, do nothing. */
}
else if(cached_store && wolfSSL_X509_STORE_up_ref(cached_store)) {
- wolfSSL_CTX_set_cert_store(wssl->ctx, cached_store);
+ wolfSSL_CTX_set_cert_store(wssl->ssl_ctx, cached_store);
}
else if(cache_criteria_met) {
/* wolfSSL's initial store in CTX is not shareable by default.
@@ -750,17 +852,17 @@ CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
failf(data, "SSL: could not create a X509 store");
return CURLE_OUT_OF_MEMORY;
}
- wolfSSL_CTX_set_cert_store(wssl->ctx, store);
+ wolfSSL_CTX_set_cert_store(wssl->ssl_ctx, store);
- result = populate_x509_store(cf, data, store, wssl);
+ result = wssl_populate_x509_store(cf, data, store, wssl);
if(!result) {
- set_cached_x509_store(cf, data, store);
+ wssl_set_cached_x509_store(cf, data, store);
}
}
else {
/* We never share the CTX's store, use it. */
- WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ctx);
- result = populate_x509_store(cf, data, store, wssl);
+ WOLFSSL_X509_STORE *store = wolfSSL_CTX_get_cert_store(wssl->ssl_ctx);
+ result = wssl_populate_x509_store(cf, data, store, wssl);
}
return result;
@@ -773,20 +875,20 @@ wssl_add_default_ciphers(bool tls13, struct dynbuf *buf)
int i;
char *str;
- for(i = 0; (str = wolfSSL_get_cipher_list(i)); i++) {
+ for(i = 0; (str = wolfSSL_get_cipher_list(i)) != NULL; i++) {
size_t n;
if((strncmp(str, "TLS13", 5) == 0) != tls13)
continue;
/* if there already is data in the string, add colon separator */
- if(Curl_dyn_len(buf)) {
- CURLcode result = Curl_dyn_addn(buf, ":", 1);
+ if(curlx_dyn_len(buf)) {
+ CURLcode result = curlx_dyn_addn(buf, ":", 1);
if(result)
return result;
}
n = strlen(str);
- if(Curl_dyn_addn(buf, str, n))
+ if(curlx_dyn_addn(buf, str, n))
return CURLE_OUT_OF_MEMORY;
}
@@ -834,30 +936,41 @@ wssl_legacy_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version)
#define wolfSSL_CTX_set_max_proto_version wssl_legacy_CTX_set_max_proto_version
#endif
-/*
- * This function loads all the client/CA certificates and CRLs. Setup the TLS
- * layer and do all necessary magic.
- */
-static CURLcode
-wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+#define QUIC_CIPHERS \
+ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \
+ "POLY1305_SHA256:TLS_AES_128_CCM_SHA256"
+#define QUIC_GROUPS "P-256:P-384:P-521"
+
+CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx,
+ struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct ssl_peer *peer,
+ const struct alpn_spec *alpns_requested,
+ Curl_wssl_ctx_setup_cb *cb_setup,
+ void *cb_user_data,
+ void *ssl_user_data,
+ Curl_wssl_init_session_reuse_cb *sess_reuse_cb)
{
+ struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
+ struct ssl_primary_config *conn_config;
+ WOLFSSL_METHOD* req_method = NULL;
+ struct alpn_spec alpns;
int res;
char *curves;
- struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
- const struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
- WOLFSSL_METHOD* req_method = NULL;
#ifdef WOLFSSL_HAVE_KYBER
word16 pqkem = 0;
size_t idx = 0;
#endif
+ CURLcode result = CURLE_FAILED_INIT;
- DEBUGASSERT(backend);
-
- if(connssl->state == ssl_connection_complete)
- return CURLE_OK;
+ DEBUGASSERT(!wctx->ssl_ctx);
+ DEBUGASSERT(!wctx->ssl);
+ conn_config = Curl_ssl_cf_get_primary_config(cf);
+ if(!conn_config) {
+ result = CURLE_FAILED_INIT;
+ goto out;
+ }
+ Curl_alpn_copy(&alpns, alpns_requested);
#if LIBWOLFSSL_VERSION_HEX < 0x04002000 /* 4.2.0 (2019) */
req_method = wolfSSLv23_client_method();
@@ -866,58 +979,62 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
#endif
if(!req_method) {
failf(data, "wolfSSL: could not create a client method");
- return CURLE_OUT_OF_MEMORY;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
- if(backend->ctx)
- wolfSSL_CTX_free(backend->ctx);
+ if(wctx->ssl_ctx)
+ wolfSSL_CTX_free(wctx->ssl_ctx);
- backend->ctx = wolfSSL_CTX_new(req_method);
- if(!backend->ctx) {
+ wctx->ssl_ctx = wolfSSL_CTX_new(req_method);
+ if(!wctx->ssl_ctx) {
failf(data, "wolfSSL: could not create a context");
- return CURLE_OUT_OF_MEMORY;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
switch(conn_config->version) {
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
case CURL_SSLVERSION_TLSv1_0:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_VERSION);
+ res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_VERSION);
break;
case CURL_SSLVERSION_TLSv1_1:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_1_VERSION);
+ res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_1_VERSION);
break;
case CURL_SSLVERSION_TLSv1_2:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_2_VERSION);
+ res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_2_VERSION);
break;
#ifdef WOLFSSL_TLS13
case CURL_SSLVERSION_TLSv1_3:
- res = wolfSSL_CTX_set_min_proto_version(backend->ctx, TLS1_3_VERSION);
+ res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_3_VERSION);
break;
#endif
default:
failf(data, "wolfSSL: unsupported minimum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(res != WOLFSSL_SUCCESS) {
failf(data, "wolfSSL: failed set the minimum TLS version");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
switch(conn_config->version_max) {
#ifdef WOLFSSL_TLS13
case CURL_SSLVERSION_MAX_TLSv1_3:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_3_VERSION);
+ res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_3_VERSION);
break;
#endif
case CURL_SSLVERSION_MAX_TLSv1_2:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_2_VERSION);
+ res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_2_VERSION);
break;
case CURL_SSLVERSION_MAX_TLSv1_1:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_1_VERSION);
+ res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_1_VERSION);
break;
case CURL_SSLVERSION_MAX_TLSv1_0:
- res = wolfSSL_CTX_set_max_proto_version(backend->ctx, TLS1_VERSION);
+ res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_VERSION);
break;
case CURL_SSLVERSION_MAX_DEFAULT:
case CURL_SSLVERSION_MAX_NONE:
@@ -925,20 +1042,23 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
break;
default:
failf(data, "wolfSSL: unsupported maximum TLS version value");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(res != WOLFSSL_SUCCESS) {
failf(data, "wolfSSL: failed set the maximum TLS version");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
#ifndef WOLFSSL_TLS13
{
char *ciphers = conn_config->cipher_list;
if(ciphers) {
- if(!SSL_CTX_set_cipher_list(backend->ctx, ciphers)) {
+ if(!SSL_CTX_set_cipher_list(wctx->ssl_ctx, ciphers)) {
failf(data, "failed setting cipher list: %s", ciphers);
- return CURLE_SSL_CIPHER;
+ result = CURLE_SSL_CIPHER;
+ goto out;
}
infof(data, "Cipher selection: %s", ciphers);
}
@@ -949,40 +1069,42 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
const char *ciphers12 = conn_config->cipher_list;
const char *ciphers13 = conn_config->cipher_list13;
struct dynbuf c;
- CURLcode result;
- Curl_dyn_init(&c, MAX_CIPHER_LEN);
+ curlx_dyn_init(&c, MAX_CIPHER_LEN);
if(ciphers13)
- result = Curl_dyn_add(&c, ciphers13);
+ result = curlx_dyn_add(&c, ciphers13);
else
result = wssl_add_default_ciphers(TRUE, &c);
if(!result) {
if(ciphers12) {
- if(Curl_dyn_len(&c))
- result = Curl_dyn_addn(&c, ":", 1);
+ if(curlx_dyn_len(&c))
+ result = curlx_dyn_addn(&c, ":", 1);
if(!result)
- result = Curl_dyn_add(&c, ciphers12);
+ result = curlx_dyn_add(&c, ciphers12);
}
else
result = wssl_add_default_ciphers(FALSE, &c);
}
if(result)
- return result;
+ goto out;
- if(!wolfSSL_CTX_set_cipher_list(backend->ctx, Curl_dyn_ptr(&c))) {
- failf(data, "failed setting cipher list: %s", Curl_dyn_ptr(&c));
- Curl_dyn_free(&c);
- return CURLE_SSL_CIPHER;
+ if(!wolfSSL_CTX_set_cipher_list(wctx->ssl_ctx, curlx_dyn_ptr(&c))) {
+ failf(data, "failed setting cipher list: %s", curlx_dyn_ptr(&c));
+ curlx_dyn_free(&c);
+ result = CURLE_SSL_CIPHER;
+ goto out;
}
- infof(data, "Cipher selection: %s", Curl_dyn_ptr(&c));
- Curl_dyn_free(&c);
+ infof(data, "Cipher selection: %s", curlx_dyn_ptr(&c));
+ curlx_dyn_free(&c);
}
#endif
curves = conn_config->curves;
- if(curves) {
+ if(!curves && cf->conn->transport == TRNSPRT_QUIC)
+ curves = (char *)CURL_UNCONST(QUIC_GROUPS);
+ if(curves) {
#ifdef WOLFSSL_HAVE_KYBER
for(idx = 0; gnm[idx].name != NULL; idx++) {
if(strncmp(curves, gnm[idx].name, strlen(gnm[idx].name)) == 0) {
@@ -994,9 +1116,10 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
if(pqkem == 0)
#endif
{
- if(!wolfSSL_CTX_set1_curves_list(backend->ctx, curves)) {
+ if(!wolfSSL_CTX_set1_curves_list(wctx->ssl_ctx, curves)) {
failf(data, "failed setting curves list: '%s'", curves);
- return CURLE_SSL_CIPHER;
+ result = CURLE_SSL_CIPHER;
+ goto out;
}
}
}
@@ -1008,30 +1131,32 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
const char *key_file = ssl_config->key;
const struct curl_blob *cert_blob = ssl_config->primary.cert_blob;
const struct curl_blob *key_blob = ssl_config->key_blob;
- int file_type = wolfssl_do_file_type(ssl_config->cert_type);
+ int file_type = wssl_do_file_type(ssl_config->cert_type);
int rc;
switch(file_type) {
case WOLFSSL_FILETYPE_PEM:
rc = cert_blob ?
- wolfSSL_CTX_use_certificate_chain_buffer(backend->ctx,
+ wolfSSL_CTX_use_certificate_chain_buffer(wctx->ssl_ctx,
cert_blob->data,
(long)cert_blob->len) :
- wolfSSL_CTX_use_certificate_chain_file(backend->ctx, cert_file);
+ wolfSSL_CTX_use_certificate_chain_file(wctx->ssl_ctx, cert_file);
break;
case WOLFSSL_FILETYPE_ASN1:
rc = cert_blob ?
- wolfSSL_CTX_use_certificate_buffer(backend->ctx, cert_blob->data,
+ wolfSSL_CTX_use_certificate_buffer(wctx->ssl_ctx, cert_blob->data,
(long)cert_blob->len, file_type) :
- wolfSSL_CTX_use_certificate_file(backend->ctx, cert_file, file_type);
+ wolfSSL_CTX_use_certificate_file(wctx->ssl_ctx, cert_file, file_type);
break;
default:
failf(data, "unknown cert type");
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto out;
}
if(rc != 1) {
failf(data, "unable to use client certificate");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(!key_blob && !key_file) {
@@ -1039,53 +1164,57 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
key_file = cert_file;
}
else
- file_type = wolfssl_do_file_type(ssl_config->key_type);
+ file_type = wssl_do_file_type(ssl_config->key_type);
rc = key_blob ?
- wolfSSL_CTX_use_PrivateKey_buffer(backend->ctx, key_blob->data,
+ wolfSSL_CTX_use_PrivateKey_buffer(wctx->ssl_ctx, key_blob->data,
(long)key_blob->len, file_type) :
- wolfSSL_CTX_use_PrivateKey_file(backend->ctx, key_file, file_type);
+ wolfSSL_CTX_use_PrivateKey_file(wctx->ssl_ctx, key_file, file_type);
if(rc != 1) {
failf(data, "unable to set private key");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
}
#else /* NO_FILESYSTEM */
if(ssl_config->primary.cert_blob) {
const struct curl_blob *cert_blob = ssl_config->primary.cert_blob;
const struct curl_blob *key_blob = ssl_config->key_blob;
- int file_type = wolfssl_do_file_type(ssl_config->cert_type);
+ int file_type = wssl_do_file_type(ssl_config->cert_type);
int rc;
switch(file_type) {
case WOLFSSL_FILETYPE_PEM:
- rc = wolfSSL_CTX_use_certificate_chain_buffer(backend->ctx,
+ rc = wolfSSL_CTX_use_certificate_chain_buffer(wctx->ssl_ctx,
cert_blob->data,
(long)cert_blob->len);
break;
case WOLFSSL_FILETYPE_ASN1:
- rc = wolfSSL_CTX_use_certificate_buffer(backend->ctx, cert_blob->data,
+ rc = wolfSSL_CTX_use_certificate_buffer(wctx->ssl_ctx, cert_blob->data,
(long)cert_blob->len, file_type);
break;
default:
failf(data, "unknown cert type");
- return CURLE_BAD_FUNCTION_ARGUMENT;
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto out;
}
if(rc != 1) {
failf(data, "unable to use client certificate");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(!key_blob)
key_blob = cert_blob;
else
- file_type = wolfssl_do_file_type(ssl_config->key_type);
+ file_type = wssl_do_file_type(ssl_config->key_type);
- if(wolfSSL_CTX_use_PrivateKey_buffer(backend->ctx, key_blob->data,
+ if(wolfSSL_CTX_use_PrivateKey_buffer(wctx->ssl_ctx, key_blob->data,
(long)key_blob->len,
file_type) != 1) {
failf(data, "unable to set private key");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
}
#endif /* !NO_FILESYSTEM */
@@ -1094,37 +1223,49 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
* fail to connect if the verification fails, or if it should continue
* anyway. In the latter case the result of the verification is checked with
* SSL_get_verify_result() below. */
- wolfSSL_CTX_set_verify(backend->ctx,
+ wolfSSL_CTX_set_verify(wctx->ssl_ctx,
conn_config->verifypeer ? WOLFSSL_VERIFY_PEER :
WOLFSSL_VERIFY_NONE, NULL);
#ifdef HAVE_SNI
- if(connssl->peer.sni) {
- size_t sni_len = strlen(connssl->peer.sni);
+ if(peer->sni) {
+ size_t sni_len = strlen(peer->sni);
if((sni_len < USHRT_MAX)) {
- if(wolfSSL_CTX_UseSNI(backend->ctx, WOLFSSL_SNI_HOST_NAME,
- connssl->peer.sni,
- (unsigned short)sni_len) != 1) {
+ if(wolfSSL_CTX_UseSNI(wctx->ssl_ctx, WOLFSSL_SNI_HOST_NAME,
+ peer->sni, (unsigned short)sni_len) != 1) {
failf(data, "Failed to set SNI");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
+ CURL_TRC_CF(data, cf, "set SNI '%s'", peer->sni);
}
}
#endif
+ if(ssl_config->primary.cache_session &&
+ cf->conn->transport != TRNSPRT_QUIC) {
+ /* Register to get notified when a new session is received */
+ wolfSSL_CTX_sess_set_new_cb(wctx->ssl_ctx, wssl_vtls_new_session_cb);
+ }
+
+ if(cb_setup) {
+ result = cb_setup(cf, data, cb_user_data);
+ if(result)
+ goto out;
+ }
+
/* give application a chance to interfere with SSL set up. */
if(data->set.ssl.fsslctx) {
- CURLcode result;
- if(!backend->x509_store_setup) {
- result = Curl_wssl_setup_x509_store(cf, data, backend);
+ if(!wctx->x509_store_setup) {
+ result = Curl_wssl_setup_x509_store(cf, data, wctx);
if(result)
- return result;
+ goto out;
}
- result = (*data->set.ssl.fsslctx)(data, backend->ctx,
+ result = (*data->set.ssl.fsslctx)(data, wctx->ssl_ctx,
data->set.ssl.fsslctxp);
if(result) {
failf(data, "error signaled by ssl ctx callback");
- return result;
+ goto out;
}
}
#ifdef NO_FILESYSTEM
@@ -1133,82 +1274,87 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
" with \"no filesystem\". Either disable peer verification"
" (insecure) or if you are building an application with libcurl you"
" can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
#endif
/* Let's make an SSL structure */
- if(backend->handle)
- wolfSSL_free(backend->handle);
- backend->handle = wolfSSL_new(backend->ctx);
- if(!backend->handle) {
+ wctx->ssl = wolfSSL_new(wctx->ssl_ctx);
+ if(!wctx->ssl) {
failf(data, "SSL: could not create a handle");
- return CURLE_OUT_OF_MEMORY;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
}
+ wolfSSL_set_app_data(wctx->ssl, ssl_user_data);
+#ifdef WOLFSSL_QUIC
+ if(cf->conn->transport == TRNSPRT_QUIC)
+ wolfSSL_set_quic_use_legacy_codepoint(wctx->ssl, 0);
+#endif
+
#ifdef WOLFSSL_HAVE_KYBER
if(pqkem) {
- if(wolfSSL_UseKeyShare(backend->handle, pqkem) != WOLFSSL_SUCCESS) {
+ if(wolfSSL_UseKeyShare(wctx->ssl, pqkem) != WOLFSSL_SUCCESS) {
failf(data, "unable to use PQ KEM");
}
}
#endif
+ /* Check if there is a cached ID we can/should use here! */
+ if(ssl_config->primary.cache_session) {
+ /* Set session from cache if there is one */
+ (void)wssl_setup_session(cf, data, wctx, &alpns,
+ peer->scache_key, sess_reuse_cb);
+ }
+
#ifdef HAVE_ALPN
- if(connssl->alpn) {
+ if(alpns.count) {
struct alpn_proto_buf proto;
- CURLcode result;
+ memset(&proto, 0, sizeof(proto));
+ Curl_alpn_to_proto_str(&proto, &alpns);
- result = Curl_alpn_to_proto_str(&proto, connssl->alpn);
- if(result ||
- wolfSSL_UseALPN(backend->handle,
- (char *)proto.data, (unsigned int)proto.len,
+ if(wolfSSL_UseALPN(wctx->ssl, (char *)proto.data,
+ (unsigned int)proto.len,
WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != WOLFSSL_SUCCESS) {
failf(data, "SSL: failed setting ALPN protocols");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
- infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+ CURL_TRC_CF(data, cf, "set ALPN: %s", proto.data);
}
#endif /* HAVE_ALPN */
#ifdef OPENSSL_EXTRA
if(Curl_tls_keylog_enabled()) {
/* Ensure the Client Random is preserved. */
- wolfSSL_KeepArrays(backend->handle);
+ wolfSSL_KeepArrays(wctx->ssl);
#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
- wolfSSL_set_tls13_secret_cb(backend->handle,
- wolfssl_tls13_secret_callback, NULL);
+ wolfSSL_set_tls13_secret_cb(wctx->ssl,
+ wssl_tls13_secret_callback, NULL);
#endif
}
#endif /* OPENSSL_EXTRA */
#ifdef HAVE_SECURE_RENEGOTIATION
- if(wolfSSL_UseSecureRenegotiation(backend->handle) != SSL_SUCCESS) {
+ if(wolfSSL_UseSecureRenegotiation(wctx->ssl) != SSL_SUCCESS) {
failf(data, "SSL: failed setting secure renegotiation");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
#endif /* HAVE_SECURE_RENEGOTIATION */
- /* Check if there is a cached ID we can/should use here! */
- if(ssl_config->primary.cache_session) {
- /* Set session from cache if there is one */
- (void)wssl_setup_session(cf, data, backend, &connssl->peer);
- /* Register to get notified when a new session is received */
- wolfSSL_set_app_data(backend->handle, cf);
- wolfSSL_CTX_sess_set_new_cb(backend->ctx, wssl_vtls_new_session_cb);
- }
-
-#ifdef USE_ECH
+#ifdef USE_ECH_WOLFSSL
if(ECH_ENABLED(data)) {
int trying_ech_now = 0;
if(data->set.str[STRING_ECH_PUBLIC]) {
infof(data, "ECH: outername not (yet) supported with wolfSSL");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
if(data->set.tls_ech == CURLECH_GREASE) {
- infof(data, "ECH: GREASE'd ECH not yet supported for wolfSSL");
- return CURLE_SSL_CONNECT_ERROR;
+ infof(data, "ECH: GREASE is done by default by wolfSSL: no need to ask");
}
if(data->set.tls_ech & CURLECH_CLA_CFG
&& data->set.str[STRING_ECH_CONFIG]) {
@@ -1217,10 +1363,12 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
b64len = (word32) strlen(b64val);
if(b64len
- && wolfSSL_SetEchConfigsBase64(backend->handle, b64val, b64len)
+ && wolfSSL_SetEchConfigsBase64(wctx->ssl, b64val, b64len)
!= WOLFSSL_SUCCESS) {
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
+ if(data->set.tls_ech & CURLECH_HARD) {
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
}
else {
trying_ech_now = 1;
@@ -1228,13 +1376,17 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
}
else {
+ struct ssl_connect_data *connssl = cf->ctx;
struct Curl_dns_entry *dns = NULL;
- dns = Curl_fetch_addr(data, connssl->peer.hostname, connssl->peer.port);
+ dns = Curl_dnscache_get(data, connssl->peer.hostname, connssl->peer.port,
+ cf->conn->ip_version);
if(!dns) {
infof(data, "ECH: requested but no DNS info available");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
+ if(data->set.tls_ech & CURLECH_HARD) {
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
}
else {
struct Curl_https_rrinfo *rinfo = NULL;
@@ -1245,11 +1397,13 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
size_t elen = rinfo->echconfiglist_len;
infof(data, "ECH: ECHConfig from DoH HTTPS RR");
- if(wolfSSL_SetEchConfigs(backend->handle, ecl, (word32) elen) !=
+ if(wolfSSL_SetEchConfigs(wctx->ssl, ecl, (word32) elen) !=
WOLFSSL_SUCCESS) {
infof(data, "ECH: wolfSSL_SetEchConfigs failed");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
+ if(data->set.tls_ech & CURLECH_HARD) {
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
}
else {
trying_ech_now = 1;
@@ -1258,49 +1412,107 @@ wolfssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
}
else {
infof(data, "ECH: requested but no ECHConfig available");
- if(data->set.tls_ech & CURLECH_HARD)
- return CURLE_SSL_CONNECT_ERROR;
+ if(data->set.tls_ech & CURLECH_HARD) {
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
+ }
}
Curl_resolv_unlink(data, &dns);
}
}
- if(trying_ech_now
- && SSL_set_min_proto_version(backend->handle, TLS1_3_VERSION) != 1) {
+ if(trying_ech_now && wolfSSL_set_min_proto_version(wctx->ssl,
+ TLS1_3_VERSION) != 1) {
infof(data, "ECH: cannot force TLSv1.3 [ERROR]");
- return CURLE_SSL_CONNECT_ERROR;
+ result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
}
-#endif /* USE_ECH */
+#endif /* USE_ECH_WOLFSSL */
+
+ result = CURLE_OK;
+
+out:
+ if(result && wctx->ssl) {
+ wolfSSL_free(wctx->ssl);
+ wctx->ssl = NULL;
+ }
+ if(result && wctx->ssl_ctx) {
+ wolfSSL_CTX_free(wctx->ssl_ctx);
+ wctx->ssl_ctx = NULL;
+ }
+ return result;
+}
+
+/*
+ * This function loads all the client/CA certificates and CRLs. Setup the TLS
+ * layer and do all necessary magic.
+ */
+static CURLcode
+wssl_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ CURLcode result;
+
+ DEBUGASSERT(wssl);
+
+ if(connssl->state == ssl_connection_complete)
+ return CURLE_OK;
+
+ result = Curl_wssl_ctx_init(wssl, cf, data, &connssl->peer,
+ connssl->alpn, NULL, NULL, cf,
+ wssl_on_session_reuse);
+ if(result)
+ return result;
+
+#ifdef HAVE_ALPN
+ if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
+ struct alpn_proto_buf proto;
+ memset(&proto, 0, sizeof(proto));
+ Curl_alpn_to_proto_str(&proto, connssl->alpn);
+ infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
+ }
+#endif
+
+ /* Enable RFC2818 checks */
+ if(conn_config->verifyhost) {
+ char *snihost = connssl->peer.sni ?
+ connssl->peer.sni : connssl->peer.hostname;
+ if(wolfSSL_check_domain_name(wssl->ssl, snihost) !=
+ WOLFSSL_SUCCESS) {
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
#ifdef USE_BIO_CHAIN
{
WOLFSSL_BIO *bio;
- bio = wolfSSL_BIO_new(wolfssl_bio_cf_method);
+ bio = wolfSSL_BIO_new(wssl_bio_cf_method);
if(!bio)
return CURLE_OUT_OF_MEMORY;
wolfSSL_BIO_set_data(bio, cf);
- wolfSSL_set_bio(backend->handle, bio, bio);
+ wolfSSL_set_bio(wssl->ssl, bio, bio);
}
#else /* USE_BIO_CHAIN */
/* pass the raw socket into the SSL layer */
- if(!wolfSSL_set_fd(backend->handle,
+ if(!wolfSSL_set_fd(wssl->ssl,
(int)Curl_conn_cf_get_socket(cf, data))) {
- failf(data, "SSL: SSL_set_fd failed");
+ failf(data, "SSL: wolfSSL_set_fd failed");
return CURLE_SSL_CONNECT_ERROR;
}
#endif /* !USE_BIO_CHAIN */
- connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
}
-static char *wolfssl_strerror(unsigned long error, char *buf,
- unsigned long size)
+static char *wssl_strerror(unsigned long error, char *buf,
+ unsigned long size)
{
DEBUGASSERT(size > 40);
*buf = '\0';
@@ -1316,15 +1528,10 @@ static char *wolfssl_strerror(unsigned long error, char *buf,
return buf;
}
-
-static CURLcode
-wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
+CURLcode Curl_wssl_verify_pinned(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ struct wssl_ctx *wssl)
{
- int ret = -1;
- struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
- struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
#ifndef CURL_DISABLE_PROXY
const char * const pinnedpubkey = Curl_ssl_cf_is_proxy(cf) ?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
@@ -1333,29 +1540,143 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY];
#endif
- DEBUGASSERT(backend);
+ if(pinnedpubkey) {
+#ifdef KEEP_PEER_CERT
+ WOLFSSL_X509 *x509;
+ const char *x509_der;
+ int x509_der_len;
+ struct Curl_X509certificate x509_parsed;
+ struct Curl_asn1Element *pubkey;
+ CURLcode result;
+
+ x509 = wolfSSL_get_peer_certificate(wssl->ssl);
+ if(!x509) {
+ failf(data, "SSL: failed retrieving server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
- wolfSSL_ERR_clear_error();
+ x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
+ if(!x509_der) {
+ failf(data, "SSL: failed retrieving ASN.1 server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
- /* Enable RFC2818 checks */
- if(conn_config->verifyhost) {
- char *snihost = connssl->peer.sni ?
- connssl->peer.sni : connssl->peer.hostname;
- if(wolfSSL_check_domain_name(backend->handle, snihost) == WOLFSSL_FAILURE)
- return CURLE_SSL_CONNECT_ERROR;
+ memset(&x509_parsed, 0, sizeof(x509_parsed));
+ if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+ pubkey = &x509_parsed.subjectPublicKeyInfo;
+ if(!pubkey->header || pubkey->end <= pubkey->header) {
+ failf(data, "SSL: failed retrieving public key from server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ result = Curl_pin_peer_pubkey(data,
+ pinnedpubkey,
+ (const unsigned char *)pubkey->header,
+ (size_t)(pubkey->end - pubkey->header));
+ wolfSSL_FreeX509(x509);
+ if(result) {
+ failf(data, "SSL: public key does not match pinned public key");
+ return result;
+ }
+#else
+ failf(data, "Library lacks pinning support built-in");
+ return CURLE_NOT_BUILT_IN;
+#endif
}
+ return CURLE_OK;
+}
- if(!backend->x509_store_setup) {
- /* After having send off the ClientHello, we prepare the x509
- * store to verify the coming certificate from the server */
- CURLcode result;
- result = Curl_wssl_setup_x509_store(cf, data, backend);
+#ifdef WOLFSSL_EARLY_DATA
+static CURLcode wssl_send_earlydata(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
+ const unsigned char *buf;
+ size_t blen;
+
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sending);
+ wssl->io_result = CURLE_OK;
+ while(Curl_bufq_peek(&connssl->earlydata, &buf, &blen)) {
+ int nwritten = 0, rc;
+
+ wolfSSL_ERR_clear_error();
+ rc = wolfSSL_write_early_data(wssl->ssl, buf, (int)blen, &nwritten);
+ CURL_TRC_CF(data, cf, "wolfSSL_write_early_data(len=%zu) -> %d, %d",
+ blen, rc, nwritten);
+ if(rc < 0) {
+ int err = wolfSSL_get_error(wssl->ssl, rc);
+ switch(err) {
+ case WOLFSSL_ERROR_NONE: /* just did not get anything */
+ case WOLFSSL_ERROR_WANT_READ:
+ case WOLFSSL_ERROR_WANT_WRITE:
+ result = CURLE_AGAIN;
+ break;
+ default: {
+ char error_buffer[256];
+ int detail = wolfSSL_get_error(wssl->ssl, err);
+ CURL_TRC_CF(data, cf, "SSL send early data, error: '%s'(%d)",
+ wssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
+ detail);
+ result = CURLE_SEND_ERROR;
+ break;
+ }
+ }
+ goto out;
+ }
+
+ Curl_bufq_skip(&connssl->earlydata, (size_t)nwritten);
+ }
+ /* sent everything there was */
+ connssl->earlydata_state = ssl_earlydata_sent;
+ if(!Curl_ssl_cf_is_proxy(cf))
+ Curl_pgrsEarlyData(data, (curl_off_t)connssl->earlydata_skip);
+ infof(data, "SSL sending %zu bytes of early data", connssl->earlydata_skip);
+out:
+ return result;
+}
+#endif /* WOLFSSL_EARLY_DATA */
+
+static CURLcode wssl_handshake(struct Curl_cfilter *cf,
+ struct Curl_easy *data)
+{
+ struct ssl_connect_data *connssl = cf->ctx;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
+ int ret = -1, detail;
+ CURLcode result;
+
+ DEBUGASSERT(wssl);
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
+
+#ifdef WOLFSSL_EARLY_DATA
+ if(connssl->earlydata_state == ssl_earlydata_sending) {
+ result = wssl_send_earlydata(cf, data);
if(result)
return result;
}
+ DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
+ (connssl->earlydata_state == ssl_earlydata_sent));
+#else
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_none);
+#endif /* WOLFSSL_EARLY_DATA */
- connssl->io_need = CURL_SSL_IO_NEED_NONE;
- ret = wolfSSL_connect(backend->handle);
+ wolfSSL_ERR_clear_error();
+ ret = wolfSSL_connect(wssl->ssl);
+
+ if(!wssl->x509_store_setup) {
+ /* After having send off the ClientHello, we prepare the x509
+ * store to verify the coming certificate from the server */
+ result = Curl_wssl_setup_x509_store(cf, data, wssl);
+ if(result) {
+ CURL_TRC_CF(data, cf, "Curl_wssl_setup_x509_store() -> %d", result);
+ return result;
+ }
+ }
#ifdef OPENSSL_EXTRA
if(Curl_tls_keylog_enabled()) {
@@ -1371,67 +1692,49 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
* changes, the worst case is that no key is logged on error.
*/
if(ret == WOLFSSL_SUCCESS ||
- (!wolfSSL_want_read(backend->handle) &&
- !wolfSSL_want_write(backend->handle))) {
- wolfssl_log_tls12_secret(backend->handle);
+ (!wolfSSL_want_read(wssl->ssl) &&
+ !wolfSSL_want_write(wssl->ssl))) {
+ wssl_log_tls12_secret(wssl->ssl);
/* Client Random and master secrets are no longer needed, erase these.
* Ignored while the handshake is still in progress. */
- wolfSSL_FreeArrays(backend->handle);
+ wolfSSL_FreeArrays(wssl->ssl);
}
}
#endif /* OPENSSL_EXTRA */
- if(ret != 1) {
- int detail = wolfSSL_get_error(backend->handle, ret);
+ detail = wolfSSL_get_error(wssl->ssl, ret);
+ CURL_TRC_CF(data, cf, "wolfSSL_connect() -> %d, detail=%d", ret, detail);
+ if(ret == WOLFSSL_SUCCESS) {
+ return CURLE_OK;
+ }
+ else {
if(WOLFSSL_ERROR_WANT_READ == detail) {
connssl->io_need = CURL_SSL_IO_NEED_RECV;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
else if(WOLFSSL_ERROR_WANT_WRITE == detail) {
connssl->io_need = CURL_SSL_IO_NEED_SEND;
- return CURLE_OK;
+ return CURLE_AGAIN;
}
- /* There is no easy way to override only the CN matching.
- * This will enable the override of both mismatching SubjectAltNames
- * as also mismatching CN fields */
else if(DOMAIN_NAME_MISMATCH == detail) {
-#if 1
+ /* There is no easy way to override only the CN matching.
+ * This will enable the override of both mismatching SubjectAltNames
+ * as also mismatching CN fields */
failf(data, " subject alt name(s) or common name do not match \"%s\"",
connssl->peer.dispname);
return CURLE_PEER_FAILED_VERIFICATION;
-#else
- /* When the wolfssl_check_domain_name() is used and you desire to
- * continue on a DOMAIN_NAME_MISMATCH, i.e. 'ssl_config.verifyhost
- * == 0', CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA
- * error. The only way to do this is currently to switch the
- * Wolfssl_check_domain_name() in and out based on the
- * 'ssl_config.verifyhost' value. */
- if(conn_config->verifyhost) {
- failf(data,
- " subject alt name(s) or common name do not match \"%s\"\n",
- connssl->dispname);
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- else {
- infof(data,
- " subject alt name(s) and/or common name do not match \"%s\"",
- connssl->dispname);
- return CURLE_OK;
- }
-#endif
}
else if(ASN_NO_SIGNER_E == detail) {
if(conn_config->verifypeer) {
failf(data, " CA signer not available for verification");
return CURLE_SSL_CACERT_BADFILE;
}
- else {
- /* Just continue with a warning if no strict certificate
- verification is required. */
- infof(data, "CA signer not available for verification, "
- "continuing anyway");
- }
+ /* Just continue with a warning if no strict certificate
+ verification is required. */
+ infof(data, "CA signer not available for verification, "
+ "continuing anyway");
+ return CURLE_OK;
}
else if(ASN_AFTER_DATE_E == detail) {
failf(data, "server verification failed: certificate has expired.");
@@ -1441,7 +1744,16 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
failf(data, "server verification failed: certificate not valid yet.");
return CURLE_PEER_FAILED_VERIFICATION;
}
-#ifdef USE_ECH
+ else if(wssl->io_result) {
+ switch(wssl->io_result) {
+ case CURLE_SEND_ERROR:
+ case CURLE_RECV_ERROR:
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ return wssl->io_result;
+ }
+ }
+#ifdef USE_ECH_WOLFSSL
else if(-1 == detail) {
/* try access a retry_config ECHConfigList for tracing */
byte echConfigs[1000];
@@ -1449,7 +1761,7 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
int rv = 0;
/* this currently does not produce the retry_configs */
- rv = wolfSSL_GetEchConfigs(backend->handle, echConfigs,
+ rv = wolfSSL_GetEchConfigs(wssl->ssl, echConfigs,
&echConfigsLen);
if(rv != WOLFSSL_SUCCESS) {
infof(data, "Failed to get ECHConfigs");
@@ -1458,160 +1770,100 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
char *b64str = NULL;
size_t blen = 0;
- rv = Curl_base64_encode((const char *)echConfigs, echConfigsLen,
- &b64str, &blen);
- if(!rv && b64str)
+ result = curlx_base64_encode((const char *)echConfigs, echConfigsLen,
+ &b64str, &blen);
+ if(!result && b64str)
infof(data, "ECH: (not yet) retry_configs %s", b64str);
free(b64str);
}
+ return CURLE_SSL_CONNECT_ERROR;
}
#endif
- else if(backend->io_result == CURLE_AGAIN) {
- return CURLE_OK;
- }
else {
char error_buffer[256];
failf(data, "SSL_connect failed with error %d: %s", detail,
- wolfssl_strerror((unsigned long)detail, error_buffer,
- sizeof(error_buffer)));
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- if(pinnedpubkey) {
-#ifdef KEEP_PEER_CERT
- WOLFSSL_X509 *x509;
- const char *x509_der;
- int x509_der_len;
- struct Curl_X509certificate x509_parsed;
- struct Curl_asn1Element *pubkey;
- CURLcode result;
-
- x509 = wolfSSL_get_peer_certificate(backend->handle);
- if(!x509) {
- failf(data, "SSL: failed retrieving server certificate");
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- }
-
- x509_der = (const char *)wolfSSL_X509_get_der(x509, &x509_der_len);
- if(!x509_der) {
- failf(data, "SSL: failed retrieving ASN.1 server certificate");
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- }
-
- memset(&x509_parsed, 0, sizeof(x509_parsed));
- if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
-
- pubkey = &x509_parsed.subjectPublicKeyInfo;
- if(!pubkey->header || pubkey->end <= pubkey->header) {
- failf(data, "SSL: failed retrieving public key from server certificate");
- return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
- }
-
- result = Curl_pin_peer_pubkey(data,
- pinnedpubkey,
- (const unsigned char *)pubkey->header,
- (size_t)(pubkey->end - pubkey->header));
- wolfSSL_FreeX509(x509);
- if(result) {
- failf(data, "SSL: public key does not match pinned public key");
- return result;
- }
-#else
- failf(data, "Library lacks pinning support built-in");
- return CURLE_NOT_BUILT_IN;
-#endif
- }
-
-#ifdef HAVE_ALPN
- if(connssl->alpn) {
- int rc;
- char *protocol = NULL;
- unsigned short protocol_len = 0;
-
- rc = wolfSSL_ALPN_GetProtocol(backend->handle, &protocol, &protocol_len);
-
- if(rc == WOLFSSL_SUCCESS) {
- Curl_alpn_set_negotiated(cf, data, connssl,
- (const unsigned char *)protocol, protocol_len);
- }
- else if(rc == WOLFSSL_ALPN_NOT_FOUND)
- Curl_alpn_set_negotiated(cf, data, connssl, NULL, 0);
- else {
- failf(data, "ALPN, failure getting protocol, error %d", rc);
+ wssl_strerror((unsigned long)detail, error_buffer,
+ sizeof(error_buffer)));
return CURLE_SSL_CONNECT_ERROR;
}
}
-#endif /* HAVE_ALPN */
-
- connssl->connecting_state = ssl_connect_3;
-#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
- infof(data, "SSL connection using %s / %s",
- wolfSSL_get_version(backend->handle),
- wolfSSL_get_cipher_name(backend->handle));
-#else
- infof(data, "SSL connected");
-#endif
-
- return CURLE_OK;
}
-static ssize_t wolfssl_send(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- const void *mem,
- size_t len,
- CURLcode *curlcode)
+static ssize_t wssl_send(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ const void *buf, size_t blen,
+ CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
- int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
- int rc;
-
- DEBUGASSERT(backend);
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ size_t total_written = 0;
+ ssize_t nwritten = -1;
+ DEBUGASSERT(wssl);
wolfSSL_ERR_clear_error();
- rc = wolfSSL_write(backend->handle, mem, memlen);
- if(rc <= 0) {
- int err = wolfSSL_get_error(backend->handle, rc);
+ if(blen) {
+ int memlen = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
+ int rc;
- switch(err) {
- case WOLFSSL_ERROR_WANT_READ:
- case WOLFSSL_ERROR_WANT_WRITE:
- /* there is data pending, re-invoke SSL_write() */
- CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
- *curlcode = CURLE_AGAIN;
- return -1;
- default:
- if(backend->io_result == CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len);
+ rc = wolfSSL_write(wssl->ssl, buf, memlen);
+ if(rc <= 0) {
+ int err = wolfSSL_get_error(wssl->ssl, rc);
+
+ switch(err) {
+ case WOLFSSL_ERROR_WANT_READ:
+ case WOLFSSL_ERROR_WANT_WRITE:
+ /* there is data pending, re-invoke wolfSSL_write() */
+ if(total_written) {
+ *curlcode = CURLE_OK;
+ nwritten = total_written;
+ goto out;
+ }
*curlcode = CURLE_AGAIN;
- return -1;
- }
- CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d", len, rc, err);
- {
- char error_buffer[256];
- failf(data, "SSL write: %s, errno %d",
- wolfssl_strerror((unsigned long)err, error_buffer,
- sizeof(error_buffer)),
- SOCKERRNO);
+ nwritten = -1;
+ goto out;
+
+ default:
+ if(wssl->io_result == CURLE_AGAIN) {
+ if(total_written) {
+ *curlcode = CURLE_OK;
+ nwritten = total_written;
+ goto out;
+ }
+ *curlcode = CURLE_AGAIN;
+ nwritten = -1;
+ goto out;
+ }
+ {
+ char error_buffer[256];
+ failf(data, "SSL write: %s, errno %d",
+ wssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
+ SOCKERRNO);
+ }
+ *curlcode = CURLE_SEND_ERROR;
+ nwritten = -1;
+ goto out;
}
- *curlcode = CURLE_SEND_ERROR;
- return -1;
}
+ else
+ total_written += rc;
}
- CURL_TRC_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc);
- return rc;
+
+ *curlcode = CURLE_OK;
+ nwritten = total_written;
+out:
+ CURL_TRC_CF(data, cf, "wssl_send(len=%zu) -> %" FMT_OFF_T ", %d",
+ blen, nwritten, *curlcode);
+ return nwritten;
}
-static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool send_shutdown, bool *done)
+static CURLcode wssl_shutdown(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool send_shutdown, bool *done)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *wctx = (struct wolfssl_ctx *)connssl->backend;
+ struct wssl_ctx *wctx = (struct wssl_ctx *)connssl->backend;
CURLcode result = CURLE_OK;
char buf[1024];
char error_buffer[256];
@@ -1620,7 +1872,7 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
int detail;
DEBUGASSERT(wctx);
- if(!wctx->handle || cf->shutdown) {
+ if(!wctx->ssl || cf->shutdown) {
*done = TRUE;
goto out;
}
@@ -1628,12 +1880,12 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
wctx->shutting_down = TRUE;
connssl->io_need = CURL_SSL_IO_NEED_NONE;
*done = FALSE;
- if(!(wolfSSL_get_shutdown(wctx->handle) & WOLFSSL_SENT_SHUTDOWN)) {
+ if(!(wolfSSL_get_shutdown(wctx->ssl) & WOLFSSL_SENT_SHUTDOWN)) {
/* We have not started the shutdown from our side yet. Check
* if the server already sent us one. */
wolfSSL_ERR_clear_error();
- nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
- err = wolfSSL_get_error(wctx->handle, nread);
+ nread = wolfSSL_read(wctx->ssl, buf, (int)sizeof(buf));
+ err = wolfSSL_get_error(wctx->ssl, nread);
CURL_TRC_CF(data, cf, "wolfSSL_read, nread=%d, err=%d", nread, err);
if(!nread && err == WOLFSSL_ERROR_ZERO_RETURN) {
bool input_pending;
@@ -1655,16 +1907,16 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
}
}
- /* SSL should now have started the shutdown from our side. Since it
+ /* wolfSSL should now have started the shutdown from our side. Since it
* was not complete, we are lacking the close notify from the server. */
if(send_shutdown) {
wolfSSL_ERR_clear_error();
- if(wolfSSL_shutdown(wctx->handle) == 1) {
+ if(wolfSSL_shutdown(wctx->ssl) == 1) {
CURL_TRC_CF(data, cf, "SSL shutdown finished");
*done = TRUE;
goto out;
}
- if(WOLFSSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->handle, nread)) {
+ if(WOLFSSL_ERROR_WANT_WRITE == wolfSSL_get_error(wctx->ssl, nread)) {
CURL_TRC_CF(data, cf, "SSL shutdown still wants to send");
connssl->io_need = CURL_SSL_IO_NEED_SEND;
goto out;
@@ -1675,11 +1927,11 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
for(i = 0; i < 10; ++i) {
wolfSSL_ERR_clear_error();
- nread = wolfSSL_read(wctx->handle, buf, (int)sizeof(buf));
+ nread = wolfSSL_read(wctx->ssl, buf, (int)sizeof(buf));
if(nread <= 0)
break;
}
- err = wolfSSL_get_error(wctx->handle, nread);
+ err = wolfSSL_get_error(wctx->ssl, nread);
switch(err) {
case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
CURL_TRC_CF(data, cf, "SSL shutdown received");
@@ -1687,7 +1939,7 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
break;
case WOLFSSL_ERROR_NONE: /* just did not get anything */
case WOLFSSL_ERROR_WANT_READ:
- /* SSL has send its notify and now wants to read the reply
+ /* wolfSSL has send its notify and now wants to read the reply
* from the server. We are not really interested in that. */
CURL_TRC_CF(data, cf, "SSL shutdown sent, want receive");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
@@ -1697,10 +1949,10 @@ static CURLcode wolfssl_shutdown(struct Curl_cfilter *cf,
connssl->io_need = CURL_SSL_IO_NEED_SEND;
break;
default:
- detail = wolfSSL_get_error(wctx->handle, err);
+ detail = wolfSSL_get_error(wctx->ssl, err);
CURL_TRC_CF(data, cf, "SSL shutdown, error: '%s'(%d)",
- wolfssl_strerror((unsigned long)err, error_buffer,
- sizeof(error_buffer)),
+ wssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
detail);
result = CURLE_RECV_ERROR;
break;
@@ -1711,92 +1963,90 @@ out:
return result;
}
-static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
+static void wssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
(void) data;
- DEBUGASSERT(backend);
+ DEBUGASSERT(wssl);
- if(backend->handle) {
- wolfSSL_free(backend->handle);
- backend->handle = NULL;
+ if(wssl->ssl) {
+ wolfSSL_free(wssl->ssl);
+ wssl->ssl = NULL;
}
- if(backend->ctx) {
- wolfSSL_CTX_free(backend->ctx);
- backend->ctx = NULL;
+ if(wssl->ssl_ctx) {
+ wolfSSL_CTX_free(wssl->ssl_ctx);
+ wssl->ssl_ctx = NULL;
}
}
-static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- char *buf, size_t blen,
- CURLcode *curlcode)
+static ssize_t wssl_recv(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ char *buf, size_t blen,
+ CURLcode *curlcode)
{
struct ssl_connect_data *connssl = cf->ctx;
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
int nread;
- DEBUGASSERT(backend);
+ DEBUGASSERT(wssl);
wolfSSL_ERR_clear_error();
*curlcode = CURLE_OK;
- nread = wolfSSL_read(backend->handle, buf, buffsize);
+ nread = wolfSSL_read(wssl->ssl, buf, buffsize);
if(nread <= 0) {
- int err = wolfSSL_get_error(backend->handle, nread);
+ int err = wolfSSL_get_error(wssl->ssl, nread);
switch(err) {
case WOLFSSL_ERROR_ZERO_RETURN: /* no more data */
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
*curlcode = CURLE_OK;
return 0;
case WOLFSSL_ERROR_NONE:
case WOLFSSL_ERROR_WANT_READ:
case WOLFSSL_ERROR_WANT_WRITE:
- if(!backend->io_result && connssl->peer_closed) {
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+ if(!wssl->io_result && connssl->peer_closed) {
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
*curlcode = CURLE_OK;
return 0;
}
/* there is data pending, re-invoke wolfSSL_read() */
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen);
*curlcode = CURLE_AGAIN;
return -1;
default:
- if(backend->io_result == CURLE_AGAIN) {
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen);
+ if(wssl->io_result == CURLE_AGAIN) {
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> AGAIN", blen);
*curlcode = CURLE_AGAIN;
return -1;
}
- else if(!backend->io_result && connssl->peer_closed) {
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen);
+ else if(!wssl->io_result && connssl->peer_closed) {
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> CLOSED", blen);
*curlcode = CURLE_OK;
return 0;
}
else {
char error_buffer[256];
failf(data, "SSL read: %s, errno %d",
- wolfssl_strerror((unsigned long)err, error_buffer,
- sizeof(error_buffer)),
+ wssl_strerror((unsigned long)err, error_buffer,
+ sizeof(error_buffer)),
SOCKERRNO);
}
*curlcode = CURLE_RECV_ERROR;
return -1;
}
}
- CURL_TRC_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread);
+
+ CURL_TRC_CF(data, cf, "wssl_recv(len=%zu) -> %d", blen, nread);
return nread;
}
-
-static size_t wolfssl_version(char *buffer, size_t size)
+size_t Curl_wssl_version(char *buffer, size_t size)
{
#if LIBWOLFSSL_VERSION_HEX >= 0x03006000
return msnprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
@@ -1806,7 +2056,7 @@ static size_t wolfssl_version(char *buffer, size_t size)
}
-static int wolfssl_init(void)
+static int wssl_init(void)
{
int ret;
@@ -1814,14 +2064,14 @@ static int wolfssl_init(void)
Curl_tls_keylog_open();
#endif
ret = (wolfSSL_Init() == WOLFSSL_SUCCESS);
- wolfssl_bio_cf_init_methods();
+ wssl_bio_cf_init_methods();
return ret;
}
-static void wolfssl_cleanup(void)
+static void wssl_cleanup(void)
{
- wolfssl_bio_cf_free_methods();
+ wssl_bio_cf_free_methods();
wolfSSL_Cleanup();
#ifdef OPENSSL_EXTRA
Curl_tls_keylog_close();
@@ -1829,31 +2079,29 @@ static void wolfssl_cleanup(void)
}
-static bool wolfssl_data_pending(struct Curl_cfilter *cf,
- const struct Curl_easy *data)
+static bool wssl_data_pending(struct Curl_cfilter *cf,
+ const struct Curl_easy *data)
{
struct ssl_connect_data *ctx = cf->ctx;
- struct wolfssl_ctx *backend;
+ struct wssl_ctx *wssl;
(void)data;
DEBUGASSERT(ctx && ctx->backend);
- backend = (struct wolfssl_ctx *)ctx->backend;
- if(backend->handle) /* SSL is in use */
- return wolfSSL_pending(backend->handle);
+ wssl = (struct wssl_ctx *)ctx->backend;
+ if(wssl->ssl) /* wolfSSL is in use */
+ return wolfSSL_pending(wssl->ssl);
else
return FALSE;
}
-static CURLcode
-wolfssl_connect_common(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool nonblocking,
- bool *done)
+static CURLcode wssl_connect(struct Curl_cfilter *cf,
+ struct Curl_easy *data,
+ bool *done)
{
- CURLcode result;
struct ssl_connect_data *connssl = cf->ctx;
- curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
+ CURLcode result = CURLE_OK;
/* check if the connection has already been established */
if(ssl_connection_complete == connssl->state) {
@@ -1861,116 +2109,108 @@ wolfssl_connect_common(struct Curl_cfilter *cf,
return CURLE_OK;
}
- if(ssl_connect_1 == connssl->connecting_state) {
- /* Find out how much more time we are allowed */
- const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
-
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
+ *done = FALSE;
+ connssl->io_need = CURL_SSL_IO_NEED_NONE;
- result = wolfssl_connect_step1(cf, data);
+ if(ssl_connect_1 == connssl->connecting_state) {
+ result = wssl_connect_step1(cf, data);
if(result)
return result;
+ connssl->connecting_state = ssl_connect_2;
}
- while(ssl_connect_2 == connssl->connecting_state) {
-
- /* check allowed time left */
- const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ if(ssl_connect_2 == connssl->connecting_state) {
+ if(connssl->earlydata_state == ssl_earlydata_await) {
+ /* We defer the handshake until request data arrives. */
+ DEBUGASSERT(connssl->state == ssl_connection_deferred);
+ goto out;
+ }
+ result = wssl_handshake(cf, data);
+ if(result == CURLE_AGAIN)
+ goto out;
+ wssl->hs_result = result;
+ connssl->connecting_state = ssl_connect_3;
+ }
- if(timeout_ms < 0) {
- /* no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
+ if(ssl_connect_3 == connssl->connecting_state) {
+ /* Once the handshake has errored, it stays in that state and will
+ * error again on every call. */
+ if(wssl->hs_result) {
+ result = wssl->hs_result;
+ goto out;
}
+ result = Curl_wssl_verify_pinned(cf, data, wssl);
+ if(result) {
+ wssl->hs_result = result;
+ goto out;
+ }
+ /* handhshake was done without errors */
+#ifdef HAVE_ALPN
+ if(connssl->alpn) {
+ int rc;
+ char *protocol = NULL;
+ unsigned short protocol_len = 0;
+
+ rc = wolfSSL_ALPN_GetProtocol(wssl->ssl, &protocol, &protocol_len);
- /* if ssl is expecting something, check if it is available. */
- if(connssl->io_need) {
- curl_socket_t writefd = (connssl->io_need & CURL_SSL_IO_NEED_SEND) ?
- sockfd : CURL_SOCKET_BAD;
- curl_socket_t readfd = (connssl->io_need & CURL_SSL_IO_NEED_RECV) ?
- sockfd : CURL_SOCKET_BAD;
- int what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- nonblocking ? 0 : timeout_ms);
- if(what < 0) {
- /* fatal error */
- failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
- return CURLE_SSL_CONNECT_ERROR;
+ if(rc == WOLFSSL_SUCCESS) {
+ Curl_alpn_set_negotiated(cf, data, connssl,
+ (const unsigned char *)protocol,
+ protocol_len);
}
- else if(0 == what) {
- if(nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
+ else if(rc == WOLFSSL_ALPN_NOT_FOUND)
+ Curl_alpn_set_negotiated(cf, data, connssl, NULL, 0);
+ else {
+ failf(data, "ALPN, failure getting protocol, error %d", rc);
+ wssl->hs_result = result = CURLE_SSL_CONNECT_ERROR;
+ goto out;
}
- /* socket is readable or writable */
}
+#endif /* HAVE_ALPN */
- /* Run transaction, and return to the caller if it failed or if
- * this connection is part of a multi handle and this loop would
- * execute again. This permits the owner of a multi handle to
- * abort a connection attempt before step2 has completed while
- * ensuring that a client using select() or epoll() will always
- * have a valid fdset to wait on.
- */
- result = wolfssl_connect_step2(cf, data);
- if(result || (nonblocking && (ssl_connect_2 == connssl->connecting_state)))
- return result;
- } /* repeat step2 until all transactions are done. */
+#if (LIBWOLFSSL_VERSION_HEX >= 0x03009010)
+ infof(data, "SSL connection using %s / %s",
+ wolfSSL_get_version(wssl->ssl),
+ wolfSSL_get_cipher_name(wssl->ssl));
+#else
+ infof(data, "SSL connected");
+#endif
- if(ssl_connect_3 == connssl->connecting_state) {
- /* In other backends, this is where we verify the certificate, but
- * wolfSSL already does that as part of the handshake. */
connssl->connecting_state = ssl_connect_done;
+ connssl->state = ssl_connection_complete;
+
+#ifdef WOLFSSL_EARLY_DATA
+ if(connssl->earlydata_state > ssl_earlydata_none) {
+ /* We should be in this state by now */
+ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent);
+ connssl->earlydata_state =
+ (wolfSSL_get_early_data_status(wssl->ssl) ==
+ WOLFSSL_EARLY_DATA_REJECTED) ?
+ ssl_earlydata_rejected : ssl_earlydata_accepted;
+ }
+#endif /* WOLFSSL_EARLY_DATA */
}
- if(ssl_connect_done == connssl->connecting_state) {
- connssl->state = ssl_connection_complete;
+ if((connssl->connecting_state == ssl_connect_done) ||
+ (connssl->state == ssl_connection_deferred)) {
*done = TRUE;
}
- else
- *done = FALSE;
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-static CURLcode wolfssl_connect_nonblocking(struct Curl_cfilter *cf,
- struct Curl_easy *data,
- bool *done)
-{
- return wolfssl_connect_common(cf, data, TRUE, done);
-}
-
-
-static CURLcode wolfssl_connect(struct Curl_cfilter *cf,
- struct Curl_easy *data)
-{
- CURLcode result;
- bool done = FALSE;
-
- result = wolfssl_connect_common(cf, data, FALSE, &done);
- if(result)
- return result;
-
- DEBUGASSERT(done);
-
- return CURLE_OK;
+out:
+ if(result) {
+ *done = FALSE;
+ if(result == CURLE_AGAIN)
+ return CURLE_OK;
+ }
+ else if((connssl->connecting_state == ssl_connect_done) ||
+ (connssl->state == ssl_connection_deferred)) {
+ *done = TRUE;
+ }
+ return result;
}
-static CURLcode wolfssl_random(struct Curl_easy *data,
- unsigned char *entropy, size_t length)
+static CURLcode wssl_random(struct Curl_easy *data,
+ unsigned char *entropy, size_t length)
{
WC_RNG rng;
(void)data;
@@ -1985,10 +2225,10 @@ static CURLcode wolfssl_random(struct Curl_easy *data,
return CURLE_OK;
}
-static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
- size_t tmplen,
- unsigned char *sha256sum /* output */,
- size_t unused)
+static CURLcode wssl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused)
{
wc_Sha256 SHA256pw;
(void)unused;
@@ -1999,14 +2239,13 @@ static CURLcode wolfssl_sha256sum(const unsigned char *tmp, /* input */
return CURLE_OK;
}
-static void *wolfssl_get_internals(struct ssl_connect_data *connssl,
- CURLINFO info UNUSED_PARAM)
+static void *wssl_get_internals(struct ssl_connect_data *connssl,
+ CURLINFO info UNUSED_PARAM)
{
- struct wolfssl_ctx *backend =
- (struct wolfssl_ctx *)connssl->backend;
+ struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend;
(void)info;
- DEBUGASSERT(backend);
- return backend->handle;
+ DEBUGASSERT(wssl);
+ return wssl->ssl;
}
const struct Curl_ssl Curl_ssl_wolfssl = {
@@ -2020,7 +2259,7 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
#endif
SSLSUPP_CA_PATH |
SSLSUPP_CAINFO_BLOB |
-#ifdef USE_ECH
+#ifdef USE_ECH_WOLFSSL
SSLSUPP_ECH |
#endif
SSLSUPP_SSL_CTX |
@@ -2030,31 +2269,27 @@ const struct Curl_ssl Curl_ssl_wolfssl = {
SSLSUPP_CA_CACHE |
SSLSUPP_CIPHER_LIST,
- sizeof(struct wolfssl_ctx),
-
- wolfssl_init, /* init */
- wolfssl_cleanup, /* cleanup */
- wolfssl_version, /* version */
- Curl_none_check_cxn, /* check_cxn */
- wolfssl_shutdown, /* shutdown */
- wolfssl_data_pending, /* data_pending */
- wolfssl_random, /* random */
- Curl_none_cert_status_request, /* cert_status_request */
- wolfssl_connect, /* connect */
- wolfssl_connect_nonblocking, /* connect_nonblocking */
+ sizeof(struct wssl_ctx),
+
+ wssl_init, /* init */
+ wssl_cleanup, /* cleanup */
+ Curl_wssl_version, /* version */
+ wssl_shutdown, /* shutdown */
+ wssl_data_pending, /* data_pending */
+ wssl_random, /* random */
+ NULL, /* cert_status_request */
+ wssl_connect, /* connect */
Curl_ssl_adjust_pollset, /* adjust_pollset */
- wolfssl_get_internals, /* get_internals */
- wolfssl_close, /* close_one */
- Curl_none_close_all, /* close_all */
- Curl_none_set_engine, /* set_engine */
- Curl_none_set_engine_default, /* set_engine_default */
- Curl_none_engines_list, /* engines_list */
- Curl_none_false_start, /* false_start */
- wolfssl_sha256sum, /* sha256sum */
- NULL, /* associate_connection */
- NULL, /* disassociate_connection */
- wolfssl_recv, /* recv decrypted data */
- wolfssl_send, /* send data to encrypt */
+ wssl_get_internals, /* get_internals */
+ wssl_close, /* close_one */
+ NULL, /* close_all */
+ NULL, /* set_engine */
+ NULL, /* set_engine_default */
+ NULL, /* engines_list */
+ NULL, /* false_start */
+ wssl_sha256sum, /* sha256sum */
+ wssl_recv, /* recv decrypted data */
+ wssl_send, /* send data to encrypt */
NULL, /* get_channel_binding */
};