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