quic: process stateless resets
authorPauli <pauli@openssl.org>
Tue, 1 Aug 2023 23:35:35 +0000 (09:35 +1000)
committerTomas Mraz <tomas@openssl.org>
Wed, 16 Aug 2023 10:07:17 +0000 (12:07 +0200)
Reviewed-by: Hugo Landau <hlandau@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21649)

include/internal/quic_demux.h
include/internal/quic_types.h
include/internal/quic_wire.h
ssl/quic/quic_channel.c
ssl/quic/quic_channel_local.h
ssl/quic/quic_demux.c
ssl/quic/quic_trace.c
ssl/quic/quic_wire.c
test/quic_txp_test.c
test/quic_wire_test.c

index d439fa67be214fec388e71827d22aa1dc6a46aeb..81077425fe02d8693fa82854ad884d96376ba53f 100644 (file)
@@ -178,6 +178,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
@@ -270,6 +278,18 @@ void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux,
                                          ossl_quic_demux_cb_fn *cb,
                                          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;
@@ -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);
 
index bc7c51c49a5bbc95f6adbfd3437afec92173d4ea..f3509da2fbf9ffdc8697d1207a1291c7ed6f809d 100644 (file)
@@ -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.
index f9f80fbc449e82561adbc2db78262bc4f409d691..35fc298ea19b9558108ce1bff64e2d43a5c5ee90 100644 (file)
@@ -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,
index a27e19781beac0a6e4c3836b283cb2d2f2e28afa..f174814a8b3b9139e080527f18e609a42ced3ce3 100644 (file)
@@ -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))
@@ -248,6 +388,13 @@ static int ch_init(QUIC_CHANNEL *ch)
                                          get_time, ch)) == NULL)
         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
@@ -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};
index dd86f390be55599f16a19728cb9a00cd84435e20..ff861f18c7c858905e7604a2fc5aba81460bdb0d 100644 (file)
@@ -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;
index 160bf28168d83bf0619135e5f3cc1447dc021434..bc2cde726b9a5f2885305aab0e2df4761b486df5 100644 (file)
@@ -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. */
index d8811402946e99e50cba30d3c1dd0199afc8500a..51ce7910cd86505c2871a8042231e4b22cf8d51a 100644 (file)
@@ -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;
index 748596d506f5985c74c7c396094201723e5aa86d..0a2130a2d177c7ab19f4393f486e68a7309cc540 100644 (file)
@@ -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;
index fd9e56816e334c583552bf92aa98f903899c5591..e6acd5af80287e0ad803f554b349cce5f31c63bd 100644 (file)
@@ -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)))
index f9c6688d99be97ccacef74d6bcb0a69092f25906..5691be7dd59b2bb0335851de18a26ce738e8026c 100644 (file)
@@ -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
+        }
     }
 };