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