VirtualBox

source: vbox/trunk/src/libs/openssl-3.0.2/test/threadstest.c@ 94403

Last change on this file since 94403 was 94320, checked in by vboxsync, 3 years ago

libs/openssl-3.0.1: Export to OSE and fix copyright headers in Makefiles, bugref:10128

File size: 16.7 KB
Line 
1/*
2 * Copyright 2016-2021 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/* test_multi below tests the thread safety of a deprecated function */
11#define OPENSSL_SUPPRESS_DEPRECATED
12
13#if defined(_WIN32)
14# include <windows.h>
15#endif
16
17#include <string.h>
18#include <openssl/crypto.h>
19#include <openssl/rsa.h>
20#include <openssl/aes.h>
21#include <openssl/rsa.h>
22#include "testutil.h"
23#include "threadstest.h"
24
25static int do_fips = 0;
26static char *privkey;
27static char *config_file = NULL;
28static int multidefault_run = 0;
29
30static int test_lock(void)
31{
32 CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
33 int res;
34
35 res = TEST_true(CRYPTO_THREAD_read_lock(lock))
36 && TEST_true(CRYPTO_THREAD_unlock(lock));
37
38 CRYPTO_THREAD_lock_free(lock);
39
40 return res;
41}
42
43static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT;
44static unsigned once_run_count = 0;
45
46static void once_do_run(void)
47{
48 once_run_count++;
49}
50
51static void once_run_thread_cb(void)
52{
53 CRYPTO_THREAD_run_once(&once_run, once_do_run);
54}
55
56static int test_once(void)
57{
58 thread_t thread;
59
60 if (!TEST_true(run_thread(&thread, once_run_thread_cb))
61 || !TEST_true(wait_for_thread(thread))
62 || !CRYPTO_THREAD_run_once(&once_run, once_do_run)
63 || !TEST_int_eq(once_run_count, 1))
64 return 0;
65 return 1;
66}
67
68static CRYPTO_THREAD_LOCAL thread_local_key;
69static unsigned destructor_run_count = 0;
70static int thread_local_thread_cb_ok = 0;
71
72static void thread_local_destructor(void *arg)
73{
74 unsigned *count;
75
76 if (arg == NULL)
77 return;
78
79 count = arg;
80
81 (*count)++;
82}
83
84static void thread_local_thread_cb(void)
85{
86 void *ptr;
87
88 ptr = CRYPTO_THREAD_get_local(&thread_local_key);
89 if (!TEST_ptr_null(ptr)
90 || !TEST_true(CRYPTO_THREAD_set_local(&thread_local_key,
91 &destructor_run_count)))
92 return;
93
94 ptr = CRYPTO_THREAD_get_local(&thread_local_key);
95 if (!TEST_ptr_eq(ptr, &destructor_run_count))
96 return;
97
98 thread_local_thread_cb_ok = 1;
99}
100
101static int test_thread_local(void)
102{
103 thread_t thread;
104 void *ptr = NULL;
105
106 if (!TEST_true(CRYPTO_THREAD_init_local(&thread_local_key,
107 thread_local_destructor)))
108 return 0;
109
110 ptr = CRYPTO_THREAD_get_local(&thread_local_key);
111 if (!TEST_ptr_null(ptr)
112 || !TEST_true(run_thread(&thread, thread_local_thread_cb))
113 || !TEST_true(wait_for_thread(thread))
114 || !TEST_int_eq(thread_local_thread_cb_ok, 1))
115 return 0;
116
117#if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
118
119 ptr = CRYPTO_THREAD_get_local(&thread_local_key);
120 if (!TEST_ptr_null(ptr))
121 return 0;
122
123# if !defined(OPENSSL_SYS_WINDOWS)
124 if (!TEST_int_eq(destructor_run_count, 1))
125 return 0;
126# endif
127#endif
128
129 if (!TEST_true(CRYPTO_THREAD_cleanup_local(&thread_local_key)))
130 return 0;
131 return 1;
132}
133
134static int test_atomic(void)
135{
136 int val = 0, ret = 0, testresult = 0;
137 uint64_t val64 = 1, ret64 = 0;
138 CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
139
140 if (!TEST_ptr(lock))
141 return 0;
142
143 if (CRYPTO_atomic_add(&val, 1, &ret, NULL)) {
144 /* This succeeds therefore we're on a platform with lockless atomics */
145 if (!TEST_int_eq(val, 1) || !TEST_int_eq(val, ret))
146 goto err;
147 } else {
148 /* This failed therefore we're on a platform without lockless atomics */
149 if (!TEST_int_eq(val, 0) || !TEST_int_eq(val, ret))
150 goto err;
151 }
152 val = 0;
153 ret = 0;
154
155 if (!TEST_true(CRYPTO_atomic_add(&val, 1, &ret, lock)))
156 goto err;
157 if (!TEST_int_eq(val, 1) || !TEST_int_eq(val, ret))
158 goto err;
159
160 if (CRYPTO_atomic_or(&val64, 2, &ret64, NULL)) {
161 /* This succeeds therefore we're on a platform with lockless atomics */
162 if (!TEST_uint_eq((unsigned int)val64, 3)
163 || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
164 goto err;
165 } else {
166 /* This failed therefore we're on a platform without lockless atomics */
167 if (!TEST_uint_eq((unsigned int)val64, 1)
168 || !TEST_int_eq((unsigned int)ret64, 0))
169 goto err;
170 }
171 val64 = 1;
172 ret64 = 0;
173
174 if (!TEST_true(CRYPTO_atomic_or(&val64, 2, &ret64, lock)))
175 goto err;
176
177 if (!TEST_uint_eq((unsigned int)val64, 3)
178 || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
179 goto err;
180
181 ret64 = 0;
182 if (CRYPTO_atomic_load(&val64, &ret64, NULL)) {
183 /* This succeeds therefore we're on a platform with lockless atomics */
184 if (!TEST_uint_eq((unsigned int)val64, 3)
185 || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
186 goto err;
187 } else {
188 /* This failed therefore we're on a platform without lockless atomics */
189 if (!TEST_uint_eq((unsigned int)val64, 3)
190 || !TEST_int_eq((unsigned int)ret64, 0))
191 goto err;
192 }
193
194 ret64 = 0;
195 if (!TEST_true(CRYPTO_atomic_load(&val64, &ret64, lock)))
196 goto err;
197
198 if (!TEST_uint_eq((unsigned int)val64, 3)
199 || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
200 goto err;
201
202 testresult = 1;
203 err:
204 CRYPTO_THREAD_lock_free(lock);
205 return testresult;
206}
207
208static OSSL_LIB_CTX *multi_libctx = NULL;
209static int multi_success;
210
211static void thread_general_worker(void)
212{
213 EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
214 EVP_MD *md = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL);
215 EVP_CIPHER_CTX *cipherctx = EVP_CIPHER_CTX_new();
216 EVP_CIPHER *ciph = EVP_CIPHER_fetch(multi_libctx, "AES-128-CBC", NULL);
217 const char *message = "Hello World";
218 size_t messlen = strlen(message);
219 /* Should be big enough for encryption output too */
220 unsigned char out[EVP_MAX_MD_SIZE];
221 const unsigned char key[AES_BLOCK_SIZE] = {
222 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
223 0x0c, 0x0d, 0x0e, 0x0f
224 };
225 const unsigned char iv[AES_BLOCK_SIZE] = {
226 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
227 0x0c, 0x0d, 0x0e, 0x0f
228 };
229 unsigned int mdoutl;
230 int ciphoutl;
231 EVP_PKEY *pkey = NULL;
232 int testresult = 0;
233 int i, isfips;
234
235 isfips = OSSL_PROVIDER_available(multi_libctx, "fips");
236
237 if (!TEST_ptr(mdctx)
238 || !TEST_ptr(md)
239 || !TEST_ptr(cipherctx)
240 || !TEST_ptr(ciph))
241 goto err;
242
243 /* Do some work */
244 for (i = 0; i < 5; i++) {
245 if (!TEST_true(EVP_DigestInit_ex(mdctx, md, NULL))
246 || !TEST_true(EVP_DigestUpdate(mdctx, message, messlen))
247 || !TEST_true(EVP_DigestFinal(mdctx, out, &mdoutl)))
248 goto err;
249 }
250 for (i = 0; i < 5; i++) {
251 if (!TEST_true(EVP_EncryptInit_ex(cipherctx, ciph, NULL, key, iv))
252 || !TEST_true(EVP_EncryptUpdate(cipherctx, out, &ciphoutl,
253 (unsigned char *)message,
254 messlen))
255 || !TEST_true(EVP_EncryptFinal(cipherctx, out, &ciphoutl)))
256 goto err;
257 }
258
259 /*
260 * We want the test to run quickly - not securely.
261 * Therefore we use an insecure bit length where we can (512).
262 * In the FIPS module though we must use a longer length.
263 */
264 pkey = EVP_PKEY_Q_keygen(multi_libctx, NULL, "RSA", isfips ? 2048 : 512);
265 if (!TEST_ptr(pkey))
266 goto err;
267
268 testresult = 1;
269 err:
270 EVP_MD_CTX_free(mdctx);
271 EVP_MD_free(md);
272 EVP_CIPHER_CTX_free(cipherctx);
273 EVP_CIPHER_free(ciph);
274 EVP_PKEY_free(pkey);
275 if (!testresult)
276 multi_success = 0;
277}
278
279static void thread_multi_simple_fetch(void)
280{
281 EVP_MD *md = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL);
282
283 if (md != NULL)
284 EVP_MD_free(md);
285 else
286 multi_success = 0;
287}
288
289static EVP_PKEY *shared_evp_pkey = NULL;
290
291static void thread_shared_evp_pkey(void)
292{
293 char *msg = "Hello World";
294 unsigned char ctbuf[256];
295 unsigned char ptbuf[256];
296 size_t ptlen, ctlen = sizeof(ctbuf);
297 EVP_PKEY_CTX *ctx = NULL;
298 int success = 0;
299 int i;
300
301 for (i = 0; i < 1 + do_fips; i++) {
302 if (i > 0)
303 EVP_PKEY_CTX_free(ctx);
304 ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey,
305 i == 0 ? "provider=default"
306 : "provider=fips");
307 if (!TEST_ptr(ctx))
308 goto err;
309
310 if (!TEST_int_ge(EVP_PKEY_encrypt_init(ctx), 0)
311 || !TEST_int_ge(EVP_PKEY_encrypt(ctx, ctbuf, &ctlen,
312 (unsigned char *)msg, strlen(msg)),
313 0))
314 goto err;
315
316 EVP_PKEY_CTX_free(ctx);
317 ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey, NULL);
318
319 if (!TEST_ptr(ctx))
320 goto err;
321
322 ptlen = sizeof(ptbuf);
323 if (!TEST_int_ge(EVP_PKEY_decrypt_init(ctx), 0)
324 || !TEST_int_gt(EVP_PKEY_decrypt(ctx, ptbuf, &ptlen, ctbuf, ctlen),
325 0)
326 || !TEST_mem_eq(msg, strlen(msg), ptbuf, ptlen))
327 goto err;
328 }
329
330 success = 1;
331
332 err:
333 EVP_PKEY_CTX_free(ctx);
334 if (!success)
335 multi_success = 0;
336}
337
338static void thread_downgrade_shared_evp_pkey(void)
339{
340#ifndef OPENSSL_NO_DEPRECATED_3_0
341 /*
342 * This test is only relevant for deprecated functions that perform
343 * downgrading
344 */
345 if (EVP_PKEY_get0_RSA(shared_evp_pkey) == NULL)
346 multi_success = 0;
347#else
348 /* Shouldn't ever get here */
349 multi_success = 0;
350#endif
351}
352
353static void thread_provider_load_unload(void)
354{
355 OSSL_PROVIDER *deflt = OSSL_PROVIDER_load(multi_libctx, "default");
356
357 if (!TEST_ptr(deflt)
358 || !TEST_true(OSSL_PROVIDER_available(multi_libctx, "default")))
359 multi_success = 0;
360
361 OSSL_PROVIDER_unload(deflt);
362}
363
364/*
365 * Do work in multiple worker threads at the same time.
366 * Test 0: General worker, using the default provider
367 * Test 1: General worker, using the fips provider
368 * Test 2: Simple fetch worker
369 * Test 3: Worker downgrading a shared EVP_PKEY
370 * Test 4: Worker using a shared EVP_PKEY
371 * Test 5: Worker loading and unloading a provider
372 */
373static int test_multi(int idx)
374{
375 thread_t thread1, thread2;
376 int testresult = 0;
377 OSSL_PROVIDER *prov = NULL, *prov2 = NULL;
378 void (*worker)(void) = NULL;
379 void (*worker2)(void) = NULL;
380 EVP_MD *sha256 = NULL;
381
382 if (idx == 1 && !do_fips)
383 return TEST_skip("FIPS not supported");
384
385#ifdef OPENSSL_NO_DEPRECATED_3_0
386 if (idx == 3)
387 return TEST_skip("Skipping tests for deprected functions");
388#endif
389
390 multi_success = 1;
391 if (!TEST_true(test_get_libctx(&multi_libctx, NULL, config_file,
392 NULL, NULL)))
393 return 0;
394
395 prov = OSSL_PROVIDER_load(multi_libctx, (idx == 1) ? "fips" : "default");
396 if (!TEST_ptr(prov))
397 goto err;
398
399 switch (idx) {
400 case 0:
401 case 1:
402 worker = thread_general_worker;
403 break;
404 case 2:
405 worker = thread_multi_simple_fetch;
406 break;
407 case 3:
408 worker2 = thread_downgrade_shared_evp_pkey;
409 /* fall through */
410 case 4:
411 /*
412 * If available we have both the default and fips providers for this
413 * test
414 */
415 if (do_fips
416 && !TEST_ptr(prov2 = OSSL_PROVIDER_load(multi_libctx, "fips")))
417 goto err;
418 if (!TEST_ptr(shared_evp_pkey = load_pkey_pem(privkey, multi_libctx)))
419 goto err;
420 worker = thread_shared_evp_pkey;
421 break;
422 case 5:
423 /*
424 * We ensure we get an md from the default provider, and then unload the
425 * provider. This ensures the provider remains around but in a
426 * deactivated state.
427 */
428 sha256 = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL);
429 OSSL_PROVIDER_unload(prov);
430 prov = NULL;
431 worker = thread_provider_load_unload;
432 break;
433 default:
434 TEST_error("Invalid test index");
435 goto err;
436 }
437 if (worker2 == NULL)
438 worker2 = worker;
439
440 if (!TEST_true(run_thread(&thread1, worker))
441 || !TEST_true(run_thread(&thread2, worker2)))
442 goto err;
443
444 worker();
445
446 testresult = 1;
447 /*
448 * Don't combine these into one if statement; must wait for both threads.
449 */
450 if (!TEST_true(wait_for_thread(thread1)))
451 testresult = 0;
452 if (!TEST_true(wait_for_thread(thread2)))
453 testresult = 0;
454 if (!TEST_true(multi_success))
455 testresult = 0;
456
457 err:
458 EVP_MD_free(sha256);
459 OSSL_PROVIDER_unload(prov);
460 OSSL_PROVIDER_unload(prov2);
461 OSSL_LIB_CTX_free(multi_libctx);
462 EVP_PKEY_free(shared_evp_pkey);
463 shared_evp_pkey = NULL;
464 multi_libctx = NULL;
465 return testresult;
466}
467
468static char *multi_load_provider = "legacy";
469/*
470 * This test attempts to load several providers at the same time, and if
471 * run with a thread sanitizer, should crash if the core provider code
472 * doesn't synchronize well enough.
473 */
474#define MULTI_LOAD_THREADS 10
475static void test_multi_load_worker(void)
476{
477 OSSL_PROVIDER *prov;
478
479 if (!TEST_ptr(prov = OSSL_PROVIDER_load(NULL, multi_load_provider))
480 || !TEST_true(OSSL_PROVIDER_unload(prov)))
481 multi_success = 0;
482}
483
484static int test_multi_default(void)
485{
486 thread_t thread1, thread2;
487 int testresult = 0;
488 OSSL_PROVIDER *prov = NULL;
489
490 /* Avoid running this test twice */
491 if (multidefault_run) {
492 TEST_skip("multi default test already run");
493 return 1;
494 }
495 multidefault_run = 1;
496
497 multi_success = 1;
498 multi_libctx = NULL;
499 prov = OSSL_PROVIDER_load(multi_libctx, "default");
500 if (!TEST_ptr(prov))
501 goto err;
502
503 if (!TEST_true(run_thread(&thread1, thread_multi_simple_fetch))
504 || !TEST_true(run_thread(&thread2, thread_multi_simple_fetch)))
505 goto err;
506
507 thread_multi_simple_fetch();
508
509 if (!TEST_true(wait_for_thread(thread1))
510 || !TEST_true(wait_for_thread(thread2))
511 || !TEST_true(multi_success))
512 goto err;
513
514 testresult = 1;
515
516 err:
517 OSSL_PROVIDER_unload(prov);
518 return testresult;
519}
520
521static int test_multi_load(void)
522{
523 thread_t threads[MULTI_LOAD_THREADS];
524 int i, res = 1;
525 OSSL_PROVIDER *prov;
526
527 /* The multidefault test must run prior to this test */
528 if (!multidefault_run) {
529 TEST_info("Running multi default test first");
530 res = test_multi_default();
531 }
532
533 /*
534 * We use the legacy provider in test_multi_load_worker because it uses a
535 * child libctx that might hit more codepaths that might be sensitive to
536 * threading issues. But in a no-legacy build that won't be loadable so
537 * we use the default provider instead.
538 */
539 prov = OSSL_PROVIDER_load(NULL, "legacy");
540 if (prov == NULL) {
541 TEST_info("Cannot load legacy provider - assuming this is a no-legacy build");
542 multi_load_provider = "default";
543 }
544 OSSL_PROVIDER_unload(prov);
545
546 multi_success = 1;
547 for (i = 0; i < MULTI_LOAD_THREADS; i++)
548 (void)TEST_true(run_thread(&threads[i], test_multi_load_worker));
549
550 for (i = 0; i < MULTI_LOAD_THREADS; i++)
551 (void)TEST_true(wait_for_thread(threads[i]));
552
553 return res && multi_success;
554}
555
556typedef enum OPTION_choice {
557 OPT_ERR = -1,
558 OPT_EOF = 0,
559 OPT_FIPS, OPT_CONFIG_FILE,
560 OPT_TEST_ENUM
561} OPTION_CHOICE;
562
563const OPTIONS *test_get_options(void)
564{
565 static const OPTIONS options[] = {
566 OPT_TEST_OPTIONS_DEFAULT_USAGE,
567 { "fips", OPT_FIPS, '-', "Test the FIPS provider" },
568 { "config", OPT_CONFIG_FILE, '<',
569 "The configuration file to use for the libctx" },
570 { NULL }
571 };
572 return options;
573}
574
575int setup_tests(void)
576{
577 OPTION_CHOICE o;
578 char *datadir;
579
580 while ((o = opt_next()) != OPT_EOF) {
581 switch (o) {
582 case OPT_FIPS:
583 do_fips = 1;
584 break;
585 case OPT_CONFIG_FILE:
586 config_file = opt_arg();
587 break;
588 case OPT_TEST_CASES:
589 break;
590 default:
591 return 0;
592 }
593 }
594
595 if (!TEST_ptr(datadir = test_get_argument(0)))
596 return 0;
597
598 privkey = test_mk_file_path(datadir, "rsakey.pem");
599 if (!TEST_ptr(privkey))
600 return 0;
601
602 /* Keep first to validate auto creation of default library context */
603 ADD_TEST(test_multi_default);
604
605 ADD_TEST(test_lock);
606 ADD_TEST(test_once);
607 ADD_TEST(test_thread_local);
608 ADD_TEST(test_atomic);
609 ADD_TEST(test_multi_load);
610 ADD_ALL_TESTS(test_multi, 6);
611 return 1;
612}
613
614void cleanup_tests(void)
615{
616 OPENSSL_free(privkey);
617}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette