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