Coverage Report

Created: 2025-12-31 06:58

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