xref: /freebsd/crypto/openssl/ssl/quic/quic_lcidm.c (revision e7be843b4a162e68651d3911f0357ed464915629)
1*e7be843bSPierre Pronchery /*
2*e7be843bSPierre Pronchery  * Copyright 2023-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 #include "internal/quic_lcidm.h"
11*e7be843bSPierre Pronchery #include "internal/quic_types.h"
12*e7be843bSPierre Pronchery #include "internal/quic_vlint.h"
13*e7be843bSPierre Pronchery #include "internal/common.h"
14*e7be843bSPierre Pronchery #include "crypto/siphash.h"
15*e7be843bSPierre Pronchery #include <openssl/lhash.h>
16*e7be843bSPierre Pronchery #include <openssl/rand.h>
17*e7be843bSPierre Pronchery #include <openssl/err.h>
18*e7be843bSPierre Pronchery 
19*e7be843bSPierre Pronchery /*
20*e7be843bSPierre Pronchery  * QUIC Local Connection ID Manager
21*e7be843bSPierre Pronchery  * ================================
22*e7be843bSPierre Pronchery  */
23*e7be843bSPierre Pronchery 
24*e7be843bSPierre Pronchery typedef struct quic_lcidm_conn_st QUIC_LCIDM_CONN;
25*e7be843bSPierre Pronchery 
26*e7be843bSPierre Pronchery enum {
27*e7be843bSPierre Pronchery     LCID_TYPE_ODCID,        /* This LCID is the ODCID from the peer */
28*e7be843bSPierre Pronchery     LCID_TYPE_INITIAL,      /* This is our Initial SCID */
29*e7be843bSPierre Pronchery     LCID_TYPE_NCID          /* This LCID was issued via a NCID frame */
30*e7be843bSPierre Pronchery };
31*e7be843bSPierre Pronchery 
32*e7be843bSPierre Pronchery typedef struct quic_lcid_st {
33*e7be843bSPierre Pronchery     QUIC_CONN_ID                cid;
34*e7be843bSPierre Pronchery     uint64_t                    seq_num;
35*e7be843bSPierre Pronchery 
36*e7be843bSPierre Pronchery     /* copy of the hash key from lcidm */
37*e7be843bSPierre Pronchery     uint64_t                    *hash_key;
38*e7be843bSPierre Pronchery 
39*e7be843bSPierre Pronchery     /* Back-pointer to the owning QUIC_LCIDM_CONN structure. */
40*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN             *conn;
41*e7be843bSPierre Pronchery 
42*e7be843bSPierre Pronchery     /* LCID_TYPE_* */
43*e7be843bSPierre Pronchery     unsigned int                type                : 2;
44*e7be843bSPierre Pronchery } QUIC_LCID;
45*e7be843bSPierre Pronchery 
46*e7be843bSPierre Pronchery DEFINE_LHASH_OF_EX(QUIC_LCID);
47*e7be843bSPierre Pronchery DEFINE_LHASH_OF_EX(QUIC_LCIDM_CONN);
48*e7be843bSPierre Pronchery 
49*e7be843bSPierre Pronchery struct quic_lcidm_conn_st {
50*e7be843bSPierre Pronchery     size_t              num_active_lcid;
51*e7be843bSPierre Pronchery     LHASH_OF(QUIC_LCID) *lcids;
52*e7be843bSPierre Pronchery     void                *opaque;
53*e7be843bSPierre Pronchery     QUIC_LCID           *odcid_lcid_obj;
54*e7be843bSPierre Pronchery     uint64_t            next_seq_num;
55*e7be843bSPierre Pronchery 
56*e7be843bSPierre Pronchery     /* Have we enrolled an ODCID? */
57*e7be843bSPierre Pronchery     unsigned int        done_odcid          : 1;
58*e7be843bSPierre Pronchery };
59*e7be843bSPierre Pronchery 
60*e7be843bSPierre Pronchery struct quic_lcidm_st {
61*e7be843bSPierre Pronchery     OSSL_LIB_CTX                *libctx;
62*e7be843bSPierre Pronchery     uint64_t                    hash_key[2]; /* random key for siphash */
63*e7be843bSPierre Pronchery     LHASH_OF(QUIC_LCID)         *lcids; /* (QUIC_CONN_ID) -> (QUIC_LCID *)  */
64*e7be843bSPierre Pronchery     LHASH_OF(QUIC_LCIDM_CONN)   *conns; /* (void *opaque) -> (QUIC_LCIDM_CONN *) */
65*e7be843bSPierre Pronchery     size_t                      lcid_len; /* Length in bytes for all LCIDs */
66*e7be843bSPierre Pronchery #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
67*e7be843bSPierre Pronchery     QUIC_CONN_ID                next_lcid;
68*e7be843bSPierre Pronchery #endif
69*e7be843bSPierre Pronchery };
70*e7be843bSPierre Pronchery 
lcid_hash(const QUIC_LCID * lcid_obj)71*e7be843bSPierre Pronchery static unsigned long lcid_hash(const QUIC_LCID *lcid_obj)
72*e7be843bSPierre Pronchery {
73*e7be843bSPierre Pronchery     SIPHASH siphash = {0, };
74*e7be843bSPierre Pronchery     unsigned long hashval = 0;
75*e7be843bSPierre Pronchery 
76*e7be843bSPierre Pronchery     if (!SipHash_set_hash_size(&siphash, sizeof(unsigned long)))
77*e7be843bSPierre Pronchery         goto out;
78*e7be843bSPierre Pronchery     if (!SipHash_Init(&siphash, (uint8_t *)lcid_obj->hash_key, 0, 0))
79*e7be843bSPierre Pronchery         goto out;
80*e7be843bSPierre Pronchery     SipHash_Update(&siphash, lcid_obj->cid.id, lcid_obj->cid.id_len);
81*e7be843bSPierre Pronchery     if (!SipHash_Final(&siphash, (unsigned char *)&hashval,
82*e7be843bSPierre Pronchery                        sizeof(unsigned long)))
83*e7be843bSPierre Pronchery         goto out;
84*e7be843bSPierre Pronchery out:
85*e7be843bSPierre Pronchery     return hashval;
86*e7be843bSPierre Pronchery }
87*e7be843bSPierre Pronchery 
lcid_comp(const QUIC_LCID * a,const QUIC_LCID * b)88*e7be843bSPierre Pronchery static int lcid_comp(const QUIC_LCID *a, const QUIC_LCID *b)
89*e7be843bSPierre Pronchery {
90*e7be843bSPierre Pronchery     return !ossl_quic_conn_id_eq(&a->cid, &b->cid);
91*e7be843bSPierre Pronchery }
92*e7be843bSPierre Pronchery 
lcidm_conn_hash(const QUIC_LCIDM_CONN * conn)93*e7be843bSPierre Pronchery static unsigned long lcidm_conn_hash(const QUIC_LCIDM_CONN *conn)
94*e7be843bSPierre Pronchery {
95*e7be843bSPierre Pronchery     return (unsigned long)(uintptr_t)conn->opaque;
96*e7be843bSPierre Pronchery }
97*e7be843bSPierre Pronchery 
lcidm_conn_comp(const QUIC_LCIDM_CONN * a,const QUIC_LCIDM_CONN * b)98*e7be843bSPierre Pronchery static int lcidm_conn_comp(const QUIC_LCIDM_CONN *a, const QUIC_LCIDM_CONN *b)
99*e7be843bSPierre Pronchery {
100*e7be843bSPierre Pronchery     return a->opaque != b->opaque;
101*e7be843bSPierre Pronchery }
102*e7be843bSPierre Pronchery 
ossl_quic_lcidm_new(OSSL_LIB_CTX * libctx,size_t lcid_len)103*e7be843bSPierre Pronchery QUIC_LCIDM *ossl_quic_lcidm_new(OSSL_LIB_CTX *libctx, size_t lcid_len)
104*e7be843bSPierre Pronchery {
105*e7be843bSPierre Pronchery     QUIC_LCIDM *lcidm = NULL;
106*e7be843bSPierre Pronchery 
107*e7be843bSPierre Pronchery     if (lcid_len > QUIC_MAX_CONN_ID_LEN)
108*e7be843bSPierre Pronchery         goto err;
109*e7be843bSPierre Pronchery 
110*e7be843bSPierre Pronchery     if ((lcidm = OPENSSL_zalloc(sizeof(*lcidm))) == NULL)
111*e7be843bSPierre Pronchery         goto err;
112*e7be843bSPierre Pronchery 
113*e7be843bSPierre Pronchery     /* generate a random key for the hash tables hash function */
114*e7be843bSPierre Pronchery     if (!RAND_bytes_ex(libctx, (unsigned char *)&lcidm->hash_key,
115*e7be843bSPierre Pronchery                        sizeof(uint64_t) * 2, 0))
116*e7be843bSPierre Pronchery         goto err;
117*e7be843bSPierre Pronchery 
118*e7be843bSPierre Pronchery     if ((lcidm->lcids = lh_QUIC_LCID_new(lcid_hash, lcid_comp)) == NULL)
119*e7be843bSPierre Pronchery         goto err;
120*e7be843bSPierre Pronchery 
121*e7be843bSPierre Pronchery     if ((lcidm->conns = lh_QUIC_LCIDM_CONN_new(lcidm_conn_hash,
122*e7be843bSPierre Pronchery                                                lcidm_conn_comp)) == NULL)
123*e7be843bSPierre Pronchery         goto err;
124*e7be843bSPierre Pronchery 
125*e7be843bSPierre Pronchery     lcidm->libctx   = libctx;
126*e7be843bSPierre Pronchery     lcidm->lcid_len = lcid_len;
127*e7be843bSPierre Pronchery     return lcidm;
128*e7be843bSPierre Pronchery 
129*e7be843bSPierre Pronchery err:
130*e7be843bSPierre Pronchery     if (lcidm != NULL) {
131*e7be843bSPierre Pronchery         lh_QUIC_LCID_free(lcidm->lcids);
132*e7be843bSPierre Pronchery         lh_QUIC_LCIDM_CONN_free(lcidm->conns);
133*e7be843bSPierre Pronchery         OPENSSL_free(lcidm);
134*e7be843bSPierre Pronchery     }
135*e7be843bSPierre Pronchery     return NULL;
136*e7be843bSPierre Pronchery }
137*e7be843bSPierre Pronchery 
138*e7be843bSPierre Pronchery static void lcidm_delete_conn(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn);
139*e7be843bSPierre Pronchery 
lcidm_delete_conn_(QUIC_LCIDM_CONN * conn,void * arg)140*e7be843bSPierre Pronchery static void lcidm_delete_conn_(QUIC_LCIDM_CONN *conn, void *arg)
141*e7be843bSPierre Pronchery {
142*e7be843bSPierre Pronchery     lcidm_delete_conn((QUIC_LCIDM *)arg, conn);
143*e7be843bSPierre Pronchery }
144*e7be843bSPierre Pronchery 
ossl_quic_lcidm_free(QUIC_LCIDM * lcidm)145*e7be843bSPierre Pronchery void ossl_quic_lcidm_free(QUIC_LCIDM *lcidm)
146*e7be843bSPierre Pronchery {
147*e7be843bSPierre Pronchery     if (lcidm == NULL)
148*e7be843bSPierre Pronchery         return;
149*e7be843bSPierre Pronchery 
150*e7be843bSPierre Pronchery     /*
151*e7be843bSPierre Pronchery      * Calling OPENSSL_lh_delete during a doall call is unsafe with our
152*e7be843bSPierre Pronchery      * current LHASH implementation for several reasons:
153*e7be843bSPierre Pronchery      *
154*e7be843bSPierre Pronchery      * - firstly, because deletes can cause the hashtable to be contracted,
155*e7be843bSPierre Pronchery      *   resulting in rehashing which might cause items in later buckets to
156*e7be843bSPierre Pronchery      *   move to earlier buckets, which might cause doall to skip an item,
157*e7be843bSPierre Pronchery      *   resulting in a memory leak;
158*e7be843bSPierre Pronchery      *
159*e7be843bSPierre Pronchery      * - secondly, because doall in general is not safe across hashtable
160*e7be843bSPierre Pronchery      *   size changes, as it caches hashtable size and pointer values
161*e7be843bSPierre Pronchery      *   while operating.
162*e7be843bSPierre Pronchery      *
163*e7be843bSPierre Pronchery      * The fix for this is to disable hashtable contraction using the following
164*e7be843bSPierre Pronchery      * call, which guarantees that no rehashing will occur so long as we only
165*e7be843bSPierre Pronchery      * call delete and not insert.
166*e7be843bSPierre Pronchery      */
167*e7be843bSPierre Pronchery     lh_QUIC_LCIDM_CONN_set_down_load(lcidm->conns, 0);
168*e7be843bSPierre Pronchery 
169*e7be843bSPierre Pronchery     lh_QUIC_LCIDM_CONN_doall_arg(lcidm->conns, lcidm_delete_conn_, lcidm);
170*e7be843bSPierre Pronchery 
171*e7be843bSPierre Pronchery     lh_QUIC_LCID_free(lcidm->lcids);
172*e7be843bSPierre Pronchery     lh_QUIC_LCIDM_CONN_free(lcidm->conns);
173*e7be843bSPierre Pronchery     OPENSSL_free(lcidm);
174*e7be843bSPierre Pronchery }
175*e7be843bSPierre Pronchery 
lcidm_get0_lcid(const QUIC_LCIDM * lcidm,const QUIC_CONN_ID * lcid)176*e7be843bSPierre Pronchery static QUIC_LCID *lcidm_get0_lcid(const QUIC_LCIDM *lcidm, const QUIC_CONN_ID *lcid)
177*e7be843bSPierre Pronchery {
178*e7be843bSPierre Pronchery     QUIC_LCID key;
179*e7be843bSPierre Pronchery 
180*e7be843bSPierre Pronchery     key.cid = *lcid;
181*e7be843bSPierre Pronchery     key.hash_key = (uint64_t *)lcidm->hash_key;
182*e7be843bSPierre Pronchery 
183*e7be843bSPierre Pronchery     if (key.cid.id_len > QUIC_MAX_CONN_ID_LEN)
184*e7be843bSPierre Pronchery         return NULL;
185*e7be843bSPierre Pronchery 
186*e7be843bSPierre Pronchery     return lh_QUIC_LCID_retrieve(lcidm->lcids, &key);
187*e7be843bSPierre Pronchery }
188*e7be843bSPierre Pronchery 
lcidm_get0_conn(const QUIC_LCIDM * lcidm,void * opaque)189*e7be843bSPierre Pronchery static QUIC_LCIDM_CONN *lcidm_get0_conn(const QUIC_LCIDM *lcidm, void *opaque)
190*e7be843bSPierre Pronchery {
191*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN key;
192*e7be843bSPierre Pronchery 
193*e7be843bSPierre Pronchery     key.opaque = opaque;
194*e7be843bSPierre Pronchery 
195*e7be843bSPierre Pronchery     return lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key);
196*e7be843bSPierre Pronchery }
197*e7be843bSPierre Pronchery 
lcidm_upsert_conn(const QUIC_LCIDM * lcidm,void * opaque)198*e7be843bSPierre Pronchery static QUIC_LCIDM_CONN *lcidm_upsert_conn(const QUIC_LCIDM *lcidm, void *opaque)
199*e7be843bSPierre Pronchery {
200*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN *conn = lcidm_get0_conn(lcidm, opaque);
201*e7be843bSPierre Pronchery 
202*e7be843bSPierre Pronchery     if (conn != NULL)
203*e7be843bSPierre Pronchery         return conn;
204*e7be843bSPierre Pronchery 
205*e7be843bSPierre Pronchery     if ((conn = OPENSSL_zalloc(sizeof(*conn))) == NULL)
206*e7be843bSPierre Pronchery         goto err;
207*e7be843bSPierre Pronchery 
208*e7be843bSPierre Pronchery     if ((conn->lcids = lh_QUIC_LCID_new(lcid_hash, lcid_comp)) == NULL)
209*e7be843bSPierre Pronchery         goto err;
210*e7be843bSPierre Pronchery 
211*e7be843bSPierre Pronchery     conn->opaque = opaque;
212*e7be843bSPierre Pronchery 
213*e7be843bSPierre Pronchery     lh_QUIC_LCIDM_CONN_insert(lcidm->conns, conn);
214*e7be843bSPierre Pronchery     if (lh_QUIC_LCIDM_CONN_error(lcidm->conns))
215*e7be843bSPierre Pronchery         goto err;
216*e7be843bSPierre Pronchery 
217*e7be843bSPierre Pronchery     return conn;
218*e7be843bSPierre Pronchery 
219*e7be843bSPierre Pronchery err:
220*e7be843bSPierre Pronchery     if (conn != NULL) {
221*e7be843bSPierre Pronchery         lh_QUIC_LCID_free(conn->lcids);
222*e7be843bSPierre Pronchery         OPENSSL_free(conn);
223*e7be843bSPierre Pronchery     }
224*e7be843bSPierre Pronchery     return NULL;
225*e7be843bSPierre Pronchery }
226*e7be843bSPierre Pronchery 
lcidm_delete_conn_lcid(QUIC_LCIDM * lcidm,QUIC_LCID * lcid_obj)227*e7be843bSPierre Pronchery static void lcidm_delete_conn_lcid(QUIC_LCIDM *lcidm, QUIC_LCID *lcid_obj)
228*e7be843bSPierre Pronchery {
229*e7be843bSPierre Pronchery     lh_QUIC_LCID_delete(lcidm->lcids, lcid_obj);
230*e7be843bSPierre Pronchery     lh_QUIC_LCID_delete(lcid_obj->conn->lcids, lcid_obj);
231*e7be843bSPierre Pronchery     assert(lcid_obj->conn->num_active_lcid > 0);
232*e7be843bSPierre Pronchery     --lcid_obj->conn->num_active_lcid;
233*e7be843bSPierre Pronchery     OPENSSL_free(lcid_obj);
234*e7be843bSPierre Pronchery }
235*e7be843bSPierre Pronchery 
236*e7be843bSPierre Pronchery /* doall_arg wrapper */
lcidm_delete_conn_lcid_(QUIC_LCID * lcid_obj,void * arg)237*e7be843bSPierre Pronchery static void lcidm_delete_conn_lcid_(QUIC_LCID *lcid_obj, void *arg)
238*e7be843bSPierre Pronchery {
239*e7be843bSPierre Pronchery     lcidm_delete_conn_lcid((QUIC_LCIDM *)arg, lcid_obj);
240*e7be843bSPierre Pronchery }
241*e7be843bSPierre Pronchery 
lcidm_delete_conn(QUIC_LCIDM * lcidm,QUIC_LCIDM_CONN * conn)242*e7be843bSPierre Pronchery static void lcidm_delete_conn(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn)
243*e7be843bSPierre Pronchery {
244*e7be843bSPierre Pronchery     /* See comment in ossl_quic_lcidm_free */
245*e7be843bSPierre Pronchery     lh_QUIC_LCID_set_down_load(conn->lcids, 0);
246*e7be843bSPierre Pronchery 
247*e7be843bSPierre Pronchery     lh_QUIC_LCID_doall_arg(conn->lcids, lcidm_delete_conn_lcid_, lcidm);
248*e7be843bSPierre Pronchery     lh_QUIC_LCIDM_CONN_delete(lcidm->conns, conn);
249*e7be843bSPierre Pronchery     lh_QUIC_LCID_free(conn->lcids);
250*e7be843bSPierre Pronchery     OPENSSL_free(conn);
251*e7be843bSPierre Pronchery }
252*e7be843bSPierre Pronchery 
lcidm_conn_new_lcid(QUIC_LCIDM * lcidm,QUIC_LCIDM_CONN * conn,const QUIC_CONN_ID * lcid)253*e7be843bSPierre Pronchery static QUIC_LCID *lcidm_conn_new_lcid(QUIC_LCIDM *lcidm, QUIC_LCIDM_CONN *conn,
254*e7be843bSPierre Pronchery                                       const QUIC_CONN_ID *lcid)
255*e7be843bSPierre Pronchery {
256*e7be843bSPierre Pronchery     QUIC_LCID *lcid_obj = NULL;
257*e7be843bSPierre Pronchery 
258*e7be843bSPierre Pronchery     if (lcid->id_len > QUIC_MAX_CONN_ID_LEN)
259*e7be843bSPierre Pronchery         return NULL;
260*e7be843bSPierre Pronchery 
261*e7be843bSPierre Pronchery     if ((lcid_obj = OPENSSL_zalloc(sizeof(*lcid_obj))) == NULL)
262*e7be843bSPierre Pronchery         goto err;
263*e7be843bSPierre Pronchery 
264*e7be843bSPierre Pronchery     lcid_obj->cid = *lcid;
265*e7be843bSPierre Pronchery     lcid_obj->conn = conn;
266*e7be843bSPierre Pronchery     lcid_obj->hash_key = lcidm->hash_key;
267*e7be843bSPierre Pronchery 
268*e7be843bSPierre Pronchery     lh_QUIC_LCID_insert(conn->lcids, lcid_obj);
269*e7be843bSPierre Pronchery     if (lh_QUIC_LCID_error(conn->lcids))
270*e7be843bSPierre Pronchery         goto err;
271*e7be843bSPierre Pronchery 
272*e7be843bSPierre Pronchery     lh_QUIC_LCID_insert(lcidm->lcids, lcid_obj);
273*e7be843bSPierre Pronchery     if (lh_QUIC_LCID_error(lcidm->lcids)) {
274*e7be843bSPierre Pronchery         lh_QUIC_LCID_delete(conn->lcids, lcid_obj);
275*e7be843bSPierre Pronchery         goto err;
276*e7be843bSPierre Pronchery     }
277*e7be843bSPierre Pronchery 
278*e7be843bSPierre Pronchery     ++conn->num_active_lcid;
279*e7be843bSPierre Pronchery     return lcid_obj;
280*e7be843bSPierre Pronchery 
281*e7be843bSPierre Pronchery err:
282*e7be843bSPierre Pronchery     OPENSSL_free(lcid_obj);
283*e7be843bSPierre Pronchery     return NULL;
284*e7be843bSPierre Pronchery }
285*e7be843bSPierre Pronchery 
ossl_quic_lcidm_get_lcid_len(const QUIC_LCIDM * lcidm)286*e7be843bSPierre Pronchery size_t ossl_quic_lcidm_get_lcid_len(const QUIC_LCIDM *lcidm)
287*e7be843bSPierre Pronchery {
288*e7be843bSPierre Pronchery     return lcidm->lcid_len;
289*e7be843bSPierre Pronchery }
290*e7be843bSPierre Pronchery 
ossl_quic_lcidm_get_num_active_lcid(const QUIC_LCIDM * lcidm,void * opaque)291*e7be843bSPierre Pronchery size_t ossl_quic_lcidm_get_num_active_lcid(const QUIC_LCIDM *lcidm,
292*e7be843bSPierre Pronchery                                            void *opaque)
293*e7be843bSPierre Pronchery {
294*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN *conn;
295*e7be843bSPierre Pronchery 
296*e7be843bSPierre Pronchery     conn = lcidm_get0_conn(lcidm, opaque);
297*e7be843bSPierre Pronchery     if (conn == NULL)
298*e7be843bSPierre Pronchery         return 0;
299*e7be843bSPierre Pronchery 
300*e7be843bSPierre Pronchery     return conn->num_active_lcid;
301*e7be843bSPierre Pronchery }
302*e7be843bSPierre Pronchery 
lcidm_generate_cid(QUIC_LCIDM * lcidm,QUIC_CONN_ID * cid)303*e7be843bSPierre Pronchery static int lcidm_generate_cid(QUIC_LCIDM *lcidm,
304*e7be843bSPierre Pronchery                               QUIC_CONN_ID *cid)
305*e7be843bSPierre Pronchery {
306*e7be843bSPierre Pronchery #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
307*e7be843bSPierre Pronchery     int i;
308*e7be843bSPierre Pronchery 
309*e7be843bSPierre Pronchery     lcidm->next_lcid.id_len = (unsigned char)lcidm->lcid_len;
310*e7be843bSPierre Pronchery     *cid = lcidm->next_lcid;
311*e7be843bSPierre Pronchery 
312*e7be843bSPierre Pronchery     for (i = lcidm->lcid_len - 1; i >= 0; --i)
313*e7be843bSPierre Pronchery         if (++lcidm->next_lcid.id[i] != 0)
314*e7be843bSPierre Pronchery             break;
315*e7be843bSPierre Pronchery 
316*e7be843bSPierre Pronchery     return 1;
317*e7be843bSPierre Pronchery #else
318*e7be843bSPierre Pronchery     return ossl_quic_gen_rand_conn_id(lcidm->libctx, lcidm->lcid_len, cid);
319*e7be843bSPierre Pronchery #endif
320*e7be843bSPierre Pronchery }
321*e7be843bSPierre Pronchery 
lcidm_generate(QUIC_LCIDM * lcidm,void * opaque,unsigned int type,QUIC_CONN_ID * lcid_out,uint64_t * seq_num)322*e7be843bSPierre Pronchery static int lcidm_generate(QUIC_LCIDM *lcidm,
323*e7be843bSPierre Pronchery                           void *opaque,
324*e7be843bSPierre Pronchery                           unsigned int type,
325*e7be843bSPierre Pronchery                           QUIC_CONN_ID *lcid_out,
326*e7be843bSPierre Pronchery                           uint64_t *seq_num)
327*e7be843bSPierre Pronchery {
328*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN *conn;
329*e7be843bSPierre Pronchery     QUIC_LCID key, *lcid_obj;
330*e7be843bSPierre Pronchery     size_t i;
331*e7be843bSPierre Pronchery #define MAX_RETRIES 8
332*e7be843bSPierre Pronchery 
333*e7be843bSPierre Pronchery     if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
334*e7be843bSPierre Pronchery         return 0;
335*e7be843bSPierre Pronchery 
336*e7be843bSPierre Pronchery     if ((type == LCID_TYPE_INITIAL && conn->next_seq_num > 0)
337*e7be843bSPierre Pronchery         || conn->next_seq_num > OSSL_QUIC_VLINT_MAX)
338*e7be843bSPierre Pronchery         return 0;
339*e7be843bSPierre Pronchery 
340*e7be843bSPierre Pronchery     i = 0;
341*e7be843bSPierre Pronchery     do {
342*e7be843bSPierre Pronchery         if (i++ >= MAX_RETRIES)
343*e7be843bSPierre Pronchery             /*
344*e7be843bSPierre Pronchery              * Too many retries; should not happen but if it does, don't loop
345*e7be843bSPierre Pronchery              * endlessly.
346*e7be843bSPierre Pronchery              */
347*e7be843bSPierre Pronchery             return 0;
348*e7be843bSPierre Pronchery 
349*e7be843bSPierre Pronchery         if (!lcidm_generate_cid(lcidm, lcid_out))
350*e7be843bSPierre Pronchery             return 0;
351*e7be843bSPierre Pronchery 
352*e7be843bSPierre Pronchery         key.cid = *lcid_out;
353*e7be843bSPierre Pronchery         key.hash_key = lcidm->hash_key;
354*e7be843bSPierre Pronchery 
355*e7be843bSPierre Pronchery         /* If a collision occurs, retry. */
356*e7be843bSPierre Pronchery     } while (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL);
357*e7be843bSPierre Pronchery 
358*e7be843bSPierre Pronchery     if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid_out)) == NULL)
359*e7be843bSPierre Pronchery         return 0;
360*e7be843bSPierre Pronchery 
361*e7be843bSPierre Pronchery     lcid_obj->seq_num   = conn->next_seq_num;
362*e7be843bSPierre Pronchery     lcid_obj->type      = type;
363*e7be843bSPierre Pronchery 
364*e7be843bSPierre Pronchery     if (seq_num != NULL)
365*e7be843bSPierre Pronchery         *seq_num = lcid_obj->seq_num;
366*e7be843bSPierre Pronchery 
367*e7be843bSPierre Pronchery     ++conn->next_seq_num;
368*e7be843bSPierre Pronchery     return 1;
369*e7be843bSPierre Pronchery }
370*e7be843bSPierre Pronchery 
ossl_quic_lcidm_enrol_odcid(QUIC_LCIDM * lcidm,void * opaque,const QUIC_CONN_ID * initial_odcid)371*e7be843bSPierre Pronchery int ossl_quic_lcidm_enrol_odcid(QUIC_LCIDM *lcidm,
372*e7be843bSPierre Pronchery                                 void *opaque,
373*e7be843bSPierre Pronchery                                 const QUIC_CONN_ID *initial_odcid)
374*e7be843bSPierre Pronchery {
375*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN *conn;
376*e7be843bSPierre Pronchery     QUIC_LCID key, *lcid_obj;
377*e7be843bSPierre Pronchery 
378*e7be843bSPierre Pronchery     if (initial_odcid == NULL || initial_odcid->id_len < QUIC_MIN_ODCID_LEN
379*e7be843bSPierre Pronchery         || initial_odcid->id_len > QUIC_MAX_CONN_ID_LEN)
380*e7be843bSPierre Pronchery         return 0;
381*e7be843bSPierre Pronchery 
382*e7be843bSPierre Pronchery     if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
383*e7be843bSPierre Pronchery         return 0;
384*e7be843bSPierre Pronchery 
385*e7be843bSPierre Pronchery     if (conn->done_odcid)
386*e7be843bSPierre Pronchery         return 0;
387*e7be843bSPierre Pronchery 
388*e7be843bSPierre Pronchery     key.cid = *initial_odcid;
389*e7be843bSPierre Pronchery     key.hash_key = lcidm->hash_key;
390*e7be843bSPierre Pronchery     if (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL)
391*e7be843bSPierre Pronchery         return 0;
392*e7be843bSPierre Pronchery 
393*e7be843bSPierre Pronchery     if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, initial_odcid)) == NULL)
394*e7be843bSPierre Pronchery         return 0;
395*e7be843bSPierre Pronchery 
396*e7be843bSPierre Pronchery     lcid_obj->seq_num       = LCIDM_ODCID_SEQ_NUM;
397*e7be843bSPierre Pronchery     lcid_obj->type          = LCID_TYPE_ODCID;
398*e7be843bSPierre Pronchery 
399*e7be843bSPierre Pronchery     conn->odcid_lcid_obj    = lcid_obj;
400*e7be843bSPierre Pronchery     conn->done_odcid        = 1;
401*e7be843bSPierre Pronchery     return 1;
402*e7be843bSPierre Pronchery }
403*e7be843bSPierre Pronchery 
ossl_quic_lcidm_generate_initial(QUIC_LCIDM * lcidm,void * opaque,QUIC_CONN_ID * initial_lcid)404*e7be843bSPierre Pronchery int ossl_quic_lcidm_generate_initial(QUIC_LCIDM *lcidm,
405*e7be843bSPierre Pronchery                                      void *opaque,
406*e7be843bSPierre Pronchery                                      QUIC_CONN_ID *initial_lcid)
407*e7be843bSPierre Pronchery {
408*e7be843bSPierre Pronchery     return lcidm_generate(lcidm, opaque, LCID_TYPE_INITIAL,
409*e7be843bSPierre Pronchery                           initial_lcid, NULL);
410*e7be843bSPierre Pronchery }
411*e7be843bSPierre Pronchery 
ossl_quic_lcidm_bind_channel(QUIC_LCIDM * lcidm,void * opaque,const QUIC_CONN_ID * lcid)412*e7be843bSPierre Pronchery int ossl_quic_lcidm_bind_channel(QUIC_LCIDM *lcidm, void *opaque,
413*e7be843bSPierre Pronchery                                  const QUIC_CONN_ID *lcid)
414*e7be843bSPierre Pronchery {
415*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN *conn;
416*e7be843bSPierre Pronchery     QUIC_LCID *lcid_obj;
417*e7be843bSPierre Pronchery 
418*e7be843bSPierre Pronchery     /*
419*e7be843bSPierre Pronchery      * the plan is simple:
420*e7be843bSPierre Pronchery      *   make sure the lcid is still unused.
421*e7be843bSPierre Pronchery      *   do the same business as ossl_quic_lcidm_gnerate_initial() does,
422*e7be843bSPierre Pronchery      *   except we will use lcid instead of generating a new one.
423*e7be843bSPierre Pronchery      */
424*e7be843bSPierre Pronchery     if (ossl_quic_lcidm_lookup(lcidm, lcid, NULL, NULL) != 0)
425*e7be843bSPierre Pronchery         return 0;
426*e7be843bSPierre Pronchery 
427*e7be843bSPierre Pronchery     if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
428*e7be843bSPierre Pronchery         return 0;
429*e7be843bSPierre Pronchery 
430*e7be843bSPierre Pronchery     if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid)) == NULL) {
431*e7be843bSPierre Pronchery         lcidm_delete_conn(lcidm, conn);
432*e7be843bSPierre Pronchery         return 0;
433*e7be843bSPierre Pronchery     }
434*e7be843bSPierre Pronchery 
435*e7be843bSPierre Pronchery     lcid_obj->seq_num = conn->next_seq_num;
436*e7be843bSPierre Pronchery     lcid_obj->type = LCID_TYPE_INITIAL;
437*e7be843bSPierre Pronchery     conn->next_seq_num++;
438*e7be843bSPierre Pronchery 
439*e7be843bSPierre Pronchery     return 1;
440*e7be843bSPierre Pronchery }
441*e7be843bSPierre Pronchery 
ossl_quic_lcidm_generate(QUIC_LCIDM * lcidm,void * opaque,OSSL_QUIC_FRAME_NEW_CONN_ID * ncid_frame)442*e7be843bSPierre Pronchery int ossl_quic_lcidm_generate(QUIC_LCIDM *lcidm,
443*e7be843bSPierre Pronchery                              void *opaque,
444*e7be843bSPierre Pronchery                              OSSL_QUIC_FRAME_NEW_CONN_ID *ncid_frame)
445*e7be843bSPierre Pronchery {
446*e7be843bSPierre Pronchery     ncid_frame->seq_num         = 0;
447*e7be843bSPierre Pronchery     ncid_frame->retire_prior_to = 0;
448*e7be843bSPierre Pronchery 
449*e7be843bSPierre Pronchery     return lcidm_generate(lcidm, opaque, LCID_TYPE_NCID,
450*e7be843bSPierre Pronchery                           &ncid_frame->conn_id,
451*e7be843bSPierre Pronchery                           &ncid_frame->seq_num);
452*e7be843bSPierre Pronchery }
453*e7be843bSPierre Pronchery 
ossl_quic_lcidm_retire_odcid(QUIC_LCIDM * lcidm,void * opaque)454*e7be843bSPierre Pronchery int ossl_quic_lcidm_retire_odcid(QUIC_LCIDM *lcidm, void *opaque)
455*e7be843bSPierre Pronchery {
456*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN *conn;
457*e7be843bSPierre Pronchery 
458*e7be843bSPierre Pronchery     if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
459*e7be843bSPierre Pronchery         return 0;
460*e7be843bSPierre Pronchery 
461*e7be843bSPierre Pronchery     if (conn->odcid_lcid_obj == NULL)
462*e7be843bSPierre Pronchery         return 0;
463*e7be843bSPierre Pronchery 
464*e7be843bSPierre Pronchery     lcidm_delete_conn_lcid(lcidm, conn->odcid_lcid_obj);
465*e7be843bSPierre Pronchery     conn->odcid_lcid_obj = NULL;
466*e7be843bSPierre Pronchery     return 1;
467*e7be843bSPierre Pronchery }
468*e7be843bSPierre Pronchery 
469*e7be843bSPierre Pronchery struct retire_args {
470*e7be843bSPierre Pronchery     QUIC_LCID           *earliest_seq_num_lcid_obj;
471*e7be843bSPierre Pronchery     uint64_t            earliest_seq_num, retire_prior_to;
472*e7be843bSPierre Pronchery };
473*e7be843bSPierre Pronchery 
retire_for_conn(QUIC_LCID * lcid_obj,void * arg)474*e7be843bSPierre Pronchery static void retire_for_conn(QUIC_LCID *lcid_obj, void *arg)
475*e7be843bSPierre Pronchery {
476*e7be843bSPierre Pronchery     struct retire_args *args = arg;
477*e7be843bSPierre Pronchery 
478*e7be843bSPierre Pronchery     /* ODCID LCID cannot be retired via this API */
479*e7be843bSPierre Pronchery     if (lcid_obj->type == LCID_TYPE_ODCID
480*e7be843bSPierre Pronchery         || lcid_obj->seq_num >= args->retire_prior_to)
481*e7be843bSPierre Pronchery         return;
482*e7be843bSPierre Pronchery 
483*e7be843bSPierre Pronchery     if (lcid_obj->seq_num < args->earliest_seq_num) {
484*e7be843bSPierre Pronchery         args->earliest_seq_num          = lcid_obj->seq_num;
485*e7be843bSPierre Pronchery         args->earliest_seq_num_lcid_obj = lcid_obj;
486*e7be843bSPierre Pronchery     }
487*e7be843bSPierre Pronchery }
488*e7be843bSPierre Pronchery 
ossl_quic_lcidm_retire(QUIC_LCIDM * lcidm,void * opaque,uint64_t retire_prior_to,const QUIC_CONN_ID * containing_pkt_dcid,QUIC_CONN_ID * retired_lcid,uint64_t * retired_seq_num,int * did_retire)489*e7be843bSPierre Pronchery int ossl_quic_lcidm_retire(QUIC_LCIDM *lcidm,
490*e7be843bSPierre Pronchery                            void *opaque,
491*e7be843bSPierre Pronchery                            uint64_t retire_prior_to,
492*e7be843bSPierre Pronchery                            const QUIC_CONN_ID *containing_pkt_dcid,
493*e7be843bSPierre Pronchery                            QUIC_CONN_ID *retired_lcid,
494*e7be843bSPierre Pronchery                            uint64_t *retired_seq_num,
495*e7be843bSPierre Pronchery                            int *did_retire)
496*e7be843bSPierre Pronchery {
497*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN key, *conn;
498*e7be843bSPierre Pronchery     struct retire_args args = {0};
499*e7be843bSPierre Pronchery 
500*e7be843bSPierre Pronchery     key.opaque = opaque;
501*e7be843bSPierre Pronchery 
502*e7be843bSPierre Pronchery     if (did_retire == NULL)
503*e7be843bSPierre Pronchery         return 0;
504*e7be843bSPierre Pronchery 
505*e7be843bSPierre Pronchery     *did_retire = 0;
506*e7be843bSPierre Pronchery     if ((conn = lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key)) == NULL)
507*e7be843bSPierre Pronchery         return 1;
508*e7be843bSPierre Pronchery 
509*e7be843bSPierre Pronchery     args.retire_prior_to    = retire_prior_to;
510*e7be843bSPierre Pronchery     args.earliest_seq_num   = UINT64_MAX;
511*e7be843bSPierre Pronchery 
512*e7be843bSPierre Pronchery     lh_QUIC_LCID_doall_arg(conn->lcids, retire_for_conn, &args);
513*e7be843bSPierre Pronchery     if (args.earliest_seq_num_lcid_obj == NULL)
514*e7be843bSPierre Pronchery         return 1;
515*e7be843bSPierre Pronchery 
516*e7be843bSPierre Pronchery     if (containing_pkt_dcid != NULL
517*e7be843bSPierre Pronchery         && ossl_quic_conn_id_eq(&args.earliest_seq_num_lcid_obj->cid,
518*e7be843bSPierre Pronchery                                 containing_pkt_dcid))
519*e7be843bSPierre Pronchery         return 0;
520*e7be843bSPierre Pronchery 
521*e7be843bSPierre Pronchery     *did_retire = 1;
522*e7be843bSPierre Pronchery     if (retired_lcid != NULL)
523*e7be843bSPierre Pronchery         *retired_lcid = args.earliest_seq_num_lcid_obj->cid;
524*e7be843bSPierre Pronchery     if (retired_seq_num != NULL)
525*e7be843bSPierre Pronchery         *retired_seq_num = args.earliest_seq_num_lcid_obj->seq_num;
526*e7be843bSPierre Pronchery 
527*e7be843bSPierre Pronchery     lcidm_delete_conn_lcid(lcidm, args.earliest_seq_num_lcid_obj);
528*e7be843bSPierre Pronchery     return 1;
529*e7be843bSPierre Pronchery }
530*e7be843bSPierre Pronchery 
ossl_quic_lcidm_cull(QUIC_LCIDM * lcidm,void * opaque)531*e7be843bSPierre Pronchery int ossl_quic_lcidm_cull(QUIC_LCIDM *lcidm, void *opaque)
532*e7be843bSPierre Pronchery {
533*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN key, *conn;
534*e7be843bSPierre Pronchery 
535*e7be843bSPierre Pronchery     key.opaque = opaque;
536*e7be843bSPierre Pronchery 
537*e7be843bSPierre Pronchery     if ((conn = lh_QUIC_LCIDM_CONN_retrieve(lcidm->conns, &key)) == NULL)
538*e7be843bSPierre Pronchery         return 0;
539*e7be843bSPierre Pronchery 
540*e7be843bSPierre Pronchery     lcidm_delete_conn(lcidm, conn);
541*e7be843bSPierre Pronchery     return 1;
542*e7be843bSPierre Pronchery }
543*e7be843bSPierre Pronchery 
ossl_quic_lcidm_lookup(QUIC_LCIDM * lcidm,const QUIC_CONN_ID * lcid,uint64_t * seq_num,void ** opaque)544*e7be843bSPierre Pronchery int ossl_quic_lcidm_lookup(QUIC_LCIDM *lcidm,
545*e7be843bSPierre Pronchery                            const QUIC_CONN_ID *lcid,
546*e7be843bSPierre Pronchery                            uint64_t *seq_num,
547*e7be843bSPierre Pronchery                            void **opaque)
548*e7be843bSPierre Pronchery {
549*e7be843bSPierre Pronchery     QUIC_LCID *lcid_obj;
550*e7be843bSPierre Pronchery 
551*e7be843bSPierre Pronchery     if (lcid == NULL)
552*e7be843bSPierre Pronchery         return 0;
553*e7be843bSPierre Pronchery 
554*e7be843bSPierre Pronchery     if ((lcid_obj = lcidm_get0_lcid(lcidm, lcid)) == NULL)
555*e7be843bSPierre Pronchery         return 0;
556*e7be843bSPierre Pronchery 
557*e7be843bSPierre Pronchery     if (seq_num != NULL)
558*e7be843bSPierre Pronchery         *seq_num        = lcid_obj->seq_num;
559*e7be843bSPierre Pronchery 
560*e7be843bSPierre Pronchery     if (opaque != NULL)
561*e7be843bSPierre Pronchery         *opaque         = lcid_obj->conn->opaque;
562*e7be843bSPierre Pronchery 
563*e7be843bSPierre Pronchery     return 1;
564*e7be843bSPierre Pronchery }
565*e7be843bSPierre Pronchery 
ossl_quic_lcidm_debug_remove(QUIC_LCIDM * lcidm,const QUIC_CONN_ID * lcid)566*e7be843bSPierre Pronchery int ossl_quic_lcidm_debug_remove(QUIC_LCIDM *lcidm,
567*e7be843bSPierre Pronchery                                  const QUIC_CONN_ID *lcid)
568*e7be843bSPierre Pronchery {
569*e7be843bSPierre Pronchery     QUIC_LCID key, *lcid_obj;
570*e7be843bSPierre Pronchery 
571*e7be843bSPierre Pronchery     key.cid = *lcid;
572*e7be843bSPierre Pronchery     key.hash_key = lcidm->hash_key;
573*e7be843bSPierre Pronchery     if ((lcid_obj = lh_QUIC_LCID_retrieve(lcidm->lcids, &key)) == NULL)
574*e7be843bSPierre Pronchery         return 0;
575*e7be843bSPierre Pronchery 
576*e7be843bSPierre Pronchery     lcidm_delete_conn_lcid(lcidm, lcid_obj);
577*e7be843bSPierre Pronchery     return 1;
578*e7be843bSPierre Pronchery }
579*e7be843bSPierre Pronchery 
ossl_quic_lcidm_debug_add(QUIC_LCIDM * lcidm,void * opaque,const QUIC_CONN_ID * lcid,uint64_t seq_num)580*e7be843bSPierre Pronchery int ossl_quic_lcidm_debug_add(QUIC_LCIDM *lcidm, void *opaque,
581*e7be843bSPierre Pronchery                               const QUIC_CONN_ID *lcid,
582*e7be843bSPierre Pronchery                               uint64_t seq_num)
583*e7be843bSPierre Pronchery {
584*e7be843bSPierre Pronchery     QUIC_LCIDM_CONN *conn;
585*e7be843bSPierre Pronchery     QUIC_LCID key, *lcid_obj;
586*e7be843bSPierre Pronchery 
587*e7be843bSPierre Pronchery     if (lcid == NULL || lcid->id_len > QUIC_MAX_CONN_ID_LEN)
588*e7be843bSPierre Pronchery         return 0;
589*e7be843bSPierre Pronchery 
590*e7be843bSPierre Pronchery     if ((conn = lcidm_upsert_conn(lcidm, opaque)) == NULL)
591*e7be843bSPierre Pronchery         return 0;
592*e7be843bSPierre Pronchery 
593*e7be843bSPierre Pronchery     key.cid = *lcid;
594*e7be843bSPierre Pronchery     key.hash_key = lcidm->hash_key;
595*e7be843bSPierre Pronchery     if (lh_QUIC_LCID_retrieve(lcidm->lcids, &key) != NULL)
596*e7be843bSPierre Pronchery         return 0;
597*e7be843bSPierre Pronchery 
598*e7be843bSPierre Pronchery     if ((lcid_obj = lcidm_conn_new_lcid(lcidm, conn, lcid)) == NULL)
599*e7be843bSPierre Pronchery         return 0;
600*e7be843bSPierre Pronchery 
601*e7be843bSPierre Pronchery     lcid_obj->seq_num   = seq_num;
602*e7be843bSPierre Pronchery     lcid_obj->type      = LCID_TYPE_NCID;
603*e7be843bSPierre Pronchery     return 1;
604*e7be843bSPierre Pronchery }
605*e7be843bSPierre Pronchery 
ossl_quic_lcidm_get_unused_cid(QUIC_LCIDM * lcidm,QUIC_CONN_ID * cid)606*e7be843bSPierre Pronchery int ossl_quic_lcidm_get_unused_cid(QUIC_LCIDM *lcidm, QUIC_CONN_ID *cid)
607*e7be843bSPierre Pronchery {
608*e7be843bSPierre Pronchery     int i;
609*e7be843bSPierre Pronchery 
610*e7be843bSPierre Pronchery     for (i = 0; i < 10; i++) {
611*e7be843bSPierre Pronchery         if (lcidm_generate_cid(lcidm, cid)
612*e7be843bSPierre Pronchery             && lcidm_get0_lcid(lcidm, cid) == NULL)
613*e7be843bSPierre Pronchery             return 1; /* not found <=> radomly generated cid is unused */
614*e7be843bSPierre Pronchery     }
615*e7be843bSPierre Pronchery 
616*e7be843bSPierre Pronchery     return 0;
617*e7be843bSPierre Pronchery }
618