This commit is contained in:
Stefan Eissing 2025-03-01 01:40:06 +08:00 committed by GitHub
commit 89c2135c13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 308 additions and 69 deletions

View File

@ -89,11 +89,13 @@ could be a privacy violation and unexpected.
## CURLSSLOPT_EARLYDATA
Tell libcurl to try sending application data as TLS1.3 early data. This option
is supported for GnuTLS and wolfSSL. This option works on a best effort basis,
is supported for GnuTLS, wolfSSL, quictls and OpenSSL (but not BoringSSL
or AWS-LC). It works on TCP and QUIC connections using ngtcp2.
This option works on a best effort basis,
in cases when it wasn't possible to send early data the request is resent
normally post-handshake.
This option does not work when using QUIC.
(Added in 8.11.0 for GnuTLS and 8.13.0 for wolfSSL)
(Added in 8.11.0 for GnuTLS and 8.13.0 for wolfSSL, quictls and OpenSSL)
# DEFAULT

View File

@ -482,6 +482,11 @@ static int cf_ngtcp2_handshake_completed(ngtcp2_conn *tconn, void *user_data)
if(ctx->use_earlydata)
Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
if(ctx->use_earlydata) {
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA)
ctx->earlydata_accepted =
(SSL_get_early_data_status(ctx->tls.ossl.ssl) !=
SSL_EARLY_DATA_REJECTED);
#endif
#ifdef USE_GNUTLS
int flags = gnutls_session_get_flags(ctx->tls.gtls.session);
ctx->earlydata_accepted = !!(flags & GNUTLS_SFLAGS_EARLY_DATA);
@ -2183,8 +2188,24 @@ static int quic_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
ctx = cf ? cf->ctx : NULL;
data = cf ? CF_DATA_CURRENT(cf) : NULL;
if(cf && data && ctx) {
unsigned char *quic_tp = NULL;
size_t quic_tp_len = 0;
#ifdef HAVE_OPENSSL_EARLYDATA
ngtcp2_ssize tplen;
uint8_t tpbuf[256];
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;
}
#endif
Curl_ossl_add_session(cf, data, ctx->peer.scache_key, ssl_sessionid,
SSL_version(ssl), "h3");
SSL_version(ssl), "h3", quic_tp, quic_tp_len);
return 1;
}
return 0;
@ -2355,6 +2376,9 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
CURLcode result = CURLE_OK;
*do_early_data = FALSE;
#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA)
ctx->earlydata_max = scs->earlydata_max;
#endif
#ifdef USE_GNUTLS
ctx->earlydata_max =
gnutls_record_get_max_early_data_size(ctx->tls.gtls.session);
@ -2366,7 +2390,8 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
ctx->earlydata_max = 0;
#endif /* WOLFSSL_EARLY_DATA */
#endif
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL)
#if defined(USE_GNUTLS) || defined(USE_WOLFSSL) || \
(defined(USE_OPENSSL) && defined(HAVE_OPENSSL_EARLYDATA))
if((!ctx->earlydata_max)) {
CURL_TRC_CF(data, cf, "SSL session does not allow earlydata");
}
@ -2394,7 +2419,7 @@ static CURLcode cf_ngtcp2_on_session_reuse(struct Curl_cfilter *cf,
}
}
}
#else /* USE_GNUTLS */
#else /* not supported in the TLS backend */
(void)data;
(void)ctx;
(void)scs;

View File

@ -88,7 +88,8 @@ CURLcode Curl_vquic_tls_init(struct curl_tls_ctx *ctx,
#ifdef USE_OPENSSL
(void)result;
return Curl_ossl_ctx_init(&ctx->ossl, cf, data, peer, alpns,
cb_setup, cb_user_data, NULL, ssl_user_data);
cb_setup, cb_user_data, NULL, ssl_user_data,
session_reuse_cb);
#elif defined(USE_GNUTLS)
return Curl_gtls_ctx_init(&ctx->gtls, cf, data, peer, alpns,
cb_setup, cb_user_data, ssl_user_data,

View File

@ -1780,8 +1780,7 @@ static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf,
Curl_bufq_skip(&connssl->earlydata, (size_t)n);
}
/* sent everything there was */
infof(data, "SSL sending %" FMT_OFF_T " bytes of early data",
connssl->earlydata_skip);
infof(data, "SSL sending %zu bytes of early data", connssl->earlydata_skip);
out:
return result;
}

View File

@ -62,6 +62,7 @@
#include "strcase.h"
#include "hostcheck.h"
#include "multiif.h"
#include "strdup.h"
#include "strerror.h"
#include "curl_printf.h"
@ -2927,10 +2928,13 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
const char *ssl_peer_key,
SSL_SESSION *session,
int ietf_tls_id,
const char *alpn)
const char *alpn,
unsigned char *quic_tp,
size_t quic_tp_len)
{
const struct ssl_config_data *config;
unsigned char *der_session_buf = NULL;
unsigned char *qtp_clone = NULL;
CURLcode result = CURLE_OK;
if(!cf || !data)
@ -2941,6 +2945,7 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
struct Curl_ssl_session *sc_session = NULL;
size_t der_session_size;
unsigned char *der_session_ptr;
size_t earlydata_max = 0;
der_session_size = i2d_SSL_SESSION(session, NULL);
if(der_session_size == 0) {
@ -2960,11 +2965,23 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
goto out;
}
result = Curl_ssl_session_create(der_session_buf, der_session_size,
ietf_tls_id, alpn,
(curl_off_t)time(NULL) +
SSL_SESSION_get_timeout(session), 0,
&sc_session);
#ifdef HAVE_OPENSSL_EARLYDATA
earlydata_max = SSL_SESSION_get_max_early_data(session);
#endif
if(quic_tp && quic_tp_len) {
qtp_clone = Curl_memdup0((char *)quic_tp, quic_tp_len);
if(!qtp_clone) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
}
result = Curl_ssl_session_create2(der_session_buf, der_session_size,
ietf_tls_id, alpn,
(curl_off_t)time(NULL) +
SSL_SESSION_get_timeout(session),
earlydata_max, qtp_clone, quic_tp_len,
&sc_session);
der_session_buf = NULL; /* took ownership of sdata */
if(!result) {
result = Curl_ssl_scache_put(cf, data, ssl_peer_key, sc_session);
@ -2987,7 +3004,8 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
struct Curl_easy *data = CF_DATA_CURRENT(cf);
struct ssl_connect_data *connssl = cf->ctx;
Curl_ossl_add_session(cf, data, connssl->peer.scache_key, ssl_sessionid,
SSL_version(ssl), connssl->negotiated.alpn);
SSL_version(ssl), connssl->negotiated.alpn,
NULL, 0);
}
return 0;
}
@ -3527,11 +3545,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
struct Curl_cfilter *cf,
struct Curl_easy *data,
struct ssl_peer *peer,
const struct alpn_spec *alpns,
const struct alpn_spec *alpns_requested,
Curl_ossl_ctx_setup_cb *cb_setup,
void *cb_user_data,
Curl_ossl_new_session_cb *cb_new_session,
void *ssl_user_data)
void *ssl_user_data,
Curl_ossl_init_session_reuse_cb *sess_reuse_cb)
{
CURLcode result = CURLE_OK;
const char *ciphers;
@ -3545,12 +3564,14 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
const char * const ssl_cert_type = ssl_config->cert_type;
const bool verifypeer = conn_config->verifypeer;
char error_buffer[256];
struct alpn_spec alpns;
/* Make funny stuff to get random input */
result = ossl_seed(data);
if(result)
return result;
Curl_alpn_copy(&alpns, alpns_requested);
ssl_config->certverifyresult = !X509_V_OK;
switch(peer->transport) {
@ -3722,22 +3743,6 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
SSL_CTX_set_mode(octx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#endif
#ifdef HAS_ALPN_OPENSSL
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");
return CURLE_SSL_CONNECT_ERROR;
}
}
#endif
if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
if(!result &&
!cert_stuff(data, octx->ssl_ctx,
@ -4020,12 +4025,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
octx->reused_session = FALSE;
if(ssl_config->primary.cache_session) {
struct Curl_ssl_session *sc_session = NULL;
struct Curl_ssl_session *scs = NULL;
result = Curl_ssl_scache_take(cf, data, peer->scache_key, &sc_session);
if(!result && sc_session && sc_session->sdata && sc_session->sdata_len) {
const unsigned char *der_sessionid = sc_session->sdata;
size_t der_sessionid_size = sc_session->sdata_len;
result = Curl_ssl_scache_take(cf, data, peer->scache_key, &scs);
if(!result && scs && scs->sdata && scs->sdata_len) {
const unsigned char *der_sessionid = scs->sdata;
size_t der_sessionid_size = scs->sdata_len;
SSL_SESSION *ssl_session = NULL;
/* If OpenSSL does not accept the session from the cache, this
@ -4040,8 +4045,29 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
sizeof(error_buffer)));
}
else {
infof(data, "SSL reusing session");
infof(data, "SSL reusing session with ALPN '%s'",
scs->alpn ? scs->alpn : "-");
octx->reused_session = TRUE;
#ifdef HAVE_OPENSSL_EARLYDATA
if(ssl_config->earlydata && scs->alpn &&
SSL_SESSION_get_max_early_data(ssl_session) &&
!cf->conn->connect_only &&
(SSL_version(octx->ssl) == TLS1_3_VERSION)) {
bool do_early_data = FALSE;
if(sess_reuse_cb) {
result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data);
if(result)
return result;
}
if(do_early_data) {
/* 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);
}
}
#else
(void)sess_reuse_cb;
#endif
}
SSL_SESSION_free(ssl_session);
}
@ -4049,12 +4075,58 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
infof(data, "SSL session not accepted by OpenSSL, continuing without");
}
}
Curl_ssl_scache_return(cf, data, peer->scache_key, sc_session);
Curl_ssl_scache_return(cf, data, peer->scache_key, scs);
}
#ifdef HAS_ALPN_OPENSSL
if(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_set_alpn_protos(octx->ssl, proto.data, (int)proto.len)) {
failf(data, "Error setting ALPN");
return CURLE_SSL_CONNECT_ERROR;
}
}
#endif
return CURLE_OK;
}
static CURLcode ossl_on_session_reuse(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct alpn_spec *alpns,
struct Curl_ssl_session *scs,
bool *do_early_data)
{
struct ssl_connect_data *connssl = cf->ctx;
CURLcode result = CURLE_OK;
*do_early_data = FALSE;
connssl->earlydata_max = scs->earlydata_max;
if(!connssl->earlydata_max) {
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 ossl_connect_step1(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
@ -4068,7 +4140,8 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
result = Curl_ossl_ctx_init(octx, cf, data, &connssl->peer,
connssl->alpn, NULL, NULL,
ossl_new_session_cb, cf);
ossl_new_session_cb, cf,
ossl_on_session_reuse);
if(result)
return result;
@ -4094,7 +4167,7 @@ static CURLcode ossl_connect_step1(struct Curl_cfilter *cf,
#endif
#ifdef HAS_ALPN_OPENSSL
if(connssl->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);
@ -4209,27 +4282,25 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf,
if(SSL_ERROR_WANT_READ == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want recv");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
return CURLE_OK;
return CURLE_AGAIN;
}
if(SSL_ERROR_WANT_WRITE == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want send");
connssl->io_need = CURL_SSL_IO_NEED_SEND;
return CURLE_OK;
return CURLE_AGAIN;
}
#ifdef SSL_ERROR_WANT_ASYNC
if(SSL_ERROR_WANT_ASYNC == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want async");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
return CURLE_AGAIN;
}
#endif
#ifdef SSL_ERROR_WANT_RETRY_VERIFY
if(SSL_ERROR_WANT_RETRY_VERIFY == detail) {
CURL_TRC_CF(data, cf, "SSL_connect() -> want retry_verify");
connssl->io_need = CURL_SSL_IO_NEED_RECV;
connssl->connecting_state = ssl_connect_2;
return CURLE_OK;
return CURLE_AGAIN;
}
#endif
else {
@ -4787,15 +4858,92 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf,
*/
result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer);
if(!result)
connssl->connecting_state = ssl_connect_done;
else
if(result)
/* on error, remove sessions we might have in the pool */
Curl_ssl_scache_remove_all(cf, data, connssl->peer.scache_key);
return result;
}
#ifdef HAVE_OPENSSL_EARLYDATA
static CURLcode ossl_send_earlydata(struct Curl_cfilter *cf,
struct Curl_easy *data)
{
struct ssl_connect_data *connssl = cf->ctx;
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
CURLcode result = CURLE_OK;
const unsigned char *buf;
size_t blen, nwritten;
int rc;
DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sending);
octx->io_result = CURLE_OK;
while(Curl_bufq_peek(&connssl->earlydata, &buf, &blen)) {
nwritten = 0;
rc = SSL_write_early_data(octx->ssl, buf, blen, &nwritten);
CURL_TRC_CF(data, cf, "SSL_write_early_data(len=%zu) -> %d, %zu",
blen, rc, nwritten);
if(rc <= 0) {
long sslerror;
char error_buffer[256];
int err = SSL_get_error(octx->ssl, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
connssl->io_need = CURL_SSL_IO_NEED_RECV;
result = CURLE_AGAIN;
goto out;
case SSL_ERROR_WANT_WRITE:
connssl->io_need = CURL_SSL_IO_NEED_SEND;
result = CURLE_AGAIN;
goto out;
case SSL_ERROR_SYSCALL: {
int sockerr = SOCKERRNO;
if(octx->io_result == CURLE_AGAIN) {
result = CURLE_AGAIN;
goto out;
}
sslerror = ERR_get_error();
if(sslerror)
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer));
else if(sockerr)
Curl_strerror(sockerr, error_buffer, sizeof(error_buffer));
else
msnprintf(error_buffer, sizeof(error_buffer), "%s",
SSL_ERROR_to_str(err));
failf(data, OSSL_PACKAGE " SSL_write:early_data: %s, errno %d",
error_buffer, sockerr);
result = CURLE_SEND_ERROR;
goto out;
}
case SSL_ERROR_SSL: {
/* A failure in the SSL library occurred, usually a protocol error.
The OpenSSL error queue contains more information on the error. */
sslerror = ERR_get_error();
failf(data, "SSL_write_early_data() error: %s",
ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
result = CURLE_SEND_ERROR;
goto out;
}
default:
/* a true error */
failf(data, OSSL_PACKAGE " SSL_write_early_data: %s, errno %d",
SSL_ERROR_to_str(err), SOCKERRNO);
result = CURLE_SEND_ERROR;
goto out;
}
}
Curl_bufq_skip(&connssl->earlydata, nwritten);
}
/* sent everything there was */
infof(data, "SSL sending %zu bytes of early data", connssl->earlydata_skip);
out:
return result;
}
#endif /* HAVE_OPENSSL_EARLYDATA */
static CURLcode ossl_connect(struct Curl_cfilter *cf,
struct Curl_easy *data,
bool *done)
@ -4813,29 +4961,63 @@ static CURLcode ossl_connect(struct Curl_cfilter *cf,
connssl->io_need = CURL_SSL_IO_NEED_NONE;
if(ssl_connect_1 == connssl->connecting_state) {
CURL_TRC_CF(data, cf, "ossl_connect, step1");
result = ossl_connect_step1(cf, data);
if(result)
goto out;
}
if(ssl_connect_2 == connssl->connecting_state) {
CURL_TRC_CF(data, cf, "ossl_connect, step2");
#ifdef HAVE_OPENSSL_EARLYDATA
if(connssl->earlydata_state == ssl_earlydata_await) {
goto out;
}
else if(connssl->earlydata_state == ssl_earlydata_sending) {
result = ossl_send_earlydata(cf, data);
if(result)
goto out;
connssl->earlydata_state = ssl_earlydata_sent;
}
#endif
DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) ||
(connssl->earlydata_state == ssl_earlydata_sent));
result = ossl_connect_step2(cf, data);
if(result)
goto out;
}
if(ssl_connect_3 == connssl->connecting_state) {
CURL_TRC_CF(data, cf, "ossl_connect, step3");
result = ossl_connect_step3(cf, data);
if(result)
goto out;
connssl->connecting_state = ssl_connect_done;
#ifdef HAVE_OPENSSL_EARLYDATA
if(connssl->earlydata_state > ssl_earlydata_none) {
struct ossl_ctx *octx = (struct ossl_ctx *)connssl->backend;
/* We should be in this state by now */
DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent);
connssl->earlydata_state =
(SSL_get_early_data_status(octx->ssl) == SSL_EARLY_DATA_ACCEPTED) ?
ssl_earlydata_accepted : ssl_earlydata_rejected;
}
#endif
}
if(ssl_connect_done == connssl->connecting_state) {
CURL_TRC_CF(data, cf, "ossl_connect, done");
connssl->state = ssl_connection_complete;
*done = TRUE;
}
out:
if(result == CURLE_AGAIN) {
*done = FALSE;
return CURLE_OK;
}
*done = ((connssl->state == ssl_connection_complete) ||
(connssl->state == ssl_connection_deferred));
return result;
}

View File

@ -49,8 +49,16 @@
#define HAVE_KEYLOG_CALLBACK
#endif
/* Check for OpenSSL 1.1.1 which has early data support. */
#undef HAVE_OPENSSL_EARLYDATA
#if OPENSSL_VERSION_NUMBER >= 0x10100010L && defined(TLS1_3_VERSION) && \
!defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC)
#define HAVE_OPENSSL_EARLYDATA
#endif
struct alpn_spec;
struct ssl_peer;
struct Curl_ssl_session;
/* Struct to hold a curl OpenSSL instance */
struct ossl_ctx {
@ -76,6 +84,11 @@ typedef CURLcode Curl_ossl_ctx_setup_cb(struct Curl_cfilter *cf,
void *user_data);
typedef int Curl_ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid);
typedef CURLcode Curl_ossl_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_ossl_ctx_init(struct ossl_ctx *octx,
struct Curl_cfilter *cf,
@ -85,7 +98,8 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx,
Curl_ossl_ctx_setup_cb *cb_setup,
void *cb_user_data,
Curl_ossl_new_session_cb *cb_new_session,
void *ssl_user_data);
void *ssl_user_data,
Curl_ossl_init_session_reuse_cb *sess_reuse_cb);
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
#define SSL_get1_peer_certificate SSL_get_peer_certificate
@ -114,7 +128,9 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf,
const char *ssl_peer_key,
SSL_SESSION *ssl_sessionid,
int ietf_tls_id,
const char *alpn);
const char *alpn,
unsigned char *quic_tp,
size_t quic_tp_len);
/*
* Get the server cert, verify it and show it, etc., only call failf() if

View File

@ -1635,8 +1635,7 @@ static CURLcode wssl_send_earlydata(struct Curl_cfilter *cf,
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 %" FMT_OFF_T " bytes of early data",
connssl->earlydata_skip);
infof(data, "SSL sending %zu bytes of early data", connssl->earlydata_skip);
out:
return result;
}

View File

@ -577,9 +577,10 @@ class TestDownload:
@pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx")
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
def test_02_32_earlydata(self, env: Env, httpd, nghttpx, proto):
if not env.curl_uses_lib('gnutls') and not env.curl_uses_lib('wolfssl'):
pytest.skip('TLS earlydata only implemented in GnuTLS/wolfSSL')
if proto == 'h3' and not env.have_h3():
if not env.curl_can_early_data():
pytest.skip('TLS earlydata not implemented')
if proto == 'h3' and \
(not env.have_h3() or not env.curl_can_h3_early_data()):
pytest.skip("h3 not supported")
count = 2
docname = 'data-10k'

View File

@ -703,9 +703,10 @@ class TestUpload:
# of 128K.
])
def test_07_70_put_earlydata(self, env: Env, httpd, nghttpx, proto, upload_size, exp_early):
if not env.curl_uses_lib('gnutls') and not env.curl_uses_lib('wolfssl'):
pytest.skip('TLS earlydata only implemented in GnuTLS/wolfSSL')
if proto == 'h3' and not env.have_h3():
if not env.curl_can_early_data():
pytest.skip('TLS earlydata not implemented')
if proto == 'h3' and \
(not env.have_h3() or not env.curl_can_h3_early_data()):
pytest.skip("h3 not supported")
count = 2
# we want this test to always connect to nghttpx, since it is

View File

@ -207,9 +207,10 @@ class TestCaddy:
@pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
def test_08_08_earlydata(self, env: Env, httpd, caddy, proto):
if not env.curl_uses_lib('gnutls') and not env.curl_uses_lib('wolfssl'):
pytest.skip('TLS earlydata only implemented in GnuTLS/wolfSSL')
if proto == 'h3' and not env.have_h3():
if not env.curl_can_early_data():
pytest.skip('TLS earlydata not implemented')
if proto == 'h3' and \
(not env.have_h3() or not env.curl_can_h3_early_data()):
pytest.skip("h3 not supported")
count = 2
docname = 'data10k.data'

View File

@ -252,8 +252,8 @@ class TestSSLUse:
if proto == 'h3' and not env.have_h3():
pytest.skip("h3 not supported")
if not env.curl_uses_lib('openssl') and \
not env.curl_uses_lib('gnutls') and \
not env.curl_uses_lib('quictls'):
not env.curl_uses_lib('gnutls') and \
not env.curl_uses_lib('quictls'):
pytest.skip("TLS library does not support --cert-status")
curl = CurlClient(env=env)
domain = 'localhost'
@ -318,8 +318,8 @@ class TestSSLUse:
if not env.have_h3():
pytest.skip("h3 not supported")
if not env.curl_uses_lib('quictls') and \
not env.curl_uses_lib('gnutls') and \
not env.curl_uses_lib('wolfssl'):
not env.curl_uses_lib('gnutls') and \
not env.curl_uses_lib('wolfssl'):
pytest.skip("QUIC session reuse not implemented")
count = 2
docname = 'data-10k'

View File

@ -382,6 +382,18 @@ class Env:
def curl_is_debug() -> bool:
return Env.CONFIG.curl_is_debug
@staticmethod
def curl_can_early_data() -> bool:
return Env.curl_uses_lib('gnutls') or \
Env.curl_uses_lib('wolfssl') or \
Env.curl_uses_lib('quictls') or \
Env.curl_uses_lib('openssl')
@staticmethod
def curl_can_h3_early_data() -> bool:
return Env.curl_can_early_data() and \
Env.curl_uses_lib('ngtcp2')
@staticmethod
def have_h3() -> bool:
return Env.have_h3_curl() and Env.have_h3_server()