]>
Commit | Line | Data |
---|---|---|
440e5d80 | 1 | /* |
da1c088f | 2 | * Copyright 2016-2023 The OpenSSL Project Authors. All Rights Reserved. |
71a04cfc | 3 | * |
909f1a2e | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
440e5d80 RS |
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 | |
71a04cfc AG |
8 | */ |
9 | ||
0855591e P |
10 | /* |
11 | * The test_multi_downgrade_shared_pkey function tests the thread safety of a | |
12 | * deprecated function. | |
13 | */ | |
14 | #ifndef OPENSSL_NO_DEPRECATED_3_0 | |
15 | # define OPENSSL_SUPPRESS_DEPRECATED | |
16 | #endif | |
8e53d94d | 17 | |
f1f5ee17 AP |
18 | #if defined(_WIN32) |
19 | # include <windows.h> | |
20 | #endif | |
21 | ||
ae95a40e | 22 | #include <string.h> |
71a04cfc | 23 | #include <openssl/crypto.h> |
f9253152 | 24 | #include <openssl/rsa.h> |
ae95a40e | 25 | #include <openssl/aes.h> |
0855591e | 26 | #include <openssl/err.h> |
b88ce46e | 27 | #include <openssl/rand.h> |
29f25a10 MC |
28 | #include <openssl/pem.h> |
29 | #include <openssl/evp.h> | |
0855591e P |
30 | #include "internal/tsan_assist.h" |
31 | #include "internal/nelem.h" | |
ee25dd45 | 32 | #include "testutil.h" |
235776b2 | 33 | #include "threadstest.h" |
71a04cfc | 34 | |
0855591e | 35 | /* Limit the maximum number of threads */ |
293e251e | 36 | #define MAXIMUM_THREADS 10 |
0855591e P |
37 | |
38 | /* Limit the maximum number of providers loaded into a library context */ | |
39 | #define MAXIMUM_PROVIDERS 4 | |
40 | ||
ae95a40e | 41 | static int do_fips = 0; |
a0134d29 | 42 | static char *privkey; |
9a633a1c | 43 | static char *config_file = NULL; |
b9bc8eb0 | 44 | static int multidefault_run = 0; |
ae95a40e | 45 | |
0855591e P |
46 | static const char *default_provider[] = { "default", NULL }; |
47 | static const char *fips_provider[] = { "fips", NULL }; | |
48 | static const char *fips_and_default_providers[] = { "default", "fips", NULL }; | |
49 | ||
b88ce46e HL |
50 | static CRYPTO_RWLOCK *global_lock; |
51 | ||
3d4d5305 P |
52 | #ifdef TSAN_REQUIRES_LOCKING |
53 | static CRYPTO_RWLOCK *tsan_lock; | |
54 | #endif | |
55 | ||
56 | /* Grab a globally unique integer value, return 0 on failure */ | |
0855591e P |
57 | static int get_new_uid(void) |
58 | { | |
59 | /* | |
60 | * Start with a nice large number to avoid potential conflicts when | |
61 | * we generate a new OID. | |
62 | */ | |
63 | static TSAN_QUALIFIER int current_uid = 1 << (sizeof(int) * 8 - 2); | |
3d4d5305 P |
64 | #ifdef TSAN_REQUIRES_LOCKING |
65 | int r; | |
66 | ||
67 | if (!TEST_true(CRYPTO_THREAD_write_lock(tsan_lock))) | |
68 | return 0; | |
69 | r = ++current_uid; | |
70 | if (!TEST_true(CRYPTO_THREAD_unlock(tsan_lock))) | |
71 | return 0; | |
72 | return r; | |
0855591e | 73 | |
3d4d5305 | 74 | #else |
0855591e | 75 | return tsan_counter(¤t_uid); |
3d4d5305 | 76 | #endif |
0855591e P |
77 | } |
78 | ||
71a04cfc AG |
79 | static int test_lock(void) |
80 | { | |
81 | CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new(); | |
743840d5 | 82 | int res; |
71a04cfc | 83 | |
743840d5 | 84 | res = TEST_true(CRYPTO_THREAD_read_lock(lock)) |
1fc97807 P |
85 | && TEST_true(CRYPTO_THREAD_unlock(lock)) |
86 | && TEST_true(CRYPTO_THREAD_write_lock(lock)) | |
743840d5 | 87 | && TEST_true(CRYPTO_THREAD_unlock(lock)); |
71a04cfc AG |
88 | |
89 | CRYPTO_THREAD_lock_free(lock); | |
90 | ||
743840d5 | 91 | return res; |
71a04cfc AG |
92 | } |
93 | ||
94 | static CRYPTO_ONCE once_run = CRYPTO_ONCE_STATIC_INIT; | |
95 | static unsigned once_run_count = 0; | |
96 | ||
97 | static void once_do_run(void) | |
98 | { | |
99 | once_run_count++; | |
100 | } | |
101 | ||
102 | static void once_run_thread_cb(void) | |
103 | { | |
104 | CRYPTO_THREAD_run_once(&once_run, once_do_run); | |
105 | } | |
106 | ||
107 | static int test_once(void) | |
108 | { | |
109 | thread_t thread; | |
71a04cfc | 110 | |
ee25dd45 P |
111 | if (!TEST_true(run_thread(&thread, once_run_thread_cb)) |
112 | || !TEST_true(wait_for_thread(thread)) | |
113 | || !CRYPTO_THREAD_run_once(&once_run, once_do_run) | |
114 | || !TEST_int_eq(once_run_count, 1)) | |
71a04cfc | 115 | return 0; |
71a04cfc AG |
116 | return 1; |
117 | } | |
118 | ||
119 | static CRYPTO_THREAD_LOCAL thread_local_key; | |
120 | static unsigned destructor_run_count = 0; | |
121 | static int thread_local_thread_cb_ok = 0; | |
122 | ||
123 | static void thread_local_destructor(void *arg) | |
124 | { | |
125 | unsigned *count; | |
126 | ||
127 | if (arg == NULL) | |
128 | return; | |
129 | ||
130 | count = arg; | |
131 | ||
132 | (*count)++; | |
133 | } | |
134 | ||
135 | static void thread_local_thread_cb(void) | |
136 | { | |
137 | void *ptr; | |
138 | ||
139 | ptr = CRYPTO_THREAD_get_local(&thread_local_key); | |
ee25dd45 P |
140 | if (!TEST_ptr_null(ptr) |
141 | || !TEST_true(CRYPTO_THREAD_set_local(&thread_local_key, | |
142 | &destructor_run_count))) | |
71a04cfc | 143 | return; |
71a04cfc AG |
144 | |
145 | ptr = CRYPTO_THREAD_get_local(&thread_local_key); | |
ee25dd45 | 146 | if (!TEST_ptr_eq(ptr, &destructor_run_count)) |
71a04cfc | 147 | return; |
71a04cfc AG |
148 | |
149 | thread_local_thread_cb_ok = 1; | |
150 | } | |
151 | ||
152 | static int test_thread_local(void) | |
153 | { | |
154 | thread_t thread; | |
155 | void *ptr = NULL; | |
156 | ||
ee25dd45 P |
157 | if (!TEST_true(CRYPTO_THREAD_init_local(&thread_local_key, |
158 | thread_local_destructor))) | |
71a04cfc | 159 | return 0; |
71a04cfc AG |
160 | |
161 | ptr = CRYPTO_THREAD_get_local(&thread_local_key); | |
ee25dd45 P |
162 | if (!TEST_ptr_null(ptr) |
163 | || !TEST_true(run_thread(&thread, thread_local_thread_cb)) | |
164 | || !TEST_true(wait_for_thread(thread)) | |
165 | || !TEST_int_eq(thread_local_thread_cb_ok, 1)) | |
71a04cfc | 166 | return 0; |
71a04cfc AG |
167 | |
168 | #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) | |
169 | ||
170 | ptr = CRYPTO_THREAD_get_local(&thread_local_key); | |
ee25dd45 | 171 | if (!TEST_ptr_null(ptr)) |
71a04cfc | 172 | return 0; |
71a04cfc AG |
173 | |
174 | # if !defined(OPENSSL_SYS_WINDOWS) | |
ee25dd45 | 175 | if (!TEST_int_eq(destructor_run_count, 1)) |
71a04cfc | 176 | return 0; |
71a04cfc | 177 | # endif |
71a04cfc AG |
178 | #endif |
179 | ||
ee25dd45 | 180 | if (!TEST_true(CRYPTO_THREAD_cleanup_local(&thread_local_key))) |
71a04cfc | 181 | return 0; |
71a04cfc AG |
182 | return 1; |
183 | } | |
184 | ||
ea08f8b2 MC |
185 | static int test_atomic(void) |
186 | { | |
187 | int val = 0, ret = 0, testresult = 0; | |
188 | uint64_t val64 = 1, ret64 = 0; | |
189 | CRYPTO_RWLOCK *lock = CRYPTO_THREAD_lock_new(); | |
190 | ||
191 | if (!TEST_ptr(lock)) | |
192 | return 0; | |
193 | ||
194 | if (CRYPTO_atomic_add(&val, 1, &ret, NULL)) { | |
195 | /* This succeeds therefore we're on a platform with lockless atomics */ | |
196 | if (!TEST_int_eq(val, 1) || !TEST_int_eq(val, ret)) | |
197 | goto err; | |
198 | } else { | |
199 | /* This failed therefore we're on a platform without lockless atomics */ | |
200 | if (!TEST_int_eq(val, 0) || !TEST_int_eq(val, ret)) | |
201 | goto err; | |
202 | } | |
203 | val = 0; | |
204 | ret = 0; | |
205 | ||
206 | if (!TEST_true(CRYPTO_atomic_add(&val, 1, &ret, lock))) | |
207 | goto err; | |
208 | if (!TEST_int_eq(val, 1) || !TEST_int_eq(val, ret)) | |
209 | goto err; | |
210 | ||
211 | if (CRYPTO_atomic_or(&val64, 2, &ret64, NULL)) { | |
212 | /* This succeeds therefore we're on a platform with lockless atomics */ | |
213 | if (!TEST_uint_eq((unsigned int)val64, 3) | |
214 | || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) | |
215 | goto err; | |
216 | } else { | |
217 | /* This failed therefore we're on a platform without lockless atomics */ | |
218 | if (!TEST_uint_eq((unsigned int)val64, 1) | |
219 | || !TEST_int_eq((unsigned int)ret64, 0)) | |
220 | goto err; | |
221 | } | |
222 | val64 = 1; | |
223 | ret64 = 0; | |
224 | ||
225 | if (!TEST_true(CRYPTO_atomic_or(&val64, 2, &ret64, lock))) | |
226 | goto err; | |
227 | ||
228 | if (!TEST_uint_eq((unsigned int)val64, 3) | |
229 | || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) | |
230 | goto err; | |
231 | ||
232 | ret64 = 0; | |
233 | if (CRYPTO_atomic_load(&val64, &ret64, NULL)) { | |
234 | /* This succeeds therefore we're on a platform with lockless atomics */ | |
235 | if (!TEST_uint_eq((unsigned int)val64, 3) | |
236 | || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) | |
237 | goto err; | |
238 | } else { | |
239 | /* This failed therefore we're on a platform without lockless atomics */ | |
240 | if (!TEST_uint_eq((unsigned int)val64, 3) | |
241 | || !TEST_int_eq((unsigned int)ret64, 0)) | |
242 | goto err; | |
243 | } | |
244 | ||
245 | ret64 = 0; | |
246 | if (!TEST_true(CRYPTO_atomic_load(&val64, &ret64, lock))) | |
247 | goto err; | |
248 | ||
249 | if (!TEST_uint_eq((unsigned int)val64, 3) | |
250 | || !TEST_uint_eq((unsigned int)val64, (unsigned int)ret64)) | |
251 | goto err; | |
252 | ||
253 | testresult = 1; | |
254 | err: | |
ea08f8b2 MC |
255 | CRYPTO_THREAD_lock_free(lock); |
256 | return testresult; | |
257 | } | |
258 | ||
ae95a40e MC |
259 | static OSSL_LIB_CTX *multi_libctx = NULL; |
260 | static int multi_success; | |
0855591e P |
261 | static OSSL_PROVIDER *multi_provider[MAXIMUM_PROVIDERS + 1]; |
262 | static size_t multi_num_threads; | |
263 | static thread_t multi_threads[MAXIMUM_THREADS]; | |
264 | ||
265 | static void multi_intialise(void) | |
266 | { | |
267 | multi_success = 1; | |
268 | multi_libctx = NULL; | |
269 | multi_num_threads = 0; | |
270 | memset(multi_threads, 0, sizeof(multi_threads)); | |
271 | memset(multi_provider, 0, sizeof(multi_provider)); | |
272 | } | |
273 | ||
b88ce46e HL |
274 | static void multi_set_success(int ok) |
275 | { | |
276 | if (CRYPTO_THREAD_write_lock(global_lock) == 0) { | |
277 | /* not synchronized, but better than not reporting failure */ | |
278 | multi_success = ok; | |
279 | return; | |
280 | } | |
281 | ||
282 | multi_success = ok; | |
283 | ||
284 | CRYPTO_THREAD_unlock(global_lock); | |
285 | } | |
286 | ||
0855591e P |
287 | static void thead_teardown_libctx(void) |
288 | { | |
289 | OSSL_PROVIDER **p; | |
290 | ||
291 | for (p = multi_provider; *p != NULL; p++) | |
292 | OSSL_PROVIDER_unload(*p); | |
293 | OSSL_LIB_CTX_free(multi_libctx); | |
294 | multi_intialise(); | |
295 | } | |
296 | ||
297 | static int thread_setup_libctx(int libctx, const char *providers[]) | |
298 | { | |
299 | size_t n; | |
300 | ||
301 | if (libctx && !TEST_true(test_get_libctx(&multi_libctx, NULL, config_file, | |
302 | NULL, NULL))) | |
303 | return 0; | |
304 | ||
305 | if (providers != NULL) | |
306 | for (n = 0; providers[n] != NULL; n++) | |
307 | if (!TEST_size_t_lt(n, MAXIMUM_PROVIDERS) | |
308 | || !TEST_ptr(multi_provider[n] = OSSL_PROVIDER_load(multi_libctx, | |
309 | providers[n]))) { | |
310 | thead_teardown_libctx(); | |
311 | return 0; | |
312 | } | |
313 | return 1; | |
314 | } | |
315 | ||
316 | static int teardown_threads(void) | |
317 | { | |
318 | size_t i; | |
319 | ||
320 | for (i = 0; i < multi_num_threads; i++) | |
321 | if (!TEST_true(wait_for_thread(multi_threads[i]))) | |
322 | return 0; | |
323 | return 1; | |
324 | } | |
325 | ||
326 | static int start_threads(size_t n, void (*thread_func)(void)) | |
327 | { | |
328 | size_t i; | |
329 | ||
330 | if (!TEST_size_t_le(multi_num_threads + n, MAXIMUM_THREADS)) | |
331 | return 0; | |
332 | ||
333 | for (i = 0 ; i < n; i++) | |
334 | if (!TEST_true(run_thread(multi_threads + multi_num_threads++, thread_func))) | |
335 | return 0; | |
336 | return 1; | |
337 | } | |
338 | ||
339 | /* Template multi-threaded test function */ | |
340 | static int thread_run_test(void (*main_func)(void), | |
341 | size_t num_threads, void (*thread_func)(void), | |
342 | int libctx, const char *providers[]) | |
343 | { | |
344 | int testresult = 0; | |
345 | ||
346 | multi_intialise(); | |
347 | if (!thread_setup_libctx(libctx, providers) | |
348 | || !start_threads(num_threads, thread_func)) | |
349 | goto err; | |
350 | ||
351 | if (main_func != NULL) | |
352 | main_func(); | |
353 | ||
354 | if (!teardown_threads() | |
355 | || !TEST_true(multi_success)) | |
356 | goto err; | |
357 | testresult = 1; | |
358 | err: | |
359 | thead_teardown_libctx(); | |
360 | return testresult; | |
361 | } | |
ae95a40e | 362 | |
b457c8f5 | 363 | static void thread_general_worker(void) |
ae95a40e MC |
364 | { |
365 | EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); | |
366 | EVP_MD *md = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL); | |
367 | EVP_CIPHER_CTX *cipherctx = EVP_CIPHER_CTX_new(); | |
368 | EVP_CIPHER *ciph = EVP_CIPHER_fetch(multi_libctx, "AES-128-CBC", NULL); | |
369 | const char *message = "Hello World"; | |
370 | size_t messlen = strlen(message); | |
371 | /* Should be big enough for encryption output too */ | |
372 | unsigned char out[EVP_MAX_MD_SIZE]; | |
373 | const unsigned char key[AES_BLOCK_SIZE] = { | |
374 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, | |
375 | 0x0c, 0x0d, 0x0e, 0x0f | |
376 | }; | |
377 | const unsigned char iv[AES_BLOCK_SIZE] = { | |
378 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, | |
379 | 0x0c, 0x0d, 0x0e, 0x0f | |
380 | }; | |
381 | unsigned int mdoutl; | |
382 | int ciphoutl; | |
ae95a40e MC |
383 | EVP_PKEY *pkey = NULL; |
384 | int testresult = 0; | |
385 | int i, isfips; | |
386 | ||
387 | isfips = OSSL_PROVIDER_available(multi_libctx, "fips"); | |
388 | ||
389 | if (!TEST_ptr(mdctx) | |
390 | || !TEST_ptr(md) | |
391 | || !TEST_ptr(cipherctx) | |
392 | || !TEST_ptr(ciph)) | |
393 | goto err; | |
394 | ||
395 | /* Do some work */ | |
396 | for (i = 0; i < 5; i++) { | |
397 | if (!TEST_true(EVP_DigestInit_ex(mdctx, md, NULL)) | |
398 | || !TEST_true(EVP_DigestUpdate(mdctx, message, messlen)) | |
399 | || !TEST_true(EVP_DigestFinal(mdctx, out, &mdoutl))) | |
400 | goto err; | |
401 | } | |
402 | for (i = 0; i < 5; i++) { | |
403 | if (!TEST_true(EVP_EncryptInit_ex(cipherctx, ciph, NULL, key, iv)) | |
404 | || !TEST_true(EVP_EncryptUpdate(cipherctx, out, &ciphoutl, | |
405 | (unsigned char *)message, | |
406 | messlen)) | |
407 | || !TEST_true(EVP_EncryptFinal(cipherctx, out, &ciphoutl))) | |
408 | goto err; | |
409 | } | |
410 | ||
f9253152 DDO |
411 | /* |
412 | * We want the test to run quickly - not securely. | |
413 | * Therefore we use an insecure bit length where we can (512). | |
414 | * In the FIPS module though we must use a longer length. | |
415 | */ | |
416 | pkey = EVP_PKEY_Q_keygen(multi_libctx, NULL, "RSA", isfips ? 2048 : 512); | |
417 | if (!TEST_ptr(pkey)) | |
ae95a40e MC |
418 | goto err; |
419 | ||
420 | testresult = 1; | |
421 | err: | |
422 | EVP_MD_CTX_free(mdctx); | |
423 | EVP_MD_free(md); | |
424 | EVP_CIPHER_CTX_free(cipherctx); | |
425 | EVP_CIPHER_free(ciph); | |
ae95a40e MC |
426 | EVP_PKEY_free(pkey); |
427 | if (!testresult) | |
b88ce46e | 428 | multi_set_success(0); |
ae95a40e MC |
429 | } |
430 | ||
b457c8f5 MC |
431 | static void thread_multi_simple_fetch(void) |
432 | { | |
a135dea4 | 433 | EVP_MD *md = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL); |
b457c8f5 MC |
434 | |
435 | if (md != NULL) | |
436 | EVP_MD_free(md); | |
437 | else | |
b88ce46e | 438 | multi_set_success(0); |
b457c8f5 MC |
439 | } |
440 | ||
a0134d29 MC |
441 | static EVP_PKEY *shared_evp_pkey = NULL; |
442 | ||
443 | static void thread_shared_evp_pkey(void) | |
444 | { | |
445 | char *msg = "Hello World"; | |
446 | unsigned char ctbuf[256]; | |
447 | unsigned char ptbuf[256]; | |
0650ac43 | 448 | size_t ptlen, ctlen = sizeof(ctbuf); |
a0134d29 MC |
449 | EVP_PKEY_CTX *ctx = NULL; |
450 | int success = 0; | |
451 | int i; | |
452 | ||
453 | for (i = 0; i < 1 + do_fips; i++) { | |
454 | if (i > 0) | |
455 | EVP_PKEY_CTX_free(ctx); | |
456 | ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey, | |
457 | i == 0 ? "provider=default" | |
458 | : "provider=fips"); | |
459 | if (!TEST_ptr(ctx)) | |
460 | goto err; | |
461 | ||
462 | if (!TEST_int_ge(EVP_PKEY_encrypt_init(ctx), 0) | |
463 | || !TEST_int_ge(EVP_PKEY_encrypt(ctx, ctbuf, &ctlen, | |
464 | (unsigned char *)msg, strlen(msg)), | |
465 | 0)) | |
466 | goto err; | |
467 | ||
468 | EVP_PKEY_CTX_free(ctx); | |
469 | ctx = EVP_PKEY_CTX_new_from_pkey(multi_libctx, shared_evp_pkey, NULL); | |
470 | ||
471 | if (!TEST_ptr(ctx)) | |
472 | goto err; | |
473 | ||
0650ac43 | 474 | ptlen = sizeof(ptbuf); |
a0134d29 | 475 | if (!TEST_int_ge(EVP_PKEY_decrypt_init(ctx), 0) |
0650ac43 | 476 | || !TEST_int_gt(EVP_PKEY_decrypt(ctx, ptbuf, &ptlen, ctbuf, ctlen), |
a0134d29 MC |
477 | 0) |
478 | || !TEST_mem_eq(msg, strlen(msg), ptbuf, ptlen)) | |
479 | goto err; | |
480 | } | |
481 | ||
482 | success = 1; | |
483 | ||
484 | err: | |
485 | EVP_PKEY_CTX_free(ctx); | |
486 | if (!success) | |
b88ce46e | 487 | multi_set_success(0); |
a0134d29 MC |
488 | } |
489 | ||
98369ef2 MC |
490 | static void thread_provider_load_unload(void) |
491 | { | |
492 | OSSL_PROVIDER *deflt = OSSL_PROVIDER_load(multi_libctx, "default"); | |
493 | ||
494 | if (!TEST_ptr(deflt) | |
495 | || !TEST_true(OSSL_PROVIDER_available(multi_libctx, "default"))) | |
b88ce46e | 496 | multi_set_success(0); |
98369ef2 MC |
497 | |
498 | OSSL_PROVIDER_unload(deflt); | |
499 | } | |
e8afd78a | 500 | |
0855591e | 501 | static int test_multi_general_worker_default_provider(void) |
ae95a40e | 502 | { |
0855591e P |
503 | return thread_run_test(&thread_general_worker, 2, &thread_general_worker, |
504 | 1, default_provider); | |
505 | } | |
ae95a40e | 506 | |
0855591e P |
507 | static int test_multi_general_worker_fips_provider(void) |
508 | { | |
509 | if (!do_fips) | |
ae95a40e | 510 | return TEST_skip("FIPS not supported"); |
0855591e P |
511 | return thread_run_test(&thread_general_worker, 2, &thread_general_worker, |
512 | 1, fips_provider); | |
513 | } | |
ae95a40e | 514 | |
0855591e P |
515 | static int test_multi_fetch_worker(void) |
516 | { | |
517 | return thread_run_test(&thread_multi_simple_fetch, | |
518 | 2, &thread_multi_simple_fetch, 1, default_provider); | |
519 | } | |
e8afd78a | 520 | |
0855591e P |
521 | static int test_multi_shared_pkey_common(void (*worker)(void)) |
522 | { | |
523 | int testresult = 0; | |
9a633a1c | 524 | |
0855591e P |
525 | multi_intialise(); |
526 | if (!thread_setup_libctx(1, do_fips ? fips_and_default_providers | |
527 | : default_provider) | |
528 | || !TEST_ptr(shared_evp_pkey = load_pkey_pem(privkey, multi_libctx)) | |
529 | || !start_threads(1, &thread_shared_evp_pkey) | |
530 | || !start_threads(1, worker)) | |
ae95a40e MC |
531 | goto err; |
532 | ||
0855591e | 533 | thread_shared_evp_pkey(); |
b457c8f5 | 534 | |
0855591e P |
535 | if (!teardown_threads() |
536 | || !TEST_true(multi_success)) | |
ae95a40e | 537 | goto err; |
ae95a40e | 538 | testresult = 1; |
0855591e P |
539 | err: |
540 | EVP_PKEY_free(shared_evp_pkey); | |
541 | thead_teardown_libctx(); | |
542 | return testresult; | |
543 | } | |
544 | ||
545 | #ifndef OPENSSL_NO_DEPRECATED_3_0 | |
546 | static void thread_downgrade_shared_evp_pkey(void) | |
547 | { | |
c3932c34 | 548 | /* |
0855591e P |
549 | * This test is only relevant for deprecated functions that perform |
550 | * downgrading | |
c3932c34 | 551 | */ |
0855591e | 552 | if (EVP_PKEY_get0_RSA(shared_evp_pkey) == NULL) |
b88ce46e | 553 | multi_set_success(0); |
0855591e P |
554 | } |
555 | ||
556 | static int test_multi_downgrade_shared_pkey(void) | |
557 | { | |
558 | return test_multi_shared_pkey_common(&thread_downgrade_shared_evp_pkey); | |
559 | } | |
560 | #endif | |
561 | ||
562 | static int test_multi_shared_pkey(void) | |
563 | { | |
564 | return test_multi_shared_pkey_common(&thread_shared_evp_pkey); | |
565 | } | |
566 | ||
567 | static int test_multi_load_unload_provider(void) | |
568 | { | |
569 | EVP_MD *sha256 = NULL; | |
570 | OSSL_PROVIDER *prov = NULL; | |
571 | int testresult = 0; | |
572 | ||
573 | multi_intialise(); | |
574 | if (!thread_setup_libctx(1, NULL) | |
575 | || !TEST_ptr(prov = OSSL_PROVIDER_load(multi_libctx, "default")) | |
576 | || !TEST_ptr(sha256 = EVP_MD_fetch(multi_libctx, "SHA2-256", NULL)) | |
577 | || !TEST_true(OSSL_PROVIDER_unload(prov))) | |
578 | goto err; | |
579 | prov = NULL; | |
580 | ||
581 | if (!start_threads(2, &thread_provider_load_unload)) | |
582 | goto err; | |
ae95a40e | 583 | |
0855591e P |
584 | thread_provider_load_unload(); |
585 | ||
586 | if (!teardown_threads() | |
587 | || !TEST_true(multi_success)) | |
588 | goto err; | |
589 | testresult = 1; | |
ae95a40e MC |
590 | err: |
591 | OSSL_PROVIDER_unload(prov); | |
0855591e P |
592 | EVP_MD_free(sha256); |
593 | thead_teardown_libctx(); | |
ae95a40e MC |
594 | return testresult; |
595 | } | |
596 | ||
293e251e | 597 | static char *multi_load_provider = "legacy"; |
2f17e978 RL |
598 | /* |
599 | * This test attempts to load several providers at the same time, and if | |
600 | * run with a thread sanitizer, should crash if the core provider code | |
601 | * doesn't synchronize well enough. | |
602 | */ | |
2f17e978 RL |
603 | static void test_multi_load_worker(void) |
604 | { | |
605 | OSSL_PROVIDER *prov; | |
606 | ||
293e251e | 607 | if (!TEST_ptr(prov = OSSL_PROVIDER_load(multi_libctx, multi_load_provider)) |
0855591e | 608 | || !TEST_true(OSSL_PROVIDER_unload(prov))) |
b88ce46e | 609 | multi_set_success(0); |
2f17e978 RL |
610 | } |
611 | ||
a135dea4 P |
612 | static int test_multi_default(void) |
613 | { | |
b9bc8eb0 P |
614 | /* Avoid running this test twice */ |
615 | if (multidefault_run) { | |
616 | TEST_skip("multi default test already run"); | |
617 | return 1; | |
618 | } | |
619 | multidefault_run = 1; | |
620 | ||
0855591e P |
621 | return thread_run_test(&thread_multi_simple_fetch, |
622 | 2, &thread_multi_simple_fetch, 0, default_provider); | |
a135dea4 P |
623 | } |
624 | ||
b9bc8eb0 P |
625 | static int test_multi_load(void) |
626 | { | |
0855591e | 627 | int res = 1; |
293e251e | 628 | OSSL_PROVIDER *prov; |
b9bc8eb0 P |
629 | |
630 | /* The multidefault test must run prior to this test */ | |
631 | if (!multidefault_run) { | |
632 | TEST_info("Running multi default test first"); | |
633 | res = test_multi_default(); | |
634 | } | |
635 | ||
293e251e MC |
636 | /* |
637 | * We use the legacy provider in test_multi_load_worker because it uses a | |
638 | * child libctx that might hit more codepaths that might be sensitive to | |
639 | * threading issues. But in a no-legacy build that won't be loadable so | |
640 | * we use the default provider instead. | |
641 | */ | |
642 | prov = OSSL_PROVIDER_load(NULL, "legacy"); | |
643 | if (prov == NULL) { | |
644 | TEST_info("Cannot load legacy provider - assuming this is a no-legacy build"); | |
645 | multi_load_provider = "default"; | |
646 | } | |
647 | OSSL_PROVIDER_unload(prov); | |
648 | ||
649 | return thread_run_test(NULL, MAXIMUM_THREADS, &test_multi_load_worker, 0, | |
650 | NULL) && res; | |
0855591e | 651 | } |
b9bc8eb0 | 652 | |
0855591e P |
653 | static void test_obj_create_one(void) |
654 | { | |
655 | char tids[12], oid[40], sn[30], ln[30]; | |
656 | int id = get_new_uid(); | |
657 | ||
658 | BIO_snprintf(tids, sizeof(tids), "%d", id); | |
659 | BIO_snprintf(oid, sizeof(oid), "1.3.6.1.4.1.16604.%s", tids); | |
660 | BIO_snprintf(sn, sizeof(sn), "short-name-%s", tids); | |
661 | BIO_snprintf(ln, sizeof(ln), "long-name-%s", tids); | |
3d4d5305 P |
662 | if (!TEST_int_ne(id, 0) |
663 | || !TEST_true(id = OBJ_create(oid, sn, ln)) | |
0855591e | 664 | || !TEST_true(OBJ_add_sigid(id, NID_sha3_256, NID_rsa))) |
b88ce46e | 665 | multi_set_success(0); |
0855591e | 666 | } |
b9bc8eb0 | 667 | |
0855591e P |
668 | static int test_obj_add(void) |
669 | { | |
670 | return thread_run_test(&test_obj_create_one, | |
671 | MAXIMUM_THREADS, &test_obj_create_one, | |
672 | 1, default_provider); | |
b9bc8eb0 P |
673 | } |
674 | ||
ef7a9b44 HL |
675 | static void test_lib_ctx_load_config_worker(void) |
676 | { | |
677 | if (!TEST_int_eq(OSSL_LIB_CTX_load_config(multi_libctx, config_file), 1)) | |
b88ce46e | 678 | multi_set_success(0); |
ef7a9b44 HL |
679 | } |
680 | ||
681 | static int test_lib_ctx_load_config(void) | |
682 | { | |
683 | return thread_run_test(&test_lib_ctx_load_config_worker, | |
684 | MAXIMUM_THREADS, &test_lib_ctx_load_config_worker, | |
685 | 1, default_provider); | |
686 | } | |
687 | ||
b88ce46e HL |
688 | #if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK) |
689 | static BIO *multi_bio1, *multi_bio2; | |
690 | ||
691 | static void test_bio_dgram_pair_worker(void) | |
692 | { | |
693 | ossl_unused int r; | |
694 | int ok = 0; | |
695 | uint8_t ch = 0; | |
696 | uint8_t scratch[64]; | |
697 | BIO_MSG msg = {0}; | |
698 | size_t num_processed = 0; | |
699 | ||
700 | if (!TEST_int_eq(RAND_bytes_ex(multi_libctx, &ch, 1, 64), 1)) | |
701 | goto err; | |
702 | ||
703 | msg.data = scratch; | |
704 | msg.data_len = sizeof(scratch); | |
705 | ||
706 | /* | |
707 | * We do not test for failure here as recvmmsg may fail if no sendmmsg | |
708 | * has been called yet. The purpose of this code is to exercise tsan. | |
709 | */ | |
710 | if (ch & 2) | |
711 | r = BIO_sendmmsg(ch & 1 ? multi_bio2 : multi_bio1, &msg, | |
712 | sizeof(BIO_MSG), 1, 0, &num_processed); | |
713 | else | |
714 | r = BIO_recvmmsg(ch & 1 ? multi_bio2 : multi_bio1, &msg, | |
715 | sizeof(BIO_MSG), 1, 0, &num_processed); | |
716 | ||
717 | ok = 1; | |
718 | err: | |
719 | if (ok == 0) | |
720 | multi_set_success(0); | |
721 | } | |
722 | ||
723 | static int test_bio_dgram_pair(void) | |
724 | { | |
725 | int r; | |
726 | BIO *bio1 = NULL, *bio2 = NULL; | |
727 | ||
728 | r = BIO_new_bio_dgram_pair(&bio1, 0, &bio2, 0); | |
729 | if (!TEST_int_eq(r, 1)) | |
730 | goto err; | |
731 | ||
732 | multi_bio1 = bio1; | |
733 | multi_bio2 = bio2; | |
734 | ||
735 | r = thread_run_test(&test_bio_dgram_pair_worker, | |
736 | MAXIMUM_THREADS, &test_bio_dgram_pair_worker, | |
737 | 1, default_provider); | |
738 | ||
739 | err: | |
740 | BIO_free(bio1); | |
741 | BIO_free(bio2); | |
742 | return r; | |
743 | } | |
744 | #endif | |
745 | ||
29f25a10 MC |
746 | static const char *pemdataraw[] = { |
747 | "-----BEGIN RSA PRIVATE KEY-----\n", | |
748 | "MIIBOgIBAAJBAMFcGsaxxdgiuuGmCkVImy4h99CqT7jwY3pexPGcnUFtR2Fh36Bp\n", | |
749 | "oncwtkZ4cAgtvd4Qs8PkxUdp6p/DlUmObdkCAwEAAQJAUR44xX6zB3eaeyvTRzms\n", | |
750 | "kHADrPCmPWnr8dxsNwiDGHzrMKLN+i/HAam+97HxIKVWNDH2ba9Mf1SA8xu9dcHZ\n", | |
751 | "AQIhAOHPCLxbtQFVxlnhSyxYeb7O323c3QulPNn3bhOipElpAiEA2zZpBE8ZXVnL\n", | |
752 | "74QjG4zINlDfH+EOEtjJJ3RtaYDugvECIBtsQDxXytChsRgDQ1TcXdStXPcDppie\n", | |
753 | "dZhm8yhRTTBZAiAZjE/U9rsIDC0ebxIAZfn3iplWh84yGB3pgUI3J5WkoQIhAInE\n", | |
754 | "HTUY5WRj5riZtkyGnbm3DvF+1eMtO2lYV+OuLcfE\n", | |
755 | "-----END RSA PRIVATE KEY-----\n", | |
756 | NULL | |
757 | }; | |
758 | ||
759 | static void test_pem_read_one(void) | |
760 | { | |
761 | EVP_PKEY *key = NULL; | |
762 | BIO *pem = NULL; | |
763 | char *pemdata; | |
764 | size_t len; | |
765 | ||
766 | pemdata = glue_strings(pemdataraw, &len); | |
767 | if (pemdata == NULL) { | |
768 | multi_set_success(0); | |
769 | goto err; | |
770 | } | |
771 | ||
772 | pem = BIO_new_mem_buf(pemdata, len); | |
773 | if (pem == NULL) { | |
774 | multi_set_success(0); | |
775 | goto err; | |
776 | } | |
777 | ||
778 | key = PEM_read_bio_PrivateKey(pem, NULL, NULL, NULL); | |
779 | if (key == NULL) | |
780 | multi_set_success(0); | |
781 | ||
782 | err: | |
783 | EVP_PKEY_free(key); | |
784 | BIO_free(pem); | |
785 | OPENSSL_free(pemdata); | |
786 | } | |
787 | ||
788 | /* Test reading PEM files in multiple threads */ | |
789 | static int test_pem_read(void) | |
790 | { | |
791 | return thread_run_test(&test_pem_read_one, MAXIMUM_THREADS, | |
792 | &test_pem_read_one, 1, default_provider); | |
793 | } | |
794 | ||
ae95a40e MC |
795 | typedef enum OPTION_choice { |
796 | OPT_ERR = -1, | |
797 | OPT_EOF = 0, | |
9a633a1c | 798 | OPT_FIPS, OPT_CONFIG_FILE, |
ae95a40e MC |
799 | OPT_TEST_ENUM |
800 | } OPTION_CHOICE; | |
801 | ||
802 | const OPTIONS *test_get_options(void) | |
803 | { | |
804 | static const OPTIONS options[] = { | |
805 | OPT_TEST_OPTIONS_DEFAULT_USAGE, | |
806 | { "fips", OPT_FIPS, '-', "Test the FIPS provider" }, | |
9a633a1c P |
807 | { "config", OPT_CONFIG_FILE, '<', |
808 | "The configuration file to use for the libctx" }, | |
ae95a40e MC |
809 | { NULL } |
810 | }; | |
811 | return options; | |
812 | } | |
813 | ||
ad887416 | 814 | int setup_tests(void) |
71a04cfc | 815 | { |
ae95a40e | 816 | OPTION_CHOICE o; |
a0134d29 | 817 | char *datadir; |
ae95a40e MC |
818 | |
819 | while ((o = opt_next()) != OPT_EOF) { | |
820 | switch (o) { | |
821 | case OPT_FIPS: | |
822 | do_fips = 1; | |
823 | break; | |
9a633a1c P |
824 | case OPT_CONFIG_FILE: |
825 | config_file = opt_arg(); | |
826 | break; | |
ae95a40e MC |
827 | case OPT_TEST_CASES: |
828 | break; | |
829 | default: | |
830 | return 0; | |
831 | } | |
832 | } | |
833 | ||
a0134d29 MC |
834 | if (!TEST_ptr(datadir = test_get_argument(0))) |
835 | return 0; | |
836 | ||
837 | privkey = test_mk_file_path(datadir, "rsakey.pem"); | |
838 | if (!TEST_ptr(privkey)) | |
839 | return 0; | |
840 | ||
b88ce46e HL |
841 | if (!TEST_ptr(global_lock = CRYPTO_THREAD_lock_new())) |
842 | return 0; | |
843 | ||
3d4d5305 P |
844 | #ifdef TSAN_REQUIRES_LOCKING |
845 | if (!TEST_ptr(tsan_lock = CRYPTO_THREAD_lock_new())) | |
846 | return 0; | |
847 | #endif | |
848 | ||
a135dea4 P |
849 | /* Keep first to validate auto creation of default library context */ |
850 | ADD_TEST(test_multi_default); | |
851 | ||
ee25dd45 P |
852 | ADD_TEST(test_lock); |
853 | ADD_TEST(test_once); | |
854 | ADD_TEST(test_thread_local); | |
ea08f8b2 | 855 | ADD_TEST(test_atomic); |
2f17e978 | 856 | ADD_TEST(test_multi_load); |
0855591e P |
857 | ADD_TEST(test_multi_general_worker_default_provider); |
858 | ADD_TEST(test_multi_general_worker_fips_provider); | |
859 | ADD_TEST(test_multi_fetch_worker); | |
860 | ADD_TEST(test_multi_shared_pkey); | |
861 | #ifndef OPENSSL_NO_DEPRECATED_3_0 | |
862 | ADD_TEST(test_multi_downgrade_shared_pkey); | |
863 | #endif | |
864 | ADD_TEST(test_multi_load_unload_provider); | |
865 | ADD_TEST(test_obj_add); | |
ef7a9b44 | 866 | ADD_TEST(test_lib_ctx_load_config); |
b88ce46e HL |
867 | #if !defined(OPENSSL_NO_DGRAM) && !defined(OPENSSL_NO_SOCK) |
868 | ADD_TEST(test_bio_dgram_pair); | |
869 | #endif | |
29f25a10 | 870 | ADD_TEST(test_pem_read); |
ad887416 | 871 | return 1; |
71a04cfc | 872 | } |
a0134d29 MC |
873 | |
874 | void cleanup_tests(void) | |
875 | { | |
876 | OPENSSL_free(privkey); | |
3d4d5305 P |
877 | #ifdef TSAN_REQUIRES_LOCKING |
878 | CRYPTO_THREAD_lock_free(tsan_lock); | |
879 | #endif | |
b88ce46e | 880 | CRYPTO_THREAD_lock_free(global_lock); |
a0134d29 | 881 | } |