1 | /*
|
---|
2 | * Copyright 2016-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 | /*
|
---|
11 | * The test_multi_downgrade_shared_pkey function tests the thread safety of a
|
---|
12 | * deprecated function.
|
---|
13 | */
|
---|
14 | #ifndef OPENSSL_NO_DEPRECATED_3_0
|
---|
15 | # define OPENSSL_SUPPRESS_DEPRECATED
|
---|
16 | #endif
|
---|
17 |
|
---|
18 | #if defined(_WIN32)
|
---|
19 | # include <windows.h>
|
---|
20 | #endif
|
---|
21 |
|
---|
22 | #include <string.h>
|
---|
23 | #include <openssl/crypto.h>
|
---|
24 | #include <openssl/rsa.h>
|
---|
25 | #include <openssl/aes.h>
|
---|
26 | #include <openssl/err.h>
|
---|
27 | #include <openssl/rand.h>
|
---|
28 | #include <openssl/pem.h>
|
---|
29 | #include <openssl/evp.h>
|
---|
30 | #include "internal/tsan_assist.h"
|
---|
31 | #include "internal/nelem.h"
|
---|
32 | #include "internal/time.h"
|
---|
33 | #include "internal/rcu.h"
|
---|
34 | #include "testutil.h"
|
---|
35 | #include "threadstest.h"
|
---|
36 |
|
---|
37 | #ifdef __SANITIZE_THREAD__
|
---|
38 | #include <sanitizer/tsan_interface.h>
|
---|
39 | #define TSAN_ACQUIRE(s) __tsan_acquire(s)
|
---|
40 | #else
|
---|
41 | #define TSAN_ACQUIRE(s)
|
---|
42 | #endif
|
---|
43 |
|
---|
44 | /* Limit the maximum number of threads */
|
---|
45 | #define MAXIMUM_THREADS 10
|
---|
46 |
|
---|
47 | /* Limit the maximum number of providers loaded into a library context */
|
---|
48 | #define MAXIMUM_PROVIDERS 4
|
---|
49 |
|
---|
50 | static int do_fips = 0;
|
---|
51 | static char *privkey;
|
---|
52 | static char *config_file = NULL;
|
---|
53 | static int multidefault_run = 0;
|
---|
54 |
|
---|
55 | static const char *default_provider[] = { "default", NULL };
|
---|
56 | static const char *fips_provider[] = { "fips", NULL };
|
---|
57 | static const char *fips_and_default_providers[] = { "default", "fips", NULL };
|
---|
58 |
|
---|
59 | static CRYPTO_RWLOCK *global_lock;
|
---|
60 |
|
---|
61 | #ifdef TSAN_REQUIRES_LOCKING
|
---|
62 | static CRYPTO_RWLOCK *tsan_lock;
|
---|
63 | #endif
|
---|
64 |
|
---|
65 | /* Grab a globally unique integer value, return 0 on failure */
|
---|
66 | static int get_new_uid(void)
|
---|
67 | {
|
---|
68 | /*
|
---|
69 | * Start with a nice large number to avoid potential conflicts when
|
---|
70 | * we generate a new OID.
|
---|
71 | */
|
---|
72 | static TSAN_QUALIFIER int current_uid = 1 << (sizeof(int) * 8 - 2);
|
---|
73 | #ifdef TSAN_REQUIRES_LOCKING
|
---|
74 | int r;
|
---|
75 |
|
---|
76 | if (!TEST_true(CRYPTO_THREAD_write_lock(tsan_lock)))
|
---|
77 | return 0;
|
---|
78 | r = ++current_uid;
|
---|
79 | if (!TEST_true(CRYPTO_THREAD_unlock(tsan_lock)))
|
---|
80 | return 0;
|
---|
81 | return r;
|
---|
82 |
|
---|
83 | #else
|
---|
84 | return tsan_counter(¤t_uid);
|
---|
85 | #endif
|
---|
86 | }
|
---|
87 |
|
---|
88 | static int test_lock(void)
|
---|
89 | {
|
---|
90 | CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
|
---|
91 | int res;
|
---|
92 |
|
---|
93 | if (!TEST_ptr(lock))
|
---|
94 | return 0;
|
---|
95 |
|
---|
96 | res = TEST_true(CRYPTO_THREAD_read_lock(lock))
|
---|
97 | && TEST_true(CRYPTO_THREAD_unlock(lock))
|
---|
98 | && TEST_true(CRYPTO_THREAD_write_lock(lock))
|
---|
99 | && TEST_true(CRYPTO_THREAD_unlock(lock));
|
---|
100 |
|
---|
101 | CRYPTO_THREAD_lock_free(lock);
|
---|
102 |
|
---|
103 | return res;
|
---|
104 | }
|
---|
105 |
|
---|
106 | #if defined(OPENSSL_THREADS)
|
---|
107 | static int contention = 0;
|
---|
108 | static int rwwriter1_done = 0;
|
---|
109 | static int rwwriter2_done = 0;
|
---|
110 | static int rwreader1_iterations = 0;
|
---|
111 | static int rwreader2_iterations = 0;
|
---|
112 | static int rwwriter1_iterations = 0;
|
---|
113 | static int rwwriter2_iterations = 0;
|
---|
114 | static int *rwwriter_ptr = NULL;
|
---|
115 | static int rw_torture_result = 1;
|
---|
116 | static CRYPTO_RWLOCK *rwtorturelock = NULL;
|
---|
117 | static CRYPTO_RWLOCK *atomiclock = NULL;
|
---|
118 |
|
---|
119 | static void rwwriter_fn(int id, int *iterations)
|
---|
120 | {
|
---|
121 | int count;
|
---|
122 | int *old, *new;
|
---|
123 | OSSL_TIME t1, t2;
|
---|
124 | t1 = ossl_time_now();
|
---|
125 |
|
---|
126 | for (count = 0; ; count++) {
|
---|
127 | new = CRYPTO_zalloc(sizeof (int), NULL, 0);
|
---|
128 | if (contention == 0)
|
---|
129 | OSSL_sleep(1000);
|
---|
130 | if (!CRYPTO_THREAD_write_lock(rwtorturelock))
|
---|
131 | abort();
|
---|
132 | if (rwwriter_ptr != NULL) {
|
---|
133 | *new = *rwwriter_ptr + 1;
|
---|
134 | } else {
|
---|
135 | *new = 0;
|
---|
136 | }
|
---|
137 | old = rwwriter_ptr;
|
---|
138 | rwwriter_ptr = new;
|
---|
139 | if (!CRYPTO_THREAD_unlock(rwtorturelock))
|
---|
140 | abort();
|
---|
141 | if (old != NULL)
|
---|
142 | CRYPTO_free(old, __FILE__, __LINE__);
|
---|
143 | t2 = ossl_time_now();
|
---|
144 | if ((ossl_time2seconds(t2) - ossl_time2seconds(t1)) >= 4)
|
---|
145 | break;
|
---|
146 | }
|
---|
147 | *iterations = count;
|
---|
148 | return;
|
---|
149 | }
|
---|
150 |
|
---|
151 | static void rwwriter1_fn(void)
|
---|
152 | {
|
---|
153 | int local;
|
---|
154 |
|
---|
155 | TEST_info("Starting writer1");
|
---|
156 | rwwriter_fn(1, &rwwriter1_iterations);
|
---|
157 | CRYPTO_atomic_add(&rwwriter1_done, 1, &local, atomiclock);
|
---|
158 | }
|
---|
159 |
|
---|
160 | static void rwwriter2_fn(void)
|
---|
161 | {
|
---|
162 | int local;
|
---|
163 |
|
---|
164 | TEST_info("Starting writer 2");
|
---|
165 | rwwriter_fn(2, &rwwriter2_iterations);
|
---|
166 | CRYPTO_atomic_add(&rwwriter2_done, 1, &local, atomiclock);
|
---|
167 | }
|
---|
168 |
|
---|
169 | static void rwreader_fn(int *iterations)
|
---|
170 | {
|
---|
171 | unsigned int count = 0;
|
---|
172 |
|
---|
173 | int old = 0;
|
---|
174 | int lw1 = 0;
|
---|
175 | int lw2 = 0;
|
---|
176 |
|
---|
177 | if (CRYPTO_THREAD_read_lock(rwtorturelock) == 0)
|
---|
178 | abort();
|
---|
179 |
|
---|
180 | while (lw1 != 1 || lw2 != 1) {
|
---|
181 | CRYPTO_atomic_add(&rwwriter1_done, 0, &lw1, atomiclock);
|
---|
182 | CRYPTO_atomic_add(&rwwriter2_done, 0, &lw2, atomiclock);
|
---|
183 |
|
---|
184 | count++;
|
---|
185 | if (rwwriter_ptr != NULL && old > *rwwriter_ptr) {
|
---|
186 | TEST_info("rwwriter pointer went backwards\n");
|
---|
187 | rw_torture_result = 0;
|
---|
188 | }
|
---|
189 | if (CRYPTO_THREAD_unlock(rwtorturelock) == 0)
|
---|
190 | abort();
|
---|
191 | *iterations = count;
|
---|
192 | if (rw_torture_result == 0) {
|
---|
193 | *iterations = count;
|
---|
194 | return;
|
---|
195 | }
|
---|
196 | if (CRYPTO_THREAD_read_lock(rwtorturelock) == 0)
|
---|
197 | abort();
|
---|
198 | }
|
---|
199 | *iterations = count;
|
---|
200 | if (CRYPTO_THREAD_unlock(rwtorturelock) == 0)
|
---|
201 | abort();
|
---|
202 | }
|
---|
203 |
|
---|
204 | static void rwreader1_fn(void)
|
---|
205 | {
|
---|
206 | TEST_info("Starting reader 1");
|
---|
207 | rwreader_fn(&rwreader1_iterations);
|
---|
208 | }
|
---|
209 |
|
---|
210 | static void rwreader2_fn(void)
|
---|
211 | {
|
---|
212 | TEST_info("Starting reader 2");
|
---|
213 | rwreader_fn(&rwreader2_iterations);
|
---|
214 | }
|
---|
215 |
|
---|
216 | static thread_t rwwriter1;
|
---|
217 | static thread_t rwwriter2;
|
---|
218 | static thread_t rwreader1;
|
---|
219 | static thread_t rwreader2;
|
---|
220 |
|
---|
221 | static int _torture_rw(void)
|
---|
222 | {
|
---|
223 | double tottime = 0;
|
---|
224 | int ret = 0;
|
---|
225 | double avr, avw;
|
---|
226 | OSSL_TIME t1, t2;
|
---|
227 | struct timeval dtime;
|
---|
228 |
|
---|
229 | rwtorturelock = CRYPTO_THREAD_lock_new();
|
---|
230 | atomiclock = CRYPTO_THREAD_lock_new();
|
---|
231 | if (!TEST_ptr(rwtorturelock) || !TEST_ptr(atomiclock))
|
---|
232 | goto out;
|
---|
233 |
|
---|
234 | rwwriter1_iterations = 0;
|
---|
235 | rwwriter2_iterations = 0;
|
---|
236 | rwreader1_iterations = 0;
|
---|
237 | rwreader2_iterations = 0;
|
---|
238 | rwwriter1_done = 0;
|
---|
239 | rwwriter2_done = 0;
|
---|
240 | rw_torture_result = 1;
|
---|
241 |
|
---|
242 | memset(&rwwriter1, 0, sizeof(thread_t));
|
---|
243 | memset(&rwwriter2, 0, sizeof(thread_t));
|
---|
244 | memset(&rwreader1, 0, sizeof(thread_t));
|
---|
245 | memset(&rwreader2, 0, sizeof(thread_t));
|
---|
246 |
|
---|
247 | TEST_info("Staring rw torture");
|
---|
248 | t1 = ossl_time_now();
|
---|
249 | if (!TEST_true(run_thread(&rwreader1, rwreader1_fn))
|
---|
250 | || !TEST_true(run_thread(&rwreader2, rwreader2_fn))
|
---|
251 | || !TEST_true(run_thread(&rwwriter1, rwwriter1_fn))
|
---|
252 | || !TEST_true(run_thread(&rwwriter2, rwwriter2_fn))
|
---|
253 | || !TEST_true(wait_for_thread(rwwriter1))
|
---|
254 | || !TEST_true(wait_for_thread(rwwriter2))
|
---|
255 | || !TEST_true(wait_for_thread(rwreader1))
|
---|
256 | || !TEST_true(wait_for_thread(rwreader2)))
|
---|
257 | goto out;
|
---|
258 |
|
---|
259 | t2 = ossl_time_now();
|
---|
260 | dtime = ossl_time_to_timeval(ossl_time_subtract(t2, t1));
|
---|
261 | tottime = dtime.tv_sec + (dtime.tv_usec / 1e6);
|
---|
262 | TEST_info("rw_torture_result is %d\n", rw_torture_result);
|
---|
263 | TEST_info("performed %d reads and %d writes over 2 read and 2 write threads in %e seconds",
|
---|
264 | rwreader1_iterations + rwreader2_iterations,
|
---|
265 | rwwriter1_iterations + rwwriter2_iterations, tottime);
|
---|
266 | if ((rwreader1_iterations + rwreader2_iterations == 0)
|
---|
267 | || (rwwriter1_iterations + rwwriter2_iterations == 0)) {
|
---|
268 | TEST_info("Threads did not iterate\n");
|
---|
269 | goto out;
|
---|
270 | }
|
---|
271 | avr = tottime / (rwreader1_iterations + rwreader2_iterations);
|
---|
272 | avw = (tottime / (rwwriter1_iterations + rwwriter2_iterations));
|
---|
273 | TEST_info("Average read time %e/read", avr);
|
---|
274 | TEST_info("Averate write time %e/write", avw);
|
---|
275 |
|
---|
276 | if (TEST_int_eq(rw_torture_result, 1))
|
---|
277 | ret = 1;
|
---|
278 | out:
|
---|
279 | CRYPTO_THREAD_lock_free(rwtorturelock);
|
---|
280 | CRYPTO_THREAD_lock_free(atomiclock);
|
---|
281 | rwtorturelock = NULL;
|
---|
282 | return ret;
|
---|
283 | }
|
---|
284 |
|
---|
285 | static int torture_rw_low(void)
|
---|
286 | {
|
---|
287 | contention = 0;
|
---|
288 | return _torture_rw();
|
---|
289 | }
|
---|
290 |
|
---|
291 | static int torture_rw_high(void)
|
---|
292 | {
|
---|
293 | contention = 1;
|
---|
294 | return _torture_rw();
|
---|
295 | }
|
---|
296 |
|
---|
297 |
|
---|
298 | # ifndef OPENSSL_SYS_MACOSX
|
---|
299 | static CRYPTO_RCU_LOCK *rcu_lock = NULL;
|
---|
300 |
|
---|
301 | static int writer1_done = 0;
|
---|
302 | static int writer2_done = 0;
|
---|
303 | static int reader1_iterations = 0;
|
---|
304 | static int reader2_iterations = 0;
|
---|
305 | static int writer1_iterations = 0;
|
---|
306 | static int writer2_iterations = 0;
|
---|
307 | static uint64_t *writer_ptr = NULL;
|
---|
308 | static uint64_t global_ctr = 0;
|
---|
309 | static int rcu_torture_result = 1;
|
---|
310 | static void free_old_rcu_data(void *data)
|
---|
311 | {
|
---|
312 | CRYPTO_free(data, NULL, 0);
|
---|
313 | }
|
---|
314 |
|
---|
315 | static void writer_fn(int id, int *iterations)
|
---|
316 | {
|
---|
317 | int count;
|
---|
318 | OSSL_TIME t1, t2;
|
---|
319 | uint64_t *old, *new;
|
---|
320 |
|
---|
321 | t1 = ossl_time_now();
|
---|
322 |
|
---|
323 | for (count = 0; ; count++) {
|
---|
324 | new = CRYPTO_zalloc(sizeof(uint64_t), NULL, 0);
|
---|
325 | if (contention == 0)
|
---|
326 | OSSL_sleep(1000);
|
---|
327 | ossl_rcu_write_lock(rcu_lock);
|
---|
328 | old = ossl_rcu_deref(&writer_ptr);
|
---|
329 | TSAN_ACQUIRE(&writer_ptr);
|
---|
330 | *new = global_ctr++;
|
---|
331 | ossl_rcu_assign_ptr(&writer_ptr, &new);
|
---|
332 | if (contention == 0)
|
---|
333 | ossl_rcu_call(rcu_lock, free_old_rcu_data, old);
|
---|
334 | ossl_rcu_write_unlock(rcu_lock);
|
---|
335 | if (contention != 0) {
|
---|
336 | ossl_synchronize_rcu(rcu_lock);
|
---|
337 | CRYPTO_free(old, NULL, 0);
|
---|
338 | }
|
---|
339 | t2 = ossl_time_now();
|
---|
340 | if ((ossl_time2seconds(t2) - ossl_time2seconds(t1)) >= 4)
|
---|
341 | break;
|
---|
342 | }
|
---|
343 | *iterations = count;
|
---|
344 | return;
|
---|
345 | }
|
---|
346 |
|
---|
347 | static void writer1_fn(void)
|
---|
348 | {
|
---|
349 | int local;
|
---|
350 |
|
---|
351 | TEST_info("Starting writer1");
|
---|
352 | writer_fn(1, &writer1_iterations);
|
---|
353 | CRYPTO_atomic_add(&writer1_done, 1, &local, atomiclock);
|
---|
354 | }
|
---|
355 |
|
---|
356 | static void writer2_fn(void)
|
---|
357 | {
|
---|
358 | int local;
|
---|
359 |
|
---|
360 | TEST_info("Starting writer2");
|
---|
361 | writer_fn(2, &writer2_iterations);
|
---|
362 | CRYPTO_atomic_add(&writer2_done, 1, &local, atomiclock);
|
---|
363 | }
|
---|
364 |
|
---|
365 | static void reader_fn(int *iterations)
|
---|
366 | {
|
---|
367 | unsigned int count = 0;
|
---|
368 | uint64_t *valp;
|
---|
369 | uint64_t val;
|
---|
370 | uint64_t oldval = 0;
|
---|
371 | int lw1 = 0;
|
---|
372 | int lw2 = 0;
|
---|
373 |
|
---|
374 | while (lw1 != 1 || lw2 != 1) {
|
---|
375 | CRYPTO_atomic_add(&writer1_done, 0, &lw1, atomiclock);
|
---|
376 | CRYPTO_atomic_add(&writer2_done, 0, &lw2, atomiclock);
|
---|
377 | count++;
|
---|
378 | ossl_rcu_read_lock(rcu_lock);
|
---|
379 | valp = ossl_rcu_deref(&writer_ptr);
|
---|
380 | val = (valp == NULL) ? 0 : *valp;
|
---|
381 |
|
---|
382 | if (oldval > val) {
|
---|
383 | TEST_info("rcu torture value went backwards! %llu : %llu", (unsigned long long)oldval, (unsigned long long)val);
|
---|
384 | rcu_torture_result = 0;
|
---|
385 | }
|
---|
386 | oldval = val; /* just try to deref the pointer */
|
---|
387 | ossl_rcu_read_unlock(rcu_lock);
|
---|
388 | if (rcu_torture_result == 0) {
|
---|
389 | *iterations = count;
|
---|
390 | return;
|
---|
391 | }
|
---|
392 | }
|
---|
393 | *iterations = count;
|
---|
394 | }
|
---|
395 |
|
---|
396 | static void reader1_fn(void)
|
---|
397 | {
|
---|
398 | TEST_info("Starting reader 1");
|
---|
399 | reader_fn(&reader1_iterations);
|
---|
400 | }
|
---|
401 |
|
---|
402 | static void reader2_fn(void)
|
---|
403 | {
|
---|
404 | TEST_info("Starting reader 2");
|
---|
405 | reader_fn(&reader2_iterations);
|
---|
406 | }
|
---|
407 |
|
---|
408 | static thread_t writer1;
|
---|
409 | static thread_t writer2;
|
---|
410 | static thread_t reader1;
|
---|
411 | static thread_t reader2;
|
---|
412 |
|
---|
413 | static int _torture_rcu(void)
|
---|
414 | {
|
---|
415 | OSSL_TIME t1, t2;
|
---|
416 | struct timeval dtime;
|
---|
417 | double tottime;
|
---|
418 | double avr, avw;
|
---|
419 | int rc = 0;
|
---|
420 |
|
---|
421 | atomiclock = CRYPTO_THREAD_lock_new();
|
---|
422 | if (!TEST_ptr(atomiclock))
|
---|
423 | goto out;
|
---|
424 |
|
---|
425 | memset(&writer1, 0, sizeof(thread_t));
|
---|
426 | memset(&writer2, 0, sizeof(thread_t));
|
---|
427 | memset(&reader1, 0, sizeof(thread_t));
|
---|
428 | memset(&reader2, 0, sizeof(thread_t));
|
---|
429 |
|
---|
430 | writer1_iterations = 0;
|
---|
431 | writer2_iterations = 0;
|
---|
432 | reader1_iterations = 0;
|
---|
433 | reader2_iterations = 0;
|
---|
434 | writer1_done = 0;
|
---|
435 | writer2_done = 0;
|
---|
436 | rcu_torture_result = 1;
|
---|
437 |
|
---|
438 | rcu_lock = ossl_rcu_lock_new(1);
|
---|
439 | if (!rcu_lock)
|
---|
440 | goto out;
|
---|
441 |
|
---|
442 | TEST_info("Staring rcu torture");
|
---|
443 | t1 = ossl_time_now();
|
---|
444 | if (!TEST_true(run_thread(&reader1, reader1_fn))
|
---|
445 | || !TEST_true(run_thread(&reader2, reader2_fn))
|
---|
446 | || !TEST_true(run_thread(&writer1, writer1_fn))
|
---|
447 | || !TEST_true(run_thread(&writer2, writer2_fn))
|
---|
448 | || !TEST_true(wait_for_thread(writer1))
|
---|
449 | || !TEST_true(wait_for_thread(writer2))
|
---|
450 | || !TEST_true(wait_for_thread(reader1))
|
---|
451 | || !TEST_true(wait_for_thread(reader2)))
|
---|
452 | goto out;
|
---|
453 |
|
---|
454 | t2 = ossl_time_now();
|
---|
455 | dtime = ossl_time_to_timeval(ossl_time_subtract(t2, t1));
|
---|
456 | tottime = dtime.tv_sec + (dtime.tv_usec / 1e6);
|
---|
457 | TEST_info("rcu_torture_result is %d\n", rcu_torture_result);
|
---|
458 | TEST_info("performed %d reads and %d writes over 2 read and 2 write threads in %e seconds",
|
---|
459 | reader1_iterations + reader2_iterations,
|
---|
460 | writer1_iterations + writer2_iterations, tottime);
|
---|
461 | if ((reader1_iterations + reader2_iterations == 0)
|
---|
462 | || (writer1_iterations + writer2_iterations == 0)) {
|
---|
463 | TEST_info("Threads did not iterate\n");
|
---|
464 | goto out;
|
---|
465 | }
|
---|
466 | avr = tottime / (reader1_iterations + reader2_iterations);
|
---|
467 | avw = tottime / (writer1_iterations + writer2_iterations);
|
---|
468 | TEST_info("Average read time %e/read", avr);
|
---|
469 | TEST_info("Average write time %e/write", avw);
|
---|
470 |
|
---|
471 | if (!TEST_int_eq(rcu_torture_result, 1))
|
---|
472 | goto out;
|
---|
473 |
|
---|
474 | rc = 1;
|
---|
475 | out:
|
---|
476 | ossl_rcu_lock_free(rcu_lock);
|
---|
477 | CRYPTO_THREAD_lock_free(atomiclock);
|
---|
478 | if (!TEST_int_eq(rcu_torture_result, 1))
|
---|
479 | return 0;
|
---|
480 |
|
---|
481 | return rc;
|
---|
482 | }
|
---|
483 |
|
---|
484 | static int torture_rcu_low(void)
|
---|
485 | {
|
---|
486 | contention = 0;
|
---|
487 | return _torture_rcu();
|
---|
488 | }
|
---|
489 |
|
---|
490 | static int torture_rcu_high(void)
|
---|
491 | {
|
---|
492 | contention = 1;
|
---|
493 | return _torture_rcu();
|
---|
494 | }
|
---|
495 | # endif
|
---|
496 | #endif
|
---|
497 |
|
---|
498 | static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT;
|
---|
499 | static unsigned once_run_count = 0;
|
---|
500 |
|
---|
501 | static void once_do_run(void)
|
---|
502 | {
|
---|
503 | once_run_count++;
|
---|
504 | }
|
---|
505 |
|
---|
506 | static void once_run_thread_cb(void)
|
---|
507 | {
|
---|
508 | CRYPTO_THREAD_run_once(&once_run, once_do_run);
|
---|
509 | }
|
---|
510 |
|
---|
511 | static int test_once(void)
|
---|
512 | {
|
---|
513 | thread_t thread;
|
---|
514 |
|
---|
515 | if (!TEST_true(run_thread(&thread, once_run_thread_cb))
|
---|
516 | || !TEST_true(wait_for_thread(thread))
|
---|
517 | || !CRYPTO_THREAD_run_once(&once_run, once_do_run)
|
---|
518 | || !TEST_int_eq(once_run_count, 1))
|
---|
519 | return 0;
|
---|
520 | return 1;
|
---|
521 | }
|
---|
522 |
|
---|
523 | static CRYPTO_THREAD_LOCAL thread_local_key;
|
---|
524 | static unsigned destructor_run_count = 0;
|
---|
525 | static int thread_local_thread_cb_ok = 0;
|
---|
526 |
|
---|
527 | static void thread_local_destructor(void *arg)
|
---|
528 | {
|
---|
529 | unsigned *count;
|
---|
530 |
|
---|
531 | if (arg == NULL)
|
---|
532 | return;
|
---|
533 |
|
---|
534 | count = arg;
|
---|
535 |
|
---|
536 | (*count)++;
|
---|
537 | }
|
---|
538 |
|
---|
539 | static void thread_local_thread_cb(void)
|
---|
540 | {
|
---|
541 | void *ptr;
|
---|
542 |
|
---|
543 | ptr = CRYPTO_THREAD_get_local(&thread_local_key);
|
---|
544 | if (!TEST_ptr_null(ptr)
|
---|
545 | || !TEST_true(CRYPTO_THREAD_set_local(&thread_local_key,
|
---|
546 | &destructor_run_count)))
|
---|
547 | return;
|
---|
548 |
|
---|
549 | ptr = CRYPTO_THREAD_get_local(&thread_local_key);
|
---|
550 | if (!TEST_ptr_eq(ptr, &destructor_run_count))
|
---|
551 | return;
|
---|
552 |
|
---|
553 | thread_local_thread_cb_ok = 1;
|
---|
554 | }
|
---|
555 |
|
---|
556 | static int test_thread_local(void)
|
---|
557 | {
|
---|
558 | thread_t thread;
|
---|
559 | void *ptr = NULL;
|
---|
560 |
|
---|
561 | if (!TEST_true(CRYPTO_THREAD_init_local(&thread_local_key,
|
---|
562 | thread_local_destructor)))
|
---|
563 | return 0;
|
---|
564 |
|
---|
565 | ptr = CRYPTO_THREAD_get_local(&thread_local_key);
|
---|
566 | if (!TEST_ptr_null(ptr)
|
---|
567 | || !TEST_true(run_thread(&thread, thread_local_thread_cb))
|
---|
568 | || !TEST_true(wait_for_thread(thread))
|
---|
569 | || !TEST_int_eq(thread_local_thread_cb_ok, 1))
|
---|
570 | return 0;
|
---|
571 |
|
---|
572 | #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
|
---|
573 |
|
---|
574 | ptr = CRYPTO_THREAD_get_local(&thread_local_key);
|
---|
575 | if (!TEST_ptr_null(ptr))
|
---|
576 | return 0;
|
---|
577 |
|
---|
578 | # if !defined(OPENSSL_SYS_WINDOWS)
|
---|
579 | if (!TEST_int_eq(destructor_run_count, 1))
|
---|
580 | return 0;
|
---|
581 | # endif
|
---|
582 | #endif
|
---|
583 |
|
---|
584 | if (!TEST_true(CRYPTO_THREAD_cleanup_local(&thread_local_key)))
|
---|
585 | return 0;
|
---|
586 | return 1;
|
---|
587 | }
|
---|
588 |
|
---|
589 | static int test_atomic(void)
|
---|
590 | {
|
---|
591 | int val = 0, ret = 0, testresult = 0;
|
---|
592 | uint64_t val64 = 1, ret64 = 0;
|
---|
593 | CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
|
---|
594 |
|
---|
595 | if (!TEST_ptr(lock))
|
---|
596 | return 0;
|
---|
597 |
|
---|
598 | if (CRYPTO_atomic_add(&val, 1, &ret, NULL)) {
|
---|
599 | /* This succeeds therefore we're on a platform with lockless atomics */
|
---|
600 | if (!TEST_int_eq(val, 1) || !TEST_int_eq(val, ret))
|
---|
601 | goto err;
|
---|
602 | } else {
|
---|
603 | /* This failed therefore we're on a platform without lockless atomics */
|
---|
604 | if (!TEST_int_eq(val, 0) || !TEST_int_eq(val, ret))
|
---|
605 | goto err;
|
---|
606 | }
|
---|
607 | val = 0;
|
---|
608 | ret = 0;
|
---|
609 |
|
---|
610 | if (!TEST_true(CRYPTO_atomic_add(&val, 1, &ret, lock)))
|
---|
611 | goto err;
|
---|
612 | if (!TEST_int_eq(val, 1) || !TEST_int_eq(val, ret))
|
---|
613 | goto err;
|
---|
614 |
|
---|
615 | if (CRYPTO_atomic_or(&val64, 2, &ret64, NULL)) {
|
---|
616 | /* This succeeds therefore we're on a platform with lockless atomics */
|
---|
617 | if (!TEST_uint_eq((unsigned int)val64, 3)
|
---|
618 | || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
|
---|
619 | goto err;
|
---|
620 | } else {
|
---|
621 | /* This failed therefore we're on a platform without lockless atomics */
|
---|
622 | if (!TEST_uint_eq((unsigned int)val64, 1)
|
---|
623 | || !TEST_int_eq((unsigned int)ret64, 0))
|
---|
624 | goto err;
|
---|
625 | }
|
---|
626 | val64 = 1;
|
---|
627 | ret64 = 0;
|
---|
628 |
|
---|
629 | if (!TEST_true(CRYPTO_atomic_or(&val64, 2, &ret64, lock)))
|
---|
630 | goto err;
|
---|
631 |
|
---|
632 | if (!TEST_uint_eq((unsigned int)val64, 3)
|
---|
633 | || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
|
---|
634 | goto err;
|
---|
635 |
|
---|
636 | ret64 = 0;
|
---|
637 | if (CRYPTO_atomic_load(&val64, &ret64, NULL)) {
|
---|
638 | /* This succeeds therefore we're on a platform with lockless atomics */
|
---|
639 | if (!TEST_uint_eq((unsigned int)val64, 3)
|
---|
640 | || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
|
---|
641 | goto err;
|
---|
642 | } else {
|
---|
643 | /* This failed therefore we're on a platform without lockless atomics */
|
---|
644 | if (!TEST_uint_eq((unsigned int)val64, 3)
|
---|
645 | || !TEST_int_eq((unsigned int)ret64, 0))
|
---|
646 | goto err;
|
---|
647 | }
|
---|
648 |
|
---|
649 | ret64 = 0;
|
---|
650 | if (!TEST_true(CRYPTO_atomic_load(&val64, &ret64, lock)))
|
---|
651 | goto err;
|
---|
652 |
|
---|
653 | if (!TEST_uint_eq((unsigned int)val64, 3)
|
---|
654 | || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
|
---|
655 | goto err;
|
---|
656 |
|
---|
657 | testresult = 1;
|
---|
658 | err:
|
---|
659 | CRYPTO_THREAD_lock_free(lock);
|
---|
660 | return testresult;
|
---|
661 | }
|
---|
662 |
|
---|
663 | static OSSL_LIB_CTX *multi_libctx = NULL;
|
---|
664 | static int multi_success;
|
---|
665 | static OSSL_PROVIDER *multi_provider[MAXIMUM_PROVIDERS + 1];
|
---|
666 | static size_t multi_num_threads;
|
---|
667 | static thread_t multi_threads[MAXIMUM_THREADS];
|
---|
668 |
|
---|
669 | static void multi_intialise(void)
|
---|
670 | {
|
---|
671 | multi_success = 1;
|
---|
672 | multi_libctx = NULL;
|
---|
673 | multi_num_threads = 0;
|
---|
674 | memset(multi_threads, 0, sizeof(multi_threads));
|
---|
675 | memset(multi_provider, 0, sizeof(multi_provider));
|
---|
676 | }
|
---|
677 |
|
---|
678 | static void multi_set_success(int ok)
|
---|
679 | {
|
---|
680 | if (CRYPTO_THREAD_write_lock(global_lock) == 0) {
|
---|
681 | /* not synchronized, but better than not reporting failure */
|
---|
682 | multi_success = ok;
|
---|
683 | return;
|
---|
684 | }
|
---|
685 |
|
---|
686 | multi_success = ok;
|
---|
687 |
|
---|
688 | CRYPTO_THREAD_unlock(global_lock);
|
---|
689 | }
|
---|
690 |
|
---|
691 | static void thead_teardown_libctx(void)
|
---|
692 | {
|
---|
693 | OSSL_PROVIDER **p;
|
---|
694 |
|
---|
695 | for (p = multi_provider; *p != NULL; p++)
|
---|
696 | OSSL_PROVIDER_unload(*p);
|
---|
697 | OSSL_LIB_CTX_free(multi_libctx);
|
---|
698 | multi_intialise();
|
---|
699 | }
|
---|
700 |
|
---|
701 | static int thread_setup_libctx(int libctx, const char *providers[])
|
---|
702 | {
|
---|
703 | size_t n;
|
---|
704 |
|
---|
705 | if (libctx && !TEST_true(test_get_libctx(&multi_libctx, NULL, config_file,
|
---|
706 | NULL, NULL)))
|
---|
707 | return 0;
|
---|
708 |
|
---|
709 | if (providers != NULL)
|
---|
710 | for (n = 0; providers[n] != NULL; n++)
|
---|
711 | if (!TEST_size_t_lt(n, MAXIMUM_PROVIDERS)
|
---|
712 | || !TEST_ptr(multi_provider[n] = OSSL_PROVIDER_load(multi_libctx,
|
---|
713 | providers[n]))) {
|
---|
714 | thead_teardown_libctx();
|
---|
715 | return 0;
|
---|
716 | }
|
---|
717 | return 1;
|
---|
718 | }
|
---|
719 |
|
---|
720 | static int teardown_threads(void)
|
---|
721 | {
|
---|
722 | size_t i;
|
---|
723 |
|
---|
724 | for (i = 0; i < multi_num_threads; i++)
|
---|
725 | if (!TEST_true(wait_for_thread(multi_threads[i])))
|
---|
726 | return 0;
|
---|
727 | return 1;
|
---|
728 | }
|
---|
729 |
|
---|
730 | static int start_threads(size_t n, void (*thread_func)(void))
|
---|
731 | {
|
---|
732 | size_t i;
|
---|
733 |
|
---|
734 | if (!TEST_size_t_le(multi_num_threads + n, MAXIMUM_THREADS))
|
---|
735 | return 0;
|
---|
736 |
|
---|
737 | for (i = 0 ; i < n; i++)
|
---|
738 | if (!TEST_true(run_thread(multi_threads + multi_num_threads++, thread_func)))
|
---|
739 | return 0;
|
---|
740 | return 1;
|
---|
741 | }
|
---|
742 |
|
---|
743 | /* Template multi-threaded test function */
|
---|
744 | static int thread_run_test(void (*main_func)(void),
|
---|
745 | size_t num_threads, void (*thread_func)(void),
|
---|
746 | int libctx, const char *providers[])
|
---|
747 | {
|
---|
748 | int testresult = 0;
|
---|
749 |
|
---|
750 | multi_intialise();
|
---|
751 | if (!thread_setup_libctx(libctx, providers)
|
---|
752 | || !start_threads(num_threads, thread_func))
|
---|
753 | goto err;
|
---|
754 |
|
---|
755 | if (main_func != NULL)
|
---|
756 | main_func();
|
---|
757 |
|
---|
758 | if (!teardown_threads()
|
---|
759 | || !TEST_true(multi_success))
|
---|
760 | goto err;
|
---|
761 | testresult = 1;
|
---|
762 | err:
|
---|
763 | thead_teardown_libctx();
|
---|
764 | return testresult;
|
---|
765 | }
|
---|
766 |
|
---|
767 | static void thread_general_worker(void)
|
---|
768 | {
|
---|
769 | EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
|
---|
770 | EVP_MD *md = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL);
|
---|
771 | EVP_CIPHER_CTX *cipherctx = EVP_CIPHER_CTX_new();
|
---|
772 | EVP_CIPHER *ciph = EVP_CIPHER_fetch(multi_libctx, "AES-128-CBC", NULL);
|
---|
773 | const char *message = "Hello World";
|
---|
774 | size_t messlen = strlen(message);
|
---|
775 | /* Should be big enough for encryption output too */
|
---|
776 | unsigned char out[EVP_MAX_MD_SIZE];
|
---|
777 | const unsigned char key[AES_BLOCK_SIZE] = {
|
---|
778 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
---|
779 | 0x0c, 0x0d, 0x0e, 0x0f
|
---|
780 | };
|
---|
781 | const unsigned char iv[AES_BLOCK_SIZE] = {
|
---|
782 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
---|
783 | 0x0c, 0x0d, 0x0e, 0x0f
|
---|
784 | };
|
---|
785 | unsigned int mdoutl;
|
---|
786 | int ciphoutl;
|
---|
787 | EVP_PKEY *pkey = NULL;
|
---|
788 | int testresult = 0;
|
---|
789 | int i, isfips;
|
---|
790 |
|
---|
791 | isfips = OSSL_PROVIDER_available(multi_libctx, "fips");
|
---|
792 |
|
---|
793 | if (!TEST_ptr(mdctx)
|
---|
794 | || !TEST_ptr(md)
|
---|
795 | || !TEST_ptr(cipherctx)
|
---|
796 | || !TEST_ptr(ciph))
|
---|
797 | goto err;
|
---|
798 |
|
---|
799 | /* Do some work */
|
---|
800 | for (i = 0; i < 5; i++) {
|
---|
801 | if (!TEST_true(EVP_DigestInit_ex(mdctx, md, NULL))
|
---|
802 | || !TEST_true(EVP_DigestUpdate(mdctx, message, messlen))
|
---|
803 | || !TEST_true(EVP_DigestFinal(mdctx, out, &mdoutl)))
|
---|
804 | goto err;
|
---|
805 | }
|
---|
806 | for (i = 0; i < 5; i++) {
|
---|
807 | if (!TEST_true(EVP_EncryptInit_ex(cipherctx, ciph, NULL, key, iv))
|
---|
808 | || !TEST_true(EVP_EncryptUpdate(cipherctx, out, &ciphoutl,
|
---|
809 | (unsigned char *)message,
|
---|
810 | messlen))
|
---|
811 | || !TEST_true(EVP_EncryptFinal(cipherctx, out, &ciphoutl)))
|
---|
812 | goto err;
|
---|
813 | }
|
---|
814 |
|
---|
815 | /*
|
---|
816 | * We want the test to run quickly - not securely.
|
---|
817 | * Therefore we use an insecure bit length where we can (512).
|
---|
818 | * In the FIPS module though we must use a longer length.
|
---|
819 | */
|
---|
820 | pkey = EVP_PKEY_Q_keygen(multi_libctx, NULL, "RSA", isfips ? 2048 : 512);
|
---|
821 | if (!TEST_ptr(pkey))
|
---|
822 | goto err;
|
---|
823 |
|
---|
824 | testresult = 1;
|
---|
825 | err:
|
---|
826 | EVP_MD_CTX_free(mdctx);
|
---|
827 | EVP_MD_free(md);
|
---|
828 | EVP_CIPHER_CTX_free(cipherctx);
|
---|
829 | EVP_CIPHER_free(ciph);
|
---|
830 | EVP_PKEY_free(pkey);
|
---|
831 | if (!testresult)
|
---|
832 | multi_set_success(0);
|
---|
833 | }
|
---|
834 |
|
---|
835 | static void thread_multi_simple_fetch(void)
|
---|
836 | {
|
---|
837 | EVP_MD *md = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL);
|
---|
838 |
|
---|
839 | if (md != NULL)
|
---|
840 | EVP_MD_free(md);
|
---|
841 | else
|
---|
842 | multi_set_success(0);
|
---|
843 | }
|
---|
844 |
|
---|
845 | static EVP_PKEY *shared_evp_pkey = NULL;
|
---|
846 |
|
---|
847 | static void thread_shared_evp_pkey(void)
|
---|
848 | {
|
---|
849 | char *msg = "Hello World";
|
---|
850 | unsigned char ctbuf[256];
|
---|
851 | unsigned char ptbuf[256];
|
---|
852 | size_t ptlen, ctlen = sizeof(ctbuf);
|
---|
853 | EVP_PKEY_CTX *ctx = NULL;
|
---|
854 | int success = 0;
|
---|
855 | int i;
|
---|
856 |
|
---|
857 | for (i = 0; i < 1 + do_fips; i++) {
|
---|
858 | if (i > 0)
|
---|
859 | EVP_PKEY_CTX_free(ctx);
|
---|
860 | ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey,
|
---|
861 | i == 0 ? "provider=default"
|
---|
862 | : "provider=fips");
|
---|
863 | if (!TEST_ptr(ctx))
|
---|
864 | goto err;
|
---|
865 |
|
---|
866 | if (!TEST_int_ge(EVP_PKEY_encrypt_init(ctx), 0)
|
---|
867 | || !TEST_int_ge(EVP_PKEY_encrypt(ctx, ctbuf, &ctlen,
|
---|
868 | (unsigned char *)msg, strlen(msg)),
|
---|
869 | 0))
|
---|
870 | goto err;
|
---|
871 |
|
---|
872 | EVP_PKEY_CTX_free(ctx);
|
---|
873 | ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey, NULL);
|
---|
874 |
|
---|
875 | if (!TEST_ptr(ctx))
|
---|
876 | goto err;
|
---|
877 |
|
---|
878 | ptlen = sizeof(ptbuf);
|
---|
879 | if (!TEST_int_ge(EVP_PKEY_decrypt_init(ctx), 0)
|
---|
880 | || !TEST_int_gt(EVP_PKEY_decrypt(ctx, ptbuf, &ptlen, ctbuf, ctlen),
|
---|
881 | 0)
|
---|
882 | || !TEST_mem_eq(msg, strlen(msg), ptbuf, ptlen))
|
---|
883 | goto err;
|
---|
884 | }
|
---|
885 |
|
---|
886 | success = 1;
|
---|
887 |
|
---|
888 | err:
|
---|
889 | EVP_PKEY_CTX_free(ctx);
|
---|
890 | if (!success)
|
---|
891 | multi_set_success(0);
|
---|
892 | }
|
---|
893 |
|
---|
894 | static void thread_provider_load_unload(void)
|
---|
895 | {
|
---|
896 | OSSL_PROVIDER *deflt = OSSL_PROVIDER_load(multi_libctx, "default");
|
---|
897 |
|
---|
898 | if (!TEST_ptr(deflt)
|
---|
899 | || !TEST_true(OSSL_PROVIDER_available(multi_libctx, "default")))
|
---|
900 | multi_set_success(0);
|
---|
901 |
|
---|
902 | OSSL_PROVIDER_unload(deflt);
|
---|
903 | }
|
---|
904 |
|
---|
905 | static int test_multi_general_worker_default_provider(void)
|
---|
906 | {
|
---|
907 | return thread_run_test(&thread_general_worker, 2, &thread_general_worker,
|
---|
908 | 1, default_provider);
|
---|
909 | }
|
---|
910 |
|
---|
911 | static int test_multi_general_worker_fips_provider(void)
|
---|
912 | {
|
---|
913 | if (!do_fips)
|
---|
914 | return TEST_skip("FIPS not supported");
|
---|
915 | return thread_run_test(&thread_general_worker, 2, &thread_general_worker,
|
---|
916 | 1, fips_provider);
|
---|
917 | }
|
---|
918 |
|
---|
919 | static int test_multi_fetch_worker(void)
|
---|
920 | {
|
---|
921 | return thread_run_test(&thread_multi_simple_fetch,
|
---|
922 | 2, &thread_multi_simple_fetch, 1, default_provider);
|
---|
923 | }
|
---|
924 |
|
---|
925 | static int test_multi_shared_pkey_common(void (*worker)(void))
|
---|
926 | {
|
---|
927 | int testresult = 0;
|
---|
928 |
|
---|
929 | multi_intialise();
|
---|
930 | if (!thread_setup_libctx(1, do_fips ? fips_and_default_providers
|
---|
931 | : default_provider)
|
---|
932 | || !TEST_ptr(shared_evp_pkey = load_pkey_pem(privkey, multi_libctx))
|
---|
933 | || !start_threads(1, &thread_shared_evp_pkey)
|
---|
934 | || !start_threads(1, worker))
|
---|
935 | goto err;
|
---|
936 |
|
---|
937 | thread_shared_evp_pkey();
|
---|
938 |
|
---|
939 | if (!teardown_threads()
|
---|
940 | || !TEST_true(multi_success))
|
---|
941 | goto err;
|
---|
942 | testresult = 1;
|
---|
943 | err:
|
---|
944 | EVP_PKEY_free(shared_evp_pkey);
|
---|
945 | thead_teardown_libctx();
|
---|
946 | return testresult;
|
---|
947 | }
|
---|
948 |
|
---|
949 | #ifndef OPENSSL_NO_DEPRECATED_3_0
|
---|
950 | static void thread_downgrade_shared_evp_pkey(void)
|
---|
951 | {
|
---|
952 | /*
|
---|
953 | * This test is only relevant for deprecated functions that perform
|
---|
954 | * downgrading
|
---|
955 | */
|
---|
956 | if (EVP_PKEY_get0_RSA(shared_evp_pkey) == NULL)
|
---|
957 | multi_set_success(0);
|
---|
958 | }
|
---|
959 |
|
---|
960 | static int test_multi_downgrade_shared_pkey(void)
|
---|
961 | {
|
---|
962 | return test_multi_shared_pkey_common(&thread_downgrade_shared_evp_pkey);
|
---|
963 | }
|
---|
964 | #endif
|
---|
965 |
|
---|
966 | static int test_multi_shared_pkey(void)
|
---|
967 | {
|
---|
968 | return test_multi_shared_pkey_common(&thread_shared_evp_pkey);
|
---|
969 | }
|
---|
970 |
|
---|
971 | static int test_multi_load_unload_provider(void)
|
---|
972 | {
|
---|
973 | EVP_MD *sha256 = NULL;
|
---|
974 | OSSL_PROVIDER *prov = NULL;
|
---|
975 | int testresult = 0;
|
---|
976 |
|
---|
977 | multi_intialise();
|
---|
978 | if (!thread_setup_libctx(1, NULL)
|
---|
979 | || !TEST_ptr(prov = OSSL_PROVIDER_load(multi_libctx, "default"))
|
---|
980 | || !TEST_ptr(sha256 = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL))
|
---|
981 | || !TEST_true(OSSL_PROVIDER_unload(prov)))
|
---|
982 | goto err;
|
---|
983 | prov = NULL;
|
---|
984 |
|
---|
985 | if (!start_threads(2, &thread_provider_load_unload))
|
---|
986 | goto err;
|
---|
987 |
|
---|
988 | thread_provider_load_unload();
|
---|
989 |
|
---|
990 | if (!teardown_threads()
|
---|
991 | || !TEST_true(multi_success))
|
---|
992 | goto err;
|
---|
993 | testresult = 1;
|
---|
994 | err:
|
---|
995 | OSSL_PROVIDER_unload(prov);
|
---|
996 | EVP_MD_free(sha256);
|
---|
997 | thead_teardown_libctx();
|
---|
998 | return testresult;
|
---|
999 | }
|
---|
1000 |
|
---|
1001 | static char *multi_load_provider = "legacy";
|
---|
1002 | /*
|
---|
1003 | * This test attempts to load several providers at the same time, and if
|
---|
1004 | * run with a thread sanitizer, should crash if the core provider code
|
---|
1005 | * doesn't synchronize well enough.
|
---|
1006 | */
|
---|
1007 | static void test_multi_load_worker(void)
|
---|
1008 | {
|
---|
1009 | OSSL_PROVIDER *prov;
|
---|
1010 |
|
---|
1011 | if (!TEST_ptr(prov = OSSL_PROVIDER_load(multi_libctx, multi_load_provider))
|
---|
1012 | || !TEST_true(OSSL_PROVIDER_unload(prov)))
|
---|
1013 | multi_set_success(0);
|
---|
1014 | }
|
---|
1015 |
|
---|
1016 | static int test_multi_default(void)
|
---|
1017 | {
|
---|
1018 | /* Avoid running this test twice */
|
---|
1019 | if (multidefault_run) {
|
---|
1020 | TEST_skip("multi default test already run");
|
---|
1021 | return 1;
|
---|
1022 | }
|
---|
1023 | multidefault_run = 1;
|
---|
1024 |
|
---|
1025 | return thread_run_test(&thread_multi_simple_fetch,
|
---|
1026 | 2, &thread_multi_simple_fetch, 0, default_provider);
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 | static int test_multi_load(void)
|
---|
1030 | {
|
---|
1031 | int res = 1;
|
---|
1032 | OSSL_PROVIDER *prov;
|
---|
1033 |
|
---|
1034 | /* The multidefault test must run prior to this test */
|
---|
1035 | if (!multidefault_run) {
|
---|
1036 | TEST_info("Running multi default test first");
|
---|
1037 | res = test_multi_default();
|
---|
1038 | }
|
---|
1039 |
|
---|
1040 | /*
|
---|
1041 | * We use the legacy provider in test_multi_load_worker because it uses a
|
---|
1042 | * child libctx that might hit more codepaths that might be sensitive to
|
---|
1043 | * threading issues. But in a no-legacy build that won't be loadable so
|
---|
1044 | * we use the default provider instead.
|
---|
1045 | */
|
---|
1046 | prov = OSSL_PROVIDER_load(NULL, "legacy");
|
---|
1047 | if (prov == NULL) {
|
---|
1048 | TEST_info("Cannot load legacy provider - assuming this is a no-legacy build");
|
---|
1049 | multi_load_provider = "default";
|
---|
1050 | }
|
---|
1051 | OSSL_PROVIDER_unload(prov);
|
---|
1052 |
|
---|
1053 | return thread_run_test(NULL, MAXIMUM_THREADS, &test_multi_load_worker, 0,
|
---|
1054 | NULL) && res;
|
---|
1055 | }
|
---|
1056 |
|
---|
1057 | static void test_obj_create_one(void)
|
---|
1058 | {
|
---|
1059 | char tids[12], oid[40], sn[30], ln[30];
|
---|
1060 | int id = get_new_uid();
|
---|
1061 |
|
---|
1062 | BIO_snprintf(tids, sizeof(tids), "%d", id);
|
---|
1063 | BIO_snprintf(oid, sizeof(oid), "1.3.6.1.4.1.16604.%s", tids);
|
---|
1064 | BIO_snprintf(sn, sizeof(sn), "short-name-%s", tids);
|
---|
1065 | BIO_snprintf(ln, sizeof(ln), "long-name-%s", tids);
|
---|
1066 | if (!TEST_int_ne(id, 0)
|
---|
1067 | || !TEST_true(id = OBJ_create(oid, sn, ln))
|
---|
1068 | || !TEST_true(OBJ_add_sigid(id, NID_sha3_256, NID_rsa)))
|
---|
1069 | multi_set_success(0);
|
---|
1070 | }
|
---|
1071 |
|
---|
1072 | static int test_obj_add(void)
|
---|
1073 | {
|
---|
1074 | return thread_run_test(&test_obj_create_one,
|
---|
1075 | MAXIMUM_THREADS, &test_obj_create_one,
|
---|
1076 | 1, default_provider);
|
---|
1077 | }
|
---|
1078 |
|
---|
1079 | static void test_lib_ctx_load_config_worker(void)
|
---|
1080 | {
|
---|
1081 | if (!TEST_int_eq(OSSL_LIB_CTX_load_config(multi_libctx, config_file), 1))
|
---|
1082 | multi_set_success(0);
|
---|
1083 | }
|
---|
1084 |
|
---|
1085 | static int test_lib_ctx_load_config(void)
|
---|
1086 | {
|
---|
1087 | return thread_run_test(&test_lib_ctx_load_config_worker,
|
---|
1088 | MAXIMUM_THREADS, &test_lib_ctx_load_config_worker,
|
---|
1089 | 1, default_provider);
|
---|
1090 | }
|
---|
1091 |
|
---|
1092 | #if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK)
|
---|
1093 | static BIO *multi_bio1, *multi_bio2;
|
---|
1094 |
|
---|
1095 | static void test_bio_dgram_pair_worker(void)
|
---|
1096 | {
|
---|
1097 | ossl_unused int r;
|
---|
1098 | int ok = 0;
|
---|
1099 | uint8_t ch = 0;
|
---|
1100 | uint8_t scratch[64];
|
---|
1101 | BIO_MSG msg = {0};
|
---|
1102 | size_t num_processed = 0;
|
---|
1103 |
|
---|
1104 | if (!TEST_int_eq(RAND_bytes_ex(multi_libctx, &ch, 1, 64), 1))
|
---|
1105 | goto err;
|
---|
1106 |
|
---|
1107 | msg.data = scratch;
|
---|
1108 | msg.data_len = sizeof(scratch);
|
---|
1109 |
|
---|
1110 | /*
|
---|
1111 | * We do not test for failure here as recvmmsg may fail if no sendmmsg
|
---|
1112 | * has been called yet. The purpose of this code is to exercise tsan.
|
---|
1113 | */
|
---|
1114 | if (ch & 2)
|
---|
1115 | r = BIO_sendmmsg(ch & 1 ? multi_bio2 : multi_bio1, &msg,
|
---|
1116 | sizeof(BIO_MSG), 1, 0, &num_processed);
|
---|
1117 | else
|
---|
1118 | r = BIO_recvmmsg(ch & 1 ? multi_bio2 : multi_bio1, &msg,
|
---|
1119 | sizeof(BIO_MSG), 1, 0, &num_processed);
|
---|
1120 |
|
---|
1121 | ok = 1;
|
---|
1122 | err:
|
---|
1123 | if (ok == 0)
|
---|
1124 | multi_set_success(0);
|
---|
1125 | }
|
---|
1126 |
|
---|
1127 | static int test_bio_dgram_pair(void)
|
---|
1128 | {
|
---|
1129 | int r;
|
---|
1130 | BIO *bio1 = NULL, *bio2 = NULL;
|
---|
1131 |
|
---|
1132 | r = BIO_new_bio_dgram_pair(&bio1, 0, &bio2, 0);
|
---|
1133 | if (!TEST_int_eq(r, 1))
|
---|
1134 | goto err;
|
---|
1135 |
|
---|
1136 | multi_bio1 = bio1;
|
---|
1137 | multi_bio2 = bio2;
|
---|
1138 |
|
---|
1139 | r = thread_run_test(&test_bio_dgram_pair_worker,
|
---|
1140 | MAXIMUM_THREADS, &test_bio_dgram_pair_worker,
|
---|
1141 | 1, default_provider);
|
---|
1142 |
|
---|
1143 | err:
|
---|
1144 | BIO_free(bio1);
|
---|
1145 | BIO_free(bio2);
|
---|
1146 | return r;
|
---|
1147 | }
|
---|
1148 | #endif
|
---|
1149 |
|
---|
1150 | static const char *pemdataraw[] = {
|
---|
1151 | "-----BEGIN RSA PRIVATE KEY-----\n",
|
---|
1152 | "MIIBOgIBAAJBAMFcGsaxxdgiuuGmCkVImy4h99CqT7jwY3pexPGcnUFtR2Fh36Bp\n",
|
---|
1153 | "oncwtkZ4cAgtvd4Qs8PkxUdp6p/DlUmObdkCAwEAAQJAUR44xX6zB3eaeyvTRzms\n",
|
---|
1154 | "kHADrPCmPWnr8dxsNwiDGHzrMKLN+i/HAam+97HxIKVWNDH2ba9Mf1SA8xu9dcHZ\n",
|
---|
1155 | "AQIhAOHPCLxbtQFVxlnhSyxYeb7O323c3QulPNn3bhOipElpAiEA2zZpBE8ZXVnL\n",
|
---|
1156 | "74QjG4zINlDfH+EOEtjJJ3RtaYDugvECIBtsQDxXytChsRgDQ1TcXdStXPcDppie\n",
|
---|
1157 | "dZhm8yhRTTBZAiAZjE/U9rsIDC0ebxIAZfn3iplWh84yGB3pgUI3J5WkoQIhAInE\n",
|
---|
1158 | "HTUY5WRj5riZtkyGnbm3DvF+1eMtO2lYV+OuLcfE\n",
|
---|
1159 | "-----END RSA PRIVATE KEY-----\n",
|
---|
1160 | NULL
|
---|
1161 | };
|
---|
1162 |
|
---|
1163 | static void test_pem_read_one(void)
|
---|
1164 | {
|
---|
1165 | EVP_PKEY *key = NULL;
|
---|
1166 | BIO *pem = NULL;
|
---|
1167 | char *pemdata;
|
---|
1168 | size_t len;
|
---|
1169 |
|
---|
1170 | pemdata = glue_strings(pemdataraw, &len);
|
---|
1171 | if (pemdata == NULL) {
|
---|
1172 | multi_set_success(0);
|
---|
1173 | goto err;
|
---|
1174 | }
|
---|
1175 |
|
---|
1176 | pem = BIO_new_mem_buf(pemdata, len);
|
---|
1177 | if (pem == NULL) {
|
---|
1178 | multi_set_success(0);
|
---|
1179 | goto err;
|
---|
1180 | }
|
---|
1181 |
|
---|
1182 | key = PEM_read_bio_PrivateKey(pem, NULL, NULL, NULL);
|
---|
1183 | if (key == NULL)
|
---|
1184 | multi_set_success(0);
|
---|
1185 |
|
---|
1186 | err:
|
---|
1187 | EVP_PKEY_free(key);
|
---|
1188 | BIO_free(pem);
|
---|
1189 | OPENSSL_free(pemdata);
|
---|
1190 | }
|
---|
1191 |
|
---|
1192 | /* Test reading PEM files in multiple threads */
|
---|
1193 | static int test_pem_read(void)
|
---|
1194 | {
|
---|
1195 | return thread_run_test(&test_pem_read_one, MAXIMUM_THREADS,
|
---|
1196 | &test_pem_read_one, 1, default_provider);
|
---|
1197 | }
|
---|
1198 |
|
---|
1199 | typedef enum OPTION_choice {
|
---|
1200 | OPT_ERR = -1,
|
---|
1201 | OPT_EOF = 0,
|
---|
1202 | OPT_FIPS, OPT_CONFIG_FILE,
|
---|
1203 | OPT_TEST_ENUM
|
---|
1204 | } OPTION_CHOICE;
|
---|
1205 |
|
---|
1206 | const OPTIONS *test_get_options(void)
|
---|
1207 | {
|
---|
1208 | static const OPTIONS options[] = {
|
---|
1209 | OPT_TEST_OPTIONS_DEFAULT_USAGE,
|
---|
1210 | { "fips", OPT_FIPS, '-', "Test the FIPS provider" },
|
---|
1211 | { "config", OPT_CONFIG_FILE, '<',
|
---|
1212 | "The configuration file to use for the libctx" },
|
---|
1213 | { NULL }
|
---|
1214 | };
|
---|
1215 | return options;
|
---|
1216 | }
|
---|
1217 |
|
---|
1218 | int setup_tests(void)
|
---|
1219 | {
|
---|
1220 | OPTION_CHOICE o;
|
---|
1221 | char *datadir;
|
---|
1222 |
|
---|
1223 | while ((o = opt_next()) != OPT_EOF) {
|
---|
1224 | switch (o) {
|
---|
1225 | case OPT_FIPS:
|
---|
1226 | do_fips = 1;
|
---|
1227 | break;
|
---|
1228 | case OPT_CONFIG_FILE:
|
---|
1229 | config_file = opt_arg();
|
---|
1230 | break;
|
---|
1231 | case OPT_TEST_CASES:
|
---|
1232 | break;
|
---|
1233 | default:
|
---|
1234 | return 0;
|
---|
1235 | }
|
---|
1236 | }
|
---|
1237 |
|
---|
1238 | if (!TEST_ptr(datadir = test_get_argument(0)))
|
---|
1239 | return 0;
|
---|
1240 |
|
---|
1241 | privkey = test_mk_file_path(datadir, "rsakey.pem");
|
---|
1242 | if (!TEST_ptr(privkey))
|
---|
1243 | return 0;
|
---|
1244 |
|
---|
1245 | if (!TEST_ptr(global_lock = CRYPTO_THREAD_lock_new()))
|
---|
1246 | return 0;
|
---|
1247 |
|
---|
1248 | #ifdef TSAN_REQUIRES_LOCKING
|
---|
1249 | if (!TEST_ptr(tsan_lock = CRYPTO_THREAD_lock_new()))
|
---|
1250 | return 0;
|
---|
1251 | #endif
|
---|
1252 |
|
---|
1253 | /* Keep first to validate auto creation of default library context */
|
---|
1254 | ADD_TEST(test_multi_default);
|
---|
1255 |
|
---|
1256 | ADD_TEST(test_lock);
|
---|
1257 | #if defined(OPENSSL_THREADS)
|
---|
1258 | ADD_TEST(torture_rw_low);
|
---|
1259 | ADD_TEST(torture_rw_high);
|
---|
1260 | # ifndef OPENSSL_SYS_MACOSX
|
---|
1261 | ADD_TEST(torture_rcu_low);
|
---|
1262 | ADD_TEST(torture_rcu_high);
|
---|
1263 | # endif
|
---|
1264 | #endif
|
---|
1265 | ADD_TEST(test_once);
|
---|
1266 | ADD_TEST(test_thread_local);
|
---|
1267 | ADD_TEST(test_atomic);
|
---|
1268 | ADD_TEST(test_multi_load);
|
---|
1269 | ADD_TEST(test_multi_general_worker_default_provider);
|
---|
1270 | ADD_TEST(test_multi_general_worker_fips_provider);
|
---|
1271 | ADD_TEST(test_multi_fetch_worker);
|
---|
1272 | ADD_TEST(test_multi_shared_pkey);
|
---|
1273 | #ifndef OPENSSL_NO_DEPRECATED_3_0
|
---|
1274 | ADD_TEST(test_multi_downgrade_shared_pkey);
|
---|
1275 | #endif
|
---|
1276 | ADD_TEST(test_multi_load_unload_provider);
|
---|
1277 | ADD_TEST(test_obj_add);
|
---|
1278 | ADD_TEST(test_lib_ctx_load_config);
|
---|
1279 | #if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK)
|
---|
1280 | ADD_TEST(test_bio_dgram_pair);
|
---|
1281 | #endif
|
---|
1282 | ADD_TEST(test_pem_read);
|
---|
1283 | return 1;
|
---|
1284 | }
|
---|
1285 |
|
---|
1286 | void cleanup_tests(void)
|
---|
1287 | {
|
---|
1288 | OPENSSL_free(privkey);
|
---|
1289 | #ifdef TSAN_REQUIRES_LOCKING
|
---|
1290 | CRYPTO_THREAD_lock_free(tsan_lock);
|
---|
1291 | #endif
|
---|
1292 | CRYPTO_THREAD_lock_free(global_lock);
|
---|
1293 | }
|
---|