wolfssl: tls early data support
Enable TLS Early Data for wolfSSL: - merge WOLFSSL_CTX and WOLFSSL setup from ngtcp2 with the general implemenation in wolfssl.c - enable for QUIC via ngtcp2 - give Curl_vquic_tls_init() a `struct alpn_spec` like used for the TCP case. Adapt gnutls and other users. - enable pytest test cases for early data with wolfSSL and while this messes up wolfssl.c anyway, do - rename all struct/functions with prefix 'wolfssl_' to 'wssl_' to not pollute that name prefix - rename `ctx/handle` to `ssl_ctx/ssl`, as used in openssl case Closes #16167
This commit is contained in:
parent
efec626ebb
commit
edd573d980
@ -89,11 +89,11 @@ could be a privacy violation and unexpected.
|
|||||||
## CURLSSLOPT_EARLYDATA
|
## CURLSSLOPT_EARLYDATA
|
||||||
|
|
||||||
Tell libcurl to try sending application data as TLS1.3 early data. This option
|
Tell libcurl to try sending application data as TLS1.3 early data. This option
|
||||||
is only supported for GnuTLS. This option works on a best effort basis,
|
is supported for GnuTLS and wolfSSL. This option works on a best effort basis,
|
||||||
in cases when it wasn't possible to send early data the request is resent
|
in cases when it wasn't possible to send early data the request is resent
|
||||||
normally post-handshake.
|
normally post-handshake.
|
||||||
This option does not work when using QUIC.
|
This option does not work when using QUIC.
|
||||||
(Added in 8.11.0)
|
(Added in 8.11.0 for GnuTLS and 8.13.0 for wolfSSL)
|
||||||
|
|
||||||
# DEFAULT
|
# DEFAULT
|
||||||
|
|
||||||
|
|||||||
@ -481,17 +481,27 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data)
|
|||||||
* the handshake time when we really did connect */
|
* the handshake time when we really did connect */
|
||||||
if(ctx->use_earlydata)
|
if(ctx->use_earlydata)
|
||||||
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
|
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
|
||||||
#ifdef USE_GNUTLS
|
|
||||||
if(ctx->use_earlydata) {
|
if(ctx->use_earlydata) {
|
||||||
|
#ifdef USE_GNUTLS
|
||||||
int flags = gnutls_session_get_flags(ctx->tls.gtls.session);
|
int flags = gnutls_session_get_flags(ctx->tls.gtls.session);
|
||||||
ctx->earlydata_accepted = !!(flags & GNUTLS_SFLAGS_EARLY_DATA);
|
ctx->earlydata_accepted = !!(flags & GNUTLS_SFLAGS_EARLY_DATA);
|
||||||
|
#endif
|
||||||
|
#ifdef USE_WOLFSSL
|
||||||
|
#ifdef WOLFSSL_EARLY_DATA
|
||||||
|
ctx->earlydata_accepted =
|
||||||
|
(wolfSSL_get_early_data_status(ctx->tls.wssl.ssl) !=
|
||||||
|
WOLFSSL_EARLY_DATA_REJECTED);
|
||||||
|
#else
|
||||||
|
DEBUGASSERT(0); /* should not come here if ED is disabled. */
|
||||||
|
ctx->earlydata_accepted = FALSE;
|
||||||
|
#endif /* WOLFSSL_EARLY_DATA */
|
||||||
|
#endif
|
||||||
CURL_TRC_CF(data, cf, "server did%s accept %zu bytes of early data",
|
CURL_TRC_CF(data, cf, "server did%s accept %zu bytes of early data",
|
||||||
ctx->earlydata_accepted ? "" : " not", ctx->earlydata_skip);
|
ctx->earlydata_accepted ? "" : " not", ctx->earlydata_skip);
|
||||||
Curl_pgrsEarlyData(data, ctx->earlydata_accepted ?
|
Curl_pgrsEarlyData(data, ctx->earlydata_accepted ?
|
||||||
(curl_off_t)ctx->earlydata_skip :
|
(curl_off_t)ctx->earlydata_skip :
|
||||||
-(curl_off_t)ctx->earlydata_skip);
|
-(curl_off_t)ctx->earlydata_skip);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2257,8 +2267,23 @@ static int wssl_quic_new_session_cb(WOLFSSL *ssl, WOLFSSL_SESSION *session)
|
|||||||
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
struct Curl_easy *data = CF_DATA_CURRENT(cf);
|
||||||
DEBUGASSERT(data);
|
DEBUGASSERT(data);
|
||||||
if(data && ctx) {
|
if(data && ctx) {
|
||||||
|
ngtcp2_ssize tplen;
|
||||||
|
uint8_t tpbuf[256];
|
||||||
|
unsigned char *quic_tp = NULL;
|
||||||
|
size_t quic_tp_len = 0;
|
||||||
|
|
||||||
|
tplen = ngtcp2_conn_encode_0rtt_transport_params(ctx->qconn, tpbuf,
|
||||||
|
sizeof(tpbuf));
|
||||||
|
if(tplen < 0)
|
||||||
|
CURL_TRC_CF(data, cf, "error encoding 0RTT transport data: %s",
|
||||||
|
ngtcp2_strerror((int)tplen));
|
||||||
|
else {
|
||||||
|
quic_tp = (unsigned char *)tpbuf;
|
||||||
|
quic_tp_len = (size_t)tplen;
|
||||||
|
}
|
||||||
(void)Curl_wssl_cache_session(cf, data, ctx->peer.scache_key,
|
(void)Curl_wssl_cache_session(cf, data, ctx->peer.scache_key,
|
||||||
session, wolfSSL_version(ssl), "h3");
|
session, wolfSSL_version(ssl),
|
||||||
|
"h3", quic_tp, quic_tp_len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -2308,13 +2333,13 @@ static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif defined(USE_WOLFSSL)
|
#elif defined(USE_WOLFSSL)
|
||||||
if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ctx) != 0) {
|
if(ngtcp2_crypto_wolfssl_configure_client_context(ctx->wssl.ssl_ctx) != 0) {
|
||||||
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
|
failf(data, "ngtcp2_crypto_wolfssl_configure_client_context failed");
|
||||||
return CURLE_FAILED_INIT;
|
return CURLE_FAILED_INIT;
|
||||||
}
|
}
|
||||||
if(ssl_config->primary.cache_session) {
|
if(ssl_config->primary.cache_session) {
|
||||||
/* Register to get notified when a new session is received */
|
/* Register to get notified when a new session is received */
|
||||||
wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ctx, wssl_quic_new_session_cb);
|
wolfSSL_CTX_sess_set_new_cb(ctx->wssl.ssl_ctx, wssl_quic_new_session_cb);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
@ -2322,6 +2347,7 @@ static CURLcode cf_ngtcp2_tls_ctx_setup(struct Curl_cfilter *cf,
|
|||||||
|
|
||||||
static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
|
static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
|
struct alpn_spec *alpns,
|
||||||
struct Curl_ssl_session *scs,
|
struct Curl_ssl_session *scs,
|
||||||
bool *do_early_data)
|
bool *do_early_data)
|
||||||
{
|
{
|
||||||
@ -2332,10 +2358,19 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
|
|||||||
#ifdef USE_GNUTLS
|
#ifdef USE_GNUTLS
|
||||||
ctx->earlydata_max =
|
ctx->earlydata_max =
|
||||||
gnutls_record_get_max_early_data_size(ctx->tls.gtls.session);
|
gnutls_record_get_max_early_data_size(ctx->tls.gtls.session);
|
||||||
|
#endif
|
||||||
|
#ifdef USE_WOLFSSL
|
||||||
|
#ifdef WOLFSSL_EARLY_DATA
|
||||||
|
ctx->earlydata_max = scs->earlydata_max;
|
||||||
|
#else
|
||||||
|
ctx->earlydata_max = 0;
|
||||||
|
#endif /* WOLFSSL_EARLY_DATA */
|
||||||
|
#endif
|
||||||
|
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL)
|
||||||
if((!ctx->earlydata_max)) {
|
if((!ctx->earlydata_max)) {
|
||||||
CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
|
CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
|
||||||
}
|
}
|
||||||
else if(strcmp("h3", scs->alpn)) {
|
else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
|
||||||
CURL_TRC_CF(data, cf, "SSL session from different ALPN, no early data");
|
CURL_TRC_CF(data, cf, "SSL session from different ALPN, no early data");
|
||||||
}
|
}
|
||||||
else if(!scs->quic_tp || !scs->quic_tp_len) {
|
else if(!scs->quic_tp || !scs->quic_tp_len) {
|
||||||
@ -2363,6 +2398,7 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
|
|||||||
(void)data;
|
(void)data;
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
(void)scs;
|
(void)scs;
|
||||||
|
(void)alpns;
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -2380,6 +2416,9 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
|||||||
CURLcode result;
|
CURLcode result;
|
||||||
const struct Curl_sockaddr_ex *sockaddr = NULL;
|
const struct Curl_sockaddr_ex *sockaddr = NULL;
|
||||||
int qfd;
|
int qfd;
|
||||||
|
static const struct alpn_spec ALPN_SPEC_H3 = {
|
||||||
|
{ "h3", "h3-29" }, 2
|
||||||
|
};
|
||||||
|
|
||||||
DEBUGASSERT(ctx->initialized);
|
DEBUGASSERT(ctx->initialized);
|
||||||
ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
|
ctx->dcid.datalen = NGTCP2_MAX_CIDLEN;
|
||||||
@ -2423,9 +2462,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
|||||||
if(rc)
|
if(rc)
|
||||||
return CURLE_QUIC_CONNECT_ERROR;
|
return CURLE_QUIC_CONNECT_ERROR;
|
||||||
|
|
||||||
#define H3_ALPN "\x2h3\x5h3-29"
|
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer, &ALPN_SPEC_H3,
|
||||||
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
|
|
||||||
H3_ALPN, sizeof(H3_ALPN) - 1,
|
|
||||||
cf_ngtcp2_tls_ctx_setup, &ctx->tls,
|
cf_ngtcp2_tls_ctx_setup, &ctx->tls,
|
||||||
&ctx->conn_ref,
|
&ctx->conn_ref,
|
||||||
cf_ngtcp2_on_session_reuse);
|
cf_ngtcp2_on_session_reuse);
|
||||||
@ -2438,7 +2475,7 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
|
|||||||
#elif defined(USE_GNUTLS)
|
#elif defined(USE_GNUTLS)
|
||||||
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
|
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.gtls.session);
|
||||||
#elif defined(USE_WOLFSSL)
|
#elif defined(USE_WOLFSSL)
|
||||||
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.handle);
|
ngtcp2_conn_set_tls_native_handle(ctx->qconn, ctx->tls.wssl.ssl);
|
||||||
#else
|
#else
|
||||||
#error "ngtcp2 TLS backend not defined"
|
#error "ngtcp2 TLS backend not defined"
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -1163,13 +1163,15 @@ static CURLcode cf_osslq_ctx_start(struct Curl_cfilter *cf,
|
|||||||
const struct Curl_sockaddr_ex *peer_addr = NULL;
|
const struct Curl_sockaddr_ex *peer_addr = NULL;
|
||||||
BIO *bio = NULL;
|
BIO *bio = NULL;
|
||||||
BIO_ADDR *baddr = NULL;
|
BIO_ADDR *baddr = NULL;
|
||||||
|
static const struct alpn_spec ALPN_SPEC_H3 = {
|
||||||
|
{ "h3" }, 1
|
||||||
|
};
|
||||||
|
|
||||||
DEBUGASSERT(ctx->initialized);
|
DEBUGASSERT(ctx->initialized);
|
||||||
|
|
||||||
#define H3_ALPN "\x2h3"
|
#define H3_ALPN "\x2h3"
|
||||||
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
|
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
|
||||||
H3_ALPN, sizeof(H3_ALPN) - 1,
|
&ALPN_SPEC_H3, NULL, NULL, NULL, NULL);
|
||||||
NULL, NULL, NULL, NULL);
|
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|||||||
@ -1267,6 +1267,9 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
|
|||||||
int rv;
|
int rv;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
const struct Curl_sockaddr_ex *sockaddr;
|
const struct Curl_sockaddr_ex *sockaddr;
|
||||||
|
static const struct alpn_spec ALPN_SPEC_H3 = {
|
||||||
|
{ "h3" }, 1
|
||||||
|
};
|
||||||
|
|
||||||
DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD);
|
DEBUGASSERT(ctx->q.sockfd != CURL_SOCKET_BAD);
|
||||||
DEBUGASSERT(ctx->initialized);
|
DEBUGASSERT(ctx->initialized);
|
||||||
@ -1304,9 +1307,7 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf,
|
|||||||
- 1);
|
- 1);
|
||||||
|
|
||||||
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
|
result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->peer,
|
||||||
QUICHE_H3_APPLICATION_PROTOCOL,
|
&ALPN_SPEC_H3, NULL, NULL, cf, NULL);
|
||||||
sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - 1,
|
|
||||||
NULL, NULL, cf, NULL);
|
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
|||||||
@ -58,178 +58,11 @@
|
|||||||
#include "curl_memory.h"
|
#include "curl_memory.h"
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
#if defined(USE_WOLFSSL)
|
|
||||||
|
|
||||||
#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"
|
|
||||||
|
|
||||||
#if defined(HAVE_SECRET_CALLBACK)
|
|
||||||
static void keylog_callback(const WOLFSSL *ssl, const char *line)
|
|
||||||
{
|
|
||||||
(void)ssl;
|
|
||||||
Curl_tls_keylog_write_line(line);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static CURLcode wssl_init_ctx(struct curl_tls_ctx *ctx,
|
|
||||||
struct Curl_cfilter *cf,
|
|
||||||
struct Curl_easy *data,
|
|
||||||
Curl_vquic_tls_ctx_setup *cb_setup,
|
|
||||||
void *cb_user_data)
|
|
||||||
{
|
|
||||||
struct ssl_primary_config *conn_config;
|
|
||||||
CURLcode result = CURLE_FAILED_INIT;
|
|
||||||
|
|
||||||
conn_config = Curl_ssl_cf_get_primary_config(cf);
|
|
||||||
if(!conn_config) {
|
|
||||||
result = CURLE_FAILED_INIT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx->wssl.ctx = wolfSSL_CTX_new(wolfTLSv1_3_client_method());
|
|
||||||
if(!ctx->wssl.ctx) {
|
|
||||||
result = CURLE_OUT_OF_MEMORY;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cb_setup) {
|
|
||||||
result = cb_setup(cf, data, cb_user_data);
|
|
||||||
if(result)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);
|
|
||||||
|
|
||||||
if(wolfSSL_CTX_set_cipher_list(ctx->wssl.ctx, conn_config->cipher_list13 ?
|
|
||||||
conn_config->cipher_list13 :
|
|
||||||
QUIC_CIPHERS) != 1) {
|
|
||||||
char error_buffer[256];
|
|
||||||
ERR_error_string_n(ERR_get_error(), error_buffer, sizeof(error_buffer));
|
|
||||||
failf(data, "wolfSSL failed to set ciphers: %s", error_buffer);
|
|
||||||
result = CURLE_BAD_FUNCTION_ARGUMENT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(wolfSSL_CTX_set1_groups_list(ctx->wssl.ctx, conn_config->curves ?
|
|
||||||
conn_config->curves :
|
|
||||||
(char *)QUIC_GROUPS) != 1) {
|
|
||||||
failf(data, "wolfSSL failed to set curves");
|
|
||||||
result = CURLE_BAD_FUNCTION_ARGUMENT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open the file if a TLS or QUIC backend has not done this before. */
|
|
||||||
Curl_tls_keylog_open();
|
|
||||||
if(Curl_tls_keylog_enabled()) {
|
|
||||||
#if defined(HAVE_SECRET_CALLBACK)
|
|
||||||
wolfSSL_CTX_set_keylog_callback(ctx->wssl.ctx, keylog_callback);
|
|
||||||
#else
|
|
||||||
failf(data, "wolfSSL was built without keylog callback");
|
|
||||||
result = CURLE_NOT_BUILT_IN;
|
|
||||||
goto out;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if(conn_config->verifypeer) {
|
|
||||||
const char * const ssl_cafile = conn_config->CAfile;
|
|
||||||
const char * const ssl_capath = conn_config->CApath;
|
|
||||||
|
|
||||||
wolfSSL_CTX_set_verify(ctx->wssl.ctx, SSL_VERIFY_PEER, NULL);
|
|
||||||
if(ssl_cafile || ssl_capath) {
|
|
||||||
/* tell wolfSSL where to find CA certificates that are used to verify
|
|
||||||
the server's certificate. */
|
|
||||||
int rc =
|
|
||||||
wolfSSL_CTX_load_verify_locations_ex(ctx->wssl.ctx, ssl_cafile,
|
|
||||||
ssl_capath,
|
|
||||||
WOLFSSL_LOAD_FLAG_IGNORE_ERR);
|
|
||||||
if(SSL_SUCCESS != rc) {
|
|
||||||
/* Fail if we insist on successfully verifying the server. */
|
|
||||||
failf(data, "error setting certificate verify locations:"
|
|
||||||
" CAfile: %s CApath: %s",
|
|
||||||
ssl_cafile ? ssl_cafile : "none",
|
|
||||||
ssl_capath ? ssl_capath : "none");
|
|
||||||
result = CURLE_SSL_CACERT_BADFILE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
infof(data, " CAfile: %s", ssl_cafile ? ssl_cafile : "none");
|
|
||||||
infof(data, " CApath: %s", ssl_capath ? ssl_capath : "none");
|
|
||||||
}
|
|
||||||
#ifdef CURL_CA_FALLBACK
|
|
||||||
else {
|
|
||||||
/* verifying the peer without any CA certificates will not work so
|
|
||||||
use wolfSSL's built-in default as fallback */
|
|
||||||
wolfSSL_CTX_set_default_verify_paths(ctx->wssl.ctx);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
wolfSSL_CTX_set_verify(ctx->wssl.ctx, SSL_VERIFY_NONE, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* give application a chance to interfere with SSL set up. */
|
|
||||||
if(data->set.ssl.fsslctx) {
|
|
||||||
Curl_set_in_callback(data, TRUE);
|
|
||||||
result = (*data->set.ssl.fsslctx)(data, ctx->wssl.ctx,
|
|
||||||
data->set.ssl.fsslctxp);
|
|
||||||
Curl_set_in_callback(data, FALSE);
|
|
||||||
if(result) {
|
|
||||||
failf(data, "error signaled by ssl ctx callback");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = CURLE_OK;
|
|
||||||
|
|
||||||
out:
|
|
||||||
if(result && ctx->wssl.ctx) {
|
|
||||||
SSL_CTX_free(ctx->wssl.ctx);
|
|
||||||
ctx->wssl.ctx = NULL;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** SSL callbacks ***/
|
|
||||||
|
|
||||||
static CURLcode wssl_init_ssl(struct curl_tls_ctx *ctx,
|
|
||||||
struct Curl_cfilter *cf,
|
|
||||||
struct Curl_easy *data,
|
|
||||||
struct ssl_peer *peer,
|
|
||||||
const char *alpn, size_t alpn_len,
|
|
||||||
void *user_data)
|
|
||||||
{
|
|
||||||
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
|
||||||
|
|
||||||
DEBUGASSERT(!ctx->wssl.handle);
|
|
||||||
DEBUGASSERT(ctx->wssl.ctx);
|
|
||||||
ctx->wssl.handle = wolfSSL_new(ctx->wssl.ctx);
|
|
||||||
|
|
||||||
wolfSSL_set_app_data(ctx->wssl.handle, user_data);
|
|
||||||
wolfSSL_set_connect_state(ctx->wssl.handle);
|
|
||||||
wolfSSL_set_quic_use_legacy_codepoint(ctx->wssl.handle, 0);
|
|
||||||
|
|
||||||
if(alpn)
|
|
||||||
wolfSSL_set_alpn_protos(ctx->wssl.handle, (const unsigned char *)alpn,
|
|
||||||
(unsigned int)alpn_len);
|
|
||||||
|
|
||||||
if(peer->sni) {
|
|
||||||
wolfSSL_UseSNI(ctx->wssl.handle, WOLFSSL_SNI_HOST_NAME,
|
|
||||||
peer->sni, (unsigned short)strlen(peer->sni));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ssl_config->primary.cache_session) {
|
|
||||||
(void)Curl_wssl_setup_session(cf, data, &ctx->wssl, peer->scache_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return CURLE_OK;
|
|
||||||
}
|
|
||||||
#endif /* defined(USE_WOLFSSL) */
|
|
||||||
|
|
||||||
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
||||||
struct Curl_cfilter *cf,
|
struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct ssl_peer *peer,
|
struct ssl_peer *peer,
|
||||||
const char *alpn, size_t alpn_len,
|
const struct alpn_spec *alpns,
|
||||||
Curl_vquic_tls_ctx_setup *cb_setup,
|
Curl_vquic_tls_ctx_setup *cb_setup,
|
||||||
void *cb_user_data, void *ssl_user_data,
|
void *cb_user_data, void *ssl_user_data,
|
||||||
Curl_vquic_session_reuse_cb *session_reuse_cb)
|
Curl_vquic_session_reuse_cb *session_reuse_cb)
|
||||||
@ -254,21 +87,16 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
|||||||
|
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
(void)result;
|
(void)result;
|
||||||
return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer,
|
return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, alpns,
|
||||||
(const unsigned char *)alpn, alpn_len,
|
|
||||||
cb_setup, cb_user_data, NULL, ssl_user_data);
|
cb_setup, cb_user_data, NULL, ssl_user_data);
|
||||||
#elif defined(USE_GNUTLS)
|
#elif defined(USE_GNUTLS)
|
||||||
return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer,
|
return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer, alpns,
|
||||||
(const unsigned char *)alpn, alpn_len,
|
|
||||||
cb_setup, cb_user_data, ssl_user_data,
|
cb_setup, cb_user_data, ssl_user_data,
|
||||||
session_reuse_cb);
|
session_reuse_cb);
|
||||||
#elif defined(USE_WOLFSSL)
|
#elif defined(USE_WOLFSSL)
|
||||||
result = wssl_init_ctx(ctx, cf, data, cb_setup, cb_user_data);
|
return Curl_wssl_ctx_init(&ctx->wssl, cf, data, peer, alpns,
|
||||||
if(result)
|
cb_setup, cb_user_data,
|
||||||
return result;
|
ssl_user_data, session_reuse_cb);
|
||||||
|
|
||||||
(void)session_reuse_cb;
|
|
||||||
return wssl_init_ssl(ctx, cf, data, peer, alpn, alpn_len, ssl_user_data);
|
|
||||||
#else
|
#else
|
||||||
#error "no TLS lib in used, should not happen"
|
#error "no TLS lib in used, should not happen"
|
||||||
return CURLE_FAILED_INIT;
|
return CURLE_FAILED_INIT;
|
||||||
@ -287,10 +115,10 @@ void Curl_vquic_tls_cleanup(struct curl_tls_ctx *ctx)
|
|||||||
gnutls_deinit(ctx->gtls.session);
|
gnutls_deinit(ctx->gtls.session);
|
||||||
Curl_gtls_shared_creds_free(&ctx->gtls.shared_creds);
|
Curl_gtls_shared_creds_free(&ctx->gtls.shared_creds);
|
||||||
#elif defined(USE_WOLFSSL)
|
#elif defined(USE_WOLFSSL)
|
||||||
if(ctx->wssl.handle)
|
if(ctx->wssl.ssl)
|
||||||
wolfSSL_free(ctx->wssl.handle);
|
wolfSSL_free(ctx->wssl.ssl);
|
||||||
if(ctx->wssl.ctx)
|
if(ctx->wssl.ssl_ctx)
|
||||||
wolfSSL_CTX_free(ctx->wssl.ctx);
|
wolfSSL_CTX_free(ctx->wssl.ssl_ctx);
|
||||||
#endif
|
#endif
|
||||||
memset(ctx, 0, sizeof(*ctx));
|
memset(ctx, 0, sizeof(*ctx));
|
||||||
}
|
}
|
||||||
@ -351,7 +179,7 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx,
|
|||||||
(void)data;
|
(void)data;
|
||||||
if(conn_config->verifyhost) {
|
if(conn_config->verifyhost) {
|
||||||
if(peer->sni) {
|
if(peer->sni) {
|
||||||
WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.handle);
|
WOLFSSL_X509* cert = wolfSSL_get_peer_certificate(ctx->wssl.ssl);
|
||||||
if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
|
if(wolfSSL_X509_check_host(cert, peer->sni, strlen(peer->sni), 0, NULL)
|
||||||
== WOLFSSL_FAILURE) {
|
== WOLFSSL_FAILURE) {
|
||||||
result = CURLE_PEER_FAILED_VERIFICATION;
|
result = CURLE_PEER_FAILED_VERIFICATION;
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
#include "curl_setup.h"
|
#include "curl_setup.h"
|
||||||
#include "bufq.h"
|
#include "bufq.h"
|
||||||
#include "vtls/vtls.h"
|
#include "vtls/vtls.h"
|
||||||
|
#include "vtls/vtls_int.h"
|
||||||
#include "vtls/openssl.h"
|
#include "vtls/openssl.h"
|
||||||
|
|
||||||
#if defined(USE_HTTP3) && \
|
#if defined(USE_HTTP3) && \
|
||||||
@ -43,7 +44,7 @@ struct curl_tls_ctx {
|
|||||||
#elif defined(USE_GNUTLS)
|
#elif defined(USE_GNUTLS)
|
||||||
struct gtls_ctx gtls;
|
struct gtls_ctx gtls;
|
||||||
#elif defined(USE_WOLFSSL)
|
#elif defined(USE_WOLFSSL)
|
||||||
struct wolfssl_ctx wssl;
|
struct wssl_ctx wssl;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ typedef CURLcode Curl_vquic_tls_ctx_setup(struct Curl_cfilter *cf,
|
|||||||
|
|
||||||
typedef CURLcode Curl_vquic_session_reuse_cb(struct Curl_cfilter *cf,
|
typedef CURLcode Curl_vquic_session_reuse_cb(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
|
struct alpn_spec *alpns,
|
||||||
struct Curl_ssl_session *scs,
|
struct Curl_ssl_session *scs,
|
||||||
bool *do_early_data);
|
bool *do_early_data);
|
||||||
|
|
||||||
@ -70,9 +72,7 @@ typedef CURLcode Curl_vquic_session_reuse_cb(struct Curl_cfilter *cf,
|
|||||||
* @param cf the connection filter involved
|
* @param cf the connection filter involved
|
||||||
* @param data the transfer involved
|
* @param data the transfer involved
|
||||||
* @param peer the peer that will be connected to
|
* @param peer the peer that will be connected to
|
||||||
* @param alpn the ALPN string in protocol format ((len+bytes+)+),
|
* @param alpns the ALPN specifications to negotiate, may be NULL
|
||||||
* may be NULL
|
|
||||||
* @param alpn_len the overall number of bytes in `alpn`
|
|
||||||
* @param cb_setup optional callback for early TLS config
|
* @param cb_setup optional callback for early TLS config
|
||||||
* @param cb_user_data user_data param for callback
|
* @param cb_user_data user_data param for callback
|
||||||
* @param ssl_user_data optional pointer to set in TLS application context
|
* @param ssl_user_data optional pointer to set in TLS application context
|
||||||
@ -82,7 +82,7 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
|
|||||||
struct Curl_cfilter *cf,
|
struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct ssl_peer *peer,
|
struct ssl_peer *peer,
|
||||||
const char *alpn, size_t alpn_len,
|
const struct alpn_spec *alpns,
|
||||||
Curl_vquic_tls_ctx_setup *cb_setup,
|
Curl_vquic_tls_ctx_setup *cb_setup,
|
||||||
void *cb_user_data,
|
void *cb_user_data,
|
||||||
void *ssl_user_data,
|
void *ssl_user_data,
|
||||||
|
|||||||
@ -1042,6 +1042,7 @@ static int keylog_callback(gnutls_session_t session, const char *label,
|
|||||||
|
|
||||||
static CURLcode gtls_on_session_reuse(struct Curl_cfilter *cf,
|
static CURLcode gtls_on_session_reuse(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
|
struct alpn_spec *alpns,
|
||||||
struct Curl_ssl_session *scs,
|
struct Curl_ssl_session *scs,
|
||||||
bool *do_early_data)
|
bool *do_early_data)
|
||||||
{
|
{
|
||||||
@ -1057,7 +1058,7 @@ static CURLcode gtls_on_session_reuse(struct Curl_cfilter *cf,
|
|||||||
/* Seems to be GnuTLS way to signal no EarlyData in session */
|
/* Seems to be GnuTLS way to signal no EarlyData in session */
|
||||||
CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
|
CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
|
||||||
}
|
}
|
||||||
else if(!Curl_alpn_contains_proto(connssl->alpn, scs->alpn)) {
|
else if(!Curl_alpn_contains_proto(alpns, scs->alpn)) {
|
||||||
CURL_TRC_CF(data, cf, "SSL session has different ALPN, no early data");
|
CURL_TRC_CF(data, cf, "SSL session has different ALPN, no early data");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -1077,7 +1078,7 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
|
|||||||
struct Curl_cfilter *cf,
|
struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct ssl_peer *peer,
|
struct ssl_peer *peer,
|
||||||
const unsigned char *alpn, size_t alpn_len,
|
const struct alpn_spec *alpns_requested,
|
||||||
Curl_gtls_ctx_setup_cb *cb_setup,
|
Curl_gtls_ctx_setup_cb *cb_setup,
|
||||||
void *cb_user_data,
|
void *cb_user_data,
|
||||||
void *ssl_user_data,
|
void *ssl_user_data,
|
||||||
@ -1086,13 +1087,16 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
|
|||||||
struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf);
|
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);
|
struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data);
|
||||||
struct Curl_ssl_session *scs = NULL;
|
struct Curl_ssl_session *scs = NULL;
|
||||||
gnutls_datum_t gtls_alpns[5];
|
gnutls_datum_t gtls_alpns[ALPN_ENTRIES_MAX];
|
||||||
size_t gtls_alpns_count = 0;
|
size_t gtls_alpns_count = 0;
|
||||||
bool gtls_session_setup = FALSE;
|
bool gtls_session_setup = FALSE;
|
||||||
|
struct alpn_spec alpns;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DEBUGASSERT(gctx);
|
DEBUGASSERT(gctx);
|
||||||
|
Curl_alpn_copy(&alpns, alpns_requested);
|
||||||
|
|
||||||
/* This might be a reconnect, so we check for a session ID in the cache
|
/* This might be a reconnect, so we check for a session ID in the cache
|
||||||
to speed up things. We need to do this before constructing the gnutls
|
to speed up things. We need to do this before constructing the gnutls
|
||||||
session since we need to set flags depending on the kind of reuse. */
|
session since we need to set flags depending on the kind of reuse. */
|
||||||
@ -1101,7 +1105,8 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
|
|||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if(scs && scs->sdata && scs->sdata_len) {
|
if(scs && scs->sdata && scs->sdata_len &&
|
||||||
|
(!scs->alpn || Curl_alpn_contains_proto(&alpns, scs->alpn))) {
|
||||||
/* we got a cached session, use it! */
|
/* we got a cached session, use it! */
|
||||||
|
|
||||||
result = gtls_client_init(cf, data, peer, scs->earlydata_max, gctx);
|
result = gtls_client_init(cf, data, peer, scs->earlydata_max, gctx);
|
||||||
@ -1115,30 +1120,19 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
|
|||||||
else {
|
else {
|
||||||
infof(data, "SSL reusing session with ALPN '%s'",
|
infof(data, "SSL reusing session with ALPN '%s'",
|
||||||
scs->alpn ? scs->alpn : "-");
|
scs->alpn ? scs->alpn : "-");
|
||||||
if(ssl_config->earlydata &&
|
if(ssl_config->earlydata && scs->alpn &&
|
||||||
!cf->conn->connect_only &&
|
!cf->conn->connect_only &&
|
||||||
(gnutls_protocol_get_version(gctx->session) == GNUTLS_TLS1_3)) {
|
(gnutls_protocol_get_version(gctx->session) == GNUTLS_TLS1_3)) {
|
||||||
bool do_early_data = FALSE;
|
bool do_early_data = FALSE;
|
||||||
if(sess_reuse_cb) {
|
if(sess_reuse_cb) {
|
||||||
result = sess_reuse_cb(cf, data, scs, &do_early_data);
|
result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data);
|
||||||
if(result)
|
if(result)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
if(do_early_data) {
|
if(do_early_data) {
|
||||||
/* We only try the ALPN protocol the session used before,
|
/* We only try the ALPN protocol the session used before,
|
||||||
* otherwise we might send early data for the wrong protocol */
|
* otherwise we might send early data for the wrong protocol */
|
||||||
gtls_alpns[0].data = (unsigned char *)scs->alpn;
|
Curl_alpn_restrict_to(&alpns, scs->alpn);
|
||||||
gtls_alpns[0].size = (unsigned)strlen(scs->alpn);
|
|
||||||
if(gnutls_alpn_set_protocols(gctx->session,
|
|
||||||
gtls_alpns, 1,
|
|
||||||
GNUTLS_ALPN_MANDATORY)) {
|
|
||||||
failf(data, "failed setting ALPN");
|
|
||||||
result = CURLE_SSL_CONNECT_ERROR;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
/* don't set again below */
|
|
||||||
gtls_alpns_count = 0;
|
|
||||||
alpn = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1168,24 +1162,14 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
|
|||||||
/* convert the ALPN string from our arguments to a list of strings that
|
/* convert the ALPN string from our arguments to a list of strings that
|
||||||
* gnutls wants and will convert internally back to this string for sending
|
* gnutls wants and will convert internally back to this string for sending
|
||||||
* to the server. nice. */
|
* to the server. nice. */
|
||||||
if(!gtls_alpns_count && alpn && alpn_len) {
|
if(!gtls_alpns_count && alpns.count) {
|
||||||
size_t i, alen = alpn_len;
|
size_t i;
|
||||||
unsigned char *salpn = (unsigned char *)alpn;
|
DEBUGASSERT(CURL_ARRAYSIZE(gtls_alpns) >= alpns.count);
|
||||||
unsigned char slen;
|
for(i = 0; i < alpns.count; ++i) {
|
||||||
for(i = 0; (i < CURL_ARRAYSIZE(gtls_alpns)) && alen; ++i) {
|
gtls_alpns[i].data = (unsigned char *)alpns.entries[i];
|
||||||
slen = salpn[0];
|
gtls_alpns[i].size = (unsigned int)strlen(alpns.entries[i]);
|
||||||
if(slen >= alen)
|
|
||||||
return CURLE_FAILED_INIT;
|
|
||||||
gtls_alpns[i].data = salpn + 1;
|
|
||||||
gtls_alpns[i].size = slen;
|
|
||||||
salpn += slen + 1;
|
|
||||||
alen -= (size_t)slen + 1;
|
|
||||||
}
|
}
|
||||||
if(alen) { /* not all alpn chars used, wrong format or too many */
|
gtls_alpns_count = alpns.count;
|
||||||
result = CURLE_FAILED_INIT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
gtls_alpns_count = i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(gtls_alpns_count &&
|
if(gtls_alpns_count &&
|
||||||
@ -1207,7 +1191,6 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||||||
struct ssl_connect_data *connssl = cf->ctx;
|
struct ssl_connect_data *connssl = cf->ctx;
|
||||||
struct gtls_ssl_backend_data *backend =
|
struct gtls_ssl_backend_data *backend =
|
||||||
(struct gtls_ssl_backend_data *)connssl->backend;
|
(struct gtls_ssl_backend_data *)connssl->backend;
|
||||||
struct alpn_proto_buf proto;
|
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
DEBUGASSERT(backend);
|
DEBUGASSERT(backend);
|
||||||
@ -1217,22 +1200,15 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
|
|||||||
same connection */
|
same connection */
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
|
|
||||||
memset(&proto, 0, sizeof(proto));
|
|
||||||
if(connssl->alpn) {
|
|
||||||
result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
|
|
||||||
if(result) {
|
|
||||||
failf(data, "Error determining ALPN");
|
|
||||||
return CURLE_SSL_CONNECT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
|
result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer,
|
||||||
proto.data, proto.len,
|
connssl->alpn, NULL, NULL, cf,
|
||||||
NULL, NULL, cf, gtls_on_session_reuse);
|
gtls_on_session_reuse);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if(connssl->alpn && (connssl->state != ssl_connection_deferred)) {
|
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);
|
Curl_alpn_to_proto_str(&proto, connssl->alpn);
|
||||||
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
|
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
struct Curl_easy;
|
struct Curl_easy;
|
||||||
struct Curl_cfilter;
|
struct Curl_cfilter;
|
||||||
|
struct alpn_spec;
|
||||||
struct ssl_primary_config;
|
struct ssl_primary_config;
|
||||||
struct ssl_config_data;
|
struct ssl_config_data;
|
||||||
struct ssl_peer;
|
struct ssl_peer;
|
||||||
@ -81,6 +82,7 @@ typedef CURLcode Curl_gtls_ctx_setup_cb(struct Curl_cfilter *cf,
|
|||||||
|
|
||||||
typedef CURLcode Curl_gtls_init_session_reuse_cb(struct Curl_cfilter *cf,
|
typedef CURLcode Curl_gtls_init_session_reuse_cb(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
|
struct alpn_spec *alpns,
|
||||||
struct Curl_ssl_session *scs,
|
struct Curl_ssl_session *scs,
|
||||||
bool *do_early_data);
|
bool *do_early_data);
|
||||||
|
|
||||||
@ -88,7 +90,7 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx,
|
|||||||
struct Curl_cfilter *cf,
|
struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct ssl_peer *peer,
|
struct ssl_peer *peer,
|
||||||
const unsigned char *alpn, size_t alpn_len,
|
const struct alpn_spec *alpns,
|
||||||
Curl_gtls_ctx_setup_cb *cb_setup,
|
Curl_gtls_ctx_setup_cb *cb_setup,
|
||||||
void *cb_user_data,
|
void *cb_user_data,
|
||||||
void *ssl_user_data,
|
void *ssl_user_data,
|
||||||
|
|||||||
@ -3527,7 +3527,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
|
|||||||
struct Curl_cfilter *cf,
|
struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct ssl_peer *peer,
|
struct ssl_peer *peer,
|
||||||
const unsigned char *alpn, size_t alpn_len,
|
const struct alpn_spec *alpns,
|
||||||
Curl_ossl_ctx_setup_cb *cb_setup,
|
Curl_ossl_ctx_setup_cb *cb_setup,
|
||||||
void *cb_user_data,
|
void *cb_user_data,
|
||||||
Curl_ossl_new_session_cb *cb_new_session,
|
Curl_ossl_new_session_cb *cb_new_session,
|
||||||
@ -3722,14 +3722,21 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
|
|||||||
SSL_CTX_set_mode(octx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
SSL_CTX_set_mode(octx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(alpn && alpn_len) {
|
|
||||||
#ifdef HAS_ALPN_OPENSSL
|
#ifdef HAS_ALPN_OPENSSL
|
||||||
if(SSL_CTX_set_alpn_protos(octx->ssl_ctx, alpn, (int)alpn_len)) {
|
if(alpns && alpns->count) {
|
||||||
|
struct alpn_proto_buf proto;
|
||||||
|
memset(&proto, 0, sizeof(proto));
|
||||||
|
result = Curl_alpn_to_proto_buf(&proto, alpns);
|
||||||
|
if(result) {
|
||||||
|
failf(data, "Error determining ALPN");
|
||||||
|
return CURLE_SSL_CONNECT_ERROR;
|
||||||
|
}
|
||||||
|
if(SSL_CTX_set_alpn_protos(octx->ssl_ctx, proto.data, (int)proto.len)) {
|
||||||
failf(data, "Error setting ALPN");
|
failf(data, "Error setting ALPN");
|
||||||
return CURLE_SSL_CONNECT_ERROR;
|
return CURLE_SSL_CONNECT_ERROR;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
|
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
|
||||||
if(!result &&
|
if(!result &&
|
||||||
@ -4053,25 +4060,14 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
|
|||||||
{
|
{
|
||||||
struct ssl_connect_data *connssl = cf->ctx;
|
struct ssl_connect_data *connssl = cf->ctx;
|
||||||
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
|
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
|
||||||
struct alpn_proto_buf proto;
|
|
||||||
BIO *bio;
|
BIO *bio;
|
||||||
CURLcode result;
|
CURLcode result;
|
||||||
|
|
||||||
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
|
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
|
||||||
DEBUGASSERT(octx);
|
DEBUGASSERT(octx);
|
||||||
memset(&proto, 0, sizeof(proto));
|
|
||||||
#ifdef HAS_ALPN_OPENSSL
|
|
||||||
if(connssl->alpn) {
|
|
||||||
result = Curl_alpn_to_proto_buf(&proto, connssl->alpn);
|
|
||||||
if(result) {
|
|
||||||
failf(data, "Error determining ALPN");
|
|
||||||
return CURLE_SSL_CONNECT_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer,
|
result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer,
|
||||||
proto.data, proto.len, NULL, NULL,
|
connssl->alpn, NULL, NULL,
|
||||||
ossl_new_session_cb, cf);
|
ossl_new_session_cb, cf);
|
||||||
if(result)
|
if(result)
|
||||||
return result;
|
return result;
|
||||||
@ -4099,6 +4095,8 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
|
|||||||
|
|
||||||
#ifdef HAS_ALPN_OPENSSL
|
#ifdef HAS_ALPN_OPENSSL
|
||||||
if(connssl->alpn) {
|
if(connssl->alpn) {
|
||||||
|
struct alpn_proto_buf proto;
|
||||||
|
memset(&proto, 0, sizeof(proto));
|
||||||
Curl_alpn_to_proto_str(&proto, connssl->alpn);
|
Curl_alpn_to_proto_str(&proto, connssl->alpn);
|
||||||
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
|
infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,6 +49,7 @@
|
|||||||
#define HAVE_KEYLOG_CALLBACK
|
#define HAVE_KEYLOG_CALLBACK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct alpn_spec;
|
||||||
struct ssl_peer;
|
struct ssl_peer;
|
||||||
|
|
||||||
/* Struct to hold a curl OpenSSL instance */
|
/* Struct to hold a curl OpenSSL instance */
|
||||||
@ -80,7 +81,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
|
|||||||
struct Curl_cfilter *cf,
|
struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct ssl_peer *peer,
|
struct ssl_peer *peer,
|
||||||
const unsigned char *alpn, size_t alpn_len,
|
const struct alpn_spec *alpns,
|
||||||
Curl_ossl_ctx_setup_cb *cb_setup,
|
Curl_ossl_ctx_setup_cb *cb_setup,
|
||||||
void *cb_user_data,
|
void *cb_user_data,
|
||||||
Curl_ossl_new_session_cb *cb_new_session,
|
Curl_ossl_new_session_cb *cb_new_session,
|
||||||
|
|||||||
@ -1831,6 +1831,24 @@ bool Curl_alpn_contains_proto(const struct alpn_spec *spec,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Curl_alpn_restrict_to(struct alpn_spec *spec, const char *proto)
|
||||||
|
{
|
||||||
|
size_t plen = strlen(proto);
|
||||||
|
DEBUGASSERT(plen < sizeof(spec->entries[0]));
|
||||||
|
if(plen < sizeof(spec->entries[0])) {
|
||||||
|
memcpy(spec->entries[0], proto, plen + 1);
|
||||||
|
spec->count = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curl_alpn_copy(struct alpn_spec *dest, const struct alpn_spec *src)
|
||||||
|
{
|
||||||
|
if(src)
|
||||||
|
memcpy(dest, src, sizeof(*dest));
|
||||||
|
else
|
||||||
|
memset(dest, 0, sizeof(*dest));
|
||||||
|
}
|
||||||
|
|
||||||
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
|
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct ssl_connect_data *connssl,
|
struct ssl_connect_data *connssl,
|
||||||
|
|||||||
@ -49,7 +49,7 @@ struct ssl_connect_data;
|
|||||||
#define ALPN_PROTO_BUF_MAX (ALPN_ENTRIES_MAX * (ALPN_NAME_MAX + 1))
|
#define ALPN_PROTO_BUF_MAX (ALPN_ENTRIES_MAX * (ALPN_NAME_MAX + 1))
|
||||||
|
|
||||||
struct alpn_spec {
|
struct alpn_spec {
|
||||||
const char entries[ALPN_ENTRIES_MAX][ALPN_NAME_MAX];
|
char entries[ALPN_ENTRIES_MAX][ALPN_NAME_MAX];
|
||||||
size_t count; /* number of entries */
|
size_t count; /* number of entries */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -62,6 +62,8 @@ CURLcode Curl_alpn_to_proto_buf(struct alpn_proto_buf *buf,
|
|||||||
const struct alpn_spec *spec);
|
const struct alpn_spec *spec);
|
||||||
CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
|
CURLcode Curl_alpn_to_proto_str(struct alpn_proto_buf *buf,
|
||||||
const struct alpn_spec *spec);
|
const struct alpn_spec *spec);
|
||||||
|
void Curl_alpn_restrict_to(struct alpn_spec *spec, const char *proto);
|
||||||
|
void Curl_alpn_copy(struct alpn_spec *dest, const struct alpn_spec *src);
|
||||||
|
|
||||||
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
|
CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
|
|||||||
1457
lib/vtls/wolfssl.c
1457
lib/vtls/wolfssl.c
File diff suppressed because it is too large
Load Diff
@ -29,19 +29,21 @@
|
|||||||
|
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
|
|
||||||
|
struct alpn_spec;
|
||||||
|
struct ssl_peer;
|
||||||
|
struct Curl_ssl_session;
|
||||||
|
|
||||||
struct WOLFSSL;
|
struct WOLFSSL;
|
||||||
typedef struct WOLFSSL WOLFSSL;
|
|
||||||
struct WOLFSSL_CTX;
|
struct WOLFSSL_CTX;
|
||||||
typedef struct WOLFSSL_CTX WOLFSSL_CTX;
|
|
||||||
struct WOLFSSL_SESSION;
|
struct WOLFSSL_SESSION;
|
||||||
typedef struct WOLFSSL_SESSION WOLFSSL_SESSION;
|
|
||||||
|
|
||||||
extern const struct Curl_ssl Curl_ssl_wolfssl;
|
extern const struct Curl_ssl Curl_ssl_wolfssl;
|
||||||
|
|
||||||
struct wolfssl_ctx {
|
struct wssl_ctx {
|
||||||
WOLFSSL_CTX *ctx;
|
struct WOLFSSL_CTX *ssl_ctx;
|
||||||
WOLFSSL *handle;
|
struct WOLFSSL *ssl;
|
||||||
CURLcode io_result; /* result of last BIO cfilter operation */
|
CURLcode io_result; /* result of last BIO cfilter operation */
|
||||||
|
CURLcode hs_result; /* result of handshake */
|
||||||
int io_send_blocked_len; /* length of last BIO write that EAGAINed */
|
int io_send_blocked_len; /* length of last BIO write that EAGAINed */
|
||||||
BIT(x509_store_setup); /* x509 store has been set up */
|
BIT(x509_store_setup); /* x509 store has been set up */
|
||||||
BIT(shutting_down); /* TLS is being shut down */
|
BIT(shutting_down); /* TLS is being shut down */
|
||||||
@ -49,21 +51,43 @@ struct wolfssl_ctx {
|
|||||||
|
|
||||||
size_t Curl_wssl_version(char *buffer, size_t size);
|
size_t Curl_wssl_version(char *buffer, size_t size);
|
||||||
|
|
||||||
|
typedef CURLcode Curl_wssl_ctx_setup_cb(struct Curl_cfilter *cf,
|
||||||
|
struct Curl_easy *data,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
typedef CURLcode Curl_wssl_init_session_reuse_cb(struct Curl_cfilter *cf,
|
||||||
|
struct Curl_easy *data,
|
||||||
|
struct alpn_spec *alpns,
|
||||||
|
struct Curl_ssl_session *scs,
|
||||||
|
bool *do_early_data);
|
||||||
|
|
||||||
|
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,
|
||||||
|
Curl_wssl_ctx_setup_cb *cb_setup,
|
||||||
|
void *cb_user_data,
|
||||||
|
void *ssl_user_data,
|
||||||
|
Curl_wssl_init_session_reuse_cb *sess_reuse_cb);
|
||||||
|
|
||||||
CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
|
CURLcode Curl_wssl_setup_x509_store(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct wolfssl_ctx *wssl);
|
struct wssl_ctx *wssl);
|
||||||
|
|
||||||
CURLcode Curl_wssl_setup_session(struct Curl_cfilter *cf,
|
CURLcode Curl_wssl_setup_session(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
struct wolfssl_ctx *wss,
|
struct wssl_ctx *wss,
|
||||||
const char *ssl_peer_key);
|
const char *ssl_peer_key);
|
||||||
|
|
||||||
CURLcode Curl_wssl_cache_session(struct Curl_cfilter *cf,
|
CURLcode Curl_wssl_cache_session(struct Curl_cfilter *cf,
|
||||||
struct Curl_easy *data,
|
struct Curl_easy *data,
|
||||||
const char *ssl_peer_key,
|
const char *ssl_peer_key,
|
||||||
WOLFSSL_SESSION *session,
|
struct WOLFSSL_SESSION *session,
|
||||||
int ietf_tls_id,
|
int ietf_tls_id,
|
||||||
const char *alpn);
|
const char *alpn,
|
||||||
|
unsigned char *quic_tp,
|
||||||
|
size_t quic_tp_len);
|
||||||
|
|
||||||
|
|
||||||
#endif /* USE_WOLFSSL */
|
#endif /* USE_WOLFSSL */
|
||||||
|
|||||||
@ -577,8 +577,8 @@ class TestDownload:
|
|||||||
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx")
|
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx")
|
||||||
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
||||||
def test_02_32_earlydata(self, env: Env, httpd, nghttpx, proto):
|
def test_02_32_earlydata(self, env: Env, httpd, nghttpx, proto):
|
||||||
if not env.curl_uses_lib('gnutls'):
|
if not env.curl_uses_lib('gnutls') and not env.curl_uses_lib('wolfssl'):
|
||||||
pytest.skip('TLS earlydata only implemented in GnuTLS')
|
pytest.skip('TLS earlydata only implemented in GnuTLS/wolfSSL')
|
||||||
if proto == 'h3' and not env.have_h3():
|
if proto == 'h3' and not env.have_h3():
|
||||||
pytest.skip("h3 not supported")
|
pytest.skip("h3 not supported")
|
||||||
count = 2
|
count = 2
|
||||||
|
|||||||
@ -703,8 +703,8 @@ class TestUpload:
|
|||||||
# of 128K.
|
# of 128K.
|
||||||
])
|
])
|
||||||
def test_07_70_put_earlydata(self, env: Env, httpd, nghttpx, proto, upload_size, exp_early):
|
def test_07_70_put_earlydata(self, env: Env, httpd, nghttpx, proto, upload_size, exp_early):
|
||||||
if not env.curl_uses_lib('gnutls'):
|
if not env.curl_uses_lib('gnutls') and not env.curl_uses_lib('wolfssl'):
|
||||||
pytest.skip('TLS earlydata only implemented in GnuTLS')
|
pytest.skip('TLS earlydata only implemented in GnuTLS/wolfSSL')
|
||||||
if proto == 'h3' and not env.have_h3():
|
if proto == 'h3' and not env.have_h3():
|
||||||
pytest.skip("h3 not supported")
|
pytest.skip("h3 not supported")
|
||||||
count = 2
|
count = 2
|
||||||
|
|||||||
@ -207,8 +207,8 @@ class TestCaddy:
|
|||||||
|
|
||||||
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
|
||||||
def test_08_08_earlydata(self, env: Env, httpd, caddy, proto):
|
def test_08_08_earlydata(self, env: Env, httpd, caddy, proto):
|
||||||
if not env.curl_uses_lib('gnutls'):
|
if not env.curl_uses_lib('gnutls') and not env.curl_uses_lib('wolfssl'):
|
||||||
pytest.skip('TLS earlydata only implemented in GnuTLS')
|
pytest.skip('TLS earlydata only implemented in GnuTLS/wolfSSL')
|
||||||
if proto == 'h3' and not env.have_h3():
|
if proto == 'h3' and not env.have_h3():
|
||||||
pytest.skip("h3 not supported")
|
pytest.skip("h3 not supported")
|
||||||
count = 2
|
count = 2
|
||||||
|
|||||||
@ -57,6 +57,7 @@ class TestShutdown:
|
|||||||
def test_19_01_check_tcp_rst(self, env: Env, httpd, proto):
|
def test_19_01_check_tcp_rst(self, env: Env, httpd, proto):
|
||||||
if env.ci_run:
|
if env.ci_run:
|
||||||
pytest.skip("seems not to work in CI")
|
pytest.skip("seems not to work in CI")
|
||||||
|
# timing critical, disable trace overrides
|
||||||
run_env = os.environ.copy()
|
run_env = os.environ.copy()
|
||||||
if 'CURL_DEBUG' in run_env:
|
if 'CURL_DEBUG' in run_env:
|
||||||
del run_env['CURL_DEBUG']
|
del run_env['CURL_DEBUG']
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user