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