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:
Stefan Eissing 2025-02-04 15:24:00 +01:00 committed by Daniel Stenberg
parent efec626ebb
commit edd573d980
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
18 changed files with 1117 additions and 804 deletions

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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);
} }

View File

@ -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,

View File

@ -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);
} }

View File

@ -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,

View File

@ -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,

View File

@ -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,

File diff suppressed because it is too large Load Diff

View File

@ -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 */

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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']