]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Backout validation of initial packet done by port_default_packet_handler()
authorAlexandr Nedvedicky <sashan@openssl.org>
Thu, 13 Feb 2025 21:55:10 +0000 (22:55 +0100)
committerNeil Horman <nhorman@openssl.org>
Mon, 17 Feb 2025 16:27:34 +0000 (11:27 -0500)
QUIC interoperability tests discovered bugs in my earlier commit #59e7c2313be7cff.
This change reverts everything out.

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Tim Hudson <tjh@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26748)

include/internal/quic_channel.h
include/internal/quic_predef.h
include/internal/quic_record_rx.h
ssl/quic/quic_channel.c
ssl/quic/quic_channel_local.h
ssl/quic/quic_port.c
ssl/quic/quic_record_rx.c

index b782f0d66b74058acdecdf67c1814d7693ddcf8e..543a5900b906f4f87a11372ad7fa929c4a53a0ba 100644 (file)
@@ -116,7 +116,6 @@ typedef struct quic_channel_args_st {
     QUIC_LCIDM      *lcidm;
     /* SRTM to register SRTs with. */
     QUIC_SRTM       *srtm;
-    OSSL_QRX        *qrx;
 
     int             is_server;
     SSL             *tls;
@@ -124,8 +123,6 @@ typedef struct quic_channel_args_st {
     /* Whether to use qlog. */
     int             use_qlog;
 
-    int             is_tserver_ch;
-
     /* Title to use for the qlog session, or NULL. */
     const char      *qlog_title;
 } QUIC_CHANNEL_ARGS;
@@ -180,7 +177,6 @@ typedef struct quic_terminate_cause_st {
  */
 QUIC_CHANNEL *ossl_quic_channel_alloc(const QUIC_CHANNEL_ARGS *args);
 int ossl_quic_channel_init(QUIC_CHANNEL *ch);
-void ossl_quic_channel_bind_qrx(QUIC_CHANNEL *tserver_ch, OSSL_QRX *qrx);
 
 
 /* No-op if ch is NULL. */
index 7d9385d950e01753e015215499287ba0ce467653..21cc074a741239ec9698ef8a1e273c7355590a3f 100644 (file)
@@ -31,7 +31,6 @@ typedef struct quic_reactor_st QUIC_REACTOR;
 typedef struct quic_reactor_wait_ctx_st QUIC_REACTOR_WAIT_CTX;
 typedef struct ossl_statm_st OSSL_STATM;
 typedef struct quic_demux_st QUIC_DEMUX;
-typedef struct ossl_qrx_st OSSL_QRX;
 typedef struct ossl_qrx_pkt_st OSSL_QRX_PKT;
 typedef struct ossl_qtx_pkt_st OSSL_QTX_PKT;
 typedef struct quic_tick_result_st QUIC_TICK_RESULT;
index 54f3a6321b1bed2f12b5b699fb029726d98b5182..10b2e0def4ea4b8bc84935a286402ceca5075317 100644 (file)
@@ -23,6 +23,7 @@
  * QUIC Record Layer - RX
  * ======================
  */
+typedef struct ossl_qrx_st OSSL_QRX;
 
 typedef struct ossl_qrx_args_st {
     OSSL_LIB_CTX   *libctx;
@@ -320,8 +321,6 @@ int ossl_qrx_set_late_validation_cb(OSSL_QRX *qrx,
  * establish a new connection.
  */
 void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *e);
-int ossl_qrx_validate_initial_packet(OSSL_QRX *qrx, QUIC_URXE *urxe,
-                                     const QUIC_CONN_ID *dcid);
 
 /*
  * Decryption of 1-RTT packets must be explicitly enabled by calling this
index 262962973fe0e72bfe18229630ec03c315c99825..4c52fd49499968f4e61ef0a22dfc62afde58570b 100644 (file)
@@ -295,44 +295,23 @@ static int ch_init(QUIC_CHANNEL *ch)
 
     ossl_quic_tx_packetiser_set_ack_tx_cb(ch->txp, ch_on_txp_ack_tx, ch);
 
-    /*
-     * qrx does not exist yet, then we must be dealing with client channel
-     * (QUIC connection initiator).
-     * If qrx exists already, then we are dealing with server channel which
-     * qrx gets created by port_default_packet_handler() before
-     * port_default_packet_handler() accepts connection and creates channel
-     * for it.
-     * The exception here is tserver which always creates channel,
-     * before the first packet is ever seen.
-     */
-    if (ch->qrx == NULL && ch->is_tserver_ch == 0) {
-        /* we are regular client, create channel */
-        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;
-
-        if ((ch->qrx = ossl_qrx_new(&qrx_args)) == NULL)
-            goto err;
-    }
+    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;
 
-    if (ch->qrx != NULL) {
-        /*
-         * callbacks for channels associated with tserver's port
-         * are set up later when we call ossl_quic_channel_bind_qrx()
-         * in port_default_packet_handler()
-         */
-        if (!ossl_qrx_set_late_validation_cb(ch->qrx,
-                                             rx_late_validate,
-                                             ch))
-            goto err;
+    if ((ch->qrx = ossl_qrx_new(&qrx_args)) == NULL)
+        goto err;
 
-        if (!ossl_qrx_set_key_update_cb(ch->qrx,
-                                        rxku_detected,
-                                        ch))
-            goto err;
-    }
+    if (!ossl_qrx_set_late_validation_cb(ch->qrx,
+                                         rx_late_validate,
+                                         ch))
+        goto err;
 
+    if (!ossl_qrx_set_key_update_cb(ch->qrx,
+                                    rxku_detected,
+                                    ch))
+        goto err;
 
     for (pn_space = QUIC_PN_SPACE_INITIAL; pn_space < QUIC_PN_SPACE_NUM; ++pn_space) {
         ch->crypto_recv[pn_space] = ossl_quic_rstream_new(NULL, NULL, 0);
@@ -447,17 +426,6 @@ int ossl_quic_channel_init(QUIC_CHANNEL *ch)
     return ch_init(ch);
 }
 
-void ossl_quic_channel_bind_qrx(QUIC_CHANNEL *tserver_ch, OSSL_QRX *qrx)
-{
-    if (tserver_ch->qrx == NULL && tserver_ch->is_tserver_ch == 1) {
-        tserver_ch->qrx = qrx;
-        ossl_qrx_set_late_validation_cb(tserver_ch->qrx, rx_late_validate,
-                                        tserver_ch);
-        ossl_qrx_set_key_update_cb(tserver_ch->qrx, rxku_detected,
-                                   tserver_ch);
-    }
-}
-
 QUIC_CHANNEL *ossl_quic_channel_alloc(const QUIC_CHANNEL_ARGS *args)
 {
     QUIC_CHANNEL *ch = NULL;
@@ -465,13 +433,11 @@ QUIC_CHANNEL *ossl_quic_channel_alloc(const QUIC_CHANNEL_ARGS *args)
     if ((ch = OPENSSL_zalloc(sizeof(*ch))) == NULL)
         return NULL;
 
-    ch->port           = args->port;
-    ch->is_server      = args->is_server;
-    ch->tls            = args->tls;
-    ch->lcidm          = args->lcidm;
-    ch->srtm           = args->srtm;
-    ch->qrx            = args->qrx;
-    ch->is_tserver_ch  = args->is_tserver_ch;
+    ch->port        = args->port;
+    ch->is_server   = args->is_server;
+    ch->tls         = args->tls;
+    ch->lcidm       = args->lcidm;
+    ch->srtm        = args->srtm;
 #ifndef OPENSSL_NO_QLOG
     ch->use_qlog    = args->use_qlog;
 
@@ -604,7 +570,7 @@ err:
 
 size_t ossl_quic_channel_get_short_header_conn_id_len(QUIC_CHANNEL *ch)
 {
-    return ossl_quic_port_get_rx_short_dcid_len(ch->port);
+    return ossl_qrx_get_short_hdr_conn_id_len(ch->qrx);
 }
 
 QUIC_STREAM *ossl_quic_channel_get_stream_by_id(QUIC_CHANNEL *ch,
@@ -3689,15 +3655,12 @@ static int ch_on_new_conn_common(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
     ossl_qtx_set_qlog_cb(ch->qtx, ch_get_qlog_cb, ch);
     ossl_quic_tx_packetiser_set_qlog_cb(ch->txp, ch_get_qlog_cb, ch);
 
-    /*
-     * Plug in secrets for the Initial EL. secrets for QRX were created in
-     * port_default_packet_handler() already.
-     */
+    /* Plug in secrets for the Initial EL. */
     if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx,
                                           ch->port->engine->propq,
                                           &ch->init_dcid,
                                           /*is_server=*/1,
-                                          NULL, ch->qtx))
+                                          ch->qrx, ch->qtx))
         return 0;
 
     /* Register the peer ODCID in the LCIDM. */
@@ -4013,12 +3976,7 @@ void ossl_quic_channel_set_msg_callback(QUIC_CHANNEL *ch,
     ossl_qtx_set_msg_callback(ch->qtx, msg_callback, msg_callback_ssl);
     ossl_quic_tx_packetiser_set_msg_callback(ch->txp, msg_callback,
                                              msg_callback_ssl);
-    /*
-     * postpone msg callback setting for tserver until port calls
-     * port_bind_channel().
-     */
-    if (ch->is_tserver_ch == 0)
-        ossl_qrx_set_msg_callback(ch->qrx, msg_callback, msg_callback_ssl);
+    ossl_qrx_set_msg_callback(ch->qrx, msg_callback, msg_callback_ssl);
 }
 
 void ossl_quic_channel_set_msg_callback_arg(QUIC_CHANNEL *ch,
@@ -4027,13 +3985,7 @@ void ossl_quic_channel_set_msg_callback_arg(QUIC_CHANNEL *ch,
     ch->msg_callback_arg = msg_callback_arg;
     ossl_qtx_set_msg_callback_arg(ch->qtx, msg_callback_arg);
     ossl_quic_tx_packetiser_set_msg_callback_arg(ch->txp, msg_callback_arg);
-
-    /*
-     * postpone msg callback setting for tserver until port calls
-     * port_bind_channel().
-     */
-    if (ch->is_tserver_ch == 0)
-        ossl_qrx_set_msg_callback_arg(ch->qrx, msg_callback_arg);
+    ossl_qrx_set_msg_callback_arg(ch->qrx, msg_callback_arg);
 }
 
 void ossl_quic_channel_set_txku_threshold_override(QUIC_CHANNEL *ch,
index cdd0969586dff3b4e4cbde5b45720fc25fa974e1..6ba6366f4b58b4cda629592648a0f77ca5034821 100644 (file)
@@ -452,9 +452,6 @@ struct quic_channel_st {
     /* Has qlog been requested? */
     unsigned int                    use_qlog                            : 1;
 
-    /* Has qlog been requested? */
-    unsigned int                    is_tserver_ch                       : 1;
-
     /* Saved error stack in case permanent error was encountered */
     ERR_STATE                       *err_state;
 
index 8f03bd89b6c5fd5433aaf0c18a403ffaa3352068..a56d119a12c005e5a0f3474c4f735445034f1ca7 100644 (file)
@@ -498,18 +498,15 @@ static SSL *port_new_handshake_layer(QUIC_PORT *port, QUIC_CHANNEL *ch)
     return tls;
 }
 
-static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, OSSL_QRX *qrx,
-                                       int is_server, int is_tserver)
+static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, int is_server)
 {
     QUIC_CHANNEL_ARGS args = {0};
     QUIC_CHANNEL *ch;
 
-    args.port          = port;
-    args.is_server     = is_server;
-    args.lcidm         = port->lcidm;
-    args.srtm          = port->srtm;
-    args.qrx           = qrx;
-    args.is_tserver_ch = is_tserver;
+    args.port       = port;
+    args.is_server  = is_server;
+    args.lcidm      = port->lcidm;
+    args.srtm       = port->srtm;
 
     /*
      * Creating a a new channel is made a bit tricky here as there is a
@@ -559,8 +556,7 @@ static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, OSSL_QRX *qrx,
 
 QUIC_CHANNEL *ossl_quic_port_create_outgoing(QUIC_PORT *port, SSL *tls)
 {
-    return port_make_channel(port, tls, NULL, /* is_server= */ 0,
-                             /* is_tserver= */ 0);
+    return port_make_channel(port, tls, /*is_server=*/0);
 }
 
 QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls)
@@ -569,12 +565,7 @@ QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls)
 
     assert(port->tserver_ch == NULL);
 
-    /*
-     * pass -1 for qrx to indicate port will create qrx
-     * later in port_default_packet_handler() when calling port_bind_channel().
-     */
-    ch = port_make_channel(port, tls, NULL, /* is_server= */ 1,
-                           /* is_tserver_ch */ 1);
+    ch = port_make_channel(port, tls, /*is_server=*/1);
     port->tserver_ch = ch;
     port->allow_incoming = 1;
     return ch;
@@ -712,8 +703,7 @@ static void port_rx_pre(QUIC_PORT *port)
  */
 static void port_bind_channel(QUIC_PORT *port, const BIO_ADDR *peer,
                               const QUIC_CONN_ID *scid, const QUIC_CONN_ID *dcid,
-                              const QUIC_CONN_ID *odcid, OSSL_QRX *qrx,
-                              QUIC_CHANNEL **new_ch)
+                              const QUIC_CONN_ID *odcid, QUIC_CHANNEL **new_ch)
 {
     QUIC_CHANNEL *ch;
 
@@ -724,13 +714,8 @@ static void port_bind_channel(QUIC_PORT *port, const BIO_ADDR *peer,
     if (port->tserver_ch != NULL) {
         ch = port->tserver_ch;
         port->tserver_ch = NULL;
-        ossl_quic_channel_bind_qrx(ch, qrx);
-        ossl_qrx_set_msg_callback(ch->qrx, ch->msg_callback,
-                                  ch->msg_callback_ssl);
-        ossl_qrx_set_msg_callback_arg(ch->qrx, ch->msg_callback_arg);
     } else {
-        ch = port_make_channel(port, NULL, qrx, /* is_server= */ 1,
-                               /* is_tserver */ 0);
+        ch = port_make_channel(port, NULL, /* is_server= */1);
     }
 
     if (ch == NULL)
@@ -1452,8 +1437,6 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
     QUIC_CHANNEL *ch = NULL, *new_ch = NULL;
     QUIC_CONN_ID odcid, scid;
     uint8_t gen_new_token = 0;
-    OSSL_QRX *qrx = NULL;
-    OSSL_QRX_ARGS qrx_args = {0};
     uint64_t cause_flags = 0;
 
     /* Don't handle anything if we are no longer running. */
@@ -1538,31 +1521,6 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
 
     odcid.id_len = 0;
 
-    /*
-     * Create qrx now so we can check integrity of packet
-     * which does not belong to any channel.
-     */
-    qrx_args.libctx             = port->engine->libctx;
-    qrx_args.demux              = port->demux;
-    qrx_args.short_conn_id_len  = dcid->id_len;
-    qrx_args.max_deferred       = 32;
-    qrx = ossl_qrx_new(&qrx_args);
-    if (qrx == NULL)
-        goto undesirable;
-
-    /*
-     * Derive secrets for qrx only.
-     */
-    if (!ossl_quic_provide_initial_secret(port->engine->libctx,
-                                          port->engine->propq,
-                                          &hdr.dst_conn_id,
-                                          /* is_server */ 1,
-                                          qrx, NULL))
-        goto undesirable;
-
-    if (ossl_qrx_validate_initial_packet(qrx, e, (const QUIC_CONN_ID *)dcid) == 0)
-        goto undesirable;
-
     /*
      * TODO(QUIC FUTURE): there should be some logic similar to accounting half-open
      * states in TCP. If we reach certain threshold, then we want to
@@ -1570,13 +1528,6 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
      */
     if (port->validate_addr == 1 && hdr.token == NULL) {
         port_send_retry(port, &e->peer, &hdr);
-        /*
-         * This is a kind of bummer because we forget secrets for initial
-         * level encryption. The secrets costs us CPU to compute. What we can
-         * do here is to store them within retry token. Then we can retrieve them
-         * from initial packet which will carry our retry token to validate
-         * client's address.
-         */
         goto undesirable;
     }
 
@@ -1602,24 +1553,13 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
          * the request is valid
          */
         if (port->validate_addr == 1) {
-            /*
-             * Again: we should consider saving initial encryption level
-             * secrets to token here to save some CPU cycles.
-             */
             port_send_retry(port, &e->peer, &hdr);
             goto undesirable;
         }
     }
 
     port_bind_channel(port, &e->peer, &scid, &hdr.dst_conn_id,
-                      &odcid, qrx, &new_ch);
-
-    /*
-     * if packet validates it gets moved to channel, we've just bound
-     * to port.
-     */
-    if (new_ch == NULL)
-        goto undesirable;
+                      &odcid, &new_ch);
 
     /*
      * Generate a token for sending in a later NEW_TOKEN frame
@@ -1628,25 +1568,16 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
         generate_new_token(new_ch, &e->peer);
 
     /*
-     * The qrx belongs to channel now, so don't free it.
-     */
-    qrx = NULL;
-
-    /*
-     * If function reaches this place, then packet got validated in
-     * ossl_qrx_validate_initial_packet(). Keep in mind the function
-     * ossl_qrx_validate_initial_packet() decrypts the packet to validate it.
-     * If packet validation was successful (and it was because we are here),
-     * then the function puts the packet to qrx->rx_pending. We must not call
-     * ossl_qrx_inject_urxe() here now, because we don't want to insert
-     * the packet to qrx->urx_pending which keeps packet waiting for decryption.
-     *
-     * We are going to call ossl_quic_demux_release_urxe() to dispose buffer
-     * which still holds encrypted data.
+     * The channel will do all the LCID registration needed, but as an
+     * optimization inject this packet directly into the channel's QRX for
+     * processing without going through the DEMUX again.
      */
+    if (new_ch != NULL) {
+        ossl_qrx_inject_urxe(new_ch->qrx, e);
+        return;
+    }
 
 undesirable:
-    ossl_qrx_free(qrx);
     ossl_quic_demux_release_urxe(port->demux, e);
 }
 
index 63aa9aff8fa1545cdf520aedd65de1d71f40d8e0..666b37f38bd3a01fb2adddda7ce42c5205173b9b 100644 (file)
@@ -173,24 +173,6 @@ struct ossl_qrx_st {
     SSL *msg_callback_ssl;
 };
 
-static RXE *qrx_ensure_free_rxe(OSSL_QRX *qrx, size_t alloc_len);
-static int qrx_validate_hdr_early(OSSL_QRX *qrx, RXE *rxe,
-                                  const QUIC_CONN_ID *first_dcid);
-static int qrx_relocate_buffer(OSSL_QRX *qrx, RXE **prxe, size_t *pi,
-                               const unsigned char **pptr, size_t buf_len);
-static int qrx_validate_hdr(OSSL_QRX *qrx, RXE *rxe);
-static RXE *qrx_reserve_rxe(RXE_LIST *rxl, RXE *rxe, size_t n);
-static int qrx_decrypt_pkt_body(OSSL_QRX *qrx, unsigned char *dst,
-                                const unsigned char *src,
-                                size_t src_len, size_t *dec_len,
-                                const unsigned char *aad, size_t aad_len,
-                                QUIC_PN pn, uint32_t enc_level,
-                                unsigned char key_phase_bit,
-                                uint64_t *rx_key_epoch);
-static int qrx_validate_hdr_late(OSSL_QRX *qrx, RXE *rxe);
-static uint32_t rxe_determine_pn_space(RXE *rxe);
-static void ignore_res(int x);
-
 OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args)
 {
     OSSL_QRX *qrx;
@@ -271,192 +253,6 @@ void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *urxe)
                           qrx->msg_callback_arg);
 }
 
-/*
- * qrx_validate_initial_pkt() is derived from qrx_process_pkt(). Unlike
- * qrx_process_pkt() the qrx_validate_initial_pkt() function can process
- * initial packet only. All other packets should be discarded. This allows
- * port_default_packet_handler() to validate incoming packet. If packet
- * is not valid, then port_default_packet_handler() must discard the
- * packet instead of creating a new channel for it.
- */
-static int qrx_validate_initial_pkt(OSSL_QRX *qrx, QUIC_URXE *urxe,
-                                    const QUIC_CONN_ID *first_dcid,
-                                    size_t datagram_len)
-{
-    PACKET pkt, orig_pkt;
-    RXE *rxe;
-    size_t i = 0, aad_len = 0, dec_len = 0;
-    const unsigned char *sop;
-    unsigned char *dst;
-    QUIC_PKT_HDR_PTRS ptrs;
-    uint32_t pn_space;
-    OSSL_QRL_ENC_LEVEL *el = NULL;
-    uint64_t rx_key_epoch = UINT64_MAX;
-
-    if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(urxe), urxe->data_len))
-        return 0;
-
-    orig_pkt = pkt;
-    sop = PACKET_data(&pkt);
-
-    /*
-     * Get a free RXE. If we need to allocate a new one, use the packet length
-     * as a good ballpark figure.
-     */
-    rxe = qrx_ensure_free_rxe(qrx, PACKET_remaining(&pkt));
-    if (rxe == NULL)
-        return 0;
-
-    /*
-     * we expect INITIAL packet only, therefore it is OK to pass
-     * short_conn_id_len as 0.
-     */
-    if (!ossl_quic_wire_decode_pkt_hdr(&pkt,
-                                       0, /* short_conn_id_len */
-                                       1, /* need second decode */
-                                       0, /* nodata -> want to read data */
-                                       &rxe->hdr, &ptrs,
-                                       NULL))
-        goto malformed;
-
-    if (rxe->hdr.type != QUIC_PKT_TYPE_INITIAL)
-        goto malformed;
-
-    if (!qrx_validate_hdr_early(qrx, rxe, NULL))
-        goto malformed;
-
-    if (ossl_qrl_enc_level_set_have_el(&qrx->el_set, QUIC_ENC_LEVEL_INITIAL) != 1)
-        goto malformed;
-
-    if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL) {
-        const unsigned char *token = rxe->hdr.token;
-
-        /*
-         * This may change the value of rxe and change the value of the token
-         * pointer as well. So we must make a temporary copy of the pointer to
-         * the token, and then copy it back into the new location of the rxe
-         */
-        if (!qrx_relocate_buffer(qrx, &rxe, &i, &token, rxe->hdr.token_len))
-            goto malformed;
-
-        rxe->hdr.token = token;
-    }
-
-    pkt = orig_pkt;
-
-    el = ossl_qrl_enc_level_set_get(&qrx->el_set, QUIC_ENC_LEVEL_INITIAL, 1);
-    assert(el != NULL); /* Already checked above */
-
-    if (!ossl_quic_hdr_protector_decrypt(&el->hpr, &ptrs))
-        goto malformed;
-
-    /*
-     * We have removed header protection, so don't attempt to do it again if
-     * the packet gets deferred and processed again.
-     */
-    pkt_mark(&urxe->hpr_removed, 0);
-
-    /* Decode the now unprotected header. */
-    if (ossl_quic_wire_decode_pkt_hdr(&pkt, 0,
-                                      0, 0, &rxe->hdr, NULL, NULL) != 1)
-        goto malformed;
-
-    /* Validate header and decode PN. */
-    if (!qrx_validate_hdr(qrx, rxe))
-        goto malformed;
-
-    /*
-     * The AAD data is the entire (unprotected) packet header including the PN.
-     * The packet header has been unprotected in place, so we can just reuse the
-     * PACKET buffer. The header ends where the payload begins.
-     */
-    aad_len = rxe->hdr.data - sop;
-
-    /* Ensure the RXE buffer size is adequate for our payload. */
-    if ((rxe = qrx_reserve_rxe(&qrx->rx_free, rxe, rxe->hdr.len + i)) == NULL)
-        goto malformed;
-
-    /*
-     * We decrypt the packet body to immediately after the token at the start of
-     * the RXE buffer (where present).
-     *
-     * Do the decryption from the PACKET (which points into URXE memory) to our
-     * RXE payload (single-copy decryption), then fixup the pointers in the
-     * header to point to our new buffer.
-     *
-     * If decryption fails this is considered a permanent error; we defer
-     * packets we don't yet have decryption keys for above, so if this fails,
-     * something has gone wrong with the handshake process or a packet has been
-     * corrupted.
-     */
-    dst = (unsigned char *)rxe_data(rxe) + i;
-    if (!qrx_decrypt_pkt_body(qrx, dst, rxe->hdr.data, rxe->hdr.len,
-                              &dec_len, sop, aad_len, rxe->pn, QUIC_ENC_LEVEL_INITIAL,
-                              rxe->hdr.key_phase, &rx_key_epoch))
-        goto malformed;
-
-    /*
-     * -----------------------------------------------------
-     *   IMPORTANT: ANYTHING ABOVE THIS LINE IS UNVERIFIED
-     *              AND MUST BE TIMING-CHANNEL SAFE.
-     * -----------------------------------------------------
-     *
-     * At this point, we have successfully authenticated the AEAD tag and no
-     * longer need to worry about exposing the PN, PN length or Key Phase bit in
-     * timing channels. Invoke any configured validation callback to allow for
-     * rejection of duplicate PNs.
-     */
-    if (!qrx_validate_hdr_late(qrx, rxe))
-        goto malformed;
-
-    pkt_mark(&urxe->processed, 0);
-
-    /*
-     * Update header to point to the decrypted buffer, which may be shorter
-     * due to AEAD tags, block padding, etc.
-     */
-    rxe->hdr.data       = dst;
-    rxe->hdr.len        = dec_len;
-    rxe->data_len       = dec_len;
-    rxe->datagram_len   = datagram_len;
-    rxe->key_epoch      = rx_key_epoch;
-
-    /* We processed the PN successfully, so update largest processed PN. */
-    pn_space = rxe_determine_pn_space(rxe);
-    if (rxe->pn > qrx->largest_pn[pn_space])
-        qrx->largest_pn[pn_space] = rxe->pn;
-
-    /* Copy across network addresses and RX time from URXE to RXE. */
-    rxe->peer           = urxe->peer;
-    rxe->local          = urxe->local;
-    rxe->time           = urxe->time;
-    rxe->datagram_id    = urxe->datagram_id;
-
-    /*
-     * The packet is decrypted, we are going to move it from
-     * rx_pending queue where it waits to be further processed
-     * by ch_rx().
-     */
-    ossl_list_rxe_remove(&qrx->rx_free, rxe);
-    ossl_list_rxe_insert_tail(&qrx->rx_pending, rxe);
-
-    return 1;
-
-malformed:
-    /* caller (port_default_packet_handler()) should discard urxe */
-    return 0;
-}
-
-int ossl_qrx_validate_initial_packet(OSSL_QRX *qrx, QUIC_URXE *urxe,
-                                     const QUIC_CONN_ID *dcid)
-{
-    urxe->processed     = 0;
-    urxe->hpr_removed   = 0;
-    urxe->deferred      = 0;
-
-    return qrx_validate_initial_pkt(qrx, urxe, dcid, urxe->data_len);
-}
-
 static void qrx_requeue_deferred(OSSL_QRX *qrx)
 {
     QUIC_URXE *e;