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