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