]> git.ipfire.org Git - thirdparty/openssl.git/blobdiff - include/internal/quic_wire_pkt.h
Copyright year updates
[thirdparty/openssl.git] / include / internal / quic_wire_pkt.h
index 0c3cbbf673020ac8a675e52e3ceeeb3669692711..18a483fc2cc688a6725d854693f5ea870c152025 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 # define OSSL_QUIC_WIRE_PKT_H
 
 # include <openssl/ssl.h>
-# include "internal/packet.h"
+# include "internal/packet_quic.h"
 # include "internal/quic_types.h"
 
-# define QUIC_VERSION_NONE   ((uint32_t)0)   /* Used for version negotiation */
-# define QUIC_VERSION_1      ((uint32_t)1)   /* QUIC v1 */
+# ifndef OPENSSL_NO_QUIC
+
+#  define QUIC_VERSION_NONE   ((uint32_t)0)   /* Used for version negotiation */
+#  define QUIC_VERSION_1      ((uint32_t)1)   /* QUIC v1 */
 
 /* QUIC logical packet type. These do not match wire values. */
-# define QUIC_PKT_TYPE_INITIAL        1
-# define QUIC_PKT_TYPE_0RTT           2
-# define QUIC_PKT_TYPE_HANDSHAKE      3
-# define QUIC_PKT_TYPE_RETRY          4
-# define QUIC_PKT_TYPE_1RTT           5
-# define QUIC_PKT_TYPE_VERSION_NEG    6
+#  define QUIC_PKT_TYPE_INITIAL        1
+#  define QUIC_PKT_TYPE_0RTT           2
+#  define QUIC_PKT_TYPE_HANDSHAKE      3
+#  define QUIC_PKT_TYPE_RETRY          4
+#  define QUIC_PKT_TYPE_1RTT           5
+#  define QUIC_PKT_TYPE_VERSION_NEG    6
 
 /*
  * Determine encryption level from packet type. Returns QUIC_ENC_LEVEL_NUM if
@@ -46,13 +48,101 @@ ossl_quic_pkt_type_to_enc_level(uint32_t pkt_type)
     }
 }
 
+static ossl_inline ossl_unused uint32_t
+ossl_quic_enc_level_to_pkt_type(uint32_t enc_level)
+{
+    switch (enc_level) {
+        case QUIC_ENC_LEVEL_INITIAL:
+            return QUIC_PKT_TYPE_INITIAL;
+        case QUIC_ENC_LEVEL_HANDSHAKE:
+            return QUIC_PKT_TYPE_HANDSHAKE;
+        case QUIC_ENC_LEVEL_0RTT:
+            return QUIC_PKT_TYPE_0RTT;
+        case QUIC_ENC_LEVEL_1RTT:
+            return QUIC_PKT_TYPE_1RTT;
+        default:
+            return UINT32_MAX;
+    }
+}
+
+/* Determine if a packet type contains an encrypted payload. */
+static ossl_inline ossl_unused int
+ossl_quic_pkt_type_is_encrypted(uint32_t pkt_type)
+{
+    switch (pkt_type) {
+        case QUIC_PKT_TYPE_RETRY:
+        case QUIC_PKT_TYPE_VERSION_NEG:
+            return 0;
+        default:
+            return 1;
+    }
+}
+
+/* Determine if a packet type contains a PN field. */
+static ossl_inline ossl_unused int
+ossl_quic_pkt_type_has_pn(uint32_t pkt_type)
+{
+    /*
+     * Currently a packet has a PN iff it is encrypted. This could change
+     * someday.
+     */
+    return ossl_quic_pkt_type_is_encrypted(pkt_type);
+}
+
+/*
+ * Determine if a packet type can appear with other packets in a datagram. Some
+ * packet types must be the sole packet in a datagram.
+ */
+static ossl_inline ossl_unused int
+ossl_quic_pkt_type_can_share_dgram(uint32_t pkt_type)
+{
+    /*
+     * Currently only the encrypted packet types can share a datagram. This
+     * could change someday.
+     */
+    return ossl_quic_pkt_type_is_encrypted(pkt_type);
+}
+
+/*
+ * Determine if the packet type must come at the end of the datagram (due to the
+ * lack of a length field).
+ */
+static ossl_inline ossl_unused int
+ossl_quic_pkt_type_must_be_last(uint32_t pkt_type)
+{
+    /*
+     * Any packet type which cannot share a datagram obviously must come last.
+     * 1-RTT also must come last as it lacks a length field.
+     */
+    return !ossl_quic_pkt_type_can_share_dgram(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).
  */
-#define QUIC_MIN_VALID_PKT_LEN_CRYPTO      21
-#define QUIC_MIN_VALID_PKT_LEN_VERSION_NEG  7
-#define QUIC_MIN_VALID_PKT_LEN              QUIC_MIN_VALID_PKT_LEN_VERSION_NEG
+#  define QUIC_MIN_VALID_PKT_LEN_CRYPTO      21
+#  define QUIC_MIN_VALID_PKT_LEN_VERSION_NEG  7
+#  define QUIC_MIN_VALID_PKT_LEN              QUIC_MIN_VALID_PKT_LEN_VERSION_NEG
 
 typedef struct quic_pkt_hdr_ptrs_st QUIC_PKT_HDR_PTRS;
 
@@ -62,7 +152,7 @@ typedef struct quic_pkt_hdr_ptrs_st QUIC_PKT_HDR_PTRS;
  *
  * Functions to apply and remove QUIC packet header protection. A header
  * protector is initialised using ossl_quic_hdr_protector_init and must be
- * destroyed using ossl_quic_hdr_protector_destroy when no longer needed.
+ * destroyed using ossl_quic_hdr_protector_cleanup when no longer needed.
  */
 typedef struct quic_hdr_protector_st {
     OSSL_LIB_CTX       *libctx;
@@ -72,9 +162,9 @@ typedef struct quic_hdr_protector_st {
     uint32_t            cipher_id;
 } QUIC_HDR_PROTECTOR;
 
-# define QUIC_HDR_PROT_CIPHER_AES_128    1
-# define QUIC_HDR_PROT_CIPHER_AES_256    2
-# define QUIC_HDR_PROT_CIPHER_CHACHA     3
+#  define QUIC_HDR_PROT_CIPHER_AES_128    1
+#  define QUIC_HDR_PROT_CIPHER_AES_256    2
+#  define QUIC_HDR_PROT_CIPHER_CHACHA     3
 
 /*
  * Initialises a header protector.
@@ -107,7 +197,7 @@ int ossl_quic_hdr_protector_init(QUIC_HDR_PROTECTOR *hpr,
  * OSSL_QUIC_HDR_PROTECTOR structure which has not been initialized, or which
  * has already been destroyed.
  */
-void ossl_quic_hdr_protector_destroy(QUIC_HDR_PROTECTOR *hpr);
+void ossl_quic_hdr_protector_cleanup(QUIC_HDR_PROTECTOR *hpr);
 
 /*
  * Removes header protection from a packet. The packet payload must currently be
@@ -252,14 +342,30 @@ typedef struct quic_pkt_hdr_st {
      */
     unsigned int    fixed       :1;
 
+    /*
+     * The unused bits in the low 4 bits of a Retry packet header's first byte.
+     * This is used to ensure that Retry packets have the same bit-for-bit
+     * representation in their header when decoding and encoding them again.
+     * This is necessary to validate Retry packet headers.
+     */
+    unsigned int    unused      :4;
+
+    /*
+     * The 'Reserved' bits in an Initial, Handshake, 0-RTT or 1-RTT packet
+     * header's first byte. These are provided so that the caller can validate
+     * that they are zero, as this must be done after packet protection is
+     * successfully removed to avoid creating a timing channel.
+     */
+    unsigned int    reserved    :2;
+
     /* [L] Version field. Valid if (type != 1RTT). */
     uint32_t        version;
 
-    /* [ALL] Number of bytes in the connection ID (max 20). Always valid. */
+    /* [ALL] The destination connection ID. Always valid. */
     QUIC_CONN_ID    dst_conn_id;
 
     /*
-     * [L] Number of bytes in the connection ID (max 20).
+     * [L] The source connection ID.
      * Valid if (type != 1RTT).
      */
     QUIC_CONN_ID    src_conn_id;
@@ -285,9 +391,13 @@ typedef struct quic_pkt_hdr_st {
     size_t                  token_len;
 
     /*
-     * [i0h] Payload length in bytes.
+     * [ALL] Payload length in bytes.
      *
-     * Valid if (type != 1RTT && type != RETRY && version).
+     * Though 1-RTT, Retry and Version Negotiation packets do not contain an
+     * explicit length field, this field is always valid and is used by the
+     * packet header encoding and decoding routines to describe the payload
+     * length, regardless of whether the packet type encoded or decoded uses an
+     * explicit length indication.
      */
     size_t                  len;
 
@@ -341,6 +451,9 @@ struct quic_pkt_hdr_ptrs_st {
  * If partial is 0, the input is assumed to have already had header protection
  * removed, and all header fields are decoded.
  *
+ * If nodata is 1, the input is assumed to have no payload data in it. Otherwise
+ * payload data must be present.
+ *
  * On success, the logical decode of the packet header is written to *hdr.
  * hdr->partial is set or cleared according to whether a partial decode was
  * performed. *ptrs is filled with pointers to various parts of the packet
@@ -357,6 +470,7 @@ struct quic_pkt_hdr_ptrs_st {
 int ossl_quic_wire_decode_pkt_hdr(PACKET *pkt,
                                   size_t short_conn_id_len,
                                   int partial,
+                                  int nodata,
                                   QUIC_PKT_HDR *hdr,
                                   QUIC_PKT_HDR_PTRS *ptrs);
 
@@ -463,4 +577,53 @@ int ossl_quic_wire_determine_pn_len(QUIC_PN pn, QUIC_PN largest_acked);
 int ossl_quic_wire_encode_pkt_hdr_pn(QUIC_PN pn,
                                      unsigned char *enc_pn,
                                      size_t enc_pn_len);
+
+/*
+ * Retry Integrity Tags
+ * ====================
+ */
+
+#  define QUIC_RETRY_INTEGRITY_TAG_LEN    16
+
+/*
+ * Validate a retry integrity tag. Returns 1 if the tag is valid.
+ *
+ * Must be called on a hdr with a type of QUIC_PKT_TYPE_RETRY with a valid data
+ * pointer.
+ *
+ * client_initial_dcid must be the original DCID used by the client in its first
+ * Initial packet, as this is used to calculate the Retry Integrity Tag.
+ *
+ * Returns 0 if the tag is invalid, if called on any other type of packet or if
+ * the body is too short.
+ */
+int ossl_quic_validate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
+                                           const char *propq,
+                                           const QUIC_PKT_HDR *hdr,
+                                           const QUIC_CONN_ID *client_initial_dcid);
+
+/*
+ * Calculates a retry integrity tag. Returns 0 on error, for example if hdr does
+ * not have a type of QUIC_PKT_TYPE_RETRY.
+ *
+ * client_initial_dcid must be the original DCID used by the client in its first
+ * Initial packet, as this is used to calculate the Retry Integrity Tag.
+ *
+ * tag must point to a buffer of QUIC_RETRY_INTEGRITY_TAG_LEN bytes in size.
+ *
+ * Note that hdr->data must point to the Retry packet body, and hdr->len must
+ * include the space for the Retry Integrity Tag. (This means that you can
+ * easily fill in a tag in a Retry packet you are generating by calling this
+ * function and passing (hdr->data + hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN) as
+ * the tag argument.) This function fails if hdr->len is too short to contain a
+ * Retry Integrity Tag.
+ */
+int ossl_quic_calculate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
+                                            const char *propq,
+                                            const QUIC_PKT_HDR *hdr,
+                                            const QUIC_CONN_ID *client_initial_dcid,
+                                            unsigned char *tag);
+
+# endif
+
 #endif