/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 | 3.87M | { |
71 | 3.87M | return (unsigned long)(uintptr_t)item->opaque; |
72 | 3.87M | } |
73 | | |
74 | | static int items_fwd_cmp(const SRTM_ITEM *a, const SRTM_ITEM *b) |
75 | 1.42M | { |
76 | 1.42M | return a->opaque != b->opaque; |
77 | 1.42M | } |
78 | | |
79 | | static unsigned long items_rev_hash(const SRTM_ITEM *item) |
80 | 6.68M | { |
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.68M | unsigned long l; |
86 | | |
87 | 6.68M | memcpy(&l, item->srt_blinded, sizeof(l)); |
88 | 6.68M | return l; |
89 | 6.68M | } |
90 | | |
91 | | static int items_rev_cmp(const SRTM_ITEM *a, const SRTM_ITEM *b) |
92 | 462k | { |
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 | 462k | return memcmp(a->srt_blinded, b->srt_blinded, sizeof(a->srt_blinded)); |
98 | 462k | } |
99 | | |
100 | | static int srtm_check_lh(QUIC_SRTM *srtm, LHASH_OF(SRTM_ITEM) *lh) |
101 | 1.33M | { |
102 | 1.33M | if (lh_SRTM_ITEM_error(lh)) { |
103 | 0 | srtm->alloc_failed = 1; |
104 | 0 | return 0; |
105 | 0 | } |
106 | | |
107 | 1.33M | return 1; |
108 | 1.33M | } |
109 | | |
110 | | QUIC_SRTM *ossl_quic_srtm_new(OSSL_LIB_CTX *libctx, const char *propq) |
111 | 56.9k | { |
112 | 56.9k | QUIC_SRTM *srtm = NULL; |
113 | 56.9k | unsigned char key[16]; |
114 | 56.9k | EVP_CIPHER *ecb = NULL; |
115 | | |
116 | 56.9k | if (RAND_priv_bytes_ex(libctx, key, sizeof(key), sizeof(key) * 8) != 1) |
117 | 0 | goto err; |
118 | | |
119 | 56.9k | 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 | 56.9k | if ((ecb = EVP_CIPHER_fetch(libctx, "AES-128-ECB", propq)) == NULL) |
124 | 0 | goto err; |
125 | | |
126 | 56.9k | if ((srtm->blind_ctx = EVP_CIPHER_CTX_new()) == NULL) |
127 | 0 | goto err; |
128 | | |
129 | 56.9k | if (!EVP_EncryptInit_ex2(srtm->blind_ctx, ecb, key, NULL, NULL)) |
130 | 0 | goto err; |
131 | | |
132 | 56.9k | EVP_CIPHER_free(ecb); |
133 | 56.9k | ecb = NULL; |
134 | | |
135 | | /* Create mappings. */ |
136 | 56.9k | if ((srtm->items_fwd = lh_SRTM_ITEM_new(items_fwd_hash, items_fwd_cmp)) == NULL |
137 | 56.9k | || (srtm->items_rev = lh_SRTM_ITEM_new(items_rev_hash, items_rev_cmp)) == NULL) |
138 | 0 | goto err; |
139 | | |
140 | 56.9k | 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 | 56.9k | } |
151 | | |
152 | | static void srtm_free_each(SRTM_ITEM *ihead) |
153 | 515k | { |
154 | 515k | SRTM_ITEM *inext, *item = ihead; |
155 | | |
156 | 590k | for (item = item->next_by_seq_num; item != NULL; item = inext) { |
157 | 75.1k | inext = item->next_by_seq_num; |
158 | 75.1k | OPENSSL_free(item); |
159 | 75.1k | } |
160 | | |
161 | 515k | OPENSSL_free(ihead); |
162 | 515k | } |
163 | | |
164 | | void ossl_quic_srtm_free(QUIC_SRTM *srtm) |
165 | 56.9k | { |
166 | 56.9k | if (srtm == NULL) |
167 | 0 | return; |
168 | | |
169 | 56.9k | lh_SRTM_ITEM_free(srtm->items_rev); |
170 | 56.9k | if (srtm->items_fwd != NULL) { |
171 | 56.9k | lh_SRTM_ITEM_doall(srtm->items_fwd, srtm_free_each); |
172 | 56.9k | lh_SRTM_ITEM_free(srtm->items_fwd); |
173 | 56.9k | } |
174 | | |
175 | 56.9k | EVP_CIPHER_CTX_free(srtm->blind_ctx); |
176 | 56.9k | OPENSSL_free(srtm); |
177 | 56.9k | } |
178 | | |
179 | | /* |
180 | | * Find a SRTM_ITEM by (opaque, seq_num). Returns NULL if no match. |
181 | | * If head is non-NULL, writes the head of the relevant opaque list to *head if |
182 | | * there is one. |
183 | | * If prev is non-NULL, writes the previous node to *prev or NULL if it is |
184 | | * the first item. |
185 | | */ |
186 | | static SRTM_ITEM *srtm_find(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num, |
187 | | SRTM_ITEM **head_p, SRTM_ITEM **prev_p) |
188 | 2.29M | { |
189 | 2.29M | SRTM_ITEM key, *item = NULL, *prev = NULL; |
190 | | |
191 | 2.29M | key.opaque = opaque; |
192 | | |
193 | 2.29M | item = lh_SRTM_ITEM_retrieve(srtm->items_fwd, &key); |
194 | 2.29M | if (head_p != NULL) |
195 | 1.80M | *head_p = item; |
196 | | |
197 | 17.7M | for (; item != NULL; prev = item, item = item->next_by_seq_num) |
198 | 16.7M | if (item->seq_num == seq_num) { |
199 | 1.06M | break; |
200 | 15.6M | } else if (item->seq_num < seq_num) { |
201 | | /* |
202 | | * List is sorted in descending order so there can't be any match |
203 | | * after this. |
204 | | */ |
205 | 206k | item = NULL; |
206 | 206k | break; |
207 | 206k | } |
208 | | |
209 | 2.29M | if (prev_p != NULL) |
210 | 484k | *prev_p = prev; |
211 | | |
212 | 2.29M | return item; |
213 | 2.29M | } |
214 | | |
215 | | /* |
216 | | * Inserts a SRTM_ITEM into the singly-linked by-sequence-number linked list. |
217 | | * The new head pointer is written to *new_head (which may or may not be |
218 | | * unchanged). |
219 | | */ |
220 | | static void sorted_insert_seq_num(SRTM_ITEM *head, SRTM_ITEM *item, SRTM_ITEM **new_head) |
221 | 219k | { |
222 | 219k | uint64_t seq_num = item->seq_num; |
223 | 219k | SRTM_ITEM *cur = head, **fixup = new_head; |
224 | | |
225 | 219k | *new_head = head; |
226 | | |
227 | 2.17M | while (cur != NULL && cur->seq_num > seq_num) { |
228 | 1.95M | fixup = &cur->next_by_seq_num; |
229 | 1.95M | cur = cur->next_by_seq_num; |
230 | 1.95M | } |
231 | | |
232 | 219k | item->next_by_seq_num = *fixup; |
233 | 219k | *fixup = item; |
234 | 219k | } |
235 | | |
236 | | /* |
237 | | * Inserts a SRTM_ITEM into the singly-linked by-SRT list. |
238 | | * The new head pointer is written to *new_head (which may or may not be |
239 | | * unchanged). |
240 | | */ |
241 | | static void sorted_insert_srt(SRTM_ITEM *head, SRTM_ITEM *item, SRTM_ITEM **new_head) |
242 | 58.9k | { |
243 | 58.9k | uintptr_t opaque = (uintptr_t)item->opaque; |
244 | 58.9k | SRTM_ITEM *cur = head, **fixup = new_head; |
245 | | |
246 | 58.9k | *new_head = head; |
247 | | |
248 | 970k | while (cur != NULL && (uintptr_t)cur->opaque > opaque) { |
249 | 911k | fixup = &cur->next_by_srt_blinded; |
250 | 911k | cur = cur->next_by_srt_blinded; |
251 | 911k | } |
252 | | |
253 | 58.9k | item->next_by_srt_blinded = *fixup; |
254 | 58.9k | *fixup = item; |
255 | 58.9k | } |
256 | | |
257 | | /* |
258 | | * Computes the blinded SRT value used for internal lookup for side channel |
259 | | * mitigation purposes. We compute this once as a cached value when an SRTM_ITEM |
260 | | * is formed. |
261 | | */ |
262 | | static int srtm_compute_blinded(QUIC_SRTM *srtm, SRTM_ITEM *item, |
263 | | const QUIC_STATELESS_RESET_TOKEN *token) |
264 | 5.64M | { |
265 | 5.64M | int outl = 0; |
266 | | |
267 | | /* |
268 | | * We use AES-128-ECB as a permutation using a random key to facilitate |
269 | | * blinding for side-channel purposes. Encrypt the token as a single AES |
270 | | * block. |
271 | | */ |
272 | 5.64M | if (!EVP_EncryptUpdate(srtm->blind_ctx, item->srt_blinded, &outl, |
273 | 5.64M | (const unsigned char *)token, sizeof(*token))) |
274 | 0 | return 0; |
275 | | |
276 | 5.64M | if (!ossl_assert(outl == sizeof(*token))) |
277 | 0 | return 0; |
278 | | |
279 | 5.64M | return 1; |
280 | 5.64M | } |
281 | | |
282 | | int ossl_quic_srtm_add(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num, |
283 | | const QUIC_STATELESS_RESET_TOKEN *token) |
284 | 1.80M | { |
285 | 1.80M | SRTM_ITEM *item = NULL, *head = NULL, *new_head, *r_item; |
286 | | |
287 | 1.80M | if (srtm->alloc_failed) |
288 | 0 | return 0; |
289 | | |
290 | | /* (opaque, seq_num) duplicates not allowed */ |
291 | 1.80M | if ((item = srtm_find(srtm, opaque, seq_num, &head, NULL)) != NULL) |
292 | 1.04M | return 0; |
293 | | |
294 | 758k | if ((item = OPENSSL_zalloc(sizeof(*item))) == NULL) |
295 | 0 | return 0; |
296 | | |
297 | 758k | item->opaque = opaque; |
298 | 758k | item->seq_num = seq_num; |
299 | 758k | item->srt = *token; |
300 | 758k | if (!srtm_compute_blinded(srtm, item, &item->srt)) { |
301 | 0 | OPENSSL_free(item); |
302 | 0 | return 0; |
303 | 0 | } |
304 | | |
305 | | /* Add to forward mapping. */ |
306 | 758k | if (head == NULL) { |
307 | | /* First item under this opaque */ |
308 | 539k | lh_SRTM_ITEM_insert(srtm->items_fwd, item); |
309 | 539k | if (!srtm_check_lh(srtm, srtm->items_fwd)) { |
310 | 0 | OPENSSL_free(item); |
311 | 0 | return 0; |
312 | 0 | } |
313 | 539k | } else { |
314 | 219k | sorted_insert_seq_num(head, item, &new_head); |
315 | 219k | if (new_head != head) { /* head changed, update in lhash */ |
316 | 60.2k | lh_SRTM_ITEM_insert(srtm->items_fwd, new_head); |
317 | 60.2k | if (!srtm_check_lh(srtm, srtm->items_fwd)) { |
318 | 0 | OPENSSL_free(item); |
319 | 0 | return 0; |
320 | 0 | } |
321 | 60.2k | } |
322 | 219k | } |
323 | | |
324 | | /* Add to reverse mapping. */ |
325 | 758k | r_item = lh_SRTM_ITEM_retrieve(srtm->items_rev, item); |
326 | 758k | if (r_item == NULL) { |
327 | | /* First item under this blinded SRT */ |
328 | 700k | lh_SRTM_ITEM_insert(srtm->items_rev, item); |
329 | 700k | if (!srtm_check_lh(srtm, srtm->items_rev)) |
330 | | /* |
331 | | * Can't free the item now as we would have to undo the insertion |
332 | | * into the forward mapping which would require an insert operation |
333 | | * to restore the previous value. which might also fail. However, |
334 | | * the item will be freed OK when we free the entire SRTM. |
335 | | */ |
336 | 0 | return 0; |
337 | 700k | } else { |
338 | 58.9k | sorted_insert_srt(r_item, item, &new_head); |
339 | 58.9k | if (new_head != r_item) { /* head changed, update in lhash */ |
340 | 25.0k | lh_SRTM_ITEM_insert(srtm->items_rev, new_head); |
341 | 25.0k | if (!srtm_check_lh(srtm, srtm->items_rev)) |
342 | | /* As above. */ |
343 | 0 | return 0; |
344 | 25.0k | } |
345 | 58.9k | } |
346 | | |
347 | 758k | return 1; |
348 | 758k | } |
349 | | |
350 | | /* Remove item from reverse mapping. */ |
351 | | static int srtm_remove_from_rev(QUIC_SRTM *srtm, SRTM_ITEM *item) |
352 | 168k | { |
353 | 168k | SRTM_ITEM *rh_item; |
354 | | |
355 | 168k | rh_item = lh_SRTM_ITEM_retrieve(srtm->items_rev, item); |
356 | 168k | assert(rh_item != NULL); |
357 | 168k | if (rh_item == item) { |
358 | | /* |
359 | | * Change lhash to point to item after this one, or remove the entry if |
360 | | * this is the last one. |
361 | | */ |
362 | 150k | if (item->next_by_srt_blinded != NULL) { |
363 | 6.03k | lh_SRTM_ITEM_insert(srtm->items_rev, item->next_by_srt_blinded); |
364 | 6.03k | if (!srtm_check_lh(srtm, srtm->items_rev)) |
365 | 0 | return 0; |
366 | 144k | } else { |
367 | 144k | lh_SRTM_ITEM_delete(srtm->items_rev, item); |
368 | 144k | } |
369 | 150k | } else { |
370 | | /* Find our entry in the SRT list */ |
371 | 172k | for (; rh_item->next_by_srt_blinded != item; |
372 | 154k | rh_item = rh_item->next_by_srt_blinded) |
373 | 154k | ; |
374 | 18.6k | rh_item->next_by_srt_blinded = item->next_by_srt_blinded; |
375 | 18.6k | } |
376 | | |
377 | 168k | return 1; |
378 | 168k | } |
379 | | |
380 | | int ossl_quic_srtm_remove(QUIC_SRTM *srtm, void *opaque, uint64_t seq_num) |
381 | 484k | { |
382 | 484k | SRTM_ITEM *item, *prev = NULL; |
383 | | |
384 | 484k | if (srtm->alloc_failed) |
385 | 0 | return 0; |
386 | | |
387 | 484k | if ((item = srtm_find(srtm, opaque, seq_num, NULL, &prev)) == NULL) |
388 | | /* No match */ |
389 | 468k | return 0; |
390 | | |
391 | | /* Remove from forward mapping. */ |
392 | 16.2k | if (prev == NULL) { |
393 | | /* |
394 | | * Change lhash to point to item after this one, or remove the entry if |
395 | | * this is the last one. |
396 | | */ |
397 | 5.48k | if (item->next_by_seq_num != NULL) { |
398 | 2.40k | lh_SRTM_ITEM_insert(srtm->items_fwd, item->next_by_seq_num); |
399 | 2.40k | if (!srtm_check_lh(srtm, srtm->items_fwd)) |
400 | 0 | return 0; |
401 | 3.08k | } else { |
402 | 3.08k | lh_SRTM_ITEM_delete(srtm->items_fwd, item); |
403 | 3.08k | } |
404 | 10.7k | } else { |
405 | 10.7k | prev->next_by_seq_num = item->next_by_seq_num; |
406 | 10.7k | } |
407 | | |
408 | | /* Remove from reverse mapping. */ |
409 | 16.2k | if (!srtm_remove_from_rev(srtm, item)) |
410 | 0 | return 0; |
411 | | |
412 | 16.2k | OPENSSL_free(item); |
413 | 16.2k | return 1; |
414 | 16.2k | } |
415 | | |
416 | | int ossl_quic_srtm_cull(QUIC_SRTM *srtm, void *opaque) |
417 | 954k | { |
418 | 954k | SRTM_ITEM key, *item = NULL, *inext, *ihead; |
419 | | |
420 | 954k | key.opaque = opaque; |
421 | | |
422 | 954k | if (srtm->alloc_failed) |
423 | 0 | return 0; |
424 | | |
425 | 954k | if ((ihead = lh_SRTM_ITEM_retrieve(srtm->items_fwd, &key)) == NULL) |
426 | 933k | return 1; /* nothing removed is a success condition */ |
427 | | |
428 | 173k | for (item = ihead; item != NULL; item = inext) { |
429 | 152k | inext = item->next_by_seq_num; |
430 | 152k | if (item != ihead) { |
431 | 131k | srtm_remove_from_rev(srtm, item); |
432 | 131k | OPENSSL_free(item); |
433 | 131k | } |
434 | 152k | } |
435 | | |
436 | 21.2k | lh_SRTM_ITEM_delete(srtm->items_fwd, ihead); |
437 | 21.2k | srtm_remove_from_rev(srtm, ihead); |
438 | 21.2k | OPENSSL_free(ihead); |
439 | 21.2k | return 1; |
440 | 954k | } |
441 | | |
442 | | int ossl_quic_srtm_lookup(QUIC_SRTM *srtm, |
443 | | const QUIC_STATELESS_RESET_TOKEN *token, |
444 | | size_t idx, |
445 | | void **opaque, uint64_t *seq_num) |
446 | 4.88M | { |
447 | 4.88M | SRTM_ITEM key, *item; |
448 | | |
449 | 4.88M | if (srtm->alloc_failed) |
450 | 0 | return 0; |
451 | | |
452 | 4.88M | if (!srtm_compute_blinded(srtm, &key, token)) |
453 | 0 | return 0; |
454 | | |
455 | 4.88M | item = lh_SRTM_ITEM_retrieve(srtm->items_rev, &key); |
456 | 5.78M | for (; idx > 0 && item != NULL; --idx, item = item->next_by_srt_blinded) |
457 | 903k | ; |
458 | 4.88M | if (item == NULL) |
459 | 4.88M | return 0; |
460 | | |
461 | 2.50k | if (opaque != NULL) |
462 | 22 | *opaque = item->opaque; |
463 | 2.50k | if (seq_num != NULL) |
464 | 0 | *seq_num = item->seq_num; |
465 | | |
466 | 2.50k | return 1; |
467 | 4.88M | } |
468 | | |
469 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
470 | | |
471 | | static uint32_t token_next = 0x5eadbeef; |
472 | | static size_t tokens_seen; |
473 | | |
474 | | struct check_args { |
475 | | uint32_t token; |
476 | | int mode; |
477 | | }; |
478 | | |
479 | | static void check_mark(SRTM_ITEM *item, void *arg) |
480 | 2.92G | { |
481 | 2.92G | struct check_args *arg_ = arg; |
482 | 2.92G | uint32_t token = arg_->token; |
483 | 2.92G | uint64_t prev_seq_num = 0; |
484 | 2.92G | void *prev_opaque = NULL; |
485 | 2.92G | int have_prev = 0; |
486 | | |
487 | 2.92G | assert(item != NULL); |
488 | | |
489 | 6.19G | while (item != NULL) { |
490 | 3.27G | if (have_prev) { |
491 | 343M | assert(!(item->opaque == prev_opaque && item->seq_num == prev_seq_num)); |
492 | 343M | if (!arg_->mode) |
493 | 343M | assert(item->opaque != prev_opaque || item->seq_num < prev_seq_num); |
494 | 343M | } |
495 | | |
496 | 3.27G | ++tokens_seen; |
497 | 3.27G | item->debug_token = token; |
498 | 3.27G | prev_opaque = item->opaque; |
499 | 3.27G | prev_seq_num = item->seq_num; |
500 | 3.27G | have_prev = 1; |
501 | | |
502 | 3.27G | if (arg_->mode) |
503 | 1.63G | item = item->next_by_srt_blinded; |
504 | 1.63G | else |
505 | 1.63G | item = item->next_by_seq_num; |
506 | 3.27G | } |
507 | 2.92G | } |
508 | | |
509 | | static void check_count(SRTM_ITEM *item, void *arg) |
510 | 2.92G | { |
511 | 2.92G | struct check_args *arg_ = arg; |
512 | 2.92G | uint32_t token = arg_->token; |
513 | | |
514 | 2.92G | assert(item != NULL); |
515 | | |
516 | 6.19G | while (item != NULL) { |
517 | 3.27G | ++tokens_seen; |
518 | 3.27G | assert(item->debug_token == token); |
519 | | |
520 | 3.27G | if (arg_->mode) |
521 | 1.63G | item = item->next_by_seq_num; |
522 | 1.63G | else |
523 | 1.63G | item = item->next_by_srt_blinded; |
524 | 3.27G | } |
525 | 2.92G | } |
526 | | |
527 | | #endif |
528 | | |
529 | | void ossl_quic_srtm_check(const QUIC_SRTM *srtm) |
530 | 3.55M | { |
531 | 3.55M | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
532 | 3.55M | struct check_args args = { 0 }; |
533 | 3.55M | size_t tokens_expected, tokens_expected_old; |
534 | | |
535 | 3.55M | args.token = token_next; |
536 | 3.55M | ++token_next; |
537 | | |
538 | 3.55M | assert(srtm != NULL); |
539 | 3.55M | assert(srtm->blind_ctx != NULL); |
540 | 3.55M | assert(srtm->items_fwd != NULL); |
541 | 3.55M | assert(srtm->items_rev != NULL); |
542 | | |
543 | 3.55M | tokens_seen = 0; |
544 | 3.55M | lh_SRTM_ITEM_doall_arg(srtm->items_fwd, check_mark, &args); |
545 | | |
546 | 3.55M | tokens_expected = tokens_seen; |
547 | 3.55M | tokens_seen = 0; |
548 | 3.55M | lh_SRTM_ITEM_doall_arg(srtm->items_rev, check_count, &args); |
549 | | |
550 | 3.55M | assert(tokens_seen == tokens_expected); |
551 | 3.55M | tokens_expected_old = tokens_expected; |
552 | | |
553 | 3.55M | args.token = token_next; |
554 | 3.55M | ++token_next; |
555 | | |
556 | 3.55M | args.mode = 1; |
557 | 3.55M | tokens_seen = 0; |
558 | 3.55M | lh_SRTM_ITEM_doall_arg(srtm->items_rev, check_mark, &args); |
559 | | |
560 | 3.55M | tokens_expected = tokens_seen; |
561 | 3.55M | tokens_seen = 0; |
562 | 3.55M | lh_SRTM_ITEM_doall_arg(srtm->items_fwd, check_count, &args); |
563 | | |
564 | 3.55M | assert(tokens_seen == tokens_expected); |
565 | 3.55M | assert(tokens_seen == tokens_expected_old); |
566 | 3.55M | #endif |
567 | 3.55M | } |