From: Hugo Landau Date: Fri, 10 Nov 2023 13:36:29 +0000 (+0000) Subject: QUIC APL, TSERVER: Start using a QUIC_ENGINE object X-Git-Tag: openssl-3.3.0-alpha1~400 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=22739cc3acf2412829a1b0e54d1033efe9679e60;p=thirdparty%2Fopenssl.git QUIC APL, TSERVER: Start using a QUIC_ENGINE object Reviewed-by: Tomas Mraz Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/22674) --- diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index a745baedb62..b6b3e283520 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -319,6 +319,7 @@ int ossl_quic_channel_is_handshake_complete(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_handshake_confirmed(const QUIC_CHANNEL *ch); QUIC_PORT *ossl_quic_channel_get0_port(QUIC_CHANNEL *ch); +QUIC_ENGINE *ossl_quic_channel_get0_engine(QUIC_CHANNEL *ch); QUIC_DEMUX *ossl_quic_channel_get0_demux(QUIC_CHANNEL *ch); SSL *ossl_quic_channel_get0_ssl(QUIC_CHANNEL *ch); diff --git a/include/internal/quic_port.h b/include/internal/quic_port.h index 74578e9267a..81811b01107 100644 --- a/include/internal/quic_port.h +++ b/include/internal/quic_port.h @@ -42,30 +42,6 @@ typedef struct quic_port_args_st { /* The engine which the QUIC port is to be a child of. */ QUIC_ENGINE *engine; - /* All channels in a QUIC event domain share the same (libctx, propq). */ - OSSL_LIB_CTX *libctx; - const char *propq; - - /* - * This must be a mutex the lifetime of which will exceed that of the port - * and all channels. The instantiator of the port is responsible for - * providing a mutex as this makes it easier to handle instantiation and - * teardown of channels in situations potentially requiring locking. - * - * Note that this is a MUTEX not a RWLOCK as it needs to be an OS mutex for - * compatibility with an OS's condition variable wait API, whereas RWLOCK - * may, depending on the build configuration, be implemented using an OS's - * mutex primitive or using its RW mutex primitive. - */ - CRYPTO_MUTEX *mutex; - - /* - * Optional function pointer to use to retrieve the current time. If NULL, - * ossl_time_now() is used. - */ - OSSL_TIME (*now_cb)(void *arg); - void *now_cb_arg; - /* * This SSL_CTX will be used when constructing the handshake layer object * inside newly created channels. @@ -134,9 +110,6 @@ OSSL_TIME ossl_quic_port_get_time(QUIC_PORT *port); int ossl_quic_port_get_rx_short_dcid_len(const QUIC_PORT *port); int ossl_quic_port_get_tx_init_dcid_len(const QUIC_PORT *port); -/* For testing use. While enabled, ticking is not performed. */ -void ossl_quic_port_set_inhibit_tick(QUIC_PORT *port, int inhibit); - /* Returns 1 if the port is running/healthy, 0 if it has failed. */ int ossl_quic_port_is_running(const QUIC_PORT *port); diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 60bcc88f84c..6a87588e900 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -17,6 +17,7 @@ #include "../ssl_local.h" #include "quic_channel_local.h" #include "quic_port_local.h" +#include "quic_engine_local.h" /* * NOTE: While this channel implementation currently has basic server support, @@ -129,12 +130,12 @@ static int ch_init(QUIC_CHANNEL *ch) /* For clients, generate our initial DCID. */ if (!ch->is_server - && !ossl_quic_gen_rand_conn_id(ch->port->libctx, tx_init_dcid_len, + && !ossl_quic_gen_rand_conn_id(ch->port->engine->libctx, tx_init_dcid_len, &ch->init_dcid)) goto err; /* We plug in a network write BIO to the QTX later when we get one. */ - qtx_args.libctx = ch->port->libctx; + qtx_args.libctx = ch->port->engine->libctx; qtx_args.mdpl = QUIC_MIN_INITIAL_DGRAM_LEN; ch->rx_max_udp_payload_size = qtx_args.mdpl; @@ -241,7 +242,7 @@ static int ch_init(QUIC_CHANNEL *ch) ossl_quic_tx_packetiser_set_ack_tx_cb(ch->txp, ch_on_txp_ack_tx, ch); - qrx_args.libctx = ch->port->libctx; + qrx_args.libctx = ch->port->engine->libctx; qrx_args.demux = ch->port->demux; qrx_args.short_conn_id_len = rx_short_dcid_len; qrx_args.max_deferred = 32; @@ -509,6 +510,11 @@ QUIC_PORT *ossl_quic_channel_get0_port(QUIC_CHANNEL *ch) return ch->port; } +QUIC_ENGINE *ossl_quic_channel_get0_engine(QUIC_CHANNEL *ch) +{ + return ossl_quic_port_get0_engine(ch->port); +} + CRYPTO_MUTEX *ossl_quic_channel_get_mutex(QUIC_CHANNEL *ch) { return ossl_quic_port_get0_mutex(ch->port); @@ -1712,7 +1718,7 @@ void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *res, } } - if (!ch->port->inhibit_tick) { + if (!ch->port->engine->inhibit_tick) { /* Handle RXKU timeouts. */ ch_rxku_tick(ch); @@ -1752,7 +1758,7 @@ void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *res, * Idle timeout differs from normal protocol violation because we do * not send a CONN_CLOSE frame; go straight to TERMINATED. */ - if (!ch->port->inhibit_tick) + if (!ch->port->engine->inhibit_tick) ch_on_idle_timeout(ch); res->net_read_desired = 0; @@ -1761,7 +1767,7 @@ void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *res, return; } - if (!ch->port->inhibit_tick) { + if (!ch->port->engine->inhibit_tick) { deadline = ossl_ackm_get_loss_detection_deadline(ch->ackm); if (!ossl_time_is_zero(deadline) && ossl_time_compare(now, deadline) >= 0) @@ -2062,8 +2068,8 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch, int channel_only) * than allow the QRX to emit a potentially malformed packet to the * upper layers. However, special casing this will do for now. */ - if (!ossl_quic_validate_retry_integrity_tag(ch->port->libctx, - ch->port->propq, + if (!ossl_quic_validate_retry_integrity_tag(ch->port->engine->libctx, + ch->port->engine->propq, ch->qrx_pkt->hdr, &ch->init_dcid)) /* Malformed retry packet, ignore. */ @@ -2391,8 +2397,8 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch) return 0; /* Plug in secrets for the Initial EL. */ - if (!ossl_quic_provide_initial_secret(ch->port->libctx, - ch->port->propq, + if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx, + ch->port->engine->propq, &ch->init_dcid, ch->is_server, ch->qrx, ch->qtx)) @@ -2491,8 +2497,8 @@ static int ch_retry(QUIC_CHANNEL *ch, * Plug in new secrets for the Initial EL. This is the only time we change * the secrets for an EL after we already provisioned it. */ - if (!ossl_quic_provide_initial_secret(ch->port->libctx, - ch->port->propq, + if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx, + ch->port->engine->propq, &ch->retry_scid, /*is_server=*/0, ch->qrx, ch->qtx)) @@ -3145,8 +3151,8 @@ int ossl_quic_channel_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer, return 0; /* Plug in secrets for the Initial EL. */ - if (!ossl_quic_provide_initial_secret(ch->port->libctx, - ch->port->propq, + if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx, + ch->port->engine->propq, &ch->init_dcid, /*is_server=*/1, ch->qrx, ch->qtx)) diff --git a/ssl/quic/quic_engine.c b/ssl/quic/quic_engine.c index 26c859e5952..9f881b3cc4f 100644 --- a/ssl/quic/quic_engine.c +++ b/ssl/quic/quic_engine.c @@ -98,6 +98,10 @@ QUIC_PORT *ossl_quic_engine_create_port(QUIC_ENGINE *qeng, { QUIC_PORT_ARGS largs = *args; + if (ossl_list_port_num(&qeng->port_list) > 0) + /* TODO(QUIC MULTIPORT): We currently support only one port. */ + return NULL; + if (largs.engine != NULL) return NULL; diff --git a/ssl/quic/quic_engine_local.h b/ssl/quic/quic_engine_local.h index 6896e30d858..214cc5e5fe6 100644 --- a/ssl/quic/quic_engine_local.h +++ b/ssl/quic/quic_engine_local.h @@ -28,6 +28,7 @@ DECLARE_LIST_OF(port, QUIC_PORT); struct quic_engine_st { + /* All objects in a QUIC event domain share the same (libctx, propq). */ OSSL_LIB_CTX *libctx; const char *propq; diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 7279c37c171..5306d6bd40a 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -15,6 +15,7 @@ #include "internal/quic_tls.h" #include "internal/quic_rx_depack.h" #include "internal/quic_error.h" +#include "internal/quic_engine.h" #include "internal/quic_port.h" #include "internal/time.h" @@ -64,7 +65,7 @@ static int block_until_pred(QUIC_CONNECTION *qc, * Any attempt to block auto-disables tick inhibition as otherwise we will * hang around forever. */ - ossl_quic_port_set_inhibit_tick(qc->port, 0); + ossl_quic_engine_set_inhibit_tick(qc->engine, 0); rtor = ossl_quic_channel_get_reactor(qc->ch); return ossl_quic_reactor_block_until_pred(rtor, pred, pred_arg, flags, @@ -545,6 +546,7 @@ void ossl_quic_free(SSL *s) ossl_quic_channel_free(ctx.qc->ch); ossl_quic_port_free(ctx.qc->port); + ossl_quic_engine_free(ctx.qc->engine); BIO_free_all(ctx.qc->net_rbio); BIO_free_all(ctx.qc->net_wbio); @@ -1489,18 +1491,25 @@ static int configure_channel(QUIC_CONNECTION *qc) QUIC_NEEDS_LOCK static int create_channel(QUIC_CONNECTION *qc) { + QUIC_ENGINE_ARGS engine_args = {0}; QUIC_PORT_ARGS port_args = {0}; - port_args.libctx = qc->ssl.ctx->libctx; - port_args.propq = qc->ssl.ctx->propq; - port_args.mutex = qc->mutex; - port_args.channel_ctx = qc->ssl.ctx; - port_args.now_cb = get_time_cb; - port_args.now_cb_arg = qc; + engine_args.libctx = qc->ssl.ctx->libctx; + engine_args.propq = qc->ssl.ctx->propq; + engine_args.mutex = qc->mutex; + engine_args.now_cb = get_time_cb; + engine_args.now_cb_arg = qc; + qc->engine = ossl_quic_engine_new(&engine_args); + if (qc->engine == NULL) { + QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL); + return 0; + } - qc->port = ossl_quic_port_new(&port_args); + port_args.channel_ctx = qc->ssl.ctx; + qc->port = ossl_quic_engine_create_port(qc->engine, &port_args); if (qc->port == NULL) { QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL); + ossl_quic_engine_free(qc->engine); return 0; } @@ -1508,6 +1517,7 @@ static int create_channel(QUIC_CONNECTION *qc) if (qc->ch == NULL) { QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL); ossl_quic_port_free(qc->port); + ossl_quic_engine_free(qc->engine); return 0; } diff --git a/ssl/quic/quic_local.h b/ssl/quic/quic_local.h index ef074daf713..ca95f46f526 100644 --- a/ssl/quic/quic_local.h +++ b/ssl/quic/quic_local.h @@ -118,6 +118,9 @@ struct quic_conn_st { SSL *tls; + /* The QUIC engine representing the QUIC event domain. */ + QUIC_ENGINE *engine; + /* The QUIC port representing the QUIC listener and socket. */ QUIC_PORT *port; diff --git a/ssl/quic/quic_port.c b/ssl/quic/quic_port.c index 897edc4a795..3dbcd10957a 100644 --- a/ssl/quic/quic_port.c +++ b/ssl/quic/quic_port.c @@ -28,7 +28,6 @@ static OSSL_TIME get_time(void *arg); static void port_default_packet_handler(QUIC_URXE *e, void *arg, const QUIC_CONN_ID *dcid); static void port_rx_pre(QUIC_PORT *port); -static void port_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags); DEFINE_LIST_OF_IMPL(ch, QUIC_CHANNEL); DEFINE_LIST_OF_IMPL(port, QUIC_PORT); @@ -41,11 +40,6 @@ QUIC_PORT *ossl_quic_port_new(const QUIC_PORT_ARGS *args) return NULL; port->engine = args->engine; - port->libctx = args->libctx; - port->propq = args->propq; - port->mutex = args->mutex; - port->now_cb = args->now_cb; - port->now_cb_arg = args->now_cb_arg; port->channel_ctx = args->channel_ctx; port->is_multi_conn = args->is_multi_conn; @@ -70,7 +64,7 @@ static int port_init(QUIC_PORT *port) { size_t rx_short_dcid_len = (port->is_multi_conn ? INIT_DCID_LEN : 0); - if (port->channel_ctx == NULL) + if (port->engine == NULL || port->channel_ctx == NULL) goto err; if ((port->err_state = OSSL_ERR_STATE_new()) == NULL) @@ -85,15 +79,14 @@ static int port_init(QUIC_PORT *port) port_default_packet_handler, port); - if ((port->srtm = ossl_quic_srtm_new(port->libctx, port->propq)) == NULL) + if ((port->srtm = ossl_quic_srtm_new(port->engine->libctx, + port->engine->propq)) == NULL) goto err; - if ((port->lcidm = ossl_quic_lcidm_new(port->libctx, rx_short_dcid_len)) == NULL) + if ((port->lcidm = ossl_quic_lcidm_new(port->engine->libctx, + rx_short_dcid_len)) == NULL) goto err; - if (port->engine == NULL) - ossl_quic_reactor_init(&port->rtor, port_tick, port, ossl_time_zero()); - port->rx_short_dcid_len = (unsigned char)rx_short_dcid_len; port->tx_init_dcid_len = INIT_DCID_LEN; port->state = QUIC_PORT_STATE_RUNNING; @@ -150,7 +143,7 @@ QUIC_ENGINE *ossl_quic_port_get0_engine(QUIC_PORT *port) QUIC_REACTOR *ossl_quic_port_get0_reactor(QUIC_PORT *port) { - return port->engine != NULL ? &port->engine->rtor : &port->rtor; + return ossl_quic_engine_get0_reactor(port->engine); } QUIC_DEMUX *ossl_quic_port_get0_demux(QUIC_PORT *port) @@ -160,15 +153,12 @@ QUIC_DEMUX *ossl_quic_port_get0_demux(QUIC_PORT *port) CRYPTO_MUTEX *ossl_quic_port_get0_mutex(QUIC_PORT *port) { - return port->mutex; + return ossl_quic_engine_get0_mutex(port->engine); } OSSL_TIME ossl_quic_port_get_time(QUIC_PORT *port) { - if (port->now_cb == NULL) - return ossl_time_now(); - - return port->now_cb(port->now_cb_arg); + return ossl_quic_engine_get_time(port->engine); } static OSSL_TIME get_time(void *port) @@ -225,10 +215,19 @@ static int port_update_poll_desc(QUIC_PORT *port, BIO *net_bio, int for_write) if (!validate_poll_descriptor(&d)) return 0; + /* + * TODO(QUIC MULTIPORT): We currently only support one port per + * engine/domain. This is necessitated because QUIC_REACTOR only supports a + * single pollable currently. In the future, once complete polling + * infrastructure has been implemented, this limitation can be removed. + * + * For now, just update the descriptor on the the engine's reactor as we are + * guaranteed to be the only port under it. + */ if (for_write) - ossl_quic_reactor_set_poll_w(&port->rtor, &d); + ossl_quic_reactor_set_poll_w(&port->engine->rtor, &d); else - ossl_quic_reactor_set_poll_r(&port->rtor, &d); + ossl_quic_reactor_set_poll_r(&port->engine->rtor, &d); return 1; } @@ -355,11 +354,6 @@ QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls) * Tick function for this port. This does everything related to network I/O for * this port's network BIOs, and services child channels. */ -static void port_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) -{ - ossl_quic_port_subtick(arg, res, flags); -} - void ossl_quic_port_subtick(QUIC_PORT *port, QUIC_TICK_RESULT *res, uint32_t flags) { @@ -369,7 +363,7 @@ void ossl_quic_port_subtick(QUIC_PORT *port, QUIC_TICK_RESULT *res, res->net_write_desired = 0; res->tick_deadline = ossl_time_infinite(); - if (!port->inhibit_tick) { + if (!port->engine->inhibit_tick) { /* Handle any incoming data from network. */ if (ossl_quic_port_is_running(port)) port_rx_pre(port); @@ -583,11 +577,6 @@ undesirable: ossl_quic_demux_release_urxe(port->demux, e); } -void ossl_quic_port_set_inhibit_tick(QUIC_PORT *port, int inhibit) -{ - port->inhibit_tick = (inhibit != 0); -} - void ossl_quic_port_raise_net_error(QUIC_PORT *port, QUIC_CHANNEL *triggering_ch) { diff --git a/ssl/quic/quic_port_local.h b/ssl/quic/quic_port_local.h index ec12872b721..f44352a8937 100644 --- a/ssl/quic/quic_port_local.h +++ b/ssl/quic/quic_port_local.h @@ -50,27 +50,9 @@ struct quic_port_st { */ OSSL_LIST_MEMBER(port, QUIC_PORT); - OSSL_LIB_CTX *libctx; - const char *propq; - - /* - * Master synchronisation mutex for the entire QUIC event domain. Used for - * thread assisted mode synchronisation. We don't own this; the instantiator - * of the port passes it to us and is responsible for freeing it after port - * destruction. - */ - CRYPTO_MUTEX *mutex; - - /* Callback used to get the current time. */ - OSSL_TIME (*now_cb)(void *arg); - void *now_cb_arg; - /* Used to create handshake layer objects inside newly created channels. */ SSL_CTX *channel_ctx; - /* Asynchronous I/O reactor. */ - QUIC_REACTOR rtor; - /* Network-side read and write BIOs. */ BIO *net_rbio, *net_wbio; @@ -103,9 +85,6 @@ struct quic_port_st { /* Is this port created to support multiple connections? */ unsigned int is_multi_conn : 1; - /* Inhibit tick for testing purposes? */ - unsigned int inhibit_tick : 1; - /* Has this port sent any packet of any kind yet? */ unsigned int have_sent_any_pkt : 1; diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c index 885f4d52421..159669ef8f8 100644 --- a/ssl/quic/quic_tserver.c +++ b/ssl/quic/quic_tserver.c @@ -11,6 +11,7 @@ #include "internal/quic_channel.h" #include "internal/quic_statm.h" #include "internal/quic_port.h" +#include "internal/quic_engine.h" #include "internal/common.h" #include "internal/time.h" #include "quic_local.h" @@ -26,9 +27,10 @@ struct quic_tserver_st { SSL *ssl; /* - * The QUIC port and channel providing the core QUIC connection + * The QUIC engine, port and channel providing the core QUIC connection * implementation. */ + QUIC_ENGINE *engine; QUIC_PORT *port; QUIC_CHANNEL *ch; @@ -78,6 +80,7 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args, const char *certfile, const char *keyfile) { QUIC_TSERVER *srv = NULL; + QUIC_ENGINE_ARGS engine_args = {0}; QUIC_PORT_ARGS port_args = {0}; QUIC_CONNECTION *qc = NULL; @@ -116,15 +119,19 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args, if (srv->tls == NULL) goto err; - port_args.libctx = srv->args.libctx; - port_args.propq = srv->args.propq; - port_args.mutex = srv->mutex; - port_args.channel_ctx = srv->ctx; - port_args.now_cb = srv->args.now_cb; - port_args.now_cb_arg = srv->args.now_cb_arg; - port_args.is_multi_conn = 1; + engine_args.libctx = srv->args.libctx; + engine_args.propq = srv->args.propq; + engine_args.mutex = srv->mutex; + engine_args.now_cb = srv->args.now_cb; + engine_args.now_cb_arg = srv->args.now_cb_arg; - if ((srv->port = ossl_quic_port_new(&port_args)) == NULL) + if ((srv->engine = ossl_quic_engine_new(&engine_args)) == NULL) + goto err; + + port_args.channel_ctx = srv->ctx; + port_args.is_multi_conn = 1; + + if ((srv->port = ossl_quic_engine_create_port(srv->engine, &port_args)) == NULL) goto err; if ((srv->ch = ossl_quic_port_create_incoming(srv->port, srv->tls)) == NULL) @@ -150,6 +157,7 @@ err: SSL_free(srv->tls); ossl_quic_channel_free(srv->ch); ossl_quic_port_free(srv->port); + ossl_quic_engine_free(srv->engine); #if defined(OPENSSL_THREADS) ossl_crypto_mutex_free(&srv->mutex); #endif @@ -167,6 +175,7 @@ void ossl_quic_tserver_free(QUIC_TSERVER *srv) ossl_quic_channel_free(srv->ch); ossl_quic_port_free(srv->port); + ossl_quic_engine_free(srv->engine); BIO_free_all(srv->args.net_rbio); BIO_free_all(srv->args.net_wbio); OPENSSL_free(srv->ssl); diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c index 2fe44cd26f6..9e53d147a68 100644 --- a/test/quic_multistream_test.c +++ b/test/quic_multistream_test.c @@ -14,7 +14,7 @@ #include "internal/quic_ssl.h" #include "internal/quic_error.h" #include "internal/quic_stream_map.h" -#include "internal/quic_port.h" +#include "internal/quic_engine.h" #include "testutil.h" #include "helpers/quictestlib.h" #if defined(OPENSSL_THREADS) @@ -1599,7 +1599,7 @@ static int run_script_worker(struct helper *h, const struct script_op *script, QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); SSL_SHUTDOWN_EX_ARGS args = {0}; - ossl_quic_port_set_inhibit_tick(ossl_quic_channel_get0_port(ch), 0); + ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch), 0); if (!TEST_ptr(c_tgt)) goto out; @@ -1927,8 +1927,8 @@ static int run_script_worker(struct helper *h, const struct script_op *script, { QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); - ossl_quic_port_set_inhibit_tick(ossl_quic_channel_get0_port(ch), - op->arg1); + ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch), + op->arg1); } break;