/src/openssl33/ssl/quic/quic_srtm.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2023-2024 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_srtm.h" |
11 | | #include "internal/common.h" |
12 | | #include <openssl/lhash.h> |
13 | | #include <openssl/core_names.h> |
14 | | #include <openssl/rand.h> |
15 | | |
16 | | /* |
17 | | * QUIC Stateless Reset Token Manager |
18 | | * ================================== |
19 | | */ |
20 | | typedef struct srtm_item_st SRTM_ITEM; |
21 | | |
22 | | #define BLINDED_SRT_LEN 16 |
23 | | |
24 | | DEFINE_LHASH_OF_EX(SRTM_ITEM); |
25 | | |
26 | | /* |
27 | | * The SRTM is implemented using two LHASH instances, one matching opaque pointers to |
28 | | * an item structure, and another matching a SRT-derived value to an item |
29 | | * structure. Multiple items with different seq_num values under a given opaque, |
30 | | * and duplicate SRTs, are handled using sorted singly-linked lists. |
31 | | * |
32 | | * The O(n) insert and lookup performance is tolerated on the basis that the |
33 | | * total number of entries for a given opaque (total number of extant CIDs for a |
34 | | * connection) should be quite small, and the QUIC protocol allows us to place a |
35 | | * hard limit on this via the active_connection_id_limit TPARAM. Thus there is |
36 | | * no risk of a large number of SRTs needing to be registered under a given |
37 | | * opaque. |
38 | | * |
39 | | * It is expected one SRTM will exist per QUIC_PORT and track all SRTs across |
40 | | * all connections for that QUIC_PORT. |
41 | | */ |
42 | | struct srtm_item_st { |
43 | | SRTM_ITEM *next_by_srt_blinded; /* SORT BY opaque DESC */ |
44 | | SRTM_ITEM *next_by_seq_num; /* SORT BY seq_num DESC */ |
45 | | void *opaque; /* \__ unique identity for item */ |
46 | | uint64_t seq_num; /* / */ |
47 | | QUIC_STATELESS_RESET_TOKEN srt; |
48 | | unsigned char srt_blinded[BLINDED_SRT_LEN]; /* H(srt) */ |
49 | | |
50 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
51 | | uint32_t debug_token; |
52 | | #endif |
53 | | }; |
54 | | |
55 | | struct quic_srtm_st { |
56 | | /* Crypto context used to calculate blinded SRTs H(srt). */ |
57 | | EVP_CIPHER_CTX *blind_ctx; /* kept with key */ |
58 | | |
59 | | LHASH_OF(SRTM_ITEM) *items_fwd; /* (opaque) -> SRTM_ITEM */ |
60 | | LHASH_OF(SRTM_ITEM) *items_rev; /* (H(srt)) -> SRTM_ITEM */ |
61 | | |
62 | | /* |
63 | | * Monotonically transitions to 1 in event of allocation failure. The only |
64 | | * valid operation on such an object is to free it. |
65 | | */ |
66 | | unsigned int alloc_failed : 1; |
67 | | }; |
68 | | |
69 | | static unsigned long items_fwd_hash(const SRTM_ITEM *item) |
70 | 4.09M | { |
71 | 4.09M | return (unsigned long)(uintptr_t)item->opaque; |
72 | 4.09M | } |
73 | | |
74 | | static int items_fwd_cmp(const SRTM_ITEM *a, const SRTM_ITEM *b) |
75 | 1.39M | { |
76 | 1.39M | return a->opaque != b->opaque; |
77 | 1.39M | } |
78 | | |
79 | | static unsigned long items_rev_hash(const SRTM_ITEM *item) |
80 | 6.73M | { |
81 | | /* |
82 | | * srt_blinded has already been through a crypto-grade hash function, so we |
83 | | * can just use bits from that. |
84 | | */ |
85 | 6.73M | unsigned long l; |
86 | | |
87 | 6.73M | memcpy(&l, item->srt_blinded, sizeof(l)); |
88 | 6.73M | return l; |
89 | 6.73M | } |
90 | | |
91 | | static int items_rev_cmp(const SRTM_ITEM *a, const SRTM_ITEM *b) |
92 | 451k | { |
93 | | /* |
94 | | * We don't need to use CRYPTO_memcmp here as the relationship of |
95 | | * srt_blinded to srt is already cryptographically obfuscated. |
96 | | */ |
97 | 451k | return memcmp(a->srt_blinded, b->srt_blinded, sizeof(a->srt_blinded)); |
98 | 451k | } |
99 | | |
100 | | static int srtm_check_lh(QUIC_SRTM *srtm, LHASH_OF(SRTM_ITEM) *lh) |
101 | 1.50M | { |
102 | 1.50M | if (lh_SRTM_ITEM_error(lh)) { |
103 | 0 | srtm->alloc_failed = 1; |
104 | 0 | return 0; |
105 | 0 | } |
106 | | |
107 | 1.50M | return 1; |
108 | 1.50M | } |
109 | | |
110 | | QUIC_SRTM *ossl_quic_srtm_new(OSSL_LIB_CTX *libctx, const char *propq) |
111 | 57.8k | { |
112 | 57.8k | QUIC_SRTM *srtm = NULL; |
113 | 57.8k | unsigned char key[16]; |
114 | 57.8k | EVP_CIPHER *ecb = NULL; |
115 | | |
116 | 57.8k | if (RAND_priv_bytes_ex(libctx, key, sizeof(key), sizeof(key) * 8) != 1) |
117 | 0 | goto err; |
118 | | |
119 | 57.8k | if ((srtm = OPENSSL_zalloc(sizeof(*srtm))) == NULL) |
120 | 0 | return NULL; |
121 | | |
122 | | /* Use AES-128-ECB as a permutation over 128-bit SRTs. */ |
123 | 57.8k | if ((ecb = EVP_CIPHER_fetch(libctx, "AES-128-ECB", propq)) == NULL) |
124 | 0 | goto err; |
125 | | |
126 | 57.8k | if ((srtm->blind_ctx = EVP_CIPHER_CTX_new()) == NULL) |
127 | 0 | goto err; |
128 | | |
129 | 57.8k | if (!EVP_EncryptInit_ex2(srtm->blind_ctx, ecb, key, NULL, NULL)) |
130 | 0 | goto err; |
131 | | |
132 | 57.8k | EVP_CIPHER_free(ecb); |
133 | 57.8k | ecb = NULL; |
134 | | |
135 | | /* Create mappings. */ |
136 | 57.8k | if ((srtm->items_fwd = lh_SRTM_ITEM_new(items_fwd_hash, items_fwd_cmp)) == NULL |
137 | 57.8k | || (srtm->items_rev = lh_SRTM_ITEM_new(items_rev_hash, items_rev_cmp)) == NULL) |
138 | 0 | goto err; |
139 | | |
140 | 57.8k | return srtm; |
141 | | |
142 | 0 | err: |
143 | | /* |
144 | | * No cleansing of key needed as blinding exists only for side channel |
145 | | * mitigation. |
146 | | */ |
147 | 0 | ossl_quic_srtm_free(srtm); |
148 | 0 | EVP_CIPHER_free(ecb); |
149 | 0 | return NULL; |
150 | 57.8k | } |
151 | | |
152 | | static void srtm_free_each(SRTM_ITEM *ihead) |
153 | 608k | { |
154 | 608k | SRTM_ITEM *inext, *item = ihead; |
155 | | |
156 | 675k | for (item = item->next_by_seq_num; item != NULL; item = inext) { |
157 | 67.4k | inext = item->next_by_seq_num; |
158 | 67.4k | OPENSSL_free(item); |
159 | 67.4k | } |
160 | | |
161 | 608k | OPENSSL_free(ihead); |
162 | 608k | } |
163 | | |
164 | | void ossl_quic_srtm_free(QUIC_SRTM *srtm) |
165 | 57.8k | { |
166 | 57.8k | if (srtm == NULL) |
167 | 0 | return; |
168 | | |
169 | 57.8k | lh_SRTM_ITEM_free(srtm->items_rev); |
170 | 57.8k | if (srtm->items_fwd != NULL) { |
171 | | /* |
172 | | * We don't need to call lh_SRTM_ITEM_set_down_load(..., 0) |
173 | | * here because srtm_free_each() callback for _doall() does |
174 | | * not call to lh_SRTIM_ITEM_delete(). |
175 | | */ |
176 | 57.8k | lh_SRTM_ITEM_doall(srtm->items_fwd, srtm_free_each); |
177 | 57.8k | lh_SRTM_ITEM_free(srtm->items_fwd); |
178 | 57.8k | } |
179 | | |
180 | 57.8k | EVP_CIPHER_CTX_free(srtm->blind_ctx); |
181 | 57.8k | OPENSSL_free(srtm); |
182 | 57.8k | } |
183 | | |
184 | | /* |
185 | | * Find a SRTM_ITEM by (opaque, seq_num). Returns NULL if no match. |
186 | | * If head is non-NULL, writes the head of the relevant opaque list to *head if |
187 | | * there is one. |
188 | | * If prev is non-NULL, writes the previous node to *prev or NULL if it is |
189 | | * the first item. |
190 | | */ |
191 | | static SRTM_ITEM *srtm_find(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num, |
192 | | SRTM_ITEM **head_p, SRTM_ITEM **prev_p) |
193 | 2.36M | { |
194 | 2.36M | SRTM_ITEM key, *item = NULL, *prev = NULL; |
195 | | |
196 | 2.36M | key.opaque = opaque; |
197 | | |
198 | 2.36M | item = lh_SRTM_ITEM_retrieve(srtm->items_fwd, &key); |
199 | 2.36M | if (head_p != NULL) |
200 | 1.88M | *head_p = item; |
201 | | |
202 | 17.7M | for (; item != NULL; prev = item, item = item->next_by_seq_num) |
203 | 16.5M | if (item->seq_num == seq_num) { |
204 | 1.05M | break; |
205 | 15.5M | } else if (item->seq_num < seq_num) { |
206 | | /* |
207 | | * List is sorted in descending order so there can't be any match |
208 | | * after this. |
209 | | */ |
210 | 193k | item = NULL; |
211 | 193k | break; |
212 | 193k | } |
213 | | |
214 | 2.36M | if (prev_p != NULL) |
215 | 489k | *prev_p = prev; |
216 | | |
217 | 2.36M | return item; |
218 | 2.36M | } |
219 | | |
220 | | /* |
221 | | * Inserts a SRTM_ITEM into the singly-linked by-sequence-number linked list. |
222 | | * The new head pointer is written to *new_head (which may or may not be |
223 | | * unchanged). |
224 | | */ |
225 | | static void sorted_insert_seq_num(SRTM_ITEM *head, SRTM_ITEM *item, SRTM_ITEM **new_head) |
226 | 210k | { |
227 | 210k | uint64_t seq_num = item->seq_num; |
228 | 210k | SRTM_ITEM *cur = head, **fixup = new_head; |
229 | | |
230 | 210k | *new_head = head; |
231 | | |
232 | 1.96M | while (cur != NULL && cur->seq_num > seq_num) { |
233 | 1.75M | fixup = &cur->next_by_seq_num; |
234 | 1.75M | cur = cur->next_by_seq_num; |
235 | 1.75M | } |
236 | | |
237 | 210k | item->next_by_seq_num = *fixup; |
238 | 210k | *fixup = item; |
239 | 210k | } |
240 | | |
241 | | /* |
242 | | * Inserts a SRTM_ITEM into the singly-linked by-SRT list. |
243 | | * The new head pointer is written to *new_head (which may or may not be |
244 | | * unchanged). |
245 | | */ |
246 | | static void sorted_insert_srt(SRTM_ITEM *head, SRTM_ITEM *item, SRTM_ITEM **new_head) |
247 | 48.7k | { |
248 | 48.7k | uintptr_t opaque = (uintptr_t)item->opaque; |
249 | 48.7k | SRTM_ITEM *cur = head, **fixup = new_head; |
250 | | |
251 | 48.7k | *new_head = head; |
252 | | |
253 | 544k | while (cur != NULL && (uintptr_t)cur->opaque > opaque) { |
254 | 495k | fixup = &cur->next_by_srt_blinded; |
255 | 495k | cur = cur->next_by_srt_blinded; |
256 | 495k | } |
257 | | |
258 | 48.7k | item->next_by_srt_blinded = *fixup; |
259 | 48.7k | *fixup = item; |
260 | 48.7k | } |
261 | | |
262 | | /* |
263 | | * Computes the blinded SRT value used for internal lookup for side channel |
264 | | * mitigation purposes. We compute this once as a cached value when an SRTM_ITEM |
265 | | * is formed. |
266 | | */ |
267 | | static int srtm_compute_blinded(QUIC_SRTM *srtm, SRTM_ITEM *item, |
268 | | const QUIC_STATELESS_RESET_TOKEN *token) |
269 | 5.60M | { |
270 | 5.60M | int outl = 0; |
271 | | |
272 | | /* |
273 | | * We use AES-128-ECB as a permutation using a random key to facilitate |
274 | | * blinding for side-channel purposes. Encrypt the token as a single AES |
275 | | * block. |
276 | | */ |
277 | 5.60M | if (!EVP_EncryptUpdate(srtm->blind_ctx, item->srt_blinded, &outl, |
278 | 5.60M | (const unsigned char *)token, sizeof(*token))) |
279 | 0 | return 0; |
280 | | |
281 | 5.60M | if (!ossl_assert(outl == sizeof(*token))) |
282 | 0 | return 0; |
283 | | |
284 | 5.60M | return 1; |
285 | 5.60M | } |
286 | | |
287 | | int ossl_quic_srtm_add(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num, |
288 | | const QUIC_STATELESS_RESET_TOKEN *token) |
289 | 1.88M | { |
290 | 1.88M | SRTM_ITEM *item = NULL, *head = NULL, *new_head, *r_item; |
291 | | |
292 | 1.88M | if (srtm->alloc_failed) |
293 | 0 | return 0; |
294 | | |
295 | | /* (opaque, seq_num) duplicates not allowed */ |
296 | 1.88M | if ((item = srtm_find(srtm, opaque, seq_num, &head, NULL)) != NULL) |
297 | 1.03M | return 0; |
298 | | |
299 | 842k | if ((item = OPENSSL_zalloc(sizeof(*item))) == NULL) |
300 | 0 | return 0; |
301 | | |
302 | 842k | item->opaque = opaque; |
303 | 842k | item->seq_num = seq_num; |
304 | 842k | item->srt = *token; |
305 | 842k | if (!srtm_compute_blinded(srtm, item, &item->srt)) { |
306 | 0 | OPENSSL_free(item); |
307 | 0 | return 0; |
308 | 0 | } |
309 | | |
310 | | /* Add to forward mapping. */ |
311 | 842k | if (head == NULL) { |
312 | | /* First item under this opaque */ |
313 | 632k | lh_SRTM_ITEM_insert(srtm->items_fwd, item); |
314 | 632k | if (!srtm_check_lh(srtm, srtm->items_fwd)) { |
315 | 0 | OPENSSL_free(item); |
316 | 0 | return 0; |
317 | 0 | } |
318 | 632k | } else { |
319 | 210k | sorted_insert_seq_num(head, item, &new_head); |
320 | 210k | if (new_head != head) { /* head changed, update in lhash */ |
321 | 51.4k | lh_SRTM_ITEM_insert(srtm->items_fwd, new_head); |
322 | 51.4k | if (!srtm_check_lh(srtm, srtm->items_fwd)) { |
323 | 0 | OPENSSL_free(item); |
324 | 0 | return 0; |
325 | 0 | } |
326 | 51.4k | } |
327 | 210k | } |
328 | | |
329 | | /* Add to reverse mapping. */ |
330 | 842k | r_item = lh_SRTM_ITEM_retrieve(srtm->items_rev, item); |
331 | 842k | if (r_item == NULL) { |
332 | | /* First item under this blinded SRT */ |
333 | 793k | lh_SRTM_ITEM_insert(srtm->items_rev, item); |
334 | 793k | if (!srtm_check_lh(srtm, srtm->items_rev)) |
335 | | /* |
336 | | * Can't free the item now as we would have to undo the insertion |
337 | | * into the forward mapping which would require an insert operation |
338 | | * to restore the previous value. which might also fail. However, |
339 | | * the item will be freed OK when we free the entire SRTM. |
340 | | */ |
341 | 0 | return 0; |
342 | 793k | } else { |
343 | 48.7k | sorted_insert_srt(r_item, item, &new_head); |
344 | 48.7k | if (new_head != r_item) { /* head changed, update in lhash */ |
345 | 19.3k | lh_SRTM_ITEM_insert(srtm->items_rev, new_head); |
346 | 19.3k | if (!srtm_check_lh(srtm, srtm->items_rev)) |
347 | | /* As above. */ |
348 | 0 | return 0; |
349 | 19.3k | } |
350 | 48.7k | } |
351 | | |
352 | 842k | return 1; |
353 | 842k | } |
354 | | |
355 | | /* Remove item from reverse mapping. */ |
356 | | static int srtm_remove_from_rev(QUIC_SRTM *srtm, SRTM_ITEM *item) |
357 | 166k | { |
358 | 166k | SRTM_ITEM *rh_item; |
359 | | |
360 | 166k | rh_item = lh_SRTM_ITEM_retrieve(srtm->items_rev, item); |
361 | 166k | assert(rh_item != NULL); |
362 | 166k | if (rh_item == item) { |
363 | | /* |
364 | | * Change lhash to point to item after this one, or remove the entry if |
365 | | * this is the last one. |
366 | | */ |
367 | 150k | if (item->next_by_srt_blinded != NULL) { |
368 | 5.37k | lh_SRTM_ITEM_insert(srtm->items_rev, item->next_by_srt_blinded); |
369 | 5.37k | if (!srtm_check_lh(srtm, srtm->items_rev)) |
370 | 0 | return 0; |
371 | 145k | } else { |
372 | 145k | lh_SRTM_ITEM_delete(srtm->items_rev, item); |
373 | 145k | } |
374 | 150k | } else { |
375 | | /* Find our entry in the SRT list */ |
376 | 178k | for (; rh_item->next_by_srt_blinded != item; |
377 | 162k | rh_item = rh_item->next_by_srt_blinded) |
378 | 162k | ; |
379 | 15.8k | rh_item->next_by_srt_blinded = item->next_by_srt_blinded; |
380 | 15.8k | } |
381 | | |
382 | 166k | return 1; |
383 | 166k | } |
384 | | |
385 | | int ossl_quic_srtm_remove(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num) |
386 | 489k | { |
387 | 489k | SRTM_ITEM *item, *prev = NULL; |
388 | | |
389 | 489k | if (srtm->alloc_failed) |
390 | 0 | return 0; |
391 | | |
392 | 489k | if ((item = srtm_find(srtm, opaque, seq_num, NULL, &prev)) == NULL) |
393 | | /* No match */ |
394 | 475k | return 0; |
395 | | |
396 | | /* Remove from forward mapping. */ |
397 | 13.6k | if (prev == NULL) { |
398 | | /* |
399 | | * Change lhash to point to item after this one, or remove the entry if |
400 | | * this is the last one. |
401 | | */ |
402 | 6.10k | if (item->next_by_seq_num != NULL) { |
403 | 2.51k | lh_SRTM_ITEM_insert(srtm->items_fwd, item->next_by_seq_num); |
404 | 2.51k | if (!srtm_check_lh(srtm, srtm->items_fwd)) |
405 | 0 | return 0; |
406 | 3.58k | } else { |
407 | 3.58k | lh_SRTM_ITEM_delete(srtm->items_fwd, item); |
408 | 3.58k | } |
409 | 7.57k | } else { |
410 | 7.57k | prev->next_by_seq_num = item->next_by_seq_num; |
411 | 7.57k | } |
412 | | |
413 | | /* Remove from reverse mapping. */ |
414 | 13.6k | if (!srtm_remove_from_rev(srtm, item)) |
415 | 0 | return 0; |
416 | | |
417 | 13.6k | OPENSSL_free(item); |
418 | 13.6k | return 1; |
419 | 13.6k | } |
420 | | |
421 | | int ossl_quic_srtm_cull(QUIC_SRTM *srtm, void *opaque) |
422 | 1.01M | { |
423 | 1.01M | SRTM_ITEM key, *item = NULL, *inext, *ihead; |
424 | | |
425 | 1.01M | key.opaque = opaque; |
426 | | |
427 | 1.01M | if (srtm->alloc_failed) |
428 | 0 | return 0; |
429 | | |
430 | 1.01M | if ((ihead = lh_SRTM_ITEM_retrieve(srtm->items_fwd, &key)) == NULL) |
431 | 994k | return 1; /* nothing removed is a success condition */ |
432 | | |
433 | 173k | for (item = ihead; item != NULL; item = inext) { |
434 | 153k | inext = item->next_by_seq_num; |
435 | 153k | if (item != ihead) { |
436 | 133k | srtm_remove_from_rev(srtm, item); |
437 | 133k | OPENSSL_free(item); |
438 | 133k | } |
439 | 153k | } |
440 | | |
441 | 20.0k | lh_SRTM_ITEM_delete(srtm->items_fwd, ihead); |
442 | 20.0k | srtm_remove_from_rev(srtm, ihead); |
443 | 20.0k | OPENSSL_free(ihead); |
444 | 20.0k | return 1; |
445 | 1.01M | } |
446 | | |
447 | | int ossl_quic_srtm_lookup(QUIC_SRTM *srtm, |
448 | | const QUIC_STATELESS_RESET_TOKEN *token, |
449 | | size_t idx, |
450 | | void **opaque, uint64_t *seq_num) |
451 | 4.76M | { |
452 | 4.76M | SRTM_ITEM key, *item; |
453 | | |
454 | 4.76M | if (srtm->alloc_failed) |
455 | 0 | return 0; |
456 | | |
457 | 4.76M | if (!srtm_compute_blinded(srtm, &key, token)) |
458 | 0 | return 0; |
459 | | |
460 | 4.76M | item = lh_SRTM_ITEM_retrieve(srtm->items_rev, &key); |
461 | 5.02M | for (; idx > 0 && item != NULL; --idx, item = item->next_by_srt_blinded) |
462 | 258k | ; |
463 | 4.76M | if (item == NULL) |
464 | 4.76M | return 0; |
465 | | |
466 | 2.03k | if (opaque != NULL) |
467 | 20 | *opaque = item->opaque; |
468 | 2.03k | if (seq_num != NULL) |
469 | 0 | *seq_num = item->seq_num; |
470 | | |
471 | 2.03k | return 1; |
472 | 4.76M | } |
473 | | |
474 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
475 | | |
476 | | static uint32_t token_next = 0x5eadbeef; |
477 | | static size_t tokens_seen; |
478 | | |
479 | | struct check_args { |
480 | | uint32_t token; |
481 | | int mode; |
482 | | }; |
483 | | |
484 | | static void check_mark(SRTM_ITEM *item, void *arg) |
485 | 3.46G | { |
486 | 3.46G | struct check_args *arg_ = arg; |
487 | 3.46G | uint32_t token = arg_->token; |
488 | 3.46G | uint64_t prev_seq_num = 0; |
489 | 3.46G | void *prev_opaque = NULL; |
490 | 3.46G | int have_prev = 0; |
491 | | |
492 | 3.46G | assert(item != NULL); |
493 | | |
494 | 7.21G | while (item != NULL) { |
495 | 3.75G | if (have_prev) { |
496 | 292M | assert(!(item->opaque == prev_opaque && item->seq_num == prev_seq_num)); |
497 | 292M | if (!arg_->mode) |
498 | 292M | assert(item->opaque != prev_opaque || item->seq_num < prev_seq_num); |
499 | 292M | } |
500 | | |
501 | 3.75G | ++tokens_seen; |
502 | 3.75G | item->debug_token = token; |
503 | 3.75G | prev_opaque = item->opaque; |
504 | 3.75G | prev_seq_num = item->seq_num; |
505 | 3.75G | have_prev = 1; |
506 | | |
507 | 3.75G | if (arg_->mode) |
508 | 1.87G | item = item->next_by_srt_blinded; |
509 | 1.87G | else |
510 | 1.87G | item = item->next_by_seq_num; |
511 | 3.75G | } |
512 | 3.46G | } |
513 | | |
514 | | static void check_count(SRTM_ITEM *item, void *arg) |
515 | 3.46G | { |
516 | 3.46G | struct check_args *arg_ = arg; |
517 | 3.46G | uint32_t token = arg_->token; |
518 | | |
519 | 3.46G | assert(item != NULL); |
520 | | |
521 | 7.21G | while (item != NULL) { |
522 | 3.75G | ++tokens_seen; |
523 | 3.75G | assert(item->debug_token == token); |
524 | | |
525 | 3.75G | if (arg_->mode) |
526 | 1.87G | item = item->next_by_seq_num; |
527 | 1.87G | else |
528 | 1.87G | item = item->next_by_srt_blinded; |
529 | 3.75G | } |
530 | 3.46G | } |
531 | | |
532 | | #endif |
533 | | |
534 | | void ossl_quic_srtm_check(const QUIC_SRTM *srtm) |
535 | 3.66M | { |
536 | 3.66M | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
537 | 3.66M | struct check_args args = { 0 }; |
538 | 3.66M | size_t tokens_expected, tokens_expected_old; |
539 | | |
540 | 3.66M | args.token = token_next; |
541 | 3.66M | ++token_next; |
542 | | |
543 | 3.66M | assert(srtm != NULL); |
544 | 3.66M | assert(srtm->blind_ctx != NULL); |
545 | 3.66M | assert(srtm->items_fwd != NULL); |
546 | 3.66M | assert(srtm->items_rev != NULL); |
547 | | |
548 | 3.66M | tokens_seen = 0; |
549 | 3.66M | lh_SRTM_ITEM_doall_arg(srtm->items_fwd, check_mark, &args); |
550 | | |
551 | 3.66M | tokens_expected = tokens_seen; |
552 | 3.66M | tokens_seen = 0; |
553 | 3.66M | lh_SRTM_ITEM_doall_arg(srtm->items_rev, check_count, &args); |
554 | | |
555 | 3.66M | assert(tokens_seen == tokens_expected); |
556 | 3.66M | tokens_expected_old = tokens_expected; |
557 | | |
558 | 3.66M | args.token = token_next; |
559 | 3.66M | ++token_next; |
560 | | |
561 | 3.66M | args.mode = 1; |
562 | 3.66M | tokens_seen = 0; |
563 | 3.66M | lh_SRTM_ITEM_doall_arg(srtm->items_rev, check_mark, &args); |
564 | | |
565 | 3.66M | tokens_expected = tokens_seen; |
566 | 3.66M | tokens_seen = 0; |
567 | 3.66M | lh_SRTM_ITEM_doall_arg(srtm->items_fwd, check_count, &args); |
568 | | |
569 | 3.66M | assert(tokens_seen == tokens_expected); |
570 | 3.66M | assert(tokens_seen == tokens_expected_old); |
571 | 3.66M | #endif |
572 | 3.66M | } |