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 | */
|
---|
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 |
|
---|
65 | static int rand_bytes(unsigned char *buf, int num)
|
---|
66 | {
|
---|
67 | return gen_bytes(RAND_get0_public(NULL), buf, num);
|
---|
68 | }
|
---|
69 |
|
---|
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 | */
|
---|
82 | static int state(EVP_RAND_CTX *drbg)
|
---|
83 | {
|
---|
84 | return EVP_RAND_get_state(drbg);
|
---|
85 | }
|
---|
86 |
|
---|
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 | }
|
---|
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 |
|
---|
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 |
|
---|
117 | static void inc_reseed_counter(EVP_RAND_CTX *drbg)
|
---|
118 | {
|
---|
119 | set_reseed_counter(drbg, reseed_counter(drbg) + 1);
|
---|
120 | }
|
---|
121 |
|
---|
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 | */
|
---|
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 | */
|
---|
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 | */
|
---|
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 | */
|
---|
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 | */
|
---|
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 | */
|
---|
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 |
|
---|
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 |
|
---|
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 | */
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
750 | static int run_thread(thread_t *t)
|
---|
751 | {
|
---|
752 | return pthread_create(t, NULL, thread_run, NULL) == 0;
|
---|
753 | }
|
---|
754 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 |
|
---|
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 | }
|
---|