aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPauli <pauli@openssl.org>2023-08-02 09:35:35 +1000
committerTomas Mraz <tomas@openssl.org>2023-08-16 12:07:17 +0200
commitcdd916313a89def99493e00b49958ced894ca209 (patch)
tree5cb1b4690011d15d974d3a820955cbf050468f79
parent945fde53a3db5011940a059fd1407b81197c9e14 (diff)
downloadopenssl-cdd916313a89def99493e00b49958ced894ca209.tar.gz
quic: process stateless resets
Reviewed-by: Hugo Landau <hlandau@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/21649)
-rw-r--r--include/internal/quic_demux.h21
-rw-r--r--include/internal/quic_types.h4
-rw-r--r--include/internal/quic_wire.h16
-rw-r--r--ssl/quic/quic_channel.c196
-rw-r--r--ssl/quic/quic_channel_local.h33
-rw-r--r--ssl/quic/quic_demux.c53
-rw-r--r--ssl/quic/quic_trace.c3
-rw-r--r--ssl/quic/quic_wire.c12
-rw-r--r--test/quic_txp_test.c4
-rw-r--r--test/quic_wire_test.c20
10 files changed, 326 insertions, 36 deletions
diff --git a/include/internal/quic_demux.h b/include/internal/quic_demux.h
index d439fa67be..81077425fe 100644
--- a/include/internal/quic_demux.h
+++ b/include/internal/quic_demux.h
@@ -179,6 +179,14 @@ typedef struct quic_demux_st QUIC_DEMUX;
typedef void (ossl_quic_demux_cb_fn)(QUIC_URXE *e, void *arg);
/*
+ * Called when a datagram is received.
+ * Returns 1 if the datagram ends with a stateless reset token and
+ * 0 if not.
+ */
+typedef int (ossl_quic_stateless_reset_cb_fn)(const unsigned char *data,
+ size_t data_len, void *arg);
+
+/*
* Creates a new demuxer. The given BIO is used to receive datagrams from the
* network using BIO_recvmmsg. short_conn_id_len is the length of destination
* connection IDs used in RX'd packets; it must have the same value for all
@@ -271,6 +279,18 @@ void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
void *cb_arg);
/*
+ * Sets a callback for stateless reset processing.
+ *
+ * If set, this callback is called for datagrams for which we cannot identify
+ * a CID. This function should return 1 if there is a stateless reset token
+ * present and 0 if not. If there is a token present, the connection should
+ * also be reset.
+ */
+void ossl_quic_demux_set_stateless_reset_handler(
+ QUIC_DEMUX *demux,
+ ossl_quic_stateless_reset_cb_fn *cb, void *cb_arg);
+
+/*
* Releases a URXE back to the demuxer. No reference must be made to the URXE or
* its buffer after calling this function. The URXE must not be in any queue;
* that is, its prev and next pointers must be NULL.
@@ -315,6 +335,7 @@ void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux,
#define QUIC_DEMUX_PUMP_RES_OK 1
#define QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL (-1)
#define QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL (-2)
+#define QUIC_DEMUX_PUMP_RES_STATELESS_RESET (-3)
int ossl_quic_demux_pump(QUIC_DEMUX *demux);
diff --git a/include/internal/quic_types.h b/include/internal/quic_types.h
index bc7c51c49a..f3509da2fb 100644
--- a/include/internal/quic_types.h
+++ b/include/internal/quic_types.h
@@ -100,6 +100,10 @@ static ossl_unused ossl_inline int ossl_quic_conn_id_eq(const QUIC_CONN_ID *a,
# define QUIC_STATELESS_RESET_TOKEN_LEN 16
+typedef struct {
+ unsigned char token[QUIC_STATELESS_RESET_TOKEN_LEN];
+} QUIC_STATELESS_RESET_TOKEN;
+
/*
* An encoded preferred_addr transport parameter cannot be shorter or longer
* than these lengths in bytes.
diff --git a/include/internal/quic_wire.h b/include/internal/quic_wire.h
index f9f80fbc44..35fc298ea1 100644
--- a/include/internal/quic_wire.h
+++ b/include/internal/quic_wire.h
@@ -208,10 +208,10 @@ typedef struct ossl_quic_frame_stop_sending_st {
/* QUIC Frame: NEW_CONNECTION_ID */
typedef struct ossl_quic_frame_new_conn_id_st {
- uint64_t seq_num;
- uint64_t retire_prior_to;
- QUIC_CONN_ID conn_id;
- unsigned char stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
+ uint64_t seq_num;
+ uint64_t retire_prior_to;
+ QUIC_CONN_ID conn_id;
+ QUIC_STATELESS_RESET_TOKEN stateless_reset;
} OSSL_QUIC_FRAME_NEW_CONN_ID;
/* QUIC Frame: CONNECTION_CLOSE */
@@ -770,10 +770,10 @@ int ossl_quic_wire_decode_transport_param_cid(PACKET *pkt,
* Decodes a QUIC transport parameter TLV containing a preferred_address.
*/
typedef struct quic_preferred_addr_st {
- uint16_t ipv4_port, ipv6_port;
- unsigned char ipv4[4], ipv6[16];
- unsigned char stateless_reset_token[QUIC_STATELESS_RESET_TOKEN_LEN];
- QUIC_CONN_ID cid;
+ uint16_t ipv4_port, ipv6_port;
+ unsigned char ipv4[4], ipv6[16];
+ QUIC_STATELESS_RESET_TOKEN stateless_reset;
+ QUIC_CONN_ID cid;
} QUIC_PREFERRED_ADDR;
int ossl_quic_wire_decode_transport_param_preferred_addr(PACKET *pkt,
diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c
index a27e19781b..f174814a8b 100644
--- a/ssl/quic/quic_channel.c
+++ b/ssl/quic/quic_channel.c
@@ -86,11 +86,13 @@ 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_raise_net_error(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_default_packet_handler(QUIC_URXE *e, void *arg);
static int ch_server_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
const QUIC_CONN_ID *peer_scid,
@@ -98,6 +100,8 @@ static int ch_server_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer,
static void ch_on_txp_ack_tx(const OSSL_QUIC_FRAME_ACK *ack, uint32_t pn_space,
void *arg);
+DEFINE_LHASH_OF_EX(QUIC_SRT_ELEM);
+
static int gen_rand_conn_id(OSSL_LIB_CTX *libctx, size_t len, QUIC_CONN_ID *cid)
{
if (len > QUIC_MAX_CONN_ID_LEN)
@@ -113,6 +117,136 @@ static int gen_rand_conn_id(OSSL_LIB_CTX *libctx, size_t len, QUIC_CONN_ID *cid)
return 1;
}
+static unsigned long chan_reset_token_hash(const QUIC_SRT_ELEM *a)
+{
+ unsigned long h;
+
+ assert(sizeof(h) <= sizeof(a->token));
+ memcpy(&h, &a->token, sizeof(h));
+ return h;
+}
+
+static int chan_reset_token_cmp(const QUIC_SRT_ELEM *a, const QUIC_SRT_ELEM *b)
+{
+ /* RFC 9000 s. 10.3.1:
+ * When comparing a datagram to stateless reset token values,
+ * endpoints MUST perform the comparison without leaking
+ * information about the value of the token. For example,
+ * performing this comparison in constant time protects the
+ * value of individual stateless reset tokens from information
+ * leakage through timing side channels.
+ *
+ * TODO(QUIC FUTURE): make this a memcmp when obfuscation is done and update
+ * comment above.
+ */
+ return CRYPTO_memcmp(&a->token, &b->token, sizeof(a->token));
+}
+
+static int reset_token_obfuscate(QUIC_SRT_ELEM *out, const unsigned char *in)
+{
+ /*
+ * TODO(QUIC FUTURE): update this to AES encrypt the token in ECB mode with a
+ * random (per channel) key.
+ */
+ memcpy(&out->token, in, sizeof(out->token));
+ return 1;
+}
+
+/*
+ * Add a stateless reset token to the channel
+ */
+static int chan_add_reset_token(QUIC_CHANNEL *ch, const unsigned char *new,
+ uint64_t seq_num)
+{
+ QUIC_SRT_ELEM *srte;
+ int err;
+
+ /* Add to list by sequence number (always the tail) */
+ if ((srte = OPENSSL_malloc(sizeof(*srte))) == NULL)
+ return 0;
+
+ ossl_list_stateless_reset_tokens_init_elem(srte);
+ ossl_list_stateless_reset_tokens_insert_tail(&ch->srt_list_seq, srte);
+ reset_token_obfuscate(srte, new);
+ srte->seq_num = seq_num;
+
+ lh_QUIC_SRT_ELEM_insert(ch->srt_hash_tok, srte);
+ err = lh_QUIC_SRT_ELEM_error(ch->srt_hash_tok);
+ if (err > 0) {
+ ossl_list_stateless_reset_tokens_remove(&ch->srt_list_seq, srte);
+ OPENSSL_free(srte);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * Remove a stateless reset token from the channel
+ * If the token isn't known, we just ignore the remove request which is safe.
+ */
+static void chan_remove_reset_token(QUIC_CHANNEL *ch, uint64_t seq_num)
+{
+ QUIC_SRT_ELEM *srte;
+
+ /*
+ * Because the list is ordered and we only ever remove CIDs in order,
+ * this loop should never iterate, but safer to provide the option.
+ */
+ for (srte = ossl_list_stateless_reset_tokens_head(&ch->srt_list_seq);
+ srte != NULL;
+ srte = ossl_list_stateless_reset_tokens_next(srte)) {
+ if (srte->seq_num > seq_num)
+ return;
+ if (srte->seq_num == seq_num) {
+ ossl_list_stateless_reset_tokens_remove(&ch->srt_list_seq, srte);
+ (void)lh_QUIC_SRT_ELEM_delete(ch->srt_hash_tok, srte);
+ OPENSSL_free(srte);
+ return;
+ }
+ }
+}
+
+/*
+ * 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 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
* ========================================
@@ -134,6 +268,12 @@ static int ch_init(QUIC_CHANNEL *ch)
uint32_t pn_space;
size_t rx_short_cid_len = ch->is_server ? INIT_DCID_LEN : 0;
+ ossl_list_stateless_reset_tokens_init(&ch->srt_list_seq);
+ ch->srt_hash_tok = lh_QUIC_SRT_ELEM_new(&chan_reset_token_hash,
+ &chan_reset_token_cmp);
+ if (ch->srt_hash_tok == NULL)
+ goto err;
+
/* For clients, generate our initial DCID. */
if (!ch->is_server
&& !gen_rand_conn_id(ch->libctx, INIT_DCID_LEN, &ch->init_dcid))
@@ -249,6 +389,13 @@ static int ch_init(QUIC_CHANNEL *ch)
goto err;
/*
+ * Setup a handler to detect stateless reset tokens.
+ */
+ ossl_quic_demux_set_stateless_reset_handler(ch->demux,
+ &ch_stateless_reset_token_handler,
+ ch);
+
+ /*
* If we are a server, setup our handler for packets not corresponding to
* any known DCID on our end. This is for handling clients establishing new
* connections.
@@ -338,6 +485,7 @@ err:
static void ch_cleanup(QUIC_CHANNEL *ch)
{
+ QUIC_SRT_ELEM *srte, *srte_next;
uint32_t pn_space;
if (ch->ackm != NULL)
@@ -373,6 +521,17 @@ static void ch_cleanup(QUIC_CHANNEL *ch)
OPENSSL_free(ch->local_transport_params);
OPENSSL_free((char *)ch->terminate_cause.reason);
OSSL_ERR_STATE_free(ch->err_state);
+
+ /* Free the stateless reset tokens */
+ for (srte = ossl_list_stateless_reset_tokens_head(&ch->srt_list_seq);
+ srte != NULL;
+ srte = srte_next) {
+ srte_next = ossl_list_stateless_reset_tokens_next(srte);
+ ossl_list_stateless_reset_tokens_remove(&ch->srt_list_seq, srte);
+ (void)lh_QUIC_SRT_ELEM_delete(ch->srt_hash_tok, srte);
+ OPENSSL_free(srte);
+ }
+ lh_QUIC_SRT_ELEM_free(ch->srt_hash_tok);
}
QUIC_CHANNEL *ossl_quic_channel_new(const QUIC_CHANNEL_ARGS *args)
@@ -1047,6 +1206,8 @@ static int ch_on_handshake_alert(void *arg, unsigned char alert_code)
x " sent when not performing a retry"
#define TP_REASON_REQUIRED(x) \
x " was not sent but is required"
+#define TP_REASON_INTERNAL_ERROR(x) \
+ x " encountered internal error"
static void txfc_bump_cwm_bidi(QUIC_STREAM *s, void *arg)
{
@@ -1392,10 +1553,11 @@ static int ch_on_transport_params(const unsigned char *params,
break;
case QUIC_TPARAM_STATELESS_RESET_TOKEN:
- /* TODO(QUIC): Handle stateless reset tokens. */
/*
- * We ignore these for now, but we must ensure a client doesn't
- * send them.
+ * We must ensure a client doesn't send them because we don't have
+ * processing for them.
+ *
+ * TODO(QUIC SERVER): remove this restriction
*/
if (ch->is_server) {
reason = TP_REASON_SERVER_ONLY("STATELESS_RESET_TOKEN");
@@ -1407,6 +1569,10 @@ static int ch_on_transport_params(const unsigned char *params,
reason = TP_REASON_MALFORMED("STATELESS_RESET_TOKEN");
goto malformed;
}
+ if (!chan_add_reset_token(ch, body, ch->cur_remote_seq_num)) {
+ reason = TP_REASON_INTERNAL_ERROR("STATELESS_RESET_TOKEN");
+ goto malformed;
+ }
break;
@@ -1793,7 +1959,9 @@ static void ch_rx_pre(QUIC_CHANNEL *ch)
* to the appropriate QRX instance.
*/
ret = ossl_quic_demux_pump(ch->demux);
- if (ret == QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL)
+ if (ret == QUIC_DEMUX_PUMP_RES_STATELESS_RESET)
+ ch_stateless_reset(ch);
+ else if (ret == QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL)
/*
* We don't care about transient failure, but permanent failure means we
* should tear down the connection as though a protocol violation
@@ -2798,6 +2966,8 @@ static int ch_enqueue_retire_conn_id(QUIC_CHANNEL *ch, uint64_t seq_num)
WPACKET wpkt;
size_t l;
+ chan_remove_reset_token(ch, seq_num);
+
if ((buf_mem = BUF_MEM_new()) == NULL)
return 0;
@@ -2900,6 +3070,16 @@ void ossl_quic_channel_on_new_conn_id(QUIC_CHANNEL *ch,
}
if (new_remote_seq_num > ch->cur_remote_seq_num) {
+ /* Add new stateless reset token */
+ if (!chan_add_reset_token(ch, f->stateless_reset.token,
+ new_remote_seq_num)) {
+ ossl_quic_channel_raise_protocol_error(
+ ch, QUIC_ERR_CONNECTION_ID_LIMIT_ERROR,
+ OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID,
+ "unable to store stateless reset token");
+
+ return;
+ }
ch->cur_remote_seq_num = new_remote_seq_num;
ch->cur_remote_dcid = f->conn_id;
ossl_quic_tx_packetiser_set_cur_dcid(ch->txp, &ch->cur_remote_dcid);
@@ -2943,6 +3123,14 @@ static void ch_save_err_state(QUIC_CHANNEL *ch)
OSSL_ERR_STATE_save(ch->err_state);
}
+static void ch_stateless_reset(QUIC_CHANNEL *ch)
+{
+ QUIC_TERMINATE_CAUSE tcause = {0};
+
+ tcause.error_code = QUIC_ERR_NO_ERROR;
+ ch_start_terminating(ch, &tcause, 1);
+}
+
static void ch_raise_net_error(QUIC_CHANNEL *ch)
{
QUIC_TERMINATE_CAUSE tcause = {0};
diff --git a/ssl/quic/quic_channel_local.h b/ssl/quic/quic_channel_local.h
index dd86f390be..ff861f18c7 100644
--- a/ssl/quic/quic_channel_local.h
+++ b/ssl/quic/quic_channel_local.h
@@ -5,6 +5,20 @@
# ifndef OPENSSL_NO_QUIC
+# include <openssl/lhash.h>
+# include "internal/list.h"
+
+
+typedef struct quic_srt_elem_st QUIC_SRT_ELEM;
+
+struct quic_srt_elem_st {
+ OSSL_LIST_MEMBER(stateless_reset_tokens, QUIC_SRT_ELEM);
+ QUIC_STATELESS_RESET_TOKEN token;
+ uint64_t seq_num;
+};
+
+DEFINE_LIST_OF(stateless_reset_tokens, QUIC_SRT_ELEM);
+
/*
* QUIC Channel Structure
* ======================
@@ -127,13 +141,30 @@ struct quic_channel_st {
*/
QUIC_CONN_ID retry_scid;
- /* The DCID we currently use to talk to the peer and its sequence num. */
+ /*
+ * The DCID we currently use to talk to the peer and its sequence num.
+ *
+ * TODO(QUIC FUTURE) consider removing the second two, both are contained in
+ * srt_list_seq (defined below).
+ *
+ * cur_remote_seq_num is same as the sequence number in the last element.
+ * cur_retire_prior_to corresponds to the sequence number in first element.
+ *
+ * Leaving them here avoids null checking etc
+ */
QUIC_CONN_ID cur_remote_dcid;
uint64_t cur_remote_seq_num;
uint64_t cur_retire_prior_to;
+
/* Server only: The DCID we currently expect the peer to use to talk to us. */
QUIC_CONN_ID cur_local_cid;
+ /* Hash of stateless reset tokens keyed on the token */
+ LHASH_OF(QUIC_SRT_ELEM) *srt_hash_tok;
+
+ /* List of the stateless reset tokens ordered by sequence number */
+ OSSL_LIST(stateless_reset_tokens) srt_list_seq;
+
/* Transport parameter values we send to our peer. */
uint64_t tx_init_max_stream_data_bidi_local;
uint64_t tx_init_max_stream_data_bidi_remote;
diff --git a/ssl/quic/quic_demux.c b/ssl/quic/quic_demux.c
index 160bf28168..bc2cde726b 100644
--- a/ssl/quic/quic_demux.c
+++ b/ssl/quic/quic_demux.c
@@ -80,6 +80,10 @@ struct quic_demux_st {
ossl_quic_demux_cb_fn *default_cb;
void *default_cb_arg;
+ /* The stateless reset token checker handler, if any. */
+ ossl_quic_stateless_reset_cb_fn *reset_token_cb;
+ void *reset_token_cb_arg;
+
/*
* List of URXEs which are not currently in use (i.e., not filled with
* unconsumed data). These are moved to the pending list as they are filled.
@@ -297,6 +301,14 @@ void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
demux->default_cb_arg = cb_arg;
}
+void ossl_quic_demux_set_stateless_reset_handler(
+ QUIC_DEMUX *demux,
+ ossl_quic_stateless_reset_cb_fn *cb, void *cb_arg)
+{
+ demux->reset_token_cb = cb;
+ demux->reset_token_cb_arg = cb_arg;
+}
+
static QUIC_URXE *demux_alloc_urxe(size_t alloc_len)
{
QUIC_URXE *e;
@@ -483,10 +495,14 @@ static QUIC_DEMUX_CONN *demux_identify_conn(QUIC_DEMUX *demux, QUIC_URXE *e)
return demux_get_by_conn_id(demux, &dst_conn_id);
}
-/* Process a single pending URXE. */
+/*
+ * Process a single pending URXE.
+ * Returning 1 on success, 0 on failure and -1 on stateless reset.
+ */
static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
{
QUIC_DEMUX_CONN *conn;
+ int r;
/* The next URXE we process should be at the head of the pending list. */
if (!ossl_assert(e == ossl_list_urxe_head(&demux->urx_pending)))
@@ -494,6 +510,29 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
assert(e->demux_state == URXE_DEMUX_STATE_PENDING);
+ /*
+ * Check if the packet ends with a stateless reset token and if it does
+ * skip it after dropping the connection.
+ *
+ * RFC 9000 s. 10.3.1 Detecting a Stateless Reset
+ * If the last 16 bytes of the datagram are identical in value to
+ * a stateless reset token, the endpoint MUST enter the draining
+ * period and not send any further packets on this connection.
+ *
+ * Returning a failure here causes the connection to enter the terminating
+ * state which achieves the desired outcome.
+ *
+ * TODO(QUIC FUTURE): only try to match unparsable packets
+ */
+ if (demux->reset_token_cb != NULL) {
+ r = demux->reset_token_cb(ossl_quic_urxe_data(e), e->data_len,
+ demux->reset_token_cb_arg);
+ if (r > 0) /* Received a stateless reset */
+ return -1;
+ if (r < 0) /* Error during stateless reset detection */
+ return 0;
+ }
+
conn = demux_identify_conn(demux, e);
if (conn == NULL) {
/*
@@ -528,10 +567,11 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e)
static int demux_process_pending_urxl(QUIC_DEMUX *demux)
{
QUIC_URXE *e;
+ int ret;
while ((e = ossl_list_urxe_head(&demux->urx_pending)) != NULL)
- if (!demux_process_pending_urxe(demux, e))
- return 0;
+ if ((ret = demux_process_pending_urxe(demux, e)) <= 0)
+ return ret;
return 1;
}
@@ -559,8 +599,9 @@ int ossl_quic_demux_pump(QUIC_DEMUX *demux)
assert(ossl_list_urxe_head(&demux->urx_pending) != NULL);
}
- if (!demux_process_pending_urxl(demux))
- return QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL;
+ if ((ret = demux_process_pending_urxl(demux)) <= 0)
+ return ret == 0 ? QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL
+ : QUIC_DEMUX_PUMP_RES_STATELESS_RESET;
return QUIC_DEMUX_PUMP_RES_OK;
}
@@ -608,7 +649,7 @@ int ossl_quic_demux_inject(QUIC_DEMUX *demux,
ossl_list_urxe_insert_tail(&demux->urx_pending, urxe);
urxe->demux_state = URXE_DEMUX_STATE_PENDING;
- return demux_process_pending_urxl(demux);
+ return demux_process_pending_urxl(demux) > 0;
}
/* Called by our user to return a URXE to the free list. */
diff --git a/ssl/quic/quic_trace.c b/ssl/quic/quic_trace.c
index d881140294..51ce7910cd 100644
--- a/ssl/quic/quic_trace.c
+++ b/ssl/quic/quic_trace.c
@@ -330,7 +330,8 @@ static int frame_new_conn_id(BIO *bio, PACKET *pkt)
BIO_puts(bio, " Connection id: ");
put_conn_id(bio, &frame_data.conn_id);
BIO_puts(bio, "\n Stateless Reset Token: ");
- put_data(bio, frame_data.stateless_reset_token, 16);
+ put_data(bio, frame_data.stateless_reset.token,
+ sizeof(frame_data.stateless_reset.token));
BIO_puts(bio, "\n");
return 1;
diff --git a/ssl/quic/quic_wire.c b/ssl/quic/quic_wire.c
index 748596d506..0a2130a2d1 100644
--- a/ssl/quic/quic_wire.c
+++ b/ssl/quic/quic_wire.c
@@ -328,8 +328,8 @@ int ossl_quic_wire_encode_frame_new_conn_id(WPACKET *pkt,
|| !WPACKET_quic_write_vlint(pkt, f->retire_prior_to)
|| !WPACKET_put_bytes_u8(pkt, f->conn_id.id_len)
|| !WPACKET_memcpy(pkt, f->conn_id.id, f->conn_id.id_len)
- || !WPACKET_memcpy(pkt, f->stateless_reset_token,
- sizeof(f->stateless_reset_token)))
+ || !WPACKET_memcpy(pkt, f->stateless_reset.token,
+ sizeof(f->stateless_reset.token)))
return 0;
return 1;
@@ -804,8 +804,8 @@ int ossl_quic_wire_decode_frame_new_conn_id(PACKET *pkt,
if (len < QUIC_MAX_CONN_ID_LEN)
memset(f->conn_id.id + len, 0, QUIC_MAX_CONN_ID_LEN - len);
- if (!PACKET_copy_bytes(pkt, f->stateless_reset_token,
- sizeof(f->stateless_reset_token)))
+ if (!PACKET_copy_bytes(pkt, f->stateless_reset.token,
+ sizeof(f->stateless_reset.token)))
return 0;
return 1;
@@ -983,8 +983,8 @@ int ossl_quic_wire_decode_transport_param_preferred_addr(PACKET *pkt,
|| !PACKET_get_1(&pkt2, &cidl)
|| cidl > QUIC_MAX_CONN_ID_LEN
|| !PACKET_copy_bytes(&pkt2, p->cid.id, cidl)
- || !PACKET_copy_bytes(&pkt2, p->stateless_reset_token,
- sizeof(p->stateless_reset_token)))
+ || !PACKET_copy_bytes(&pkt2, p->stateless_reset.token,
+ sizeof(p->stateless_reset.token)))
return 0;
p->ipv4_port = (uint16_t)ipv4_port;
diff --git a/test/quic_txp_test.c b/test/quic_txp_test.c
index fd9e56816e..e6acd5af80 100644
--- a/test/quic_txp_test.c
+++ b/test/quic_txp_test.c
@@ -403,7 +403,7 @@ static int schedule_cfq_new_conn_id(struct helper *h)
ncid.seq_num = 2345;
ncid.retire_prior_to = 1234;
ncid.conn_id = cid_1;
- memcpy(ncid.stateless_reset_token, reset_token_1, sizeof(reset_token_1));
+ memcpy(ncid.stateless_reset.token, reset_token_1, sizeof(reset_token_1));
if (!TEST_ptr(buf_mem = BUF_MEM_new()))
goto err;
@@ -442,7 +442,7 @@ static int check_cfq_new_conn_id(struct helper *h)
|| !TEST_uint64_t_eq(h->frame.new_conn_id.retire_prior_to, 1234)
|| !TEST_mem_eq(&h->frame.new_conn_id.conn_id, sizeof(cid_1),
&cid_1, sizeof(cid_1))
- || !TEST_mem_eq(&h->frame.new_conn_id.stateless_reset_token,
+ || !TEST_mem_eq(&h->frame.new_conn_id.stateless_reset.token,
sizeof(reset_token_1),
reset_token_1,
sizeof(reset_token_1)))
diff --git a/test/quic_wire_test.c b/test/quic_wire_test.c
index f9c6688d99..5691be7dd5 100644
--- a/test/quic_wire_test.c
+++ b/test/quic_wire_test.c
@@ -746,8 +746,10 @@ static const OSSL_QUIC_FRAME_NEW_CONN_ID encode_case_16_f = {
{0x33, 0x44, 0x55, 0x66}
},
{
- 0xde, 0x06, 0xcb, 0x76, 0x5d, 0xb1, 0xa7, 0x71,
- 0x78, 0x09, 0xbb, 0xe8, 0x50, 0x19, 0x12, 0x9a
+ {
+ 0xde, 0x06, 0xcb, 0x76, 0x5d, 0xb1, 0xa7, 0x71,
+ 0x78, 0x09, 0xbb, 0xe8, 0x50, 0x19, 0x12, 0x9a
+ }
}
};
@@ -783,10 +785,10 @@ static int encode_case_16_dec(PACKET *pkt, ossl_ssize_t fail)
encode_case_16_conn_id, sizeof(encode_case_16_conn_id)))
return 0;
- if (!TEST_mem_eq(f.stateless_reset_token,
- sizeof(f.stateless_reset_token),
- encode_case_16_f.stateless_reset_token,
- sizeof(encode_case_16_f.stateless_reset_token)))
+ if (!TEST_mem_eq(f.stateless_reset.token,
+ sizeof(f.stateless_reset.token),
+ encode_case_16_f.stateless_reset.token,
+ sizeof(encode_case_16_f.stateless_reset.token)))
return 0;
return 1;
@@ -811,8 +813,10 @@ static const OSSL_QUIC_FRAME_NEW_CONN_ID encode_case_16b_f = {
{0x33, 0x44, 0x55, 0x66}
},
{
- 0xde, 0x06, 0xcb, 0x76, 0x5d, 0xb1, 0xa7, 0x71,
- 0x78, 0x09, 0xbb, 0xe8, 0x50, 0x19, 0x12, 0x9a
+ {
+ 0xde, 0x06, 0xcb, 0x76, 0x5d, 0xb1, 0xa7, 0x71,
+ 0x78, 0x09, 0xbb, 0xe8, 0x50, 0x19, 0x12, 0x9a
+ }
}
};