]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add new token generation transmission
authorNeil Horman <nhorman@openssl.org>
Sun, 12 Jan 2025 03:16:16 +0000 (22:16 -0500)
committerNeil Horman <nhorman@openssl.org>
Mon, 17 Feb 2025 16:27:33 +0000 (11:27 -0500)
When we bind a channel, create a NEW_TOKEN token to be sent on the next
available datagram, once the channel is validated

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Saša Nedvědický <sashan@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/26517)

include/internal/quic_channel.h
ssl/quic/quic_channel.c
ssl/quic/quic_port.c

index c426cfad68da58b689abef2d339ad061f18abe2b..852551e56242a32e3a1ce2667e375037aa0d3ca4 100644 (file)
@@ -210,6 +210,13 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch);
 void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code,
                                    const char *app_reason);
 
+/**
+ * @brief schedules a NEW_TOKEN frame for sending on the channel
+ */
+int ossl_quic_channel_schedule_new_token(QUIC_CHANNEL *ch,
+                                         const unsigned char *token,
+                                         size_t token_len);
+
 /*
  * Called when the handshake is confirmed.
  */
index 19d0513059d40039e1e0ab934d8a66e603b700a6..3c13437bb54a25886bc1cbb7dd9f1116b2312026 100644 (file)
@@ -517,6 +517,55 @@ SSL *ossl_quic_channel_get0_tls(QUIC_CHANNEL *ch)
     return ch->tls;
 }
 
+static void free_buf_mem(unsigned char *buf, size_t buf_len, void *arg)
+{
+    BUF_MEM_free((BUF_MEM *)arg);
+}
+
+int ossl_quic_channel_schedule_new_token(QUIC_CHANNEL *ch,
+                                         const unsigned char *token,
+                                         size_t token_len)
+{
+    int rc = 0;
+    QUIC_CFQ_ITEM *cfq_item;
+    WPACKET wpkt;
+    BUF_MEM *buf_mem = NULL;
+    size_t l = 0;
+
+    buf_mem = BUF_MEM_new();
+    if (buf_mem == NULL)
+        goto err;
+
+    if (!WPACKET_init(&wpkt, buf_mem))
+        goto err;
+
+    if (!ossl_quic_wire_encode_frame_new_token(&wpkt, token,
+                                               token_len)) {
+        WPACKET_cleanup(&wpkt);
+        goto err;
+    }
+
+    WPACKET_finish(&wpkt);
+
+    if (!WPACKET_get_total_written(&wpkt, &l))
+        goto err;
+
+    cfq_item = ossl_quic_cfq_add_frame(ch->cfq, 1,
+                                       QUIC_PN_SPACE_APP,
+                                       OSSL_QUIC_FRAME_TYPE_NEW_TOKEN, 0,
+                                       (unsigned char *)buf_mem->data, l,
+                                       free_buf_mem,
+                                       buf_mem);
+    if (cfq_item == NULL)
+        goto err;
+
+    rc = 1;
+err:
+    if (!rc)
+        BUF_MEM_free(buf_mem);
+    return rc;
+}
+
 QUIC_STREAM *ossl_quic_channel_get_stream_by_id(QUIC_CHANNEL *ch,
                                                 uint64_t stream_id)
 {
index 863ff2f6d7c1efee11dbb6adac847e1ce0bd89fd..da658c8a5bef8245d9b1e249b7508d51bc7075b5 100644 (file)
@@ -794,7 +794,8 @@ static void cleanup_validation_token(QUIC_VALIDATION_TOKEN *token)
 }
 
 /**
- * @brief Generates a validation token for a RETRY packet.
+ * @brief Generates a validation token for a RETRY/NEW_TOKEN packet.
+ *
  *
  * @param peer  Address of the client peer receiving the packet.
  * @param odcid DCID of the connection attempt.
@@ -803,10 +804,11 @@ static void cleanup_validation_token(QUIC_VALIDATION_TOKEN *token)
  *
  * @return 1 if validation token is filled successfully, 0 otherwise.
  */
-static int generate_retry_token(BIO_ADDR *peer, QUIC_CONN_ID odcid,
-                                QUIC_CONN_ID rscid, QUIC_VALIDATION_TOKEN *token)
+static int generate_token(BIO_ADDR *peer, QUIC_CONN_ID odcid,
+                          QUIC_CONN_ID rscid, QUIC_VALIDATION_TOKEN *token,
+                          int is_retry)
 {
-    token->is_retry = 1;
+    token->is_retry = is_retry;
     token->timestamp = ossl_time_now();
     token->remote_addr = NULL;
     token->odcid = odcid;
@@ -1082,8 +1084,8 @@ static void port_send_retry(QUIC_PORT *port,
         goto err;
 
     /* Generate retry validation token */
-    if (!generate_retry_token(peer, client_hdr->dst_conn_id,
-                              hdr.src_conn_id, &token)
+    if (!generate_token(peer, client_hdr->dst_conn_id,
+                        hdr.src_conn_id, &token, 1)
         || !marshal_validation_token(&token, buffer, &token_buf_len)
         || !encrypt_validation_token(port, buffer, token_buf_len, NULL,
                                      &ct_len)
@@ -1336,6 +1338,36 @@ err:
     return ret;
 }
 
+static void generate_new_token(QUIC_CHANNEL *ch, BIO_ADDR *peer)
+{
+    QUIC_CONN_ID rscid = { 0 };
+    QUIC_VALIDATION_TOKEN token;
+    unsigned char buffer[ENCRYPTED_TOKEN_MAX_LEN];
+    unsigned char ct_buf[ENCRYPTED_TOKEN_MAX_LEN];
+    size_t ct_len;
+    size_t token_buf_len = 0;
+
+    /* Clients never send a NEW_TOKEN */
+    if (!ch->is_server)
+        return;
+
+    if (!ossl_quic_lcidm_get_unused_cid(ch->port->lcidm, &rscid))
+        return;
+
+    if (!generate_token(peer, ch->init_dcid, rscid, &token, 0)
+        || !marshal_validation_token(&token, buffer, &token_buf_len)
+        || !encrypt_validation_token(ch->port, buffer, token_buf_len, NULL,
+                                     &ct_len)
+        || ct_len > ENCRYPTED_TOKEN_MAX_LEN
+        || !encrypt_validation_token(ch->port, buffer, token_buf_len, ct_buf,
+                                     &ct_len)
+        || !ossl_assert(ct_len >= QUIC_RETRY_INTEGRITY_TAG_LEN))
+        return;
+
+    ossl_quic_channel_schedule_new_token(ch, ct_buf, ct_len);
+    cleanup_validation_token(&token);
+}
+
 /*
  * This is called by the demux when we get a packet not destined for any known
  * DCID.
@@ -1457,6 +1489,11 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
     port_bind_channel(port, &e->peer, &scid, &hdr.dst_conn_id,
                       &odcid, &new_ch);
 
+    /*
+     * Generate a token for sending in a later NEW_TOKEN frame
+     */
+    generate_new_token(new_ch, &e->peer);
+
     /*
      * The channel will do all the LCID registration needed, but as an
      * optimization inject this packet directly into the channel's QRX for