]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add lookup for initial token assignment on channel start
authorNeil Horman <nhorman@openssl.org>
Thu, 16 Jan 2025 20:34:33 +0000 (15:34 -0500)
committerNeil Horman <nhorman@openssl.org>
Mon, 17 Feb 2025 16:27:33 +0000 (11:27 -0500)
Start assiging initial tokens, and validating them on receipt

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)

ssl/quic/quic_channel.c
ssl/quic/quic_port.c

index 3c13437bb54a25886bc1cbb7dd9f1116b2312026..a9b453e69f223f0bee336c2fdee09dfc1cbc4051 100644 (file)
@@ -18,6 +18,7 @@
 #include "internal/qlog_event_helpers.h"
 #include "internal/quic_txp.h"
 #include "internal/quic_tls.h"
+#include "internal/quic_ssl.h"
 #include "../ssl_local.h"
 #include "quic_channel_local.h"
 #include "quic_port_local.h"
@@ -2778,8 +2779,18 @@ static void ch_record_state_transition(QUIC_CHANNEL *ch, uint32_t new_state)
                                                           ch->handshake_confirmed);
 }
 
+static void free_peer_token(const unsigned char *token,
+                            size_t token_len, void *arg)
+{
+    ossl_quic_free_peer_token((QTOK *)arg);
+}
+
 int ossl_quic_channel_start(QUIC_CHANNEL *ch)
 {
+    uint8_t *token;
+    size_t token_len;
+    void *token_ptr;
+
     if (ch->is_server)
         /*
          * This is not used by the server. The server moves to active
@@ -2795,6 +2806,18 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch)
     if (!ossl_quic_tx_packetiser_set_peer(ch->txp, &ch->cur_peer_addr))
         return 0;
 
+    /*
+     * Look to see if we have a token, and if so, set it on the packetiser
+     */
+    if (!ch->is_server && ossl_quic_get_peer_token(ch->port->channel_ctx,
+                                                   &ch->cur_peer_addr,
+                                                   &token, &token_len,
+                                                   &token_ptr)) {
+        if (!ossl_quic_tx_packetiser_set_initial_token(ch->txp, token,
+                                                       token_len, free_token,
+                                                       token_ptr))
+            free_token(NULL, 0, token_ptr);
+    }
     /* Plug in secrets for the Initial EL. */
     if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx,
                                           ch->port->engine->propq,
@@ -2827,6 +2850,11 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch)
     return 1;
 }
 
+static void free_token(const unsigned char *token, size_t token_len, void *arg)
+{
+    OPENSSL_free((char *)token);
+}
+
 /* Start a locally initiated connection shutdown. */
 void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code,
                                    const char *app_reason)
@@ -2843,11 +2871,6 @@ void ossl_quic_channel_local_close(QUIC_CHANNEL *ch, uint64_t app_error_code,
     ch_start_terminating(ch, &tcause, 0);
 }
 
-static void free_token(const unsigned char *buf, size_t buf_len, void *arg)
-{
-    OPENSSL_free((unsigned char *)buf);
-}
-
 /**
  * ch_restart - Restarts the QUIC channel by simulating loss of the initial
  * packet. This forces the packet to be regenerated with the updated protocol
index 29b0edf878bb3173c099ba83b363619a59a0a524..f85c5579ef698c370d00eca2a7fccaa499ee2b49 100644 (file)
@@ -1487,8 +1487,23 @@ static void port_default_packet_handler(QUIC_URXE *e, void *arg,
      */
     if (hdr.token != NULL) {
         if (port_validate_token(&hdr, port, &e->peer,
-                                &odcid, &scid) == 0)
-            goto undesirable;
+                                &odcid, &scid) == 0) {
+            /*
+             * RFC 9000 s 8.1.3
+             * When a server receives an Initial packet with an address
+             * validation token, it MUST attempt to validate the token,
+             * unless it has already completed address validation.
+             * If the token is invalid, then the server SHOULD proceed as
+             * if the client did not have a validated address,
+             * including potentially sending a Retry packet
+             * Note: If address validation is disabled, just act like
+             * The request is valid
+             */
+            if (port->validate_addr == 1) {
+                port_send_retry(port, &e->peer, &hdr);
+                goto undesirable;
+            }
+        }
     }
 
     port_bind_channel(port, &e->peer, &scid, &hdr.dst_conn_id,