diff --git a/CHANGES.md b/CHANGES.md index 3607dd06f9..991a862504 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -30,6 +30,10 @@ OpenSSL 3.5 ### Changes between 3.4 and 3.5 [xx XXX xxxx] +* Added new API to enable 0-RTT for 3rd party QUIC stacks. + + *Cheng Zhang* + * Added support for a new callback registration SSL_CTX_set_new_pending_conn_cb, which allows for application notification of new connection SSL object creation, which occurs independently of calls to SSL_accept_connection(). diff --git a/doc/man3/SSL_set_quic_tls_cbs.pod b/doc/man3/SSL_set_quic_tls_cbs.pod index 87a4d3a214..c196771543 100644 --- a/doc/man3/SSL_set_quic_tls_cbs.pod +++ b/doc/man3/SSL_set_quic_tls_cbs.pod @@ -9,7 +9,8 @@ OSSL_FUNC_SSL_QUIC_TLS_yield_secret_fn, OSSL_FUNC_SSL_QUIC_TLS_got_transport_params_fn, OSSL_FUNC_SSL_QUIC_TLS_alert_fn, SSL_set_quic_tls_cbs, -SSL_set_quic_tls_transport_params +SSL_set_quic_tls_transport_params, +SSL_set_quic_tls_early_data_enabled - Use the OpenSSL TLS implementation for a third party QUIC implementation =head1 SYNOPSIS @@ -59,6 +60,7 @@ SSL_set_quic_tls_transport_params int SSL_set_quic_tls_transport_params(SSL *s, const unsigned char *params, size_t params_len); + int SSL_set_quic_tls_early_data_enabled(SSL *s, int enabled); =head1 DESCRIPTION @@ -133,6 +135,9 @@ function must have been called by the time the transport parameters need to be sent. For a client this will be before the connection has been initiated. For a server this might typically occur during the got_transport_params_cb. +The SSL_set_quic_tls_early_data_enabled() function is used to enable the 0-RTT +feature for a third party QUIC implementation. + =head1 RETURN VALUES These functions return 1 on success and 0 on failure. diff --git a/include/internal/quic_tls.h b/include/internal/quic_tls.h index 5e53a45d52..c444a60fe3 100644 --- a/include/internal/quic_tls.h +++ b/include/internal/quic_tls.h @@ -108,4 +108,5 @@ int ossl_quic_tls_get_error(QUIC_TLS *qtls, int ossl_quic_tls_is_cert_request(QUIC_TLS *qtls); int ossl_quic_tls_has_bad_max_early_data(QUIC_TLS *qtls); +int ossl_quic_tls_set_early_data_enabled(QUIC_TLS *qtls, int enabled); #endif diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index e25899f627..511ceb6418 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -2878,6 +2878,8 @@ int SSL_set_quic_tls_transport_params(SSL *s, const unsigned char *params, size_t params_len); +int SSL_set_quic_tls_early_data_enabled(SSL *s, int enabled); + # ifdef __cplusplus } # endif diff --git a/ssl/quic/quic_tls.c b/ssl/quic/quic_tls.c index 6d524d73ee..546d09d46b 100644 --- a/ssl/quic/quic_tls.c +++ b/ssl/quic/quic_tls.c @@ -912,3 +912,30 @@ int ossl_quic_tls_has_bad_max_early_data(QUIC_TLS *qtls) */ return max_early_data != 0xffffffff && max_early_data != 0; } + +int ossl_quic_tls_set_early_data_enabled(QUIC_TLS *qtls, int enabled) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(qtls->args.s); + + if (!SSL_IS_QUIC_HANDSHAKE(sc) || !SSL_in_before(qtls->args.s)) + return 0; + + if (!enabled) { + sc->max_early_data = 0; + sc->early_data_state = SSL_EARLY_DATA_NONE; + return 1; + } + + if (sc->server) { + sc->max_early_data = 0xffffffff; + sc->early_data_state = SSL_EARLY_DATA_ACCEPTING; + return 1; + } + + if ((sc->session == NULL || sc->session->ext.max_early_data != 0xffffffff) + && sc->psk_use_session_cb == NULL) + return 0; + + sc->early_data_state = SSL_EARLY_DATA_CONNECTING; + return 1; +} diff --git a/ssl/quic/quic_tls_api.c b/ssl/quic/quic_tls_api.c index 4ba9f934c1..3c202a3094 100644 --- a/ssl/quic/quic_tls_api.c +++ b/ssl/quic/quic_tls_api.c @@ -189,3 +189,20 @@ int SSL_set_quic_tls_transport_params(SSL *s, return ossl_quic_tls_set_transport_params(sc->qtls, params, params_len); } + +int SSL_set_quic_tls_early_data_enabled(SSL *s, int enabled) +{ + SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); + + if (!SSL_is_tls(s)) { + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + if (sc->qtls == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); + return 0; + } + + return ossl_quic_tls_set_early_data_enabled(sc->qtls, enabled); +} diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f1c679083f..5d01b1d394 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -4946,6 +4946,13 @@ int SSL_do_handshake(SSL *s) ret = sc->handshake_func(s); } } + + if (ret == 1 && SSL_IS_QUIC_HANDSHAKE(sc) && !SSL_is_init_finished(s)) { + sc->rwstate = SSL_READING; + BIO_clear_retry_flags(SSL_get_rbio(s)); + BIO_set_retry_read(SSL_get_rbio(s)); + ret = 0; + } return ret; } diff --git a/test/sslapitest.c b/test/sslapitest.c index e5b999a29b..1d4fbab581 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -12800,7 +12800,7 @@ static void assert_no_end_of_early_data(int write_p, int version, int content_ty end_of_early_data = 1; } -static int test_no_end_of_early_data(void) +static int test_quic_tls_early_data(void) { SSL_CTX *sctx = NULL, *cctx = NULL; SSL *serverssl = NULL, *clientssl = NULL; @@ -12869,15 +12869,17 @@ static int test_no_end_of_early_data(void) sizeof(sparams)))) goto end; - SSL_CONNECTION_FROM_SSL(clientssl)->early_data_state = SSL_EARLY_DATA_CONNECTING; - SSL_CONNECTION_FROM_SSL(serverssl)->early_data_state = SSL_EARLY_DATA_ACCEPTING; + SSL_set_quic_tls_early_data_enabled(serverssl, 1); + SSL_set_quic_tls_early_data_enabled(clientssl, 1); SSL_set_msg_callback(serverssl, assert_no_end_of_early_data); SSL_set_msg_callback(clientssl, assert_no_end_of_early_data); - if (!TEST_int_eq(SSL_connect(clientssl), 1) - || !TEST_int_eq(SSL_accept(serverssl), 1) - || !TEST_int_eq(SSL_get_early_data_status(serverssl), SSL_EARLY_DATA_ACCEPTED)) + if (!TEST_int_eq(SSL_connect(clientssl), 0) + || !TEST_int_eq(SSL_accept(serverssl), 0) + || !TEST_int_eq(SSL_get_early_data_status(serverssl), SSL_EARLY_DATA_ACCEPTED) + || !TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_WANT_READ) + || !TEST_int_eq(SSL_get_error(serverssl, 0), SSL_ERROR_WANT_READ)) goto end; /* Check the encryption levels are what we expect them to be */ @@ -13262,7 +13264,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_alpn, 4); #if !defined(OSSL_NO_USABLE_TLS1_3) ADD_TEST(test_quic_tls); - ADD_TEST(test_no_end_of_early_data); + ADD_TEST(test_quic_tls_early_data); #endif return 1; diff --git a/util/libssl.num b/util/libssl.num index 6918652575..797df2b2f3 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -589,6 +589,7 @@ SSL_set_block_padding_ex 589 3_4_0 EXIST::FUNCTION: SSL_get1_builtin_sigalgs 590 3_4_0 EXIST::FUNCTION: SSL_set_quic_tls_cbs ? 3_5_0 EXIST::FUNCTION: SSL_set_quic_tls_transport_params ? 3_5_0 EXIST::FUNCTION: +SSL_set_quic_tls_early_data_enabled ? 3_5_0 EXIST::FUNCTION: OSSL_QUIC_server_method ? 3_5_0 EXIST::FUNCTION:QUIC SSL_is_listener ? 3_5_0 EXIST::FUNCTION: SSL_get0_listener ? 3_5_0 EXIST::FUNCTION: