2 * Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
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
10 /* test_multi below tests the thread safety of a deprecated function */
11 #define OPENSSL_SUPPRESS_DEPRECATED
18 #include <openssl/crypto.h>
19 #include <openssl/rsa.h>
20 #include <openssl/aes.h>
21 #include <openssl/rsa.h>
23 #include "threadstest.h"
25 static int do_fips = 0;
27 static char *config_file = NULL;
28 static int multidefault_run = 0;
30 static int test_lock(void)
32 CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
35 res = TEST_true(CRYPTO_THREAD_read_lock(lock))
36 && TEST_true(CRYPTO_THREAD_unlock(lock));
38 CRYPTO_THREAD_lock_free(lock);
43 static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT;
44 static unsigned once_run_count = 0;
46 static void once_do_run(void)
51 static void once_run_thread_cb(void)
53 CRYPTO_THREAD_run_once(&once_run, once_do_run);
56 static int test_once(void)
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))
68 static CRYPTO_THREAD_LOCAL thread_local_key;
69 static unsigned destructor_run_count = 0;
70 static int thread_local_thread_cb_ok = 0;
72 static void thread_local_destructor(void *arg)
84 static void thread_local_thread_cb(void)
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)))
94 ptr = CRYPTO_THREAD_get_local(&thread_local_key);
95 if (!TEST_ptr_eq(ptr, &destructor_run_count))
98 thread_local_thread_cb_ok = 1;
101 static int test_thread_local(void)
106 if (!TEST_true(CRYPTO_THREAD_init_local(&thread_local_key,
107 thread_local_destructor)))
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))
117 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG)
119 ptr = CRYPTO_THREAD_get_local(&thread_local_key);
120 if (!TEST_ptr_null(ptr))
123 # if !defined(OPENSSL_SYS_WINDOWS)
124 if (!TEST_int_eq(destructor_run_count, 1))
129 if (!TEST_true(CRYPTO_THREAD_cleanup_local(&thread_local_key)))
134 static int test_atomic(void)
136 int val = 0, ret = 0, testresult = 0;
137 uint64_t val64 = 1, ret64 = 0;
138 CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new();
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))
148 /* This failed therefore we're on a platform without lockless atomics */
149 if (!TEST_int_eq(val, 0) || !TEST_int_eq(val, ret))
155 if (!TEST_true(CRYPTO_atomic_add(&val, 1, &ret, lock)))
157 if (!TEST_int_eq(val, 1) || !TEST_int_eq(val, ret))
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))
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))
174 if (!TEST_true(CRYPTO_atomic_or(&val64, 2, &ret64, lock)))
177 if (!TEST_uint_eq((unsigned int)val64, 3)
178 || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
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))
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))
195 if (!TEST_true(CRYPTO_atomic_load(&val64, &ret64, lock)))
198 if (!TEST_uint_eq((unsigned int)val64, 3)
199 || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64))
204 CRYPTO_THREAD_lock_free(lock);
208 static OSSL_LIB_CTX *multi_libctx = NULL;
209 static int multi_success;
211 static void thread_general_worker(void)
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
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
231 EVP_PKEY *pkey = NULL;
235 isfips = OSSL_PROVIDER_available(multi_libctx, "fips");
239 || !TEST_ptr(cipherctx)
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)))
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,
255 || !TEST_true(EVP_EncryptFinal(cipherctx, out, &ciphoutl)))
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.
264 pkey = EVP_PKEY_Q_keygen(multi_libctx, NULL, "RSA", isfips ? 2048 : 512);
270 EVP_MD_CTX_free(mdctx);
272 EVP_CIPHER_CTX_free(cipherctx);
273 EVP_CIPHER_free(ciph);
279 static void thread_multi_simple_fetch(void)
281 EVP_MD *md = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL);
289 static EVP_PKEY *shared_evp_pkey = NULL;
291 static void thread_shared_evp_pkey(void)
293 char *msg = "Hello World";
294 unsigned char ctbuf[256];
295 unsigned char ptbuf[256];
296 size_t ptlen = sizeof(ptbuf), ctlen = sizeof(ctbuf);
297 EVP_PKEY_CTX *ctx = NULL;
301 for (i = 0; i < 1 + do_fips; i++) {
303 EVP_PKEY_CTX_free(ctx);
304 ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey,
305 i == 0 ? "provider=default"
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)),
316 EVP_PKEY_CTX_free(ctx);
317 ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey, NULL);
322 if (!TEST_int_ge(EVP_PKEY_decrypt_init(ctx), 0)
323 || !TEST_int_ge(EVP_PKEY_decrypt(ctx, ptbuf, &ptlen, ctbuf, ctlen),
325 || !TEST_mem_eq(msg, strlen(msg), ptbuf, ptlen))
332 EVP_PKEY_CTX_free(ctx);
337 static void thread_downgrade_shared_evp_pkey(void)
339 #ifndef OPENSSL_NO_DEPRECATED_3_0
341 * This test is only relevant for deprecated functions that perform
344 if (EVP_PKEY_get0_RSA(shared_evp_pkey) == NULL)
347 /* Shouldn't ever get here */
352 static void thread_provider_load_unload(void)
354 OSSL_PROVIDER *deflt = OSSL_PROVIDER_load(multi_libctx, "default");
357 || !TEST_true(OSSL_PROVIDER_available(multi_libctx, "default")))
360 OSSL_PROVIDER_unload(deflt);
364 * Do work in multiple worker threads at the same time.
365 * Test 0: General worker, using the default provider
366 * Test 1: General worker, using the fips provider
367 * Test 2: Simple fetch worker
368 * Test 3: Worker downgrading a shared EVP_PKEY
369 * Test 4: Worker using a shared EVP_PKEY
370 * Test 5: Worker loading and unloading a provider
372 static int test_multi(int idx)
374 thread_t thread1, thread2;
376 OSSL_PROVIDER *prov = NULL, *prov2 = NULL;
377 void (*worker)(void) = NULL;
378 void (*worker2)(void) = NULL;
379 EVP_MD *sha256 = NULL;
381 if (idx == 1 && !do_fips)
382 return TEST_skip("FIPS not supported");
384 #ifdef OPENSSL_NO_DEPRECATED_3_0
386 return TEST_skip("Skipping tests for deprected functions");
390 if (!TEST_true(test_get_libctx(&multi_libctx, NULL, config_file,
394 prov = OSSL_PROVIDER_load(multi_libctx, (idx == 1) ? "fips" : "default");
401 worker = thread_general_worker;
404 worker = thread_multi_simple_fetch;
407 worker2 = thread_downgrade_shared_evp_pkey;
411 * If available we have both the default and fips providers for this
415 && !TEST_ptr(prov2 = OSSL_PROVIDER_load(multi_libctx, "fips")))
417 if (!TEST_ptr(shared_evp_pkey = load_pkey_pem(privkey, multi_libctx)))
419 worker = thread_shared_evp_pkey;
423 * We ensure we get an md from the default provider, and then unload the
424 * provider. This ensures the provider remains around but in a
427 sha256 = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL);
428 OSSL_PROVIDER_unload(prov);
430 worker = thread_provider_load_unload;
433 TEST_error("Invalid test index");
439 if (!TEST_true(run_thread(&thread1, worker))
440 || !TEST_true(run_thread(&thread2, worker2)))
447 * Don't combine these into one if statement; must wait for both threads.
449 if (!TEST_true(wait_for_thread(thread1)))
451 if (!TEST_true(wait_for_thread(thread2)))
453 if (!TEST_true(multi_success))
458 OSSL_PROVIDER_unload(prov);
459 OSSL_PROVIDER_unload(prov2);
460 OSSL_LIB_CTX_free(multi_libctx);
461 EVP_PKEY_free(shared_evp_pkey);
462 shared_evp_pkey = NULL;
468 * This test attempts to load several providers at the same time, and if
469 * run with a thread sanitizer, should crash if the core provider code
470 * doesn't synchronize well enough.
472 #define MULTI_LOAD_THREADS 3
473 static void test_multi_load_worker(void)
477 (void)TEST_ptr(prov = OSSL_PROVIDER_load(NULL, "default"));
478 (void)TEST_true(OSSL_PROVIDER_unload(prov));
481 static int test_multi_default(void)
483 thread_t thread1, thread2;
485 OSSL_PROVIDER *prov = NULL;
487 /* Avoid running this test twice */
488 if (multidefault_run) {
489 TEST_skip("multi default test already run");
492 multidefault_run = 1;
496 prov = OSSL_PROVIDER_load(multi_libctx, "default");
500 if (!TEST_true(run_thread(&thread1, thread_multi_simple_fetch))
501 || !TEST_true(run_thread(&thread2, thread_multi_simple_fetch)))
504 thread_multi_simple_fetch();
506 if (!TEST_true(wait_for_thread(thread1))
507 || !TEST_true(wait_for_thread(thread2))
508 || !TEST_true(multi_success))
514 OSSL_PROVIDER_unload(prov);
518 static int test_multi_load(void)
520 thread_t threads[MULTI_LOAD_THREADS];
523 /* The multidefault test must run prior to this test */
524 if (!multidefault_run) {
525 TEST_info("Running multi default test first");
526 res = test_multi_default();
529 for (i = 0; i < MULTI_LOAD_THREADS; i++)
530 (void)TEST_true(run_thread(&threads[i], test_multi_load_worker));
532 for (i = 0; i < MULTI_LOAD_THREADS; i++)
533 (void)TEST_true(wait_for_thread(threads[i]));
538 typedef enum OPTION_choice {
541 OPT_FIPS, OPT_CONFIG_FILE,
545 const OPTIONS *test_get_options(void)
547 static const OPTIONS options[] = {
548 OPT_TEST_OPTIONS_DEFAULT_USAGE,
549 { "fips", OPT_FIPS, '-', "Test the FIPS provider" },
550 { "config", OPT_CONFIG_FILE, '<',
551 "The configuration file to use for the libctx" },
557 int setup_tests(void)
562 while ((o = opt_next()) != OPT_EOF) {
567 case OPT_CONFIG_FILE:
568 config_file = opt_arg();
577 if (!TEST_ptr(datadir = test_get_argument(0)))
580 privkey = test_mk_file_path(datadir, "rsakey.pem");
581 if (!TEST_ptr(privkey))
584 /* Keep first to validate auto creation of default library context */
585 ADD_TEST(test_multi_default);
589 ADD_TEST(test_thread_local);
590 ADD_TEST(test_atomic);
591 ADD_TEST(test_multi_load);
592 ADD_ALL_TESTS(test_multi, 6);
596 void cleanup_tests(void)
598 OPENSSL_free(privkey);