VirtualBox

source: vbox/trunk/src/libs/openssl-3.0.7/test/threadstest.c@ 97371

最後變更 在這個檔案從97371是 94404,由 vboxsync 提交於 3 年 前

libs/openssl: Update to 3.0.2 and switch to it, bugref:10128

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

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