]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
QUIC CONFORMANCE: Packet handling fixes
authorHugo Landau <hlandau@openssl.org>
Tue, 6 Jun 2023 15:25:10 +0000 (16:25 +0100)
committerPauli <pauli@openssl.org>
Sun, 16 Jul 2023 22:17:57 +0000 (08:17 +1000)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21135)

include/internal/quic_wire_pkt.h
ssl/quic/quic_channel.c
ssl/quic/quic_rx_depack.c

index 5979a5ceb536b83e71d49577d6d9064a80958e60..966c0122744b5e0413f53974a134e49f5b7358bd 100644 (file)
@@ -118,6 +118,24 @@ ossl_quic_pkt_type_must_be_last(uint32_t pkt_type)
         || pkt_type == QUIC_PKT_TYPE_1RTT;
 }
 
+/*
+ * Determine if the packet type has a version field.
+ */
+static ossl_inline ossl_unused int
+ossl_quic_pkt_type_has_version(uint32_t pkt_type)
+{
+    return pkt_type != QUIC_PKT_TYPE_1RTT && pkt_type != QUIC_PKT_TYPE_VERSION_NEG;
+}
+
+/*
+ * Determine if the packet type has a SCID field.
+ */
+static ossl_inline ossl_unused int
+ossl_quic_pkt_type_has_scid(uint32_t pkt_type)
+{
+    return pkt_type != QUIC_PKT_TYPE_1RTT;
+}
+
 /*
  * Smallest possible QUIC packet size as per RFC (aside from version negotiation
  * packets).
index 7598fe589d9a473a0cfb9af93c25f130f8411a71..76b117c32b92bab03c76cc6ca4e24e8dcdd4432b 100644 (file)
@@ -1032,6 +1032,7 @@ static int ch_on_transport_params(const unsigned char *params,
     int got_max_udp_payload_size = 0;
     int got_max_idle_timeout = 0;
     int got_active_conn_id_limit = 0;
+    int got_disable_active_migration = 0;
     QUIC_CONN_ID cid;
     const char *reason = "bad transport parameter";
 
@@ -1359,8 +1360,31 @@ static int ch_on_transport_params(const unsigned char *params,
 
         case QUIC_TPARAM_DISABLE_ACTIVE_MIGRATION:
             /* We do not currently handle migration, so nothing to do. */
+            if (got_disable_active_migration) {
+                /* must not appear more than once */
+                reason = TP_REASON_DUP("DISABLE_ACTIVE_MIGRATION");
+                goto malformed;
+            }
+
+            body = ossl_quic_wire_decode_transport_param_bytes(&pkt, &id, &len);
+            if (body == NULL || len > 0) {
+                reason = TP_REASON_MALFORMED("DISABLE_ACTIVE_MIGRATION");
+                goto malformed;
+            }
+
+            got_disable_active_migration = 1;
+            break;
+
         default:
-            /* Skip over and ignore. */
+            /*
+             * Skip over and ignore.
+             *
+             * RFC 9000 s. 7.4: We SHOULD treat duplicated transport parameters
+             * as a connection error, but we are not required to. Currently,
+             * handle this programmatically by checking for duplicates in the
+             * parameters that we recognise, as above, but don't bother
+             * maintaining a list of duplicates for anything we don't recognise.
+             */
             body = ossl_quic_wire_decode_transport_param_bytes(&pkt, &id,
                                                                &len);
             if (body == NULL)
@@ -1776,6 +1800,28 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch)
             return;
     }
 
+    if (!ch->is_server
+        && ch->have_received_enc_pkt
+        && ossl_quic_pkt_type_has_scid(ch->qrx_pkt->hdr->type)) {
+        /*
+         * RFC 9000 s. 7.2. "Once a client has received a valid Initial packet
+         * from the server, it MUST discard any subsequent packet it receives on
+         * that connection with a different SCID."
+         */
+        if (!ossl_quic_conn_id_eq(&ch->qrx_pkt->hdr->src_conn_id,
+                                  &ch->init_scid))
+            return;
+    }
+
+    if (ossl_quic_pkt_type_has_version(ch->qrx_pkt->hdr->type)
+        && ch->qrx_pkt->hdr->version != QUIC_VERSION_1)
+        /*
+         * RFC 9000 s. 5.2.1: If a client receives a packet that uses a
+         * different version than it initially selected, it MUST discard the
+         * packet. We only ever use v1, so require it.
+         */
+        return;
+
     /* Handle incoming packet. */
     switch (ch->qrx_pkt->hdr->type) {
     case QUIC_PKT_TYPE_RETRY:
index d4a140d974820daefdfcf1e604e0f3c136403856..88a893cf247748da33c2bb62928fce8dea3b5c61 100644 (file)
@@ -914,6 +914,19 @@ static int depack_process_frames(QUIC_CHANNEL *ch, PACKET *pkt,
 {
     uint32_t pkt_type = parent_pkt->hdr->type;
 
+    if (PACKET_remaining(pkt) == 0) {
+        /*
+         * RFC 9000 s. 12.4: An endpoint MUST treat receipt of a packet
+         * containing no frames as a connection error of type
+         * PROTOCOL_VIOLATION.
+         */
+        ossl_quic_channel_raise_protocol_error(ch,
+                                               QUIC_ERR_PROTOCOL_VIOLATION,
+                                               0,
+                                               "empty packet payload");
+        return 0;
+    }
+
     while (PACKET_remaining(pkt) > 0) {
         uint64_t frame_type;
         const unsigned char *sof = NULL;