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