xref: /netbsd-src/crypto/external/bsd/openssl/dist/test/threadstest.c (revision 8fbed61efdd901c0e09614c9f45356aeeab23fe3)
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