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