/src/openssl/ssl/quic/quic_wire_pkt.c
Line  | Count  | Source  | 
1  |  | /*  | 
2  |  |  * Copyright 2022-2025 The OpenSSL Project Authors. All Rights Reserved.  | 
3  |  |  *  | 
4  |  |  * Licensed under the Apache License 2.0 (the "License").  You may not use  | 
5  |  |  * this file except in compliance with the License.  You can obtain a copy  | 
6  |  |  * in the file LICENSE in the source distribution or at  | 
7  |  |  * https://www.openssl.org/source/license.html  | 
8  |  |  */  | 
9  |  |  | 
10  |  | #include <openssl/err.h>  | 
11  |  | #include "internal/common.h"  | 
12  |  | #include "internal/quic_wire_pkt.h"  | 
13  |  |  | 
14  |  | int ossl_quic_hdr_protector_init(QUIC_HDR_PROTECTOR *hpr,  | 
15  |  |                                  OSSL_LIB_CTX *libctx,  | 
16  |  |                                  const char *propq,  | 
17  |  |                                  uint32_t cipher_id,  | 
18  |  |                                  const unsigned char *quic_hp_key,  | 
19  |  |                                  size_t quic_hp_key_len)  | 
20  | 0  | { | 
21  | 0  |     const char *cipher_name = NULL;  | 
22  |  | 
  | 
23  | 0  |     switch (cipher_id) { | 
24  | 0  |         case QUIC_HDR_PROT_CIPHER_AES_128:  | 
25  | 0  |             cipher_name = "AES-128-ECB";  | 
26  | 0  |             break;  | 
27  | 0  |         case QUIC_HDR_PROT_CIPHER_AES_256:  | 
28  | 0  |             cipher_name = "AES-256-ECB";  | 
29  | 0  |             break;  | 
30  | 0  |         case QUIC_HDR_PROT_CIPHER_CHACHA:  | 
31  | 0  |             cipher_name = "ChaCha20";  | 
32  | 0  |             break;  | 
33  | 0  |         default:  | 
34  | 0  |             ERR_raise(ERR_LIB_SSL, ERR_R_UNSUPPORTED);  | 
35  | 0  |             return 0;  | 
36  | 0  |     }  | 
37  |  |  | 
38  | 0  |     hpr->cipher_ctx = EVP_CIPHER_CTX_new();  | 
39  | 0  |     if (hpr->cipher_ctx == NULL) { | 
40  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
41  | 0  |         return 0;  | 
42  | 0  |     }  | 
43  |  |  | 
44  | 0  |     hpr->cipher = EVP_CIPHER_fetch(libctx, cipher_name, propq);  | 
45  | 0  |     if (hpr->cipher == NULL  | 
46  | 0  |         || quic_hp_key_len != (size_t)EVP_CIPHER_get_key_length(hpr->cipher)) { | 
47  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
48  | 0  |         goto err;  | 
49  | 0  |     }  | 
50  |  |  | 
51  | 0  |     if (!EVP_CipherInit_ex(hpr->cipher_ctx, hpr->cipher, NULL,  | 
52  | 0  |                            quic_hp_key, NULL, 1)) { | 
53  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
54  | 0  |         goto err;  | 
55  | 0  |     }  | 
56  |  |  | 
57  | 0  |     hpr->libctx     = libctx;  | 
58  | 0  |     hpr->propq      = propq;  | 
59  | 0  |     hpr->cipher_id  = cipher_id;  | 
60  | 0  |     return 1;  | 
61  |  |  | 
62  | 0  | err:  | 
63  | 0  |     ossl_quic_hdr_protector_cleanup(hpr);  | 
64  | 0  |     return 0;  | 
65  | 0  | }  | 
66  |  |  | 
67  |  | void ossl_quic_hdr_protector_cleanup(QUIC_HDR_PROTECTOR *hpr)  | 
68  | 0  | { | 
69  | 0  |     EVP_CIPHER_CTX_free(hpr->cipher_ctx);  | 
70  | 0  |     hpr->cipher_ctx = NULL;  | 
71  |  | 
  | 
72  | 0  |     EVP_CIPHER_free(hpr->cipher);  | 
73  | 0  |     hpr->cipher = NULL;  | 
74  | 0  | }  | 
75  |  |  | 
76  |  | static int hdr_generate_mask(QUIC_HDR_PROTECTOR *hpr,  | 
77  |  |                              const unsigned char *sample, size_t sample_len,  | 
78  |  |                              unsigned char *mask)  | 
79  | 0  | { | 
80  | 0  |     int l = 0;  | 
81  | 0  |     unsigned char dst[16];  | 
82  | 0  |     static const unsigned char zeroes[5] = {0}; | 
83  | 0  |     size_t i;  | 
84  |  | 
  | 
85  | 0  |     if (hpr->cipher_id == QUIC_HDR_PROT_CIPHER_AES_128  | 
86  | 0  |         || hpr->cipher_id == QUIC_HDR_PROT_CIPHER_AES_256) { | 
87  | 0  |         if (sample_len < 16) { | 
88  | 0  |             ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);  | 
89  | 0  |             return 0;  | 
90  | 0  |         }  | 
91  |  |  | 
92  | 0  |         if (!EVP_CipherInit_ex(hpr->cipher_ctx, NULL, NULL, NULL, NULL, 1)  | 
93  | 0  |             || !EVP_CipherUpdate(hpr->cipher_ctx, dst, &l, sample, 16)) { | 
94  | 0  |             ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
95  | 0  |             return 0;  | 
96  | 0  |         }  | 
97  |  |  | 
98  | 0  |         for (i = 0; i < 5; ++i)  | 
99  | 0  |             mask[i] = dst[i];  | 
100  | 0  |     } else if (hpr->cipher_id == QUIC_HDR_PROT_CIPHER_CHACHA) { | 
101  | 0  |         if (sample_len < 16) { | 
102  | 0  |             ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);  | 
103  | 0  |             return 0;  | 
104  | 0  |         }  | 
105  |  |  | 
106  | 0  |         if (!EVP_CipherInit_ex(hpr->cipher_ctx, NULL, NULL, NULL, sample, 1)  | 
107  | 0  |             || !EVP_CipherUpdate(hpr->cipher_ctx, mask, &l,  | 
108  | 0  |                                  zeroes, sizeof(zeroes))) { | 
109  | 0  |             ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
110  | 0  |             return 0;  | 
111  | 0  |         }  | 
112  | 0  |     } else { | 
113  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);  | 
114  | 0  |         assert(0);  | 
115  | 0  |         return 0;  | 
116  | 0  |     }  | 
117  |  |  | 
118  | 0  | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION  | 
119  |  |     /* No matter what we did above we use the same mask in fuzzing mode */  | 
120  | 0  |     memset(mask, 0, 5);  | 
121  | 0  | #endif  | 
122  |  | 
  | 
123  | 0  |     return 1;  | 
124  | 0  | }  | 
125  |  |  | 
126  |  | int ossl_quic_hdr_protector_decrypt(QUIC_HDR_PROTECTOR *hpr,  | 
127  |  |                                     QUIC_PKT_HDR_PTRS *ptrs)  | 
128  | 0  | { | 
129  | 0  |     return ossl_quic_hdr_protector_decrypt_fields(hpr,  | 
130  | 0  |                                                   ptrs->raw_sample,  | 
131  | 0  |                                                   ptrs->raw_sample_len,  | 
132  | 0  |                                                   ptrs->raw_start,  | 
133  | 0  |                                                   ptrs->raw_pn);  | 
134  | 0  | }  | 
135  |  |  | 
136  |  | int ossl_quic_hdr_protector_decrypt_fields(QUIC_HDR_PROTECTOR *hpr,  | 
137  |  |                                            const unsigned char *sample,  | 
138  |  |                                            size_t sample_len,  | 
139  |  |                                            unsigned char *first_byte,  | 
140  |  |                                            unsigned char *pn_bytes)  | 
141  | 0  | { | 
142  | 0  |     unsigned char mask[5], pn_len, i;  | 
143  |  | 
  | 
144  | 0  |     if (!hdr_generate_mask(hpr, sample, sample_len, mask))  | 
145  | 0  |         return 0;  | 
146  |  |  | 
147  | 0  |     *first_byte ^= mask[0] & ((*first_byte & 0x80) != 0 ? 0xf : 0x1f);  | 
148  | 0  |     pn_len = (*first_byte & 0x3) + 1;  | 
149  |  | 
  | 
150  | 0  |     for (i = 0; i < pn_len; ++i)  | 
151  | 0  |         pn_bytes[i] ^= mask[i + 1];  | 
152  |  | 
  | 
153  | 0  |     return 1;  | 
154  | 0  | }  | 
155  |  |  | 
156  |  | int ossl_quic_hdr_protector_encrypt(QUIC_HDR_PROTECTOR *hpr,  | 
157  |  |                                     QUIC_PKT_HDR_PTRS *ptrs)  | 
158  | 0  | { | 
159  | 0  |     return ossl_quic_hdr_protector_encrypt_fields(hpr,  | 
160  | 0  |                                                   ptrs->raw_sample,  | 
161  | 0  |                                                   ptrs->raw_sample_len,  | 
162  | 0  |                                                   ptrs->raw_start,  | 
163  | 0  |                                                   ptrs->raw_pn);  | 
164  | 0  | }  | 
165  |  |  | 
166  |  | int ossl_quic_hdr_protector_encrypt_fields(QUIC_HDR_PROTECTOR *hpr,  | 
167  |  |                                            const unsigned char *sample,  | 
168  |  |                                            size_t sample_len,  | 
169  |  |                                            unsigned char *first_byte,  | 
170  |  |                                            unsigned char *pn_bytes)  | 
171  | 0  | { | 
172  | 0  |     unsigned char mask[5], pn_len, i;  | 
173  |  | 
  | 
174  | 0  |     if (!hdr_generate_mask(hpr, sample, sample_len, mask))  | 
175  | 0  |         return 0;  | 
176  |  |  | 
177  | 0  |     pn_len = (*first_byte & 0x3) + 1;  | 
178  | 0  |     for (i = 0; i < pn_len; ++i)  | 
179  | 0  |         pn_bytes[i] ^= mask[i + 1];  | 
180  |  | 
  | 
181  | 0  |     *first_byte ^= mask[0] & ((*first_byte & 0x80) != 0 ? 0xf : 0x1f);  | 
182  | 0  |     return 1;  | 
183  | 0  | }  | 
184  |  |  | 
185  |  | int ossl_quic_wire_decode_pkt_hdr(PACKET *pkt,  | 
186  |  |                                   size_t short_conn_id_len,  | 
187  |  |                                   int partial,  | 
188  |  |                                   int nodata,  | 
189  |  |                                   QUIC_PKT_HDR *hdr,  | 
190  |  |                                   QUIC_PKT_HDR_PTRS *ptrs,  | 
191  |  |                                   uint64_t *fail_cause)  | 
192  | 0  | { | 
193  | 0  |     unsigned int b0;  | 
194  | 0  |     unsigned char *pn = NULL;  | 
195  | 0  |     size_t l = PACKET_remaining(pkt);  | 
196  |  | 
  | 
197  | 0  |     if (fail_cause != NULL)  | 
198  | 0  |         *fail_cause = QUIC_PKT_HDR_DECODE_DECODE_ERR;  | 
199  |  | 
  | 
200  | 0  |     if (ptrs != NULL) { | 
201  | 0  |         ptrs->raw_start         = (unsigned char *)PACKET_data(pkt);  | 
202  | 0  |         ptrs->raw_sample        = NULL;  | 
203  | 0  |         ptrs->raw_sample_len    = 0;  | 
204  | 0  |         ptrs->raw_pn            = NULL;  | 
205  | 0  |     }  | 
206  |  | 
  | 
207  | 0  |     if (l < QUIC_MIN_VALID_PKT_LEN  | 
208  | 0  |         || !PACKET_get_1(pkt, &b0))  | 
209  | 0  |         return 0;  | 
210  |  |  | 
211  | 0  |     hdr->partial    = partial;  | 
212  | 0  |     hdr->unused     = 0;  | 
213  | 0  |     hdr->reserved   = 0;  | 
214  |  | 
  | 
215  | 0  |     if ((b0 & 0x80) == 0) { | 
216  |  |         /* Short header. */  | 
217  | 0  |         if (short_conn_id_len > QUIC_MAX_CONN_ID_LEN)  | 
218  | 0  |             return 0;  | 
219  |  |  | 
220  | 0  |         if ((b0 & 0x40) == 0 /* fixed bit not set? */  | 
221  | 0  |             || l < QUIC_MIN_VALID_PKT_LEN_CRYPTO)  | 
222  | 0  |             return 0;  | 
223  |  |  | 
224  | 0  |         hdr->type       = QUIC_PKT_TYPE_1RTT;  | 
225  | 0  |         hdr->fixed      = 1;  | 
226  | 0  |         hdr->spin_bit   = (b0 & 0x20) != 0;  | 
227  | 0  |         if (partial) { | 
228  | 0  |             hdr->key_phase  = 0; /* protected, zero for now */  | 
229  | 0  |             hdr->pn_len     = 0; /* protected, zero for now */  | 
230  | 0  |             hdr->reserved   = 0; /* protected, zero for now */  | 
231  | 0  |         } else { | 
232  | 0  |             hdr->key_phase  = (b0 & 0x04) != 0;  | 
233  | 0  |             hdr->pn_len     = (b0 & 0x03) + 1;  | 
234  | 0  |             hdr->reserved   = (b0 & 0x18) >> 3;  | 
235  | 0  |         }  | 
236  |  |  | 
237  |  |         /* Copy destination connection ID field to header structure. */  | 
238  | 0  |         if (!PACKET_copy_bytes(pkt, hdr->dst_conn_id.id, short_conn_id_len))  | 
239  | 0  |             return 0;  | 
240  |  |  | 
241  | 0  |         hdr->dst_conn_id.id_len = (unsigned char)short_conn_id_len;  | 
242  |  |  | 
243  |  |         /*  | 
244  |  |          * Skip over the PN. If this is a partial decode, the PN length field  | 
245  |  |          * currently has header protection applied. Thus we do not know the  | 
246  |  |          * length of the PN but we are allowed to assume it is 4 bytes long at  | 
247  |  |          * this stage.  | 
248  |  |          */  | 
249  | 0  |         memset(hdr->pn, 0, sizeof(hdr->pn));  | 
250  | 0  |         pn = (unsigned char *)PACKET_data(pkt);  | 
251  | 0  |         if (partial) { | 
252  | 0  |             if (!PACKET_forward(pkt, sizeof(hdr->pn)))  | 
253  | 0  |                 return 0;  | 
254  | 0  |         } else { | 
255  | 0  |             if (!PACKET_copy_bytes(pkt, hdr->pn, hdr->pn_len))  | 
256  | 0  |                 return 0;  | 
257  | 0  |         }  | 
258  |  |  | 
259  |  |         /* Fields not used in short-header packets. */  | 
260  | 0  |         hdr->version            = 0;  | 
261  | 0  |         hdr->src_conn_id.id_len = 0;  | 
262  | 0  |         hdr->token              = NULL;  | 
263  | 0  |         hdr->token_len          = 0;  | 
264  |  |  | 
265  |  |         /*  | 
266  |  |          * Short-header packets always come last in a datagram, the length  | 
267  |  |          * is the remainder of the buffer.  | 
268  |  |          */  | 
269  | 0  |         hdr->len                = PACKET_remaining(pkt);  | 
270  | 0  |         hdr->data               = PACKET_data(pkt);  | 
271  |  |  | 
272  |  |         /*  | 
273  |  |          * Skip over payload. Since this is a short header packet, which cannot  | 
274  |  |          * be followed by any other kind of packet, this advances us to the end  | 
275  |  |          * of the datagram.  | 
276  |  |          */  | 
277  | 0  |         if (!PACKET_forward(pkt, hdr->len))  | 
278  | 0  |             return 0;  | 
279  | 0  |     } else { | 
280  |  |         /* Long header. */  | 
281  | 0  |         unsigned long version;  | 
282  | 0  |         unsigned int dst_conn_id_len, src_conn_id_len, raw_type;  | 
283  |  | 
  | 
284  | 0  |         if (!PACKET_get_net_4(pkt, &version))  | 
285  | 0  |             return 0;  | 
286  |  |  | 
287  |  |         /*  | 
288  |  |          * All QUIC packets must have the fixed bit set, except exceptionally  | 
289  |  |          * for Version Negotiation packets.  | 
290  |  |          */  | 
291  | 0  |         if (version != 0 && (b0 & 0x40) == 0)  | 
292  | 0  |             return 0;  | 
293  |  |  | 
294  | 0  |         if (!PACKET_get_1(pkt, &dst_conn_id_len)  | 
295  | 0  |             || dst_conn_id_len > QUIC_MAX_CONN_ID_LEN  | 
296  | 0  |             || !PACKET_copy_bytes(pkt, hdr->dst_conn_id.id, dst_conn_id_len)  | 
297  | 0  |             || !PACKET_get_1(pkt, &src_conn_id_len)  | 
298  | 0  |             || src_conn_id_len > QUIC_MAX_CONN_ID_LEN  | 
299  | 0  |             || !PACKET_copy_bytes(pkt, hdr->src_conn_id.id, src_conn_id_len))  | 
300  | 0  |             return 0;  | 
301  |  |  | 
302  | 0  |         hdr->version            = (uint32_t)version;  | 
303  | 0  |         hdr->dst_conn_id.id_len = (unsigned char)dst_conn_id_len;  | 
304  | 0  |         hdr->src_conn_id.id_len = (unsigned char)src_conn_id_len;  | 
305  |  | 
  | 
306  | 0  |         if (version == 0) { | 
307  |  |             /*  | 
308  |  |              * Version negotiation packet. Version negotiation packets are  | 
309  |  |              * identified by a version field of 0 and the type bits in the first  | 
310  |  |              * byte are ignored (they may take any value, and we ignore them).  | 
311  |  |              */  | 
312  | 0  |             hdr->type       = QUIC_PKT_TYPE_VERSION_NEG;  | 
313  | 0  |             hdr->fixed      = (b0 & 0x40) != 0;  | 
314  |  | 
  | 
315  | 0  |             hdr->data       = PACKET_data(pkt);  | 
316  | 0  |             hdr->len        = PACKET_remaining(pkt);  | 
317  |  |  | 
318  |  |             /*  | 
319  |  |              * Version negotiation packets must contain an array of u32s, so it  | 
320  |  |              * is invalid for their payload length to not be divisible by 4.  | 
321  |  |              */  | 
322  | 0  |             if ((hdr->len % 4) != 0)  | 
323  | 0  |                 return 0;  | 
324  |  |  | 
325  |  |             /* Version negotiation packets are always fully decoded. */  | 
326  | 0  |             hdr->partial    = 0;  | 
327  |  |  | 
328  |  |             /* Fields not used in version negotiation packets. */  | 
329  | 0  |             hdr->pn_len             = 0;  | 
330  | 0  |             hdr->spin_bit           = 0;  | 
331  | 0  |             hdr->key_phase          = 0;  | 
332  | 0  |             hdr->token              = NULL;  | 
333  | 0  |             hdr->token_len          = 0;  | 
334  | 0  |             memset(hdr->pn, 0, sizeof(hdr->pn));  | 
335  |  | 
  | 
336  | 0  |             if (!PACKET_forward(pkt, hdr->len))  | 
337  | 0  |                 return 0;  | 
338  | 0  |         } else if (version != QUIC_VERSION_1) { | 
339  | 0  |             if (fail_cause != NULL)  | 
340  | 0  |                 *fail_cause |= QUIC_PKT_HDR_DECODE_BAD_VERSION;  | 
341  |  |             /* Unknown version, do not decode. */  | 
342  | 0  |             return 0;  | 
343  | 0  |         } else { | 
344  | 0  |             if (l < QUIC_MIN_VALID_PKT_LEN_CRYPTO)  | 
345  | 0  |                 return 0;  | 
346  |  |  | 
347  |  |             /* Get long packet type and decode to QUIC_PKT_TYPE_*. */  | 
348  | 0  |             raw_type = ((b0 >> 4) & 0x3);  | 
349  |  | 
  | 
350  | 0  |             switch (raw_type) { | 
351  | 0  |             case 0:  | 
352  | 0  |                 hdr->type = QUIC_PKT_TYPE_INITIAL;  | 
353  | 0  |                 break;  | 
354  | 0  |             case 1:  | 
355  | 0  |                 hdr->type = QUIC_PKT_TYPE_0RTT;  | 
356  | 0  |                 break;  | 
357  | 0  |             case 2:  | 
358  | 0  |                 hdr->type = QUIC_PKT_TYPE_HANDSHAKE;  | 
359  | 0  |                 break;  | 
360  | 0  |             case 3:  | 
361  | 0  |                 hdr->type = QUIC_PKT_TYPE_RETRY;  | 
362  | 0  |                 break;  | 
363  | 0  |             }  | 
364  |  |  | 
365  | 0  |             hdr->pn_len     = 0;  | 
366  | 0  |             hdr->fixed      = 1;  | 
367  |  |  | 
368  |  |             /* Fields not used in long-header packets. */  | 
369  | 0  |             hdr->spin_bit   = 0;  | 
370  | 0  |             hdr->key_phase  = 0;  | 
371  |  | 
  | 
372  | 0  |             if (hdr->type == QUIC_PKT_TYPE_INITIAL) { | 
373  |  |                 /* Initial packet. */  | 
374  | 0  |                 uint64_t token_len;  | 
375  |  | 
  | 
376  | 0  |                 if (!PACKET_get_quic_vlint(pkt, &token_len)  | 
377  | 0  |                     || token_len > SIZE_MAX  | 
378  | 0  |                     || !PACKET_get_bytes(pkt, &hdr->token, (size_t)token_len))  | 
379  | 0  |                     return 0;  | 
380  |  |  | 
381  | 0  |                 hdr->token_len  = (size_t)token_len;  | 
382  | 0  |                 if (token_len == 0)  | 
383  | 0  |                     hdr->token = NULL;  | 
384  | 0  |             } else { | 
385  | 0  |                 hdr->token      = NULL;  | 
386  | 0  |                 hdr->token_len  = 0;  | 
387  | 0  |             }  | 
388  |  |  | 
389  | 0  |             if (hdr->type == QUIC_PKT_TYPE_RETRY) { | 
390  |  |                 /* Retry packet. */  | 
391  | 0  |                 hdr->data       = PACKET_data(pkt);  | 
392  | 0  |                 hdr->len        = PACKET_remaining(pkt);  | 
393  |  |  | 
394  |  |                 /* Retry packets are always fully decoded. */  | 
395  | 0  |                 hdr->partial    = 0;  | 
396  |  |  | 
397  |  |                 /* Unused bits in Retry header. */  | 
398  | 0  |                 hdr->unused     = b0 & 0x0f;  | 
399  |  |  | 
400  |  |                 /* Fields not used in Retry packets. */  | 
401  | 0  |                 memset(hdr->pn, 0, sizeof(hdr->pn));  | 
402  |  | 
  | 
403  | 0  |                 if (!PACKET_forward(pkt, hdr->len))  | 
404  | 0  |                     return 0;  | 
405  | 0  |             } else { | 
406  |  |                 /* Initial, 0-RTT or Handshake packet. */  | 
407  | 0  |                 uint64_t len;  | 
408  |  | 
  | 
409  | 0  |                 hdr->pn_len     = partial ? 0 : ((b0 & 0x03) + 1);  | 
410  | 0  |                 hdr->reserved   = partial ? 0 : ((b0 & 0x0C) >> 2);  | 
411  |  | 
  | 
412  | 0  |                 if (!PACKET_get_quic_vlint(pkt, &len)  | 
413  | 0  |                         || len < sizeof(hdr->pn))  | 
414  | 0  |                     return 0;  | 
415  |  |  | 
416  | 0  |                 if (!nodata && len > PACKET_remaining(pkt))  | 
417  | 0  |                     return 0;  | 
418  |  |  | 
419  |  |                 /*  | 
420  |  |                  * Skip over the PN. If this is a partial decode, the PN length  | 
421  |  |                  * field currently has header protection applied. Thus we do not  | 
422  |  |                  * know the length of the PN but we are allowed to assume it is  | 
423  |  |                  * 4 bytes long at this stage.  | 
424  |  |                  */  | 
425  | 0  |                 pn = (unsigned char *)PACKET_data(pkt);  | 
426  | 0  |                 memset(hdr->pn, 0, sizeof(hdr->pn));  | 
427  | 0  |                 if (partial) { | 
428  | 0  |                     if (!PACKET_forward(pkt, sizeof(hdr->pn)))  | 
429  | 0  |                         return 0;  | 
430  |  |  | 
431  | 0  |                     hdr->len = (size_t)(len - sizeof(hdr->pn));  | 
432  | 0  |                 } else { | 
433  | 0  |                     if (!PACKET_copy_bytes(pkt, hdr->pn, hdr->pn_len))  | 
434  | 0  |                         return 0;  | 
435  |  |  | 
436  | 0  |                     hdr->len = (size_t)(len - hdr->pn_len);  | 
437  | 0  |                 }  | 
438  |  |  | 
439  | 0  |                 if (nodata) { | 
440  | 0  |                     hdr->data = NULL;  | 
441  | 0  |                 } else { | 
442  | 0  |                     hdr->data = PACKET_data(pkt);  | 
443  |  |  | 
444  |  |                     /* Skip over packet body. */  | 
445  | 0  |                     if (!PACKET_forward(pkt, hdr->len))  | 
446  | 0  |                         return 0;  | 
447  | 0  |                 }  | 
448  | 0  |             }  | 
449  | 0  |         }  | 
450  | 0  |     }  | 
451  |  |  | 
452  | 0  |     if (ptrs != NULL) { | 
453  | 0  |         ptrs->raw_pn = pn;  | 
454  | 0  |         if (pn != NULL) { | 
455  | 0  |             ptrs->raw_sample        = pn + 4;  | 
456  | 0  |             ptrs->raw_sample_len    = PACKET_end(pkt) - ptrs->raw_sample;  | 
457  | 0  |         }  | 
458  | 0  |     }  | 
459  |  |  | 
460  |  |     /*  | 
461  |  |      * Good decode, clear the generic DECODE_ERR flag  | 
462  |  |      */  | 
463  | 0  |     if (fail_cause != NULL)  | 
464  | 0  |         *fail_cause &= ~QUIC_PKT_HDR_DECODE_DECODE_ERR;  | 
465  |  | 
  | 
466  | 0  |     return 1;  | 
467  | 0  | }  | 
468  |  |  | 
469  |  | int ossl_quic_wire_encode_pkt_hdr(WPACKET *pkt,  | 
470  |  |                                   size_t short_conn_id_len,  | 
471  |  |                                   const QUIC_PKT_HDR *hdr,  | 
472  |  |                                   QUIC_PKT_HDR_PTRS *ptrs)  | 
473  | 0  | { | 
474  | 0  |     unsigned char b0;  | 
475  | 0  |     size_t off_start, off_sample, off_pn;  | 
476  | 0  |     unsigned char *start = WPACKET_get_curr(pkt);  | 
477  |  | 
  | 
478  | 0  |     if (!WPACKET_get_total_written(pkt, &off_start))  | 
479  | 0  |         return 0;  | 
480  |  |  | 
481  | 0  |     if (ptrs != NULL) { | 
482  |  |         /* ptrs would not be stable on non-static WPACKET */  | 
483  | 0  |         if (!ossl_assert(pkt->staticbuf != NULL))  | 
484  | 0  |             return 0;  | 
485  | 0  |         ptrs->raw_start         = NULL;  | 
486  | 0  |         ptrs->raw_sample        = NULL;  | 
487  | 0  |         ptrs->raw_sample_len    = 0;  | 
488  | 0  |         ptrs->raw_pn            = 0;  | 
489  | 0  |     }  | 
490  |  |  | 
491  |  |     /* Cannot serialize a partial header, or one whose DCID length is wrong. */  | 
492  | 0  |     if (hdr->partial  | 
493  | 0  |         || (hdr->type == QUIC_PKT_TYPE_1RTT  | 
494  | 0  |             && hdr->dst_conn_id.id_len != short_conn_id_len))  | 
495  | 0  |         return 0;  | 
496  |  |  | 
497  | 0  |     if (hdr->type == QUIC_PKT_TYPE_1RTT) { | 
498  |  |         /* Short header. */  | 
499  |  |  | 
500  |  |         /*  | 
501  |  |          * Cannot serialize a header whose DCID length is wrong, or with an  | 
502  |  |          * invalid PN length.  | 
503  |  |          */  | 
504  | 0  |         if (hdr->dst_conn_id.id_len != short_conn_id_len  | 
505  | 0  |             || short_conn_id_len > QUIC_MAX_CONN_ID_LEN  | 
506  | 0  |             || hdr->pn_len < 1 || hdr->pn_len > 4)  | 
507  | 0  |             return 0;  | 
508  |  |  | 
509  | 0  |         b0 = (hdr->spin_bit << 5)  | 
510  | 0  |              | (hdr->key_phase << 2)  | 
511  | 0  |              | (hdr->pn_len - 1)  | 
512  | 0  |              | (hdr->reserved << 3)  | 
513  | 0  |              | 0x40; /* fixed bit */  | 
514  |  | 
  | 
515  | 0  |         if (!WPACKET_put_bytes_u8(pkt, b0)  | 
516  | 0  |             || !WPACKET_memcpy(pkt, hdr->dst_conn_id.id, short_conn_id_len)  | 
517  | 0  |             || !WPACKET_get_total_written(pkt, &off_pn)  | 
518  | 0  |             || !WPACKET_memcpy(pkt, hdr->pn, hdr->pn_len))  | 
519  | 0  |             return 0;  | 
520  | 0  |     } else { | 
521  |  |         /* Long header. */  | 
522  | 0  |         unsigned int raw_type;  | 
523  |  | 
  | 
524  | 0  |         if (hdr->dst_conn_id.id_len > QUIC_MAX_CONN_ID_LEN  | 
525  | 0  |             || hdr->src_conn_id.id_len > QUIC_MAX_CONN_ID_LEN)  | 
526  | 0  |             return 0;  | 
527  |  |  | 
528  | 0  |         if (ossl_quic_pkt_type_has_pn(hdr->type)  | 
529  | 0  |             && (hdr->pn_len < 1 || hdr->pn_len > 4))  | 
530  | 0  |             return 0;  | 
531  |  |  | 
532  | 0  |         switch (hdr->type) { | 
533  | 0  |             case QUIC_PKT_TYPE_VERSION_NEG:  | 
534  | 0  |                 if (hdr->version != 0)  | 
535  | 0  |                     return 0;  | 
536  |  |  | 
537  |  |                 /* Version negotiation packets use zero for the type bits */  | 
538  | 0  |                 raw_type = 0;  | 
539  | 0  |                 break;  | 
540  |  |  | 
541  | 0  |             case QUIC_PKT_TYPE_INITIAL:     raw_type = 0; break;  | 
542  | 0  |             case QUIC_PKT_TYPE_0RTT:        raw_type = 1; break;  | 
543  | 0  |             case QUIC_PKT_TYPE_HANDSHAKE:   raw_type = 2; break;  | 
544  | 0  |             case QUIC_PKT_TYPE_RETRY:       raw_type = 3; break;  | 
545  | 0  |             default:  | 
546  | 0  |                 return 0;  | 
547  | 0  |         }  | 
548  |  |  | 
549  | 0  |         b0 = (raw_type << 4) | 0x80; /* long */  | 
550  | 0  |         if (hdr->type != QUIC_PKT_TYPE_VERSION_NEG || hdr->fixed)  | 
551  | 0  |             b0 |= 0x40; /* fixed */  | 
552  | 0  |         if (ossl_quic_pkt_type_has_pn(hdr->type)) { | 
553  | 0  |             b0 |= hdr->pn_len - 1;  | 
554  | 0  |             b0 |= (hdr->reserved << 2);  | 
555  | 0  |         }  | 
556  | 0  |         if (hdr->type == QUIC_PKT_TYPE_RETRY)  | 
557  | 0  |             b0 |= hdr->unused;  | 
558  |  | 
  | 
559  | 0  |         if (!WPACKET_put_bytes_u8(pkt, b0)  | 
560  | 0  |             || !WPACKET_put_bytes_u32(pkt, hdr->version)  | 
561  | 0  |             || !WPACKET_put_bytes_u8(pkt, hdr->dst_conn_id.id_len)  | 
562  | 0  |             || !WPACKET_memcpy(pkt, hdr->dst_conn_id.id,  | 
563  | 0  |                                hdr->dst_conn_id.id_len)  | 
564  | 0  |             || !WPACKET_put_bytes_u8(pkt, hdr->src_conn_id.id_len)  | 
565  | 0  |             || !WPACKET_memcpy(pkt, hdr->src_conn_id.id,  | 
566  | 0  |                                hdr->src_conn_id.id_len))  | 
567  | 0  |             return 0;  | 
568  |  |  | 
569  | 0  |         if (hdr->type == QUIC_PKT_TYPE_VERSION_NEG) { | 
570  | 0  |             if (hdr->len > 0 && !WPACKET_reserve_bytes(pkt, hdr->len, NULL))  | 
571  | 0  |                 return 0;  | 
572  |  |  | 
573  | 0  |             return 1;  | 
574  | 0  |         }  | 
575  |  |  | 
576  | 0  |         if (hdr->type == QUIC_PKT_TYPE_INITIAL) { | 
577  | 0  |             if (!WPACKET_quic_write_vlint(pkt, hdr->token_len)  | 
578  | 0  |                 || !WPACKET_memcpy(pkt, hdr->token, hdr->token_len))  | 
579  | 0  |                 return 0;  | 
580  | 0  |         }  | 
581  |  |  | 
582  | 0  |         if (hdr->type == QUIC_PKT_TYPE_RETRY) { | 
583  | 0  |             if (!WPACKET_memcpy(pkt, hdr->token, hdr->token_len))  | 
584  | 0  |                 return 0;  | 
585  | 0  |             return 1;  | 
586  | 0  |         }  | 
587  |  |  | 
588  | 0  |         if (!WPACKET_quic_write_vlint(pkt, hdr->len + hdr->pn_len)  | 
589  | 0  |             || !WPACKET_get_total_written(pkt, &off_pn)  | 
590  | 0  |             || !WPACKET_memcpy(pkt, hdr->pn, hdr->pn_len))  | 
591  | 0  |             return 0;  | 
592  | 0  |     }  | 
593  |  |  | 
594  | 0  |     if (hdr->len > 0 && !WPACKET_reserve_bytes(pkt, hdr->len, NULL))  | 
595  | 0  |         return 0;  | 
596  |  |  | 
597  | 0  |     off_sample = off_pn + 4;  | 
598  |  | 
  | 
599  | 0  |     if (ptrs != NULL) { | 
600  | 0  |         ptrs->raw_start         = start;  | 
601  | 0  |         ptrs->raw_sample        = start + (off_sample - off_start);  | 
602  | 0  |         ptrs->raw_sample_len  | 
603  | 0  |             = WPACKET_get_curr(pkt) + hdr->len - ptrs->raw_sample;  | 
604  | 0  |         ptrs->raw_pn            = start + (off_pn - off_start);  | 
605  | 0  |     }  | 
606  |  | 
  | 
607  | 0  |     return 1;  | 
608  | 0  | }  | 
609  |  |  | 
610  |  | size_t ossl_quic_wire_get_encoded_pkt_hdr_len(size_t short_conn_id_len,  | 
611  |  |                                               const QUIC_PKT_HDR *hdr)  | 
612  | 0  | { | 
613  | 0  |     size_t len = 0, enclen;  | 
614  |  |  | 
615  |  |     /* Cannot serialize a partial header, or one whose DCID length is wrong. */  | 
616  | 0  |     if (hdr->partial  | 
617  | 0  |         || (hdr->type == QUIC_PKT_TYPE_1RTT  | 
618  | 0  |             && hdr->dst_conn_id.id_len != short_conn_id_len))  | 
619  | 0  |         return 0;  | 
620  |  |  | 
621  | 0  |     if (hdr->type == QUIC_PKT_TYPE_1RTT) { | 
622  |  |         /* Short header. */  | 
623  |  |  | 
624  |  |         /*  | 
625  |  |          * Cannot serialize a header whose DCID length is wrong, or with an  | 
626  |  |          * invalid PN length.  | 
627  |  |          */  | 
628  | 0  |         if (hdr->dst_conn_id.id_len != short_conn_id_len  | 
629  | 0  |             || short_conn_id_len > QUIC_MAX_CONN_ID_LEN  | 
630  | 0  |             || hdr->pn_len < 1 || hdr->pn_len > 4)  | 
631  | 0  |             return 0;  | 
632  |  |  | 
633  | 0  |         return 1 + short_conn_id_len + hdr->pn_len;  | 
634  | 0  |     } else { | 
635  |  |         /* Long header. */  | 
636  | 0  |         if (hdr->dst_conn_id.id_len > QUIC_MAX_CONN_ID_LEN  | 
637  | 0  |             || hdr->src_conn_id.id_len > QUIC_MAX_CONN_ID_LEN)  | 
638  | 0  |             return 0;  | 
639  |  |  | 
640  | 0  |         len += 1 /* Initial byte */ + 4 /* Version */  | 
641  | 0  |             + 1 + hdr->dst_conn_id.id_len /* DCID Len, DCID */  | 
642  | 0  |             + 1 + hdr->src_conn_id.id_len /* SCID Len, SCID */  | 
643  | 0  |             ;  | 
644  |  | 
  | 
645  | 0  |         if (ossl_quic_pkt_type_has_pn(hdr->type)) { | 
646  | 0  |             if (hdr->pn_len < 1 || hdr->pn_len > 4)  | 
647  | 0  |                 return 0;  | 
648  |  |  | 
649  | 0  |             len += hdr->pn_len;  | 
650  | 0  |         }  | 
651  |  |  | 
652  | 0  |         if (hdr->type == QUIC_PKT_TYPE_INITIAL) { | 
653  | 0  |             enclen = ossl_quic_vlint_encode_len(hdr->token_len);  | 
654  | 0  |             if (!enclen)  | 
655  | 0  |                 return 0;  | 
656  |  |  | 
657  | 0  |             len += enclen + hdr->token_len;  | 
658  | 0  |         }  | 
659  |  |  | 
660  | 0  |         if (!ossl_quic_pkt_type_must_be_last(hdr->type)) { | 
661  | 0  |             enclen = ossl_quic_vlint_encode_len(hdr->len + hdr->pn_len);  | 
662  | 0  |             if (!enclen)  | 
663  | 0  |                 return 0;  | 
664  |  |  | 
665  | 0  |             len += enclen;  | 
666  | 0  |         }  | 
667  |  |  | 
668  | 0  |         return len;  | 
669  | 0  |     }  | 
670  | 0  | }  | 
671  |  |  | 
672  |  | int ossl_quic_wire_get_pkt_hdr_dst_conn_id(const unsigned char *buf,  | 
673  |  |                                            size_t buf_len,  | 
674  |  |                                            size_t short_conn_id_len,  | 
675  |  |                                            QUIC_CONN_ID *dst_conn_id)  | 
676  | 0  | { | 
677  | 0  |     unsigned char b0;  | 
678  | 0  |     size_t blen;  | 
679  |  | 
  | 
680  | 0  |     if (buf_len < QUIC_MIN_VALID_PKT_LEN  | 
681  | 0  |         || short_conn_id_len > QUIC_MAX_CONN_ID_LEN)  | 
682  | 0  |         return 0;  | 
683  |  |  | 
684  | 0  |     b0 = buf[0];  | 
685  | 0  |     if ((b0 & 0x80) != 0) { | 
686  |  |         /*  | 
687  |  |          * Long header. We need 6 bytes (initial byte, 4 version bytes, DCID  | 
688  |  |          * length byte to begin with). This is covered by the buf_len test  | 
689  |  |          * above.  | 
690  |  |          */  | 
691  |  |  | 
692  |  |         /*  | 
693  |  |          * If the version field is non-zero (meaning that this is not a Version  | 
694  |  |          * Negotiation packet), the fixed bit must be set.  | 
695  |  |          */  | 
696  | 0  |         if ((buf[1] || buf[2] || buf[3] || buf[4]) && (b0 & 0x40) == 0)  | 
697  | 0  |             return 0;  | 
698  |  |  | 
699  | 0  |         blen = (size_t)buf[5]; /* DCID Length */  | 
700  | 0  |         if (blen > QUIC_MAX_CONN_ID_LEN  | 
701  | 0  |             || buf_len < QUIC_MIN_VALID_PKT_LEN + blen)  | 
702  | 0  |             return 0;  | 
703  |  |  | 
704  | 0  |         dst_conn_id->id_len = (unsigned char)blen;  | 
705  | 0  |         memcpy(dst_conn_id->id, buf + 6, blen);  | 
706  | 0  |         return 1;  | 
707  | 0  |     } else { | 
708  |  |         /* Short header. */  | 
709  | 0  |         if ((b0 & 0x40) == 0)  | 
710  |  |             /* Fixed bit not set, not a valid QUIC packet header. */  | 
711  | 0  |             return 0;  | 
712  |  |  | 
713  | 0  |         if (buf_len < QUIC_MIN_VALID_PKT_LEN_CRYPTO + short_conn_id_len)  | 
714  | 0  |             return 0;  | 
715  |  |  | 
716  | 0  |         dst_conn_id->id_len = (unsigned char)short_conn_id_len;  | 
717  | 0  |         memcpy(dst_conn_id->id, buf + 1, short_conn_id_len);  | 
718  | 0  |         return 1;  | 
719  | 0  |     }  | 
720  | 0  | }  | 
721  |  |  | 
722  |  | int ossl_quic_wire_decode_pkt_hdr_pn(const unsigned char *enc_pn,  | 
723  |  |                                      size_t enc_pn_len,  | 
724  |  |                                      QUIC_PN largest_pn,  | 
725  |  |                                      QUIC_PN *res_pn)  | 
726  | 0  | { | 
727  | 0  |     int64_t expected_pn, truncated_pn, candidate_pn, pn_win, pn_hwin, pn_mask;  | 
728  |  | 
  | 
729  | 0  |     switch (enc_pn_len) { | 
730  | 0  |         case 1:  | 
731  | 0  |             truncated_pn = enc_pn[0];  | 
732  | 0  |             break;  | 
733  | 0  |         case 2:  | 
734  | 0  |             truncated_pn = ((QUIC_PN)enc_pn[0] << 8)  | 
735  | 0  |                          |  (QUIC_PN)enc_pn[1];  | 
736  | 0  |             break;  | 
737  | 0  |         case 3:  | 
738  | 0  |             truncated_pn = ((QUIC_PN)enc_pn[0] << 16)  | 
739  | 0  |                          | ((QUIC_PN)enc_pn[1] << 8)  | 
740  | 0  |                          |  (QUIC_PN)enc_pn[2];  | 
741  | 0  |             break;  | 
742  | 0  |         case 4:  | 
743  | 0  |             truncated_pn = ((QUIC_PN)enc_pn[0] << 24)  | 
744  | 0  |                          | ((QUIC_PN)enc_pn[1] << 16)  | 
745  | 0  |                          | ((QUIC_PN)enc_pn[2] << 8)  | 
746  | 0  |                          |  (QUIC_PN)enc_pn[3];  | 
747  | 0  |             break;  | 
748  | 0  |         default:  | 
749  | 0  |             return 0;  | 
750  | 0  |     }  | 
751  |  |  | 
752  |  |     /* Implemented as per RFC 9000 Section A.3. */  | 
753  | 0  |     expected_pn     = largest_pn + 1;  | 
754  | 0  |     pn_win          = ((int64_t)1) << (enc_pn_len * 8);  | 
755  | 0  |     pn_hwin         = pn_win / 2;  | 
756  | 0  |     pn_mask         = pn_win - 1;  | 
757  | 0  |     candidate_pn    = (expected_pn & ~pn_mask) | truncated_pn;  | 
758  | 0  |     if (candidate_pn <= expected_pn - pn_hwin  | 
759  | 0  |         && candidate_pn < (((int64_t)1) << 62) - pn_win)  | 
760  | 0  |         *res_pn = candidate_pn + pn_win;  | 
761  | 0  |     else if (candidate_pn > expected_pn + pn_hwin  | 
762  | 0  |              && candidate_pn >= pn_win)  | 
763  | 0  |         *res_pn = candidate_pn - pn_win;  | 
764  | 0  |     else  | 
765  | 0  |         *res_pn = candidate_pn;  | 
766  | 0  |     return 1;  | 
767  | 0  | }  | 
768  |  |  | 
769  |  | /* From RFC 9000 Section A.2. Simplified implementation. */  | 
770  |  | int ossl_quic_wire_determine_pn_len(QUIC_PN pn,  | 
771  |  |                                     QUIC_PN largest_acked)  | 
772  | 0  | { | 
773  | 0  |     uint64_t num_unacked  | 
774  | 0  |         = (largest_acked == QUIC_PN_INVALID) ? pn + 1 : pn - largest_acked;  | 
775  |  |  | 
776  |  |     /*  | 
777  |  |      * num_unacked \in [    0, 2** 7] -> 1 byte  | 
778  |  |      * num_unacked \in (2** 7, 2**15] -> 2 bytes  | 
779  |  |      * num_unacked \in (2**15, 2**23] -> 3 bytes  | 
780  |  |      * num_unacked \in (2**23,      ] -> 4 bytes  | 
781  |  |      */  | 
782  |  | 
  | 
783  | 0  |     if (num_unacked <= (1U<<7))  return 1;  | 
784  | 0  |     if (num_unacked <= (1U<<15)) return 2;  | 
785  | 0  |     if (num_unacked <= (1U<<23)) return 3;  | 
786  | 0  |     return 4;  | 
787  | 0  | }  | 
788  |  |  | 
789  |  | int ossl_quic_wire_encode_pkt_hdr_pn(QUIC_PN pn,  | 
790  |  |                                      unsigned char *enc_pn,  | 
791  |  |                                      size_t enc_pn_len)  | 
792  | 0  | { | 
793  | 0  |     switch (enc_pn_len) { | 
794  | 0  |         case 1:  | 
795  | 0  |             enc_pn[0] = (unsigned char)pn;  | 
796  | 0  |             break;  | 
797  | 0  |         case 2:  | 
798  | 0  |             enc_pn[1] = (unsigned char)pn;  | 
799  | 0  |             enc_pn[0] = (unsigned char)(pn >> 8);  | 
800  | 0  |             break;  | 
801  | 0  |         case 3:  | 
802  | 0  |             enc_pn[2] = (unsigned char)pn;  | 
803  | 0  |             enc_pn[1] = (unsigned char)(pn >> 8);  | 
804  | 0  |             enc_pn[0] = (unsigned char)(pn >> 16);  | 
805  | 0  |             break;  | 
806  | 0  |         case 4:  | 
807  | 0  |             enc_pn[3] = (unsigned char)pn;  | 
808  | 0  |             enc_pn[2] = (unsigned char)(pn >> 8);  | 
809  | 0  |             enc_pn[1] = (unsigned char)(pn >> 16);  | 
810  | 0  |             enc_pn[0] = (unsigned char)(pn >> 24);  | 
811  | 0  |             break;  | 
812  | 0  |         default:  | 
813  | 0  |             return 0;  | 
814  | 0  |     }  | 
815  |  |  | 
816  | 0  |     return 1;  | 
817  | 0  | }  | 
818  |  |  | 
819  |  | int ossl_quic_validate_retry_integrity_tag(OSSL_LIB_CTX *libctx,  | 
820  |  |                                            const char *propq,  | 
821  |  |                                            const QUIC_PKT_HDR *hdr,  | 
822  |  |                                            const QUIC_CONN_ID *client_initial_dcid)  | 
823  | 0  | { | 
824  | 0  |     unsigned char expected_tag[QUIC_RETRY_INTEGRITY_TAG_LEN];  | 
825  | 0  |     const unsigned char *actual_tag;  | 
826  |  | 
  | 
827  | 0  |     if (hdr == NULL || hdr->len < QUIC_RETRY_INTEGRITY_TAG_LEN)  | 
828  | 0  |         return 0;  | 
829  |  |  | 
830  | 0  |     if (!ossl_quic_calculate_retry_integrity_tag(libctx, propq,  | 
831  | 0  |                                                  hdr, client_initial_dcid,  | 
832  | 0  |                                                  expected_tag))  | 
833  | 0  |         return 0;  | 
834  |  |  | 
835  | 0  |     actual_tag = hdr->data + hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN;  | 
836  |  | 
  | 
837  | 0  |     return !CRYPTO_memcmp(expected_tag, actual_tag,  | 
838  | 0  |                           QUIC_RETRY_INTEGRITY_TAG_LEN);  | 
839  | 0  | }  | 
840  |  |  | 
841  |  | /* RFC 9001 s. 5.8 */  | 
842  |  | static const unsigned char retry_integrity_key[] = { | 
843  |  |     0xbe, 0x0c, 0x69, 0x0b, 0x9f, 0x66, 0x57, 0x5a,  | 
844  |  |     0x1d, 0x76, 0x6b, 0x54, 0xe3, 0x68, 0xc8, 0x4e  | 
845  |  | };  | 
846  |  |  | 
847  |  | static const unsigned char retry_integrity_nonce[] = { | 
848  |  |     0x46, 0x15, 0x99, 0xd3, 0x5d, 0x63, 0x2b, 0xf2,  | 
849  |  |     0x23, 0x98, 0x25, 0xbb  | 
850  |  | };  | 
851  |  |  | 
852  |  | int ossl_quic_calculate_retry_integrity_tag(OSSL_LIB_CTX *libctx,  | 
853  |  |                                             const char *propq,  | 
854  |  |                                             const QUIC_PKT_HDR *hdr,  | 
855  |  |                                             const QUIC_CONN_ID *client_initial_dcid,  | 
856  |  |                                             unsigned char *tag)  | 
857  | 0  | { | 
858  | 0  |     EVP_CIPHER *cipher = NULL;  | 
859  | 0  |     EVP_CIPHER_CTX *cctx = NULL;  | 
860  | 0  |     int ok = 0, l = 0, l2 = 0, wpkt_valid = 0;  | 
861  | 0  |     WPACKET wpkt;  | 
862  |  |     /* Worst case length of the Retry Psuedo-Packet header is 68 bytes. */  | 
863  | 0  |     unsigned char buf[128];  | 
864  | 0  |     QUIC_PKT_HDR hdr2;  | 
865  | 0  |     size_t hdr_enc_len = 0;  | 
866  |  | 
  | 
867  | 0  |     if (hdr->type != QUIC_PKT_TYPE_RETRY || hdr->version == 0  | 
868  | 0  |         || hdr->len < QUIC_RETRY_INTEGRITY_TAG_LEN  | 
869  | 0  |         || hdr->data == NULL  | 
870  | 0  |         || client_initial_dcid == NULL || tag == NULL  | 
871  | 0  |         || client_initial_dcid->id_len > QUIC_MAX_CONN_ID_LEN) { | 
872  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);  | 
873  | 0  |         goto err;  | 
874  | 0  |     }  | 
875  |  |  | 
876  |  |     /*  | 
877  |  |      * Do not reserve packet body in WPACKET. Retry packet header  | 
878  |  |      * does not contain a Length field so this does not affect  | 
879  |  |      * the serialized packet header.  | 
880  |  |      */  | 
881  | 0  |     hdr2 = *hdr;  | 
882  | 0  |     hdr2.len = 0;  | 
883  |  |  | 
884  |  |     /* Assemble retry psuedo-packet. */  | 
885  | 0  |     if (!WPACKET_init_static_len(&wpkt, buf, sizeof(buf), 0)) { | 
886  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);  | 
887  | 0  |         goto err;  | 
888  | 0  |     }  | 
889  |  |  | 
890  | 0  |     wpkt_valid = 1;  | 
891  |  |  | 
892  |  |     /* Prepend original DCID to the packet. */  | 
893  | 0  |     if (!WPACKET_put_bytes_u8(&wpkt, client_initial_dcid->id_len)  | 
894  | 0  |         || !WPACKET_memcpy(&wpkt, client_initial_dcid->id,  | 
895  | 0  |                            client_initial_dcid->id_len)) { | 
896  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);  | 
897  | 0  |         goto err;  | 
898  | 0  |     }  | 
899  |  |  | 
900  |  |     /* Encode main retry header. */  | 
901  | 0  |     if (!ossl_quic_wire_encode_pkt_hdr(&wpkt, hdr2.dst_conn_id.id_len,  | 
902  | 0  |                                        &hdr2, NULL))  | 
903  | 0  |         goto err;  | 
904  |  |  | 
905  | 0  |     if (!WPACKET_get_total_written(&wpkt, &hdr_enc_len)) { | 
906  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_CRYPTO_LIB);  | 
907  | 0  |         goto err;  | 
908  | 0  |     }  | 
909  |  |  | 
910  |  |     /* Create and initialise cipher context. */  | 
911  |  |     /* TODO(QUIC FUTURE): Cipher fetch caching. */  | 
912  | 0  |     if ((cipher = EVP_CIPHER_fetch(libctx, "AES-128-GCM", propq)) == NULL) { | 
913  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
914  | 0  |         goto err;  | 
915  | 0  |     }  | 
916  |  |  | 
917  | 0  |     if ((cctx = EVP_CIPHER_CTX_new()) == NULL) { | 
918  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
919  | 0  |         goto err;  | 
920  | 0  |     }  | 
921  |  |  | 
922  | 0  |     if (!EVP_CipherInit_ex(cctx, cipher, NULL,  | 
923  | 0  |                            retry_integrity_key, retry_integrity_nonce, /*enc=*/1)) { | 
924  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
925  | 0  |         goto err;  | 
926  | 0  |     }  | 
927  |  |  | 
928  |  |     /* Feed packet header as AAD data. */  | 
929  | 0  |     if (EVP_CipherUpdate(cctx, NULL, &l, buf, (int)hdr_enc_len) != 1) { | 
930  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
931  | 0  |         goto err;  | 
932  | 0  |     }  | 
933  |  |  | 
934  |  |     /* Feed packet body as AAD data. */  | 
935  | 0  |     if (EVP_CipherUpdate(cctx, NULL, &l, hdr->data,  | 
936  | 0  |                          (int)(hdr->len - QUIC_RETRY_INTEGRITY_TAG_LEN)) != 1) { | 
937  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
938  | 0  |         goto err;  | 
939  | 0  |     }  | 
940  |  |  | 
941  |  |     /* Finalise and get tag. */  | 
942  | 0  |     if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) { | 
943  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
944  | 0  |         goto err;  | 
945  | 0  |     }  | 
946  |  |  | 
947  | 0  |     if (EVP_CIPHER_CTX_ctrl(cctx, EVP_CTRL_AEAD_GET_TAG,  | 
948  | 0  |                             QUIC_RETRY_INTEGRITY_TAG_LEN,  | 
949  | 0  |                             tag) != 1) { | 
950  | 0  |         ERR_raise(ERR_LIB_SSL, ERR_R_EVP_LIB);  | 
951  | 0  |         goto err;  | 
952  | 0  |     }  | 
953  |  |  | 
954  | 0  |     ok = 1;  | 
955  | 0  | err:  | 
956  | 0  |     EVP_CIPHER_free(cipher);  | 
957  | 0  |     EVP_CIPHER_CTX_free(cctx);  | 
958  | 0  |     if (wpkt_valid)  | 
959  | 0  |         WPACKET_finish(&wpkt);  | 
960  |  | 
  | 
961  | 0  |     return ok;  | 
962  | 0  | }  |