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