xref: /freebsd/crypto/openssl/test/drbgtest.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 2011-2024 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 /* We need to use some deprecated APIs */
11 #define OPENSSL_SUPPRESS_DEPRECATED
12 
13 #include <string.h>
14 #include "internal/nelem.h"
15 #include <openssl/crypto.h>
16 #include <openssl/err.h>
17 #include <openssl/rand.h>
18 #include <openssl/obj_mac.h>
19 #include <openssl/evp.h>
20 #include <openssl/aes.h>
21 #include "../crypto/rand/rand_local.h"
22 #include "../include/crypto/rand.h"
23 #include "../include/crypto/evp.h"
24 #include "../providers/implementations/rands/drbg_local.h"
25 #include "../crypto/evp/evp_local.h"
26 
27 #if defined(_WIN32)
28 #include <windows.h>
29 #endif
30 
31 #if defined(OPENSSL_SYS_UNIX)
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #endif
36 
37 #include "testutil.h"
38 
39 /*
40  * DRBG generate wrappers
41  */
gen_bytes(EVP_RAND_CTX * drbg,unsigned char * buf,int num)42 static int gen_bytes(EVP_RAND_CTX *drbg, unsigned char *buf, int num)
43 {
44 #ifndef OPENSSL_NO_DEPRECATED_3_0
45     const RAND_METHOD *meth = RAND_get_rand_method();
46 
47     if (meth != NULL && meth != RAND_OpenSSL()) {
48         if (meth->bytes != NULL)
49             return meth->bytes(buf, num);
50         return -1;
51     }
52 #endif
53 
54     if (drbg != NULL)
55         return EVP_RAND_generate(drbg, buf, num, 0, 0, NULL, 0);
56     return 0;
57 }
58 
rand_bytes(unsigned char * buf,int num)59 static int rand_bytes(unsigned char *buf, int num)
60 {
61     return gen_bytes(RAND_get0_public(NULL), buf, num);
62 }
63 
rand_priv_bytes(unsigned char * buf,int num)64 static int rand_priv_bytes(unsigned char *buf, int num)
65 {
66     return gen_bytes(RAND_get0_private(NULL), buf, num);
67 }
68 
69 /* size of random output generated in test_drbg_reseed() */
70 #define RANDOM_SIZE 16
71 
72 /*
73  * DRBG query functions
74  */
state(EVP_RAND_CTX * drbg)75 static int state(EVP_RAND_CTX *drbg)
76 {
77     return EVP_RAND_get_state(drbg);
78 }
79 
query_rand_uint(EVP_RAND_CTX * drbg,const char * name)80 static unsigned int query_rand_uint(EVP_RAND_CTX *drbg, const char *name)
81 {
82     OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
83     unsigned int n;
84 
85     *params = OSSL_PARAM_construct_uint(name, &n);
86     if (EVP_RAND_CTX_get_params(drbg, params))
87         return n;
88     return 0;
89 }
90 
91 #define DRBG_UINT(name)                          \
92     static unsigned int name(EVP_RAND_CTX *drbg) \
93     {                                            \
94         return query_rand_uint(drbg, #name);     \
95     }
DRBG_UINT(reseed_counter)96 DRBG_UINT(reseed_counter)
97 
98 static PROV_DRBG *prov_rand(EVP_RAND_CTX *drbg)
99 {
100     return (PROV_DRBG *)drbg->algctx;
101 }
102 
set_reseed_counter(EVP_RAND_CTX * drbg,unsigned int n)103 static void set_reseed_counter(EVP_RAND_CTX *drbg, unsigned int n)
104 {
105     PROV_DRBG *p = prov_rand(drbg);
106 
107     p->reseed_counter = n;
108 }
109 
inc_reseed_counter(EVP_RAND_CTX * drbg)110 static void inc_reseed_counter(EVP_RAND_CTX *drbg)
111 {
112     set_reseed_counter(drbg, reseed_counter(drbg) + 1);
113 }
114 
reseed_time(EVP_RAND_CTX * drbg)115 static time_t reseed_time(EVP_RAND_CTX *drbg)
116 {
117     OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
118     time_t t;
119 
120     *params = OSSL_PARAM_construct_time_t(OSSL_DRBG_PARAM_RESEED_TIME, &t);
121     if (EVP_RAND_CTX_get_params(drbg, params))
122         return t;
123     return 0;
124 }
125 
126 /*
127  * When building the FIPS module, it isn't possible to disable the continuous
128  * RNG tests.  Tests that require this are skipped and this means a detection
129  * mechanism for the FIPS provider being in use.
130  */
using_fips_rng(void)131 static int using_fips_rng(void)
132 {
133     EVP_RAND_CTX *primary = RAND_get0_primary(NULL);
134     const OSSL_PROVIDER *prov;
135     const char *name;
136 
137     if (!TEST_ptr(primary))
138         return 0;
139 
140     prov = EVP_RAND_get0_provider(EVP_RAND_CTX_get0_rand(primary));
141     if (!TEST_ptr(prov))
142         return 0;
143     name = OSSL_PROVIDER_get0_name(prov);
144     return strstr(name, "FIPS Provider") != NULL;
145 }
146 
147 /*
148  * Disable CRNG testing if it is enabled.
149  * This stub remains to indicate the calling locations where it is necessary.
150  * Once the RNG infrastructure is able to disable these tests, it should be
151  * reconstituted.
152  */
disable_crngt(EVP_RAND_CTX * drbg)153 static int disable_crngt(EVP_RAND_CTX *drbg)
154 {
155     return 1;
156 }
157 
158 /*
159  * Generates random output using rand_bytes() and rand_priv_bytes()
160  * and checks whether the three shared DRBGs were reseeded as
161  * expected.
162  *
163  * |expect_success|: expected outcome (as reported by RAND_status())
164  * |primary|, |public|, |private|: pointers to the three shared DRBGs
165  * |public_random|, |private_random|: generated random output
166  * |expect_xxx_reseed| =
167  *       1:  it is expected that the specified DRBG is reseeded
168  *       0:  it is expected that the specified DRBG is not reseeded
169  *      -1:  don't check whether the specified DRBG was reseeded or not
170  * |reseed_when|: if nonzero, used instead of time(NULL) to set the
171  *                |before_reseed| time.
172  */
test_drbg_reseed(int expect_success,EVP_RAND_CTX * primary,EVP_RAND_CTX * public,EVP_RAND_CTX * private,unsigned char * public_random,unsigned char * private_random,int expect_primary_reseed,int expect_public_reseed,int expect_private_reseed,time_t reseed_when)173 static int test_drbg_reseed(int expect_success,
174     EVP_RAND_CTX *primary,
175     EVP_RAND_CTX *public,
176     EVP_RAND_CTX *private,
177     unsigned char *public_random,
178     unsigned char *private_random,
179     int expect_primary_reseed,
180     int expect_public_reseed,
181     int expect_private_reseed,
182     time_t reseed_when)
183 {
184     time_t before_reseed, after_reseed;
185     int expected_state = (expect_success ? DRBG_READY : DRBG_ERROR);
186     unsigned int primary_reseed, public_reseed, private_reseed;
187     unsigned char dummy[RANDOM_SIZE];
188 
189     if (public_random == NULL)
190         public_random = dummy;
191 
192     if (private_random == NULL)
193         private_random = dummy;
194 
195     /*
196      * step 1: check preconditions
197      */
198 
199     /* Test whether seed propagation is enabled */
200     if (!TEST_int_ne(primary_reseed = reseed_counter(primary), 0)
201         || !TEST_int_ne(public_reseed = reseed_counter(public), 0)
202         || !TEST_int_ne(private_reseed = reseed_counter(private), 0))
203         return 0;
204 
205     /*
206      * step 2: generate random output
207      */
208 
209     if (reseed_when == 0)
210         reseed_when = time(NULL);
211 
212     /* Generate random output from the public and private DRBG */
213     before_reseed = expect_primary_reseed == 1 ? reseed_when : 0;
214     if (!TEST_int_eq(rand_bytes((unsigned char *)public_random,
215                          RANDOM_SIZE),
216             expect_success)
217         || !TEST_int_eq(rand_priv_bytes((unsigned char *)private_random,
218                             RANDOM_SIZE),
219             expect_success))
220         return 0;
221     after_reseed = time(NULL);
222 
223     /*
224      * step 3: check postconditions
225      */
226 
227     /* Test whether reseeding succeeded as expected */
228     if (!TEST_int_eq(state(primary), expected_state)
229         || !TEST_int_eq(state(public), expected_state)
230         || !TEST_int_eq(state(private), expected_state))
231         return 0;
232 
233     if (expect_primary_reseed >= 0) {
234         /* Test whether primary DRBG was reseeded as expected */
235         if (!TEST_int_ge(reseed_counter(primary), primary_reseed))
236             return 0;
237     }
238 
239     if (expect_public_reseed >= 0) {
240         /* Test whether public DRBG was reseeded as expected */
241         if (!TEST_int_ge(reseed_counter(public), public_reseed)
242             || !TEST_uint_ge(reseed_counter(public),
243                 reseed_counter(primary)))
244             return 0;
245     }
246 
247     if (expect_private_reseed >= 0) {
248         /* Test whether public DRBG was reseeded as expected */
249         if (!TEST_int_ge(reseed_counter(private), private_reseed)
250             || !TEST_uint_ge(reseed_counter(private),
251                 reseed_counter(primary)))
252             return 0;
253     }
254 
255     if (expect_success == 1) {
256         /* Test whether reseed time of primary DRBG is set correctly */
257         if (!TEST_time_t_le(before_reseed, reseed_time(primary))
258             || !TEST_time_t_le(reseed_time(primary), after_reseed))
259             return 0;
260 
261         /* Test whether reseed times of child DRBGs are synchronized with primary */
262         if (!TEST_time_t_ge(reseed_time(public), reseed_time(primary))
263             || !TEST_time_t_ge(reseed_time(private), reseed_time(primary)))
264             return 0;
265     } else {
266         ERR_clear_error();
267     }
268 
269     return 1;
270 }
271 
272 #if defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_RAND_SEED_EGD)
273 /* number of children to fork */
274 #define DRBG_FORK_COUNT 9
275 /* two results per child, two for the parent */
276 #define DRBG_FORK_RESULT_COUNT (2 * (DRBG_FORK_COUNT + 1))
277 
278 typedef struct drbg_fork_result_st {
279 
280     unsigned char random[RANDOM_SIZE]; /* random output */
281 
282     int pindex; /* process index (0: parent, 1,2,3...: children)*/
283     pid_t pid; /* process id */
284     int private; /* true if the private drbg was used */
285     char name[10]; /* 'parent' resp. 'child 1', 'child 2', ... */
286 } drbg_fork_result;
287 
288 /*
289  * Sort the drbg_fork_result entries in lexicographical order
290  *
291  * This simplifies finding duplicate random output and makes
292  * the printout in case of an error more readable.
293  */
compare_drbg_fork_result(const void * left,const void * right)294 static int compare_drbg_fork_result(const void *left, const void *right)
295 {
296     int result;
297     const drbg_fork_result *l = left;
298     const drbg_fork_result *r = right;
299 
300     /* separate public and private results */
301     result = l->private - r->private;
302 
303     if (result == 0)
304         result = memcmp(l->random, r->random, RANDOM_SIZE);
305 
306     if (result == 0)
307         result = l->pindex - r->pindex;
308 
309     return result;
310 }
311 
312 /*
313  * Sort two-byte chunks of random data
314  *
315  * Used for finding collisions in two-byte chunks
316  */
compare_rand_chunk(const void * left,const void * right)317 static int compare_rand_chunk(const void *left, const void *right)
318 {
319     return memcmp(left, right, 2);
320 }
321 
322 /*
323  * Test whether primary, public and private DRBG are reseeded
324  * in the child after forking the process. Collect the random
325  * output of the public and private DRBG and send it back to
326  * the parent process.
327  */
test_drbg_reseed_in_child(EVP_RAND_CTX * primary,EVP_RAND_CTX * public,EVP_RAND_CTX * private,drbg_fork_result result[2])328 static int test_drbg_reseed_in_child(EVP_RAND_CTX *primary,
329     EVP_RAND_CTX *public,
330     EVP_RAND_CTX *private,
331     drbg_fork_result result[2])
332 {
333     int rv = 0, status;
334     int fd[2];
335     pid_t pid;
336     unsigned char random[2 * RANDOM_SIZE];
337 
338     if (!TEST_int_ge(pipe(fd), 0))
339         return 0;
340 
341     if (!TEST_int_ge(pid = fork(), 0)) {
342         close(fd[0]);
343         close(fd[1]);
344         return 0;
345     } else if (pid > 0) {
346 
347         /* I'm the parent; close the write end */
348         close(fd[1]);
349 
350         /* wait for children to terminate and collect their random output */
351         if (TEST_int_eq(waitpid(pid, &status, 0), pid)
352             && TEST_int_eq(status, 0)
353             && TEST_true(read(fd[0], &random[0], sizeof(random))
354                 == sizeof(random))) {
355 
356             /* random output of public drbg */
357             result[0].pid = pid;
358             result[0].private = 0;
359             memcpy(result[0].random, &random[0], RANDOM_SIZE);
360 
361             /* random output of private drbg */
362             result[1].pid = pid;
363             result[1].private = 1;
364             memcpy(result[1].random, &random[RANDOM_SIZE], RANDOM_SIZE);
365 
366             rv = 1;
367         }
368 
369         /* close the read end */
370         close(fd[0]);
371 
372         return rv;
373 
374     } else {
375 
376         /* I'm the child; close the read end */
377         close(fd[0]);
378 
379         /* check whether all three DRBGs reseed and send output to parent */
380         if (TEST_true(test_drbg_reseed(1, primary, public, private,
381                 &random[0], &random[RANDOM_SIZE],
382                 1, 1, 1, 0))
383             && TEST_true(write(fd[1], random, sizeof(random))
384                 == sizeof(random))) {
385 
386             rv = 1;
387         }
388 
389         /* close the write end */
390         close(fd[1]);
391 
392         /* convert boolean to exit code */
393         exit(rv == 0);
394     }
395 }
396 
test_rand_reseed_on_fork(EVP_RAND_CTX * primary,EVP_RAND_CTX * public,EVP_RAND_CTX * private)397 static int test_rand_reseed_on_fork(EVP_RAND_CTX *primary,
398     EVP_RAND_CTX *public,
399     EVP_RAND_CTX *private)
400 {
401     unsigned int i;
402     pid_t pid = getpid();
403     int verbose = (getenv("V") != NULL);
404     int success = 1;
405     int duplicate[2] = { 0, 0 };
406     unsigned char random[2 * RANDOM_SIZE];
407     unsigned char sample[DRBG_FORK_RESULT_COUNT * RANDOM_SIZE];
408     unsigned char *psample = &sample[0];
409     drbg_fork_result result[DRBG_FORK_RESULT_COUNT];
410     drbg_fork_result *presult = &result[2];
411 
412     memset(&result, 0, sizeof(result));
413 
414     for (i = 1; i <= DRBG_FORK_COUNT; ++i) {
415 
416         presult[0].pindex = presult[1].pindex = i;
417 
418         BIO_snprintf(presult[0].name, sizeof(presult[0].name), "child %d", i);
419         strcpy(presult[1].name, presult[0].name);
420 
421         /* collect the random output of the children */
422         if (!TEST_true(test_drbg_reseed_in_child(primary,
423                 public,
424                 private,
425                 presult)))
426             return 0;
427 
428         presult += 2;
429     }
430 
431     /* collect the random output of the parent */
432     if (!TEST_true(test_drbg_reseed(1,
433             primary, public, private,
434             &random[0], &random[RANDOM_SIZE],
435             0, 0, 0, 0)))
436         return 0;
437 
438     strcpy(result[0].name, "parent");
439     strcpy(result[1].name, "parent");
440 
441     /* output of public drbg */
442     result[0].pid = pid;
443     result[0].private = 0;
444     memcpy(result[0].random, &random[0], RANDOM_SIZE);
445 
446     /* output of private drbg */
447     result[1].pid = pid;
448     result[1].private = 1;
449     memcpy(result[1].random, &random[RANDOM_SIZE], RANDOM_SIZE);
450 
451     /* collect all sampled random data in a single buffer */
452     for (i = 0; i < DRBG_FORK_RESULT_COUNT; ++i) {
453         memcpy(psample, &result[i].random[0], RANDOM_SIZE);
454         psample += RANDOM_SIZE;
455     }
456 
457     /* sort the results... */
458     qsort(result, DRBG_FORK_RESULT_COUNT, sizeof(drbg_fork_result),
459         compare_drbg_fork_result);
460 
461     /* ...and count duplicate prefixes by looking at the first byte only */
462     for (i = 1; i < DRBG_FORK_RESULT_COUNT; ++i) {
463         if (result[i].random[0] == result[i - 1].random[0]) {
464             /* count public and private duplicates separately */
465             ++duplicate[result[i].private];
466         }
467     }
468 
469     if (duplicate[0] >= DRBG_FORK_COUNT - 1) {
470         /* just too many duplicates to be a coincidence */
471         TEST_note("ERROR: %d duplicate prefixes in public random output", duplicate[0]);
472         success = 0;
473     }
474 
475     if (duplicate[1] >= DRBG_FORK_COUNT - 1) {
476         /* just too many duplicates to be a coincidence */
477         TEST_note("ERROR: %d duplicate prefixes in private random output", duplicate[1]);
478         success = 0;
479     }
480 
481     duplicate[0] = 0;
482 
483     /* sort the two-byte chunks... */
484     qsort(sample, sizeof(sample) / 2, 2, compare_rand_chunk);
485 
486     /* ...and count duplicate chunks */
487     for (i = 2, psample = sample + 2; i < sizeof(sample); i += 2, psample += 2) {
488         if (compare_rand_chunk(psample - 2, psample) == 0)
489             ++duplicate[0];
490     }
491 
492     if (duplicate[0] >= DRBG_FORK_COUNT - 1) {
493         /* just too many duplicates to be a coincidence */
494         TEST_note("ERROR: %d duplicate chunks in random output", duplicate[0]);
495         success = 0;
496     }
497 
498     if (verbose || !success) {
499 
500         for (i = 0; i < DRBG_FORK_RESULT_COUNT; ++i) {
501             char *rand_hex = OPENSSL_buf2hexstr(result[i].random, RANDOM_SIZE);
502 
503             TEST_note("    random: %s, pid: %d (%s, %s)",
504                 rand_hex,
505                 result[i].pid,
506                 result[i].name,
507                 result[i].private ? "private" : "public");
508 
509             OPENSSL_free(rand_hex);
510         }
511     }
512 
513     return success;
514 }
515 
test_rand_fork_safety(int i)516 static int test_rand_fork_safety(int i)
517 {
518     int success = 1;
519     unsigned char random[1];
520     EVP_RAND_CTX *primary, *public, *private;
521 
522     /* All three DRBGs should be non-null */
523     if (!TEST_ptr(primary = RAND_get0_primary(NULL))
524         || !TEST_ptr(public = RAND_get0_public(NULL))
525         || !TEST_ptr(private = RAND_get0_private(NULL)))
526         return 0;
527 
528     /* run the actual test */
529     if (!TEST_true(test_rand_reseed_on_fork(primary, public, private)))
530         success = 0;
531 
532     /* request a single byte from each of the DRBGs before the next run */
533     if (!TEST_int_gt(RAND_bytes(random, 1), 0) || !TEST_int_gt(RAND_priv_bytes(random, 1), 0))
534         success = 0;
535 
536     return success;
537 }
538 #endif
539 
540 /*
541  * Test whether the default rand_method (RAND_OpenSSL()) is
542  * setup correctly, in particular whether reseeding works
543  * as designed.
544  */
test_rand_reseed(void)545 static int test_rand_reseed(void)
546 {
547     EVP_RAND_CTX *primary, *public, *private;
548     unsigned char rand_add_buf[256];
549     int rv = 0;
550     time_t before_reseed;
551 
552     if (using_fips_rng())
553         return TEST_skip("CRNGT cannot be disabled");
554 
555 #ifndef OPENSSL_NO_DEPRECATED_3_0
556     /* Check whether RAND_OpenSSL() is the default method */
557     if (!TEST_ptr_eq(RAND_get_rand_method(), RAND_OpenSSL()))
558         return 0;
559 #endif
560 
561     /* All three DRBGs should be non-null */
562     if (!TEST_ptr(primary = RAND_get0_primary(NULL))
563         || !TEST_ptr(public = RAND_get0_public(NULL))
564         || !TEST_ptr(private = RAND_get0_private(NULL)))
565         return 0;
566 
567     /* There should be three distinct DRBGs, two of them chained to primary */
568     if (!TEST_ptr_ne(public, private)
569         || !TEST_ptr_ne(public, primary)
570         || !TEST_ptr_ne(private, primary)
571         || !TEST_ptr_eq(prov_rand(public)->parent, prov_rand(primary))
572         || !TEST_ptr_eq(prov_rand(private)->parent, prov_rand(primary)))
573         return 0;
574 
575     /* Disable CRNG testing for the primary DRBG */
576     if (!TEST_true(disable_crngt(primary)))
577         return 0;
578 
579     /* uninstantiate the three global DRBGs */
580     EVP_RAND_uninstantiate(primary);
581     EVP_RAND_uninstantiate(private);
582     EVP_RAND_uninstantiate(public);
583 
584     /*
585      * Test initial seeding of shared DRBGs
586      */
587     if (!TEST_true(test_drbg_reseed(1,
588             primary, public, private,
589             NULL, NULL,
590             1, 1, 1, 0)))
591         goto error;
592 
593     /*
594      * Test initial state of shared DRBGs
595      */
596     if (!TEST_true(test_drbg_reseed(1,
597             primary, public, private,
598             NULL, NULL,
599             0, 0, 0, 0)))
600         goto error;
601 
602     /*
603      * Test whether the public and private DRBG are both reseeded when their
604      * reseed counters differ from the primary's reseed counter.
605      */
606     inc_reseed_counter(primary);
607     if (!TEST_true(test_drbg_reseed(1,
608             primary, public, private,
609             NULL, NULL,
610             0, 1, 1, 0)))
611         goto error;
612 
613     /*
614      * Test whether the public DRBG is reseeded when its reseed counter differs
615      * from the primary's reseed counter.
616      */
617     inc_reseed_counter(primary);
618     inc_reseed_counter(private);
619     if (!TEST_true(test_drbg_reseed(1,
620             primary, public, private,
621             NULL, NULL,
622             0, 1, 0, 0)))
623         goto error;
624 
625     /*
626      * Test whether the private DRBG is reseeded when its reseed counter differs
627      * from the primary's reseed counter.
628      */
629     inc_reseed_counter(primary);
630     inc_reseed_counter(public);
631     if (!TEST_true(test_drbg_reseed(1,
632             primary, public, private,
633             NULL, NULL,
634             0, 0, 1, 0)))
635         goto error;
636 
637     /* fill 'randomness' buffer with some arbitrary data */
638     memset(rand_add_buf, 'r', sizeof(rand_add_buf));
639 
640     /*
641      * Test whether all three DRBGs are reseeded by RAND_add().
642      * The before_reseed time has to be measured here and passed into the
643      * test_drbg_reseed() test, because the primary DRBG gets already reseeded
644      * in RAND_add(), whence the check for the condition
645      * before_reseed <= reseed_time(primary) will fail if the time value happens
646      * to increase between the RAND_add() and the test_drbg_reseed() call.
647      */
648     before_reseed = time(NULL);
649     RAND_add(rand_add_buf, sizeof(rand_add_buf), sizeof(rand_add_buf));
650     if (!TEST_true(test_drbg_reseed(1,
651             primary, public, private,
652             NULL, NULL,
653             1, 1, 1,
654             before_reseed)))
655         goto error;
656 
657     rv = 1;
658 
659 error:
660     return rv;
661 }
662 
663 #if defined(OPENSSL_THREADS)
664 static int multi_thread_rand_bytes_succeeded = 1;
665 static int multi_thread_rand_priv_bytes_succeeded = 1;
666 
set_reseed_time_interval(EVP_RAND_CTX * drbg,int t)667 static int set_reseed_time_interval(EVP_RAND_CTX *drbg, int t)
668 {
669     OSSL_PARAM params[2];
670 
671     params[0] = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL,
672         &t);
673     params[1] = OSSL_PARAM_construct_end();
674     return EVP_RAND_CTX_set_params(drbg, params);
675 }
676 
run_multi_thread_test(void)677 static void run_multi_thread_test(void)
678 {
679     unsigned char buf[256];
680     time_t start = time(NULL);
681     EVP_RAND_CTX *public = NULL, *private = NULL;
682 
683     if (!TEST_ptr(public = RAND_get0_public(NULL))
684         || !TEST_ptr(private = RAND_get0_private(NULL))
685         || !TEST_true(set_reseed_time_interval(private, 1))
686         || !TEST_true(set_reseed_time_interval(public, 1))) {
687         multi_thread_rand_bytes_succeeded = 0;
688         return;
689     }
690 
691     do {
692         if (rand_bytes(buf, sizeof(buf)) <= 0)
693             multi_thread_rand_bytes_succeeded = 0;
694         if (rand_priv_bytes(buf, sizeof(buf)) <= 0)
695             multi_thread_rand_priv_bytes_succeeded = 0;
696     } while (time(NULL) - start < 5);
697 }
698 
699 #if defined(OPENSSL_SYS_WINDOWS)
700 
701 typedef HANDLE thread_t;
702 
thread_run(LPVOID arg)703 static DWORD WINAPI thread_run(LPVOID arg)
704 {
705     run_multi_thread_test();
706     /*
707      * Because we're linking with a static library, we must stop each
708      * thread explicitly, or so says OPENSSL_thread_stop(3)
709      */
710     OPENSSL_thread_stop();
711     return 0;
712 }
713 
run_thread(thread_t * t)714 static int run_thread(thread_t *t)
715 {
716     *t = CreateThread(NULL, 0, thread_run, NULL, 0, NULL);
717     return *t != NULL;
718 }
719 
wait_for_thread(thread_t thread)720 static int wait_for_thread(thread_t thread)
721 {
722     return WaitForSingleObject(thread, INFINITE) == 0;
723 }
724 
725 #else
726 
727 typedef pthread_t thread_t;
728 
thread_run(void * arg)729 static void *thread_run(void *arg)
730 {
731     run_multi_thread_test();
732     /*
733      * Because we're linking with a static library, we must stop each
734      * thread explicitly, or so says OPENSSL_thread_stop(3)
735      */
736     OPENSSL_thread_stop();
737     return NULL;
738 }
739 
run_thread(thread_t * t)740 static int run_thread(thread_t *t)
741 {
742     return pthread_create(t, NULL, thread_run, NULL) == 0;
743 }
744 
wait_for_thread(thread_t thread)745 static int wait_for_thread(thread_t thread)
746 {
747     return pthread_join(thread, NULL) == 0;
748 }
749 
750 #endif
751 
752 /*
753  * The main thread will also run the test, so we'll have THREADS+1 parallel
754  * tests running
755  */
756 #define THREADS 3
757 
test_multi_thread(void)758 static int test_multi_thread(void)
759 {
760     thread_t t[THREADS];
761     int i;
762 
763     for (i = 0; i < THREADS; i++)
764         run_thread(&t[i]);
765     run_multi_thread_test();
766     for (i = 0; i < THREADS; i++)
767         wait_for_thread(t[i]);
768 
769     if (!TEST_true(multi_thread_rand_bytes_succeeded))
770         return 0;
771     if (!TEST_true(multi_thread_rand_priv_bytes_succeeded))
772         return 0;
773 
774     return 1;
775 }
776 #endif
777 
new_drbg(EVP_RAND_CTX * parent)778 static EVP_RAND_CTX *new_drbg(EVP_RAND_CTX *parent)
779 {
780     OSSL_PARAM params[2];
781     EVP_RAND *rand = NULL;
782     EVP_RAND_CTX *drbg = NULL;
783 
784     params[0] = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER,
785         "AES-256-CTR", 0);
786     params[1] = OSSL_PARAM_construct_end();
787 
788     if (!TEST_ptr(rand = EVP_RAND_fetch(NULL, "CTR-DRBG", NULL))
789         || !TEST_ptr(drbg = EVP_RAND_CTX_new(rand, parent))
790         || !TEST_true(EVP_RAND_CTX_set_params(drbg, params))) {
791         EVP_RAND_CTX_free(drbg);
792         drbg = NULL;
793     }
794     EVP_RAND_free(rand);
795     return drbg;
796 }
797 
test_rand_prediction_resistance(void)798 static int test_rand_prediction_resistance(void)
799 {
800     EVP_RAND_CTX *x = NULL, *y = NULL, *z = NULL;
801     unsigned char buf1[51], buf2[sizeof(buf1)];
802     int ret = 0, xreseed, yreseed, zreseed;
803 
804     if (using_fips_rng())
805         return TEST_skip("CRNGT cannot be disabled");
806 
807     /* Initialise a three long DRBG chain */
808     if (!TEST_ptr(x = new_drbg(NULL))
809         || !TEST_true(disable_crngt(x))
810         || !TEST_true(EVP_RAND_instantiate(x, 0, 0, NULL, 0, NULL))
811         || !TEST_ptr(y = new_drbg(x))
812         || !TEST_true(EVP_RAND_instantiate(y, 0, 0, NULL, 0, NULL))
813         || !TEST_ptr(z = new_drbg(y))
814         || !TEST_true(EVP_RAND_instantiate(z, 0, 0, NULL, 0, NULL)))
815         goto err;
816 
817     /*
818      * During a normal reseed, only the last DRBG in the chain should
819      * be reseeded.
820      */
821     inc_reseed_counter(y);
822     xreseed = reseed_counter(x);
823     yreseed = reseed_counter(y);
824     zreseed = reseed_counter(z);
825     if (!TEST_true(EVP_RAND_reseed(z, 0, NULL, 0, NULL, 0))
826         || !TEST_int_eq(reseed_counter(x), xreseed)
827         || !TEST_int_eq(reseed_counter(y), yreseed)
828         || !TEST_int_gt(reseed_counter(z), zreseed))
829         goto err;
830 
831     /*
832      * When prediction resistance is requested, the request should be
833      * propagated to the primary, so that the entire DRBG chain reseeds.
834      */
835     zreseed = reseed_counter(z);
836     if (!TEST_true(EVP_RAND_reseed(z, 1, NULL, 0, NULL, 0))
837         || !TEST_int_gt(reseed_counter(x), xreseed)
838         || !TEST_int_gt(reseed_counter(y), yreseed)
839         || !TEST_int_gt(reseed_counter(z), zreseed))
840         goto err;
841 
842     /*
843      * During a normal generate, only the last DRBG should be reseed */
844     inc_reseed_counter(y);
845     xreseed = reseed_counter(x);
846     yreseed = reseed_counter(y);
847     zreseed = reseed_counter(z);
848     if (!TEST_true(EVP_RAND_generate(z, buf1, sizeof(buf1), 0, 0, NULL, 0))
849         || !TEST_int_eq(reseed_counter(x), xreseed)
850         || !TEST_int_eq(reseed_counter(y), yreseed)
851         || !TEST_int_gt(reseed_counter(z), zreseed))
852         goto err;
853 
854     /*
855      * When a prediction resistant generate is requested, the request
856      * should be propagated to the primary, reseeding the entire DRBG chain.
857      */
858     zreseed = reseed_counter(z);
859     if (!TEST_true(EVP_RAND_generate(z, buf2, sizeof(buf2), 0, 1, NULL, 0))
860         || !TEST_int_gt(reseed_counter(x), xreseed)
861         || !TEST_int_gt(reseed_counter(y), yreseed)
862         || !TEST_int_gt(reseed_counter(z), zreseed)
863         || !TEST_mem_ne(buf1, sizeof(buf1), buf2, sizeof(buf2)))
864         goto err;
865 
866     /* Verify that a normal reseed still only reseeds the last DRBG */
867     inc_reseed_counter(y);
868     xreseed = reseed_counter(x);
869     yreseed = reseed_counter(y);
870     zreseed = reseed_counter(z);
871     if (!TEST_true(EVP_RAND_reseed(z, 0, NULL, 0, NULL, 0))
872         || !TEST_int_eq(reseed_counter(x), xreseed)
873         || !TEST_int_eq(reseed_counter(y), yreseed)
874         || !TEST_int_gt(reseed_counter(z), zreseed))
875         goto err;
876 
877     ret = 1;
878 err:
879     EVP_RAND_CTX_free(z);
880     EVP_RAND_CTX_free(y);
881     EVP_RAND_CTX_free(x);
882     return ret;
883 }
884 
setup_tests(void)885 int setup_tests(void)
886 {
887     ADD_TEST(test_rand_reseed);
888 #if defined(OPENSSL_SYS_UNIX) && !defined(OPENSSL_RAND_SEED_EGD)
889     ADD_ALL_TESTS(test_rand_fork_safety, RANDOM_SIZE);
890 #endif
891     ADD_TEST(test_rand_prediction_resistance);
892 #if defined(OPENSSL_THREADS)
893     ADD_TEST(test_multi_thread);
894 #endif
895     return 1;
896 }
897