xref: /freebsd/crypto/openssl/include/internal/quic_wire_pkt.h (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.
3*e7be843bSPierre Pronchery  *
4*e7be843bSPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5*e7be843bSPierre Pronchery  * this file except in compliance with the License.  You can obtain a copy
6*e7be843bSPierre Pronchery  * in the file LICENSE in the source distribution or at
7*e7be843bSPierre Pronchery  * https://www.openssl.org/source/license.html
8*e7be843bSPierre Pronchery  */
9*e7be843bSPierre Pronchery 
10*e7be843bSPierre Pronchery #ifndef OSSL_QUIC_WIRE_PKT_H
11*e7be843bSPierre Pronchery # define OSSL_QUIC_WIRE_PKT_H
12*e7be843bSPierre Pronchery 
13*e7be843bSPierre Pronchery # include <openssl/ssl.h>
14*e7be843bSPierre Pronchery # include "internal/packet_quic.h"
15*e7be843bSPierre Pronchery # include "internal/quic_types.h"
16*e7be843bSPierre Pronchery 
17*e7be843bSPierre Pronchery # ifndef OPENSSL_NO_QUIC
18*e7be843bSPierre Pronchery 
19*e7be843bSPierre Pronchery #  define QUIC_VERSION_NONE   ((uint32_t)0)   /* Used for version negotiation */
20*e7be843bSPierre Pronchery #  define QUIC_VERSION_1      ((uint32_t)1)   /* QUIC v1 */
21*e7be843bSPierre Pronchery 
22*e7be843bSPierre Pronchery /* QUIC logical packet type. These do not match wire values. */
23*e7be843bSPierre Pronchery #  define QUIC_PKT_TYPE_INITIAL        1
24*e7be843bSPierre Pronchery #  define QUIC_PKT_TYPE_0RTT           2
25*e7be843bSPierre Pronchery #  define QUIC_PKT_TYPE_HANDSHAKE      3
26*e7be843bSPierre Pronchery #  define QUIC_PKT_TYPE_RETRY          4
27*e7be843bSPierre Pronchery #  define QUIC_PKT_TYPE_1RTT           5
28*e7be843bSPierre Pronchery #  define QUIC_PKT_TYPE_VERSION_NEG    6
29*e7be843bSPierre Pronchery 
30*e7be843bSPierre Pronchery /*
31*e7be843bSPierre Pronchery  * Determine encryption level from packet type. Returns QUIC_ENC_LEVEL_NUM if
32*e7be843bSPierre Pronchery  * the packet is not of a type which is encrypted.
33*e7be843bSPierre Pronchery  */
34*e7be843bSPierre Pronchery static ossl_inline ossl_unused uint32_t
ossl_quic_pkt_type_to_enc_level(uint32_t pkt_type)35*e7be843bSPierre Pronchery ossl_quic_pkt_type_to_enc_level(uint32_t pkt_type)
36*e7be843bSPierre Pronchery {
37*e7be843bSPierre Pronchery     switch (pkt_type) {
38*e7be843bSPierre Pronchery         case QUIC_PKT_TYPE_INITIAL:
39*e7be843bSPierre Pronchery             return QUIC_ENC_LEVEL_INITIAL;
40*e7be843bSPierre Pronchery         case QUIC_PKT_TYPE_HANDSHAKE:
41*e7be843bSPierre Pronchery             return QUIC_ENC_LEVEL_HANDSHAKE;
42*e7be843bSPierre Pronchery         case QUIC_PKT_TYPE_0RTT:
43*e7be843bSPierre Pronchery             return QUIC_ENC_LEVEL_0RTT;
44*e7be843bSPierre Pronchery         case QUIC_PKT_TYPE_1RTT:
45*e7be843bSPierre Pronchery             return QUIC_ENC_LEVEL_1RTT;
46*e7be843bSPierre Pronchery         default:
47*e7be843bSPierre Pronchery             return QUIC_ENC_LEVEL_NUM;
48*e7be843bSPierre Pronchery     }
49*e7be843bSPierre Pronchery }
50*e7be843bSPierre Pronchery 
51*e7be843bSPierre Pronchery static ossl_inline ossl_unused uint32_t
ossl_quic_enc_level_to_pkt_type(uint32_t enc_level)52*e7be843bSPierre Pronchery ossl_quic_enc_level_to_pkt_type(uint32_t enc_level)
53*e7be843bSPierre Pronchery {
54*e7be843bSPierre Pronchery     switch (enc_level) {
55*e7be843bSPierre Pronchery         case QUIC_ENC_LEVEL_INITIAL:
56*e7be843bSPierre Pronchery             return QUIC_PKT_TYPE_INITIAL;
57*e7be843bSPierre Pronchery         case QUIC_ENC_LEVEL_HANDSHAKE:
58*e7be843bSPierre Pronchery             return QUIC_PKT_TYPE_HANDSHAKE;
59*e7be843bSPierre Pronchery         case QUIC_ENC_LEVEL_0RTT:
60*e7be843bSPierre Pronchery             return QUIC_PKT_TYPE_0RTT;
61*e7be843bSPierre Pronchery         case QUIC_ENC_LEVEL_1RTT:
62*e7be843bSPierre Pronchery             return QUIC_PKT_TYPE_1RTT;
63*e7be843bSPierre Pronchery         default:
64*e7be843bSPierre Pronchery             return UINT32_MAX;
65*e7be843bSPierre Pronchery     }
66*e7be843bSPierre Pronchery }
67*e7be843bSPierre Pronchery 
68*e7be843bSPierre Pronchery /* Determine if a packet type contains an encrypted payload. */
69*e7be843bSPierre Pronchery static ossl_inline ossl_unused int
ossl_quic_pkt_type_is_encrypted(uint32_t pkt_type)70*e7be843bSPierre Pronchery ossl_quic_pkt_type_is_encrypted(uint32_t pkt_type)
71*e7be843bSPierre Pronchery {
72*e7be843bSPierre Pronchery     switch (pkt_type) {
73*e7be843bSPierre Pronchery         case QUIC_PKT_TYPE_RETRY:
74*e7be843bSPierre Pronchery         case QUIC_PKT_TYPE_VERSION_NEG:
75*e7be843bSPierre Pronchery             return 0;
76*e7be843bSPierre Pronchery         default:
77*e7be843bSPierre Pronchery             return 1;
78*e7be843bSPierre Pronchery     }
79*e7be843bSPierre Pronchery }
80*e7be843bSPierre Pronchery 
81*e7be843bSPierre Pronchery /* Determine if a packet type contains a PN field. */
82*e7be843bSPierre Pronchery static ossl_inline ossl_unused int
ossl_quic_pkt_type_has_pn(uint32_t pkt_type)83*e7be843bSPierre Pronchery ossl_quic_pkt_type_has_pn(uint32_t pkt_type)
84*e7be843bSPierre Pronchery {
85*e7be843bSPierre Pronchery     /*
86*e7be843bSPierre Pronchery      * Currently a packet has a PN iff it is encrypted. This could change
87*e7be843bSPierre Pronchery      * someday.
88*e7be843bSPierre Pronchery      */
89*e7be843bSPierre Pronchery     return ossl_quic_pkt_type_is_encrypted(pkt_type);
90*e7be843bSPierre Pronchery }
91*e7be843bSPierre Pronchery 
92*e7be843bSPierre Pronchery /*
93*e7be843bSPierre Pronchery  * Determine if a packet type can appear with other packets in a datagram. Some
94*e7be843bSPierre Pronchery  * packet types must be the sole packet in a datagram.
95*e7be843bSPierre Pronchery  */
96*e7be843bSPierre Pronchery static ossl_inline ossl_unused int
ossl_quic_pkt_type_can_share_dgram(uint32_t pkt_type)97*e7be843bSPierre Pronchery ossl_quic_pkt_type_can_share_dgram(uint32_t pkt_type)
98*e7be843bSPierre Pronchery {
99*e7be843bSPierre Pronchery     /*
100*e7be843bSPierre Pronchery      * Currently only the encrypted packet types can share a datagram. This
101*e7be843bSPierre Pronchery      * could change someday.
102*e7be843bSPierre Pronchery      */
103*e7be843bSPierre Pronchery     return ossl_quic_pkt_type_is_encrypted(pkt_type);
104*e7be843bSPierre Pronchery }
105*e7be843bSPierre Pronchery 
106*e7be843bSPierre Pronchery /*
107*e7be843bSPierre Pronchery  * Determine if the packet type must come at the end of the datagram (due to the
108*e7be843bSPierre Pronchery  * lack of a length field).
109*e7be843bSPierre Pronchery  */
110*e7be843bSPierre Pronchery static ossl_inline ossl_unused int
ossl_quic_pkt_type_must_be_last(uint32_t pkt_type)111*e7be843bSPierre Pronchery ossl_quic_pkt_type_must_be_last(uint32_t pkt_type)
112*e7be843bSPierre Pronchery {
113*e7be843bSPierre Pronchery     /*
114*e7be843bSPierre Pronchery      * Any packet type which cannot share a datagram obviously must come last.
115*e7be843bSPierre Pronchery      * 1-RTT also must come last as it lacks a length field.
116*e7be843bSPierre Pronchery      */
117*e7be843bSPierre Pronchery     return !ossl_quic_pkt_type_can_share_dgram(pkt_type)
118*e7be843bSPierre Pronchery         || pkt_type == QUIC_PKT_TYPE_1RTT;
119*e7be843bSPierre Pronchery }
120*e7be843bSPierre Pronchery 
121*e7be843bSPierre Pronchery /*
122*e7be843bSPierre Pronchery  * Determine if the packet type has a version field.
123*e7be843bSPierre Pronchery  */
124*e7be843bSPierre Pronchery static ossl_inline ossl_unused int
ossl_quic_pkt_type_has_version(uint32_t pkt_type)125*e7be843bSPierre Pronchery ossl_quic_pkt_type_has_version(uint32_t pkt_type)
126*e7be843bSPierre Pronchery {
127*e7be843bSPierre Pronchery     return pkt_type != QUIC_PKT_TYPE_1RTT && pkt_type != QUIC_PKT_TYPE_VERSION_NEG;
128*e7be843bSPierre Pronchery }
129*e7be843bSPierre Pronchery 
130*e7be843bSPierre Pronchery /*
131*e7be843bSPierre Pronchery  * Determine if the packet type has a SCID field.
132*e7be843bSPierre Pronchery  */
133*e7be843bSPierre Pronchery static ossl_inline ossl_unused int
ossl_quic_pkt_type_has_scid(uint32_t pkt_type)134*e7be843bSPierre Pronchery ossl_quic_pkt_type_has_scid(uint32_t pkt_type)
135*e7be843bSPierre Pronchery {
136*e7be843bSPierre Pronchery     return pkt_type != QUIC_PKT_TYPE_1RTT;
137*e7be843bSPierre Pronchery }
138*e7be843bSPierre Pronchery 
139*e7be843bSPierre Pronchery /*
140*e7be843bSPierre Pronchery  * Smallest possible QUIC packet size as per RFC (aside from version negotiation
141*e7be843bSPierre Pronchery  * packets).
142*e7be843bSPierre Pronchery  */
143*e7be843bSPierre Pronchery #  define QUIC_MIN_VALID_PKT_LEN_CRYPTO      21
144*e7be843bSPierre Pronchery #  define QUIC_MIN_VALID_PKT_LEN_VERSION_NEG  7
145*e7be843bSPierre Pronchery #  define QUIC_MIN_VALID_PKT_LEN              QUIC_MIN_VALID_PKT_LEN_VERSION_NEG
146*e7be843bSPierre Pronchery 
147*e7be843bSPierre Pronchery typedef struct quic_pkt_hdr_ptrs_st QUIC_PKT_HDR_PTRS;
148*e7be843bSPierre Pronchery 
149*e7be843bSPierre Pronchery /*
150*e7be843bSPierre Pronchery  * QUIC Packet Header Protection
151*e7be843bSPierre Pronchery  * =============================
152*e7be843bSPierre Pronchery  *
153*e7be843bSPierre Pronchery  * Functions to apply and remove QUIC packet header protection. A header
154*e7be843bSPierre Pronchery  * protector is initialised using ossl_quic_hdr_protector_init and must be
155*e7be843bSPierre Pronchery  * destroyed using ossl_quic_hdr_protector_cleanup when no longer needed.
156*e7be843bSPierre Pronchery  */
157*e7be843bSPierre Pronchery typedef struct quic_hdr_protector_st {
158*e7be843bSPierre Pronchery     OSSL_LIB_CTX       *libctx;
159*e7be843bSPierre Pronchery     const char         *propq;
160*e7be843bSPierre Pronchery     EVP_CIPHER_CTX     *cipher_ctx;
161*e7be843bSPierre Pronchery     EVP_CIPHER         *cipher;
162*e7be843bSPierre Pronchery     uint32_t            cipher_id;
163*e7be843bSPierre Pronchery } QUIC_HDR_PROTECTOR;
164*e7be843bSPierre Pronchery 
165*e7be843bSPierre Pronchery #  define QUIC_HDR_PROT_CIPHER_AES_128    1
166*e7be843bSPierre Pronchery #  define QUIC_HDR_PROT_CIPHER_AES_256    2
167*e7be843bSPierre Pronchery #  define QUIC_HDR_PROT_CIPHER_CHACHA     3
168*e7be843bSPierre Pronchery 
169*e7be843bSPierre Pronchery /*
170*e7be843bSPierre Pronchery  * Initialises a header protector.
171*e7be843bSPierre Pronchery  *
172*e7be843bSPierre Pronchery  *   cipher_id:
173*e7be843bSPierre Pronchery  *      The header protection cipher method to use. One of
174*e7be843bSPierre Pronchery  *      QUIC_HDR_PROT_CIPHER_*. Must be chosen based on negotiated TLS cipher
175*e7be843bSPierre Pronchery  *      suite.
176*e7be843bSPierre Pronchery  *
177*e7be843bSPierre Pronchery  *   quic_hp_key:
178*e7be843bSPierre Pronchery  *      This must be the "quic hp" key derived from a traffic secret.
179*e7be843bSPierre Pronchery  *
180*e7be843bSPierre Pronchery  *      The length of the quic_hp_key must correspond to that expected for the
181*e7be843bSPierre Pronchery  *      given cipher ID.
182*e7be843bSPierre Pronchery  *
183*e7be843bSPierre Pronchery  * The header protector performs amortisable initialisation in this function,
184*e7be843bSPierre Pronchery  * therefore a header protector should be used for as long as possible.
185*e7be843bSPierre Pronchery  *
186*e7be843bSPierre Pronchery  * Returns 1 on success and 0 on failure.
187*e7be843bSPierre Pronchery  */
188*e7be843bSPierre Pronchery int ossl_quic_hdr_protector_init(QUIC_HDR_PROTECTOR *hpr,
189*e7be843bSPierre Pronchery                                  OSSL_LIB_CTX *libctx,
190*e7be843bSPierre Pronchery                                  const char *propq,
191*e7be843bSPierre Pronchery                                  uint32_t cipher_id,
192*e7be843bSPierre Pronchery                                  const unsigned char *quic_hp_key,
193*e7be843bSPierre Pronchery                                  size_t quic_hp_key_len);
194*e7be843bSPierre Pronchery 
195*e7be843bSPierre Pronchery /*
196*e7be843bSPierre Pronchery  * Destroys a header protector. This is also safe to call on a zero-initialized
197*e7be843bSPierre Pronchery  * OSSL_QUIC_HDR_PROTECTOR structure which has not been initialized, or which
198*e7be843bSPierre Pronchery  * has already been destroyed.
199*e7be843bSPierre Pronchery  */
200*e7be843bSPierre Pronchery void ossl_quic_hdr_protector_cleanup(QUIC_HDR_PROTECTOR *hpr);
201*e7be843bSPierre Pronchery 
202*e7be843bSPierre Pronchery /*
203*e7be843bSPierre Pronchery  * Removes header protection from a packet. The packet payload must currently be
204*e7be843bSPierre Pronchery  * encrypted (i.e., you must remove header protection before decrypting packets
205*e7be843bSPierre Pronchery  * received). The function examines the header buffer to determine which bytes
206*e7be843bSPierre Pronchery  * of the header need to be decrypted.
207*e7be843bSPierre Pronchery  *
208*e7be843bSPierre Pronchery  * If this function fails, no data is modified.
209*e7be843bSPierre Pronchery  *
210*e7be843bSPierre Pronchery  * This is implemented as a call to ossl_quic_hdr_protector_decrypt_fields().
211*e7be843bSPierre Pronchery  *
212*e7be843bSPierre Pronchery  * Returns 1 on success and 0 on failure.
213*e7be843bSPierre Pronchery  */
214*e7be843bSPierre Pronchery int ossl_quic_hdr_protector_decrypt(QUIC_HDR_PROTECTOR *hpr,
215*e7be843bSPierre Pronchery                                     QUIC_PKT_HDR_PTRS *ptrs);
216*e7be843bSPierre Pronchery 
217*e7be843bSPierre Pronchery /*
218*e7be843bSPierre Pronchery  * Applies header protection to a packet. The packet payload must already have
219*e7be843bSPierre Pronchery  * been encrypted (i.e., you must apply header protection after encrypting
220*e7be843bSPierre Pronchery  * a packet). The function examines the header buffer to determine which bytes
221*e7be843bSPierre Pronchery  * of the header need to be encrypted.
222*e7be843bSPierre Pronchery  *
223*e7be843bSPierre Pronchery  * This is implemented as a call to ossl_quic_hdr_protector_encrypt_fields().
224*e7be843bSPierre Pronchery  *
225*e7be843bSPierre Pronchery  * Returns 1 on success and 0 on failure.
226*e7be843bSPierre Pronchery  */
227*e7be843bSPierre Pronchery int ossl_quic_hdr_protector_encrypt(QUIC_HDR_PROTECTOR *hpr,
228*e7be843bSPierre Pronchery                                     QUIC_PKT_HDR_PTRS *ptrs);
229*e7be843bSPierre Pronchery 
230*e7be843bSPierre Pronchery /*
231*e7be843bSPierre Pronchery  * Removes header protection from a packet. The packet payload must currently
232*e7be843bSPierre Pronchery  * be encrypted. This is a low-level function which assumes you have already
233*e7be843bSPierre Pronchery  * determined which parts of the packet header need to be decrypted.
234*e7be843bSPierre Pronchery  *
235*e7be843bSPierre Pronchery  * sample:
236*e7be843bSPierre Pronchery  *   The range of bytes in the packet to be used to generate the header
237*e7be843bSPierre Pronchery  *   protection mask. It is permissible to set sample_len to the size of the
238*e7be843bSPierre Pronchery  *   remainder of the packet; this function will only use as many bytes as
239*e7be843bSPierre Pronchery  *   needed. If not enough sample bytes are provided, this function fails.
240*e7be843bSPierre Pronchery  *
241*e7be843bSPierre Pronchery  * first_byte:
242*e7be843bSPierre Pronchery  *   The first byte of the QUIC packet header to be decrypted.
243*e7be843bSPierre Pronchery  *
244*e7be843bSPierre Pronchery  * pn:
245*e7be843bSPierre Pronchery  *   Pointer to the start of the PN field. The caller is responsible
246*e7be843bSPierre Pronchery  *   for ensuring at least four bytes follow this pointer.
247*e7be843bSPierre Pronchery  *
248*e7be843bSPierre Pronchery  * Returns 1 on success and 0 on failure.
249*e7be843bSPierre Pronchery  */
250*e7be843bSPierre Pronchery int ossl_quic_hdr_protector_decrypt_fields(QUIC_HDR_PROTECTOR *hpr,
251*e7be843bSPierre Pronchery                                            const unsigned char *sample,
252*e7be843bSPierre Pronchery                                            size_t sample_len,
253*e7be843bSPierre Pronchery                                            unsigned char *first_byte,
254*e7be843bSPierre Pronchery                                            unsigned char *pn_bytes);
255*e7be843bSPierre Pronchery 
256*e7be843bSPierre Pronchery /*
257*e7be843bSPierre Pronchery  * Works analogously to ossl_hdr_protector_decrypt_fields, but applies header
258*e7be843bSPierre Pronchery  * protection instead of removing it.
259*e7be843bSPierre Pronchery  */
260*e7be843bSPierre Pronchery int ossl_quic_hdr_protector_encrypt_fields(QUIC_HDR_PROTECTOR *hpr,
261*e7be843bSPierre Pronchery                                            const unsigned char *sample,
262*e7be843bSPierre Pronchery                                            size_t sample_len,
263*e7be843bSPierre Pronchery                                            unsigned char *first_byte,
264*e7be843bSPierre Pronchery                                            unsigned char *pn_bytes);
265*e7be843bSPierre Pronchery 
266*e7be843bSPierre Pronchery /*
267*e7be843bSPierre Pronchery  * QUIC Packet Header
268*e7be843bSPierre Pronchery  * ==================
269*e7be843bSPierre Pronchery  *
270*e7be843bSPierre Pronchery  * This structure provides a logical representation of a QUIC packet header.
271*e7be843bSPierre Pronchery  *
272*e7be843bSPierre Pronchery  * QUIC packet formats fall into the following categories:
273*e7be843bSPierre Pronchery  *
274*e7be843bSPierre Pronchery  *   Long Packets, which is subdivided into five possible packet types:
275*e7be843bSPierre Pronchery  *     Version Negotiation (a special case);
276*e7be843bSPierre Pronchery  *     Initial;
277*e7be843bSPierre Pronchery  *     0-RTT;
278*e7be843bSPierre Pronchery  *     Handshake; and
279*e7be843bSPierre Pronchery  *     Retry
280*e7be843bSPierre Pronchery  *
281*e7be843bSPierre Pronchery  *   Short Packets, which comprises only a single packet type (1-RTT).
282*e7be843bSPierre Pronchery  *
283*e7be843bSPierre Pronchery  * The packet formats vary and common fields are found in some packets but
284*e7be843bSPierre Pronchery  * not others. The below table indicates which fields are present in which
285*e7be843bSPierre Pronchery  * kinds of packet. * indicates header protection is applied.
286*e7be843bSPierre Pronchery  *
287*e7be843bSPierre Pronchery  *   SLLLLL         Legend: 1=1-RTT, i=Initial, 0=0-RTT, h=Handshake
288*e7be843bSPierre Pronchery  *   1i0hrv                 r=Retry, v=Version Negotiation
289*e7be843bSPierre Pronchery  *   ------
290*e7be843bSPierre Pronchery  *   1i0hrv         Header Form (0=Short, 1=Long)
291*e7be843bSPierre Pronchery  *   1i0hr          Fixed Bit (always 1)
292*e7be843bSPierre Pronchery  *   1              Spin Bit
293*e7be843bSPierre Pronchery  *   1       *      Reserved Bits
294*e7be843bSPierre Pronchery  *   1       *      Key Phase
295*e7be843bSPierre Pronchery  *   1i0h    *      Packet Number Length
296*e7be843bSPierre Pronchery  *    i0hr?         Long Packet Type
297*e7be843bSPierre Pronchery  *    i0h           Type-Specific Bits
298*e7be843bSPierre Pronchery  *    i0hr          Version (note: always 0 for Version Negotiation packets)
299*e7be843bSPierre Pronchery  *   1i0hrv         Destination Connection ID
300*e7be843bSPierre Pronchery  *    i0hrv         Source Connection ID
301*e7be843bSPierre Pronchery  *   1i0h    *      Packet Number
302*e7be843bSPierre Pronchery  *    i             Token
303*e7be843bSPierre Pronchery  *    i0h           Length
304*e7be843bSPierre Pronchery  *       r          Retry Token
305*e7be843bSPierre Pronchery  *       r          Retry Integrity Tag
306*e7be843bSPierre Pronchery  *
307*e7be843bSPierre Pronchery  * For each field below, the conditions under which the field is valid are
308*e7be843bSPierre Pronchery  * specified. If a field is not currently valid, it is initialized to a zero or
309*e7be843bSPierre Pronchery  * NULL value.
310*e7be843bSPierre Pronchery  */
311*e7be843bSPierre Pronchery typedef struct quic_pkt_hdr_st {
312*e7be843bSPierre Pronchery     /* [ALL] A QUIC_PKT_TYPE_* value. Always valid. */
313*e7be843bSPierre Pronchery     unsigned int    type        :8;
314*e7be843bSPierre Pronchery 
315*e7be843bSPierre Pronchery     /* [S] Value of the spin bit. Valid if (type == 1RTT). */
316*e7be843bSPierre Pronchery     unsigned int    spin_bit    :1;
317*e7be843bSPierre Pronchery 
318*e7be843bSPierre Pronchery     /*
319*e7be843bSPierre Pronchery      * [S] Value of the Key Phase bit in the short packet.
320*e7be843bSPierre Pronchery      * Valid if (type == 1RTT && !partial).
321*e7be843bSPierre Pronchery      */
322*e7be843bSPierre Pronchery     unsigned int    key_phase   :1;
323*e7be843bSPierre Pronchery 
324*e7be843bSPierre Pronchery     /*
325*e7be843bSPierre Pronchery      * [1i0h] Length of packet number in bytes. This is the decoded value.
326*e7be843bSPierre Pronchery      * Valid if ((type == 1RTT || (version && type != RETRY)) && !partial).
327*e7be843bSPierre Pronchery      */
328*e7be843bSPierre Pronchery     unsigned int    pn_len      :4;
329*e7be843bSPierre Pronchery 
330*e7be843bSPierre Pronchery     /*
331*e7be843bSPierre Pronchery      * [ALL] Set to 1 if this is a partial decode because the packet header
332*e7be843bSPierre Pronchery      * has not yet been deprotected. pn_len, pn and key_phase are not valid if
333*e7be843bSPierre Pronchery      * this is set.
334*e7be843bSPierre Pronchery      */
335*e7be843bSPierre Pronchery     unsigned int    partial     :1;
336*e7be843bSPierre Pronchery 
337*e7be843bSPierre Pronchery     /*
338*e7be843bSPierre Pronchery      * [ALL] Whether the fixed bit was set. Note that only Version Negotiation
339*e7be843bSPierre Pronchery      * packets are allowed to have this unset, so this will always be 1 for all
340*e7be843bSPierre Pronchery      * other packet types (decode will fail if it is not set). Ignored when
341*e7be843bSPierre Pronchery      * encoding unless encoding a Version Negotiation packet.
342*e7be843bSPierre Pronchery      */
343*e7be843bSPierre Pronchery     unsigned int    fixed       :1;
344*e7be843bSPierre Pronchery 
345*e7be843bSPierre Pronchery     /*
346*e7be843bSPierre Pronchery      * The unused bits in the low 4 bits of a Retry packet header's first byte.
347*e7be843bSPierre Pronchery      * This is used to ensure that Retry packets have the same bit-for-bit
348*e7be843bSPierre Pronchery      * representation in their header when decoding and encoding them again.
349*e7be843bSPierre Pronchery      * This is necessary to validate Retry packet headers.
350*e7be843bSPierre Pronchery      */
351*e7be843bSPierre Pronchery     unsigned int    unused      :4;
352*e7be843bSPierre Pronchery 
353*e7be843bSPierre Pronchery     /*
354*e7be843bSPierre Pronchery      * The 'Reserved' bits in an Initial, Handshake, 0-RTT or 1-RTT packet
355*e7be843bSPierre Pronchery      * header's first byte. These are provided so that the caller can validate
356*e7be843bSPierre Pronchery      * that they are zero, as this must be done after packet protection is
357*e7be843bSPierre Pronchery      * successfully removed to avoid creating a timing channel.
358*e7be843bSPierre Pronchery      */
359*e7be843bSPierre Pronchery     unsigned int    reserved    :2;
360*e7be843bSPierre Pronchery 
361*e7be843bSPierre Pronchery     /* [L] Version field. Valid if (type != 1RTT). */
362*e7be843bSPierre Pronchery     uint32_t        version;
363*e7be843bSPierre Pronchery 
364*e7be843bSPierre Pronchery     /* [ALL] The destination connection ID. Always valid. */
365*e7be843bSPierre Pronchery     QUIC_CONN_ID    dst_conn_id;
366*e7be843bSPierre Pronchery 
367*e7be843bSPierre Pronchery     /*
368*e7be843bSPierre Pronchery      * [L] The source connection ID.
369*e7be843bSPierre Pronchery      * Valid if (type != 1RTT).
370*e7be843bSPierre Pronchery      */
371*e7be843bSPierre Pronchery     QUIC_CONN_ID    src_conn_id;
372*e7be843bSPierre Pronchery 
373*e7be843bSPierre Pronchery     /*
374*e7be843bSPierre Pronchery      * [1i0h] Relatively-encoded packet number in raw, encoded form. The correct
375*e7be843bSPierre Pronchery      * decoding of this value is context-dependent. The number of bytes valid in
376*e7be843bSPierre Pronchery      * this buffer is determined by pn_len above. If the decode was partial,
377*e7be843bSPierre Pronchery      * this field is not valid.
378*e7be843bSPierre Pronchery      *
379*e7be843bSPierre Pronchery      * Valid if ((type == 1RTT || (version && type != RETRY)) && !partial).
380*e7be843bSPierre Pronchery      */
381*e7be843bSPierre Pronchery     unsigned char           pn[4];
382*e7be843bSPierre Pronchery 
383*e7be843bSPierre Pronchery     /*
384*e7be843bSPierre Pronchery      * [i] Token field in Initial packet. Points to memory inside the decoded
385*e7be843bSPierre Pronchery      * PACKET, and therefore is valid for as long as the PACKET's buffer is
386*e7be843bSPierre Pronchery      * valid. token_len is the length of the token in bytes.
387*e7be843bSPierre Pronchery      *
388*e7be843bSPierre Pronchery      * Valid if (type == INITIAL).
389*e7be843bSPierre Pronchery      */
390*e7be843bSPierre Pronchery     const unsigned char    *token;
391*e7be843bSPierre Pronchery     size_t                  token_len;
392*e7be843bSPierre Pronchery 
393*e7be843bSPierre Pronchery     /*
394*e7be843bSPierre Pronchery      * [ALL] Payload length in bytes.
395*e7be843bSPierre Pronchery      *
396*e7be843bSPierre Pronchery      * Though 1-RTT, Retry and Version Negotiation packets do not contain an
397*e7be843bSPierre Pronchery      * explicit length field, this field is always valid and is used by the
398*e7be843bSPierre Pronchery      * packet header encoding and decoding routines to describe the payload
399*e7be843bSPierre Pronchery      * length, regardless of whether the packet type encoded or decoded uses an
400*e7be843bSPierre Pronchery      * explicit length indication.
401*e7be843bSPierre Pronchery      */
402*e7be843bSPierre Pronchery     size_t                  len;
403*e7be843bSPierre Pronchery 
404*e7be843bSPierre Pronchery     /*
405*e7be843bSPierre Pronchery      * Pointer to start of payload data in the packet. Points to memory inside
406*e7be843bSPierre Pronchery      * the decoded PACKET, and therefore is valid for as long as the PACKET'S
407*e7be843bSPierre Pronchery      * buffer is valid. The length of the buffer in bytes is in len above.
408*e7be843bSPierre Pronchery      *
409*e7be843bSPierre Pronchery      * For Version Negotiation packets, points to the array of supported
410*e7be843bSPierre Pronchery      * versions.
411*e7be843bSPierre Pronchery      *
412*e7be843bSPierre Pronchery      * For Retry packets, points to the Retry packet payload, which comprises
413*e7be843bSPierre Pronchery      * the Retry Token followed by a 16-byte Retry Integrity Tag.
414*e7be843bSPierre Pronchery      *
415*e7be843bSPierre Pronchery      * Regardless of whether a packet is a Version Negotiation packet (where the
416*e7be843bSPierre Pronchery      * payload contains a list of supported versions), a Retry packet (where the
417*e7be843bSPierre Pronchery      * payload contains a Retry Token and Retry Integrity Tag), or any other
418*e7be843bSPierre Pronchery      * packet type (where the payload contains frames), the payload is not
419*e7be843bSPierre Pronchery      * validated and the user must parse the payload bearing this in mind.
420*e7be843bSPierre Pronchery      *
421*e7be843bSPierre Pronchery      * If the decode was partial (partial is set), this points to the start of
422*e7be843bSPierre Pronchery      * the packet number field, rather than the protected payload, as the length
423*e7be843bSPierre Pronchery      * of the packet number field is unknown. The len field reflects this in
424*e7be843bSPierre Pronchery      * this case (i.e., the len field is the number of payload bytes plus the
425*e7be843bSPierre Pronchery      * number of bytes comprising the PN).
426*e7be843bSPierre Pronchery      */
427*e7be843bSPierre Pronchery     const unsigned char    *data;
428*e7be843bSPierre Pronchery } QUIC_PKT_HDR;
429*e7be843bSPierre Pronchery 
430*e7be843bSPierre Pronchery /*
431*e7be843bSPierre Pronchery  * Extra information which can be output by the packet header decode functions
432*e7be843bSPierre Pronchery  * for the assistance of the header protector. This avoids the header protector
433*e7be843bSPierre Pronchery  * needing to partially re-decode the packet header.
434*e7be843bSPierre Pronchery  */
435*e7be843bSPierre Pronchery struct quic_pkt_hdr_ptrs_st {
436*e7be843bSPierre Pronchery     unsigned char    *raw_start;        /* start of packet */
437*e7be843bSPierre Pronchery     unsigned char    *raw_sample;       /* start of sampling range */
438*e7be843bSPierre Pronchery     size_t            raw_sample_len;   /* maximum length of sampling range */
439*e7be843bSPierre Pronchery 
440*e7be843bSPierre Pronchery     /*
441*e7be843bSPierre Pronchery      * Start of PN field. Guaranteed to be NULL unless at least four bytes are
442*e7be843bSPierre Pronchery      * available via this pointer.
443*e7be843bSPierre Pronchery      */
444*e7be843bSPierre Pronchery     unsigned char    *raw_pn;
445*e7be843bSPierre Pronchery };
446*e7be843bSPierre Pronchery 
447*e7be843bSPierre Pronchery /*
448*e7be843bSPierre Pronchery  * If partial is 1, reads the unprotected parts of a protected packet header
449*e7be843bSPierre Pronchery  * from a PACKET, performing a partial decode.
450*e7be843bSPierre Pronchery  *
451*e7be843bSPierre Pronchery  * If partial is 0, the input is assumed to have already had header protection
452*e7be843bSPierre Pronchery  * removed, and all header fields are decoded.
453*e7be843bSPierre Pronchery  *
454*e7be843bSPierre Pronchery  * If nodata is 1, the input is assumed to have no payload data in it. Otherwise
455*e7be843bSPierre Pronchery  * payload data must be present.
456*e7be843bSPierre Pronchery  *
457*e7be843bSPierre Pronchery  * On success, the logical decode of the packet header is written to *hdr.
458*e7be843bSPierre Pronchery  * hdr->partial is set or cleared according to whether a partial decode was
459*e7be843bSPierre Pronchery  * performed. *ptrs is filled with pointers to various parts of the packet
460*e7be843bSPierre Pronchery  * buffer.
461*e7be843bSPierre Pronchery  *
462*e7be843bSPierre Pronchery  * In order to decode short packets, the connection ID length being used must be
463*e7be843bSPierre Pronchery  * known contextually, and should be passed as short_conn_id_len. If
464*e7be843bSPierre Pronchery  * short_conn_id_len is set to an invalid value (a value greater than
465*e7be843bSPierre Pronchery  * QUIC_MAX_CONN_ID_LEN), this function fails when trying to decode a short
466*e7be843bSPierre Pronchery  * packet, but succeeds for long packets.
467*e7be843bSPierre Pronchery  *
468*e7be843bSPierre Pronchery  * fail_cause is a bitmask of the reasons decode might have failed
469*e7be843bSPierre Pronchery  * as defined below, useful when you need to interrogate parts of
470*e7be843bSPierre Pronchery  * a header even if its otherwise undecodeable.  May be NULL.
471*e7be843bSPierre Pronchery  *
472*e7be843bSPierre Pronchery  * Returns 1 on success and 0 on failure.
473*e7be843bSPierre Pronchery  */
474*e7be843bSPierre Pronchery 
475*e7be843bSPierre Pronchery #  define QUIC_PKT_HDR_DECODE_DECODE_ERR  (1 << 0)
476*e7be843bSPierre Pronchery #  define QUIC_PKT_HDR_DECODE_BAD_VERSION (1 << 1)
477*e7be843bSPierre Pronchery 
478*e7be843bSPierre Pronchery int ossl_quic_wire_decode_pkt_hdr(PACKET *pkt,
479*e7be843bSPierre Pronchery                                   size_t short_conn_id_len,
480*e7be843bSPierre Pronchery                                   int partial,
481*e7be843bSPierre Pronchery                                   int nodata,
482*e7be843bSPierre Pronchery                                   QUIC_PKT_HDR *hdr,
483*e7be843bSPierre Pronchery                                   QUIC_PKT_HDR_PTRS *ptrs,
484*e7be843bSPierre Pronchery                                   uint64_t *fail_cause);
485*e7be843bSPierre Pronchery 
486*e7be843bSPierre Pronchery /*
487*e7be843bSPierre Pronchery  * Encodes a packet header. The packet is written to pkt.
488*e7be843bSPierre Pronchery  *
489*e7be843bSPierre Pronchery  * The length of the (encrypted) packet payload should be written to hdr->len
490*e7be843bSPierre Pronchery  * and will be placed in the serialized packet header. The payload data itself
491*e7be843bSPierre Pronchery  * is not copied; the caller should write hdr->len bytes of encrypted payload to
492*e7be843bSPierre Pronchery  * the WPACKET immediately after the call to this function. However,
493*e7be843bSPierre Pronchery  * WPACKET_reserve_bytes is called for the payload size.
494*e7be843bSPierre Pronchery  *
495*e7be843bSPierre Pronchery  * This function does not apply header protection. You must apply header
496*e7be843bSPierre Pronchery  * protection yourself after calling this function. *ptrs is filled with
497*e7be843bSPierre Pronchery  * pointers which can be passed to a header protector, but this must be
498*e7be843bSPierre Pronchery  * performed after the encrypted payload is written.
499*e7be843bSPierre Pronchery  *
500*e7be843bSPierre Pronchery  * The pointers in *ptrs are direct pointers into the WPACKET buffer. If more
501*e7be843bSPierre Pronchery  * data is written to the WPACKET buffer, WPACKET buffer reallocations may
502*e7be843bSPierre Pronchery  * occur, causing these pointers to become invalid. Therefore, you must not call
503*e7be843bSPierre Pronchery  * any write WPACKET function between this call and the call to
504*e7be843bSPierre Pronchery  * ossl_quic_hdr_protector_encrypt. This function calls WPACKET_reserve_bytes
505*e7be843bSPierre Pronchery  * for the payload length, so you may assume hdr->len bytes are already free to
506*e7be843bSPierre Pronchery  * write at the WPACKET cursor location once this function returns successfully.
507*e7be843bSPierre Pronchery  * It is recommended that you call this function, write the encrypted payload,
508*e7be843bSPierre Pronchery  * call ossl_quic_hdr_protector_encrypt, and then call
509*e7be843bSPierre Pronchery  * WPACKET_allocate_bytes(hdr->len).
510*e7be843bSPierre Pronchery  *
511*e7be843bSPierre Pronchery  * Version Negotiation and Retry packets do not use header protection; for these
512*e7be843bSPierre Pronchery  * header types, the fields in *ptrs are all written as zero. Version
513*e7be843bSPierre Pronchery  * Negotiation, Retry and 1-RTT packets do not contain a Length field, but
514*e7be843bSPierre Pronchery  * hdr->len bytes of data are still reserved in the WPACKET.
515*e7be843bSPierre Pronchery  *
516*e7be843bSPierre Pronchery  * If serializing a short packet and short_conn_id_len does not match the DCID
517*e7be843bSPierre Pronchery  * specified in hdr, the function fails.
518*e7be843bSPierre Pronchery  *
519*e7be843bSPierre Pronchery  * Returns 1 on success and 0 on failure.
520*e7be843bSPierre Pronchery  */
521*e7be843bSPierre Pronchery int ossl_quic_wire_encode_pkt_hdr(WPACKET *pkt,
522*e7be843bSPierre Pronchery                                   size_t short_conn_id_len,
523*e7be843bSPierre Pronchery                                   const QUIC_PKT_HDR *hdr,
524*e7be843bSPierre Pronchery                                   QUIC_PKT_HDR_PTRS *ptrs);
525*e7be843bSPierre Pronchery 
526*e7be843bSPierre Pronchery /*
527*e7be843bSPierre Pronchery  * Retrieves only the DCID from a packet header. This is intended for demuxer
528*e7be843bSPierre Pronchery  * use. It avoids the need to parse the rest of the packet header twice.
529*e7be843bSPierre Pronchery  *
530*e7be843bSPierre Pronchery  * Information on packet length is not decoded, as this only needs to be used on
531*e7be843bSPierre Pronchery  * the first packet in a datagram, therefore this takes a buffer and not a
532*e7be843bSPierre Pronchery  * PACKET.
533*e7be843bSPierre Pronchery  *
534*e7be843bSPierre Pronchery  * Returns 1 on success and 0 on failure.
535*e7be843bSPierre Pronchery  */
536*e7be843bSPierre Pronchery int ossl_quic_wire_get_pkt_hdr_dst_conn_id(const unsigned char *buf,
537*e7be843bSPierre Pronchery                                            size_t buf_len,
538*e7be843bSPierre Pronchery                                            size_t short_conn_id_len,
539*e7be843bSPierre Pronchery                                            QUIC_CONN_ID *dst_conn_id);
540*e7be843bSPierre Pronchery 
541*e7be843bSPierre Pronchery /*
542*e7be843bSPierre Pronchery  * Precisely predicts the encoded length of a packet header structure.
543*e7be843bSPierre Pronchery  *
544*e7be843bSPierre Pronchery  * May return 0 if the packet header is not valid, but the fact that this
545*e7be843bSPierre Pronchery  * function returns non-zero does not guarantee that
546*e7be843bSPierre Pronchery  * ossl_quic_wire_encode_pkt_hdr() will succeed.
547*e7be843bSPierre Pronchery  */
548*e7be843bSPierre Pronchery int ossl_quic_wire_get_encoded_pkt_hdr_len(size_t short_conn_id_len,
549*e7be843bSPierre Pronchery                                            const QUIC_PKT_HDR *hdr);
550*e7be843bSPierre Pronchery 
551*e7be843bSPierre Pronchery /*
552*e7be843bSPierre Pronchery  * Packet Number Encoding
553*e7be843bSPierre Pronchery  * ======================
554*e7be843bSPierre Pronchery  */
555*e7be843bSPierre Pronchery 
556*e7be843bSPierre Pronchery /*
557*e7be843bSPierre Pronchery  * Decode an encoded packet header QUIC PN.
558*e7be843bSPierre Pronchery  *
559*e7be843bSPierre Pronchery  * enc_pn is the raw encoded PN to decode. enc_pn_len is its length in bytes as
560*e7be843bSPierre Pronchery  * indicated by packet headers. largest_pn is the largest PN successfully
561*e7be843bSPierre Pronchery  * processed in the relevant PN space.
562*e7be843bSPierre Pronchery  *
563*e7be843bSPierre Pronchery  * The resulting PN is written to *res_pn.
564*e7be843bSPierre Pronchery  *
565*e7be843bSPierre Pronchery  * Returns 1 on success or 0 on failure.
566*e7be843bSPierre Pronchery  */
567*e7be843bSPierre Pronchery int ossl_quic_wire_decode_pkt_hdr_pn(const unsigned char *enc_pn,
568*e7be843bSPierre Pronchery                                      size_t enc_pn_len,
569*e7be843bSPierre Pronchery                                      QUIC_PN largest_pn,
570*e7be843bSPierre Pronchery                                      QUIC_PN *res_pn);
571*e7be843bSPierre Pronchery 
572*e7be843bSPierre Pronchery /*
573*e7be843bSPierre Pronchery  * Determine how many bytes should be used to encode a PN. Returns the number of
574*e7be843bSPierre Pronchery  * bytes (which will be in range [1, 4]).
575*e7be843bSPierre Pronchery  */
576*e7be843bSPierre Pronchery int ossl_quic_wire_determine_pn_len(QUIC_PN pn, QUIC_PN largest_acked);
577*e7be843bSPierre Pronchery 
578*e7be843bSPierre Pronchery /*
579*e7be843bSPierre Pronchery  * Encode a PN for a packet header using the specified number of bytes, which
580*e7be843bSPierre Pronchery  * should have been determined by calling ossl_quic_wire_determine_pn_len. The
581*e7be843bSPierre Pronchery  * PN encoding process is done in two parts to allow the caller to override PN
582*e7be843bSPierre Pronchery  * encoding length if it wishes.
583*e7be843bSPierre Pronchery  *
584*e7be843bSPierre Pronchery  * Returns 1 on success and 0 on failure.
585*e7be843bSPierre Pronchery  */
586*e7be843bSPierre Pronchery int ossl_quic_wire_encode_pkt_hdr_pn(QUIC_PN pn,
587*e7be843bSPierre Pronchery                                      unsigned char *enc_pn,
588*e7be843bSPierre Pronchery                                      size_t enc_pn_len);
589*e7be843bSPierre Pronchery 
590*e7be843bSPierre Pronchery /*
591*e7be843bSPierre Pronchery  * Retry Integrity Tags
592*e7be843bSPierre Pronchery  * ====================
593*e7be843bSPierre Pronchery  */
594*e7be843bSPierre Pronchery 
595*e7be843bSPierre Pronchery #  define QUIC_RETRY_INTEGRITY_TAG_LEN    16
596*e7be843bSPierre Pronchery 
597*e7be843bSPierre Pronchery /*
598*e7be843bSPierre Pronchery  * Validate a retry integrity tag. Returns 1 if the tag is valid.
599*e7be843bSPierre Pronchery  *
600*e7be843bSPierre Pronchery  * Must be called on a hdr with a type of QUIC_PKT_TYPE_RETRY with a valid data
601*e7be843bSPierre Pronchery  * pointer.
602*e7be843bSPierre Pronchery  *
603*e7be843bSPierre Pronchery  * client_initial_dcid must be the original DCID used by the client in its first
604*e7be843bSPierre Pronchery  * Initial packet, as this is used to calculate the Retry Integrity Tag.
605*e7be843bSPierre Pronchery  *
606*e7be843bSPierre Pronchery  * Returns 0 if the tag is invalid, if called on any other type of packet or if
607*e7be843bSPierre Pronchery  * the body is too short.
608*e7be843bSPierre Pronchery  */
609*e7be843bSPierre Pronchery int ossl_quic_validate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
610*e7be843bSPierre Pronchery                                            const char *propq,
611*e7be843bSPierre Pronchery                                            const QUIC_PKT_HDR *hdr,
612*e7be843bSPierre Pronchery                                            const QUIC_CONN_ID *client_initial_dcid);
613*e7be843bSPierre Pronchery 
614*e7be843bSPierre Pronchery /*
615*e7be843bSPierre Pronchery  * Calculates a retry integrity tag. Returns 0 on error, for example if hdr does
616*e7be843bSPierre Pronchery  * not have a type of QUIC_PKT_TYPE_RETRY.
617*e7be843bSPierre Pronchery  *
618*e7be843bSPierre Pronchery  * client_initial_dcid must be the original DCID used by the client in its first
619*e7be843bSPierre Pronchery  * Initial packet, as this is used to calculate the Retry Integrity Tag.
620*e7be843bSPierre Pronchery  *
621*e7be843bSPierre Pronchery  * tag must point to a buffer of QUIC_RETRY_INTEGRITY_TAG_LEN bytes in size.
622*e7be843bSPierre Pronchery  *
623*e7be843bSPierre Pronchery  * Note that hdr->data must point to the Retry packet body, and hdr->len must
624*e7be843bSPierre Pronchery  * include the space for the Retry Integrity Tag. (This means that you can
625*e7be843bSPierre Pronchery  * easily fill in a tag in a Retry packet you are generating by calling this
626*e7be843bSPierre Pronchery  * function and passing (hdr->data + hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN) as
627*e7be843bSPierre Pronchery  * the tag argument.) This function fails if hdr->len is too short to contain a
628*e7be843bSPierre Pronchery  * Retry Integrity Tag.
629*e7be843bSPierre Pronchery  */
630*e7be843bSPierre Pronchery int ossl_quic_calculate_retry_integrity_tag(OSSL_LIB_CTX *libctx,
631*e7be843bSPierre Pronchery                                             const char *propq,
632*e7be843bSPierre Pronchery                                             const QUIC_PKT_HDR *hdr,
633*e7be843bSPierre Pronchery                                             const QUIC_CONN_ID *client_initial_dcid,
634*e7be843bSPierre Pronchery                                             unsigned char *tag);
635*e7be843bSPierre Pronchery 
636*e7be843bSPierre Pronchery # endif
637*e7be843bSPierre Pronchery 
638*e7be843bSPierre Pronchery #endif
639