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