/*
- * 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
}
}
+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;
*
* 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;
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.
* 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
*/
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;
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;
* 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
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);
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