summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHugo Landau <hlandau@openssl.org>2023-11-09 11:27:13 +0100
committerHugo Landau <hlandau@openssl.org>2023-12-21 09:11:59 +0100
commit6107619899e50b307e9644625a8050de88c603cc (patch)
tree8cbcfe498a2aef6b6393c198031363712c1d3559
parentQUIC PORT: Add SRTM wiring (diff)
downloadopenssl-6107619899e50b307e9644625a8050de88c603cc.tar.xz
openssl-6107619899e50b307e9644625a8050de88c603cc.zip
QUIC PORT: Partially move stateless reset handling to port
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/22674)
-rw-r--r--include/internal/quic_channel.h3
-rw-r--r--ssl/quic/quic_channel.c50
-rw-r--r--ssl/quic/quic_port.c49
3 files changed, 56 insertions, 46 deletions
diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h
index c696f93324..bdc48e5084 100644
--- a/include/internal/quic_channel.h
+++ b/include/internal/quic_channel.h
@@ -273,6 +273,9 @@ void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *r,
/* For use by QUIC_PORT only. */
void ossl_quic_channel_raise_net_error(QUIC_CHANNEL *ch);
+/* For use by QUIC_PORT only. */
+void ossl_quic_channel_on_stateless_reset(QUIC_CHANNEL *ch);
+
/*
* Queries and Accessors
* =====================
diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c
index aa5ea0971e..c363b3bdde 100644
--- a/ssl/quic/quic_channel.c
+++ b/ssl/quic/quic_channel.c
@@ -89,12 +89,10 @@ static int ch_discard_el(QUIC_CHANNEL *ch,
static void ch_on_idle_timeout(QUIC_CHANNEL *ch);
static void ch_update_idle(QUIC_CHANNEL *ch);
static void ch_update_ping_deadline(QUIC_CHANNEL *ch);
-static void ch_stateless_reset(QUIC_CHANNEL *ch);
static void ch_on_terminating_timeout(QUIC_CHANNEL *ch);
static void ch_start_terminating(QUIC_CHANNEL *ch,
const QUIC_TERMINATE_CAUSE *tcause,
int force_immediate);
-static int ch_stateless_reset_token_handler(const unsigned char *data, size_t datalen, void *arg);
static void ch_on_txp_ack_tx(const OSSL_QUIC_FRAME_ACK *ack, uint32_t pn_space,
void *arg);
static void ch_rx_handle_version_neg(QUIC_CHANNEL *ch, OSSL_QRX_PKT *pkt);
@@ -208,47 +206,6 @@ static void chan_remove_reset_token(QUIC_CHANNEL *ch, uint64_t seq_num)
}
/*
- * This is called by the demux whenever a new datagram arrives
- *
- * TODO(QUIC FUTURE): optimise this to only be called for unparsable packets
- */
-static int ossl_unused ch_stateless_reset_token_handler(const unsigned char *data,
- size_t datalen, void *arg)
-{
- QUIC_SRT_ELEM srte;
- QUIC_CHANNEL *ch = (QUIC_CHANNEL *)arg;
-
- /*
- * Perform some fast and cheap checks for a packet not being a stateless
- * reset token. RFC 9000 s. 10.3 specifies this layout for stateless
- * reset packets:
- *
- * Stateless Reset {
- * Fixed Bits (2) = 1,
- * Unpredictable Bits (38..),
- * Stateless Reset Token (128),
- * }
- *
- * It also specifies:
- * However, endpoints MUST treat any packet ending in a valid
- * stateless reset token as a Stateless Reset, as other QUIC
- * versions might allow the use of a long header.
- *
- * We can rapidly check for the minimum length and that the first pair
- * of bits in the first byte are 01 or 11.
- *
- * The function returns 1 if it is a stateless reset packet, 0 if it isn't
- * and -1 if an error was encountered.
- */
- if (datalen < QUIC_STATELESS_RESET_TOKEN_LEN + 5 || (0100 & *data) != 0100)
- return 0;
- memset(&srte, 0, sizeof(srte));
- if (!reset_token_obfuscate(&srte, data + datalen - sizeof(srte.token)))
- return -1;
- return lh_QUIC_SRT_ELEM_retrieve(ch->srt_hash_tok, &srte) != NULL;
-}
-
-/*
* QUIC Channel Initialization and Teardown
* ========================================
*/
@@ -3072,12 +3029,13 @@ static void ch_save_err_state(QUIC_CHANNEL *ch)
OSSL_ERR_STATE_save(ch->err_state);
}
-static void ossl_unused ch_stateless_reset(QUIC_CHANNEL *ch)
+void ossl_quic_channel_on_stateless_reset(QUIC_CHANNEL *ch)
{
QUIC_TERMINATE_CAUSE tcause = {0};
- tcause.error_code = QUIC_ERR_NO_ERROR;
- ch_start_terminating(ch, &tcause, 1);
+ tcause.error_code = QUIC_ERR_NO_ERROR;
+ tcause.remote = 1;
+ ch_start_terminating(ch, &tcause, 0);
}
void ossl_quic_channel_raise_net_error(QUIC_CHANNEL *ch)
diff --git a/ssl/quic/quic_port.c b/ssl/quic/quic_port.c
index b128477c0a..bf351e923c 100644
--- a/ssl/quic/quic_port.c
+++ b/ssl/quic/quic_port.c
@@ -381,6 +381,52 @@ static void port_on_new_conn(QUIC_PORT *port, const BIO_ADDR *peer,
}
}
+static int port_try_handle_stateless_reset(QUIC_PORT *port, const QUIC_URXE *e)
+{
+ size_t i;
+ const unsigned char *data = ossl_quic_urxe_data(e);
+ void *opaque = NULL;
+
+ /*
+ * Perform some fast and cheap checks for a packet not being a stateless
+ * reset token. RFC 9000 s. 10.3 specifies this layout for stateless
+ * reset packets:
+ *
+ * Stateless Reset {
+ * Fixed Bits (2) = 1,
+ * Unpredictable Bits (38..),
+ * Stateless Reset Token (128),
+ * }
+ *
+ * It also specifies:
+ * However, endpoints MUST treat any packet ending in a valid
+ * stateless reset token as a Stateless Reset, as other QUIC
+ * versions might allow the use of a long header.
+ *
+ * We can rapidly check for the minimum length and that the first pair
+ * of bits in the first byte are 01 or 11.
+ *
+ * The function returns 1 if it is a stateless reset packet, 0 if it isn't
+ * and -1 if an error was encountered.
+ */
+ if (e->data_len < QUIC_STATELESS_RESET_TOKEN_LEN + 5
+ || (0100 & *data) != 0100)
+ return 0;
+
+ for (i = 0;; ++i) {
+ if (!ossl_quic_srtm_lookup(port->srtm,
+ (QUIC_STATELESS_RESET_TOKEN *)(data + e->data_len
+ - sizeof(QUIC_STATELESS_RESET_TOKEN)),
+ i, &opaque, NULL))
+ break;
+
+ assert(opaque != NULL);
+ ossl_quic_channel_on_stateless_reset((QUIC_CHANNEL *)opaque);
+ }
+
+ return i > 0;
+}
+
/*
* This is called by the demux when we get a packet not destined for any known
* DCID.
@@ -392,6 +438,9 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg)
QUIC_PKT_HDR hdr;
QUIC_CHANNEL *new_ch = NULL;
+ if (port_try_handle_stateless_reset(port, e))
+ goto undesirable;
+
// TODO review this
if (port->tserver_ch == NULL)
goto undesirable;