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