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