]>
Commit | Line | Data |
---|---|---|
12fb8c3d | 1 | /* |
33388b44 | 2 | * Copyright 2011-2020 The OpenSSL Project Authors. All Rights Reserved. |
12fb8c3d | 3 | * |
909f1a2e | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
12fb8c3d RS |
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 | ||
3f078163 P |
10 | /* |
11 | * RAND_DRBG_set is deprecated for public use, but still ok for | |
12 | * internal use. | |
13 | */ | |
14 | #include "internal/deprecated.h" | |
15 | ||
12fb8c3d | 16 | #include <string.h> |
176db6dc | 17 | #include "internal/nelem.h" |
12fb8c3d RS |
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> | |
706457b7 | 24 | #include "../crypto/rand/rand_local.h" |
25f2138b | 25 | #include "../include/crypto/rand.h" |
924663c3 | 26 | #include "../include/crypto/evp.h" |
3f078163 P |
27 | #include "../providers/implementations/rands/drbg_local.h" |
28 | #include "../crypto/evp/evp_local.h" | |
12fb8c3d | 29 | |
440bce8f KR |
30 | #if defined(_WIN32) |
31 | # include <windows.h> | |
32 | #endif | |
33 | ||
08073700 RB |
34 | #if defined(__TANDEM) |
35 | # if defined(OPENSSL_TANDEM_FLOSS) | |
36 | # include <floss.h(floss_fork)> | |
37 | # endif | |
38 | #endif | |
84952925 DMSP |
39 | |
40 | #if defined(OPENSSL_SYS_UNIX) | |
41 | # include <sys/types.h> | |
42 | # include <sys/wait.h> | |
43 | # include <unistd.h> | |
44 | #endif | |
45 | ||
12fb8c3d RS |
46 | #include "testutil.h" |
47 | #include "drbgtest.h" | |
48 | ||
7d615e21 P |
49 | /* |
50 | * DRBG generate wrappers | |
51 | */ | |
52 | static int gen_bytes(EVP_RAND_CTX *drbg, unsigned char *buf, int num) | |
53 | { | |
54 | const RAND_METHOD *meth = RAND_get_rand_method(); | |
12fb8c3d | 55 | |
7d615e21 P |
56 | if (meth != NULL && meth != RAND_OpenSSL()) { |
57 | if (meth->bytes != NULL) | |
58 | return meth->bytes(buf, num); | |
59 | return -1; | |
60 | } | |
8164d91d | 61 | |
7d615e21 P |
62 | if (drbg != NULL) |
63 | return EVP_RAND_generate(drbg, buf, num, 0, 0, NULL, 0); | |
64 | return 0; | |
65 | } | |
12fb8c3d | 66 | |
7d615e21 P |
67 | static int rand_bytes(unsigned char *buf, int num) |
68 | { | |
69 | return gen_bytes(RAND_get0_public(NULL), buf, num); | |
70 | } | |
8bf36651 | 71 | |
7d615e21 P |
72 | static int rand_priv_bytes(unsigned char *buf, int num) |
73 | { | |
74 | return gen_bytes(RAND_get0_private(NULL), buf, num); | |
75 | } | |
12fb8c3d | 76 | |
09e76c5d DMSP |
77 | |
78 | /* size of random output generated in test_drbg_reseed() */ | |
79 | #define RANDOM_SIZE 16 | |
80 | ||
3f078163 P |
81 | /* |
82 | * DRBG query functions | |
83 | */ | |
7d615e21 | 84 | static int state(EVP_RAND_CTX *drbg) |
3f078163 | 85 | { |
7d615e21 | 86 | return EVP_RAND_state(drbg); |
3f078163 P |
87 | } |
88 | ||
7d615e21 | 89 | static unsigned int query_rand_uint(EVP_RAND_CTX *drbg, const char *name) |
3f078163 P |
90 | { |
91 | OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
92 | unsigned int n; | |
93 | ||
94 | *params = OSSL_PARAM_construct_uint(name, &n); | |
7d615e21 | 95 | if (EVP_RAND_get_ctx_params(drbg, params)) |
3f078163 P |
96 | return n; |
97 | return 0; | |
98 | } | |
99 | ||
3f078163 | 100 | #define DRBG_UINT(name) \ |
7d615e21 | 101 | static unsigned int name(EVP_RAND_CTX *drbg) \ |
3f078163 P |
102 | { \ |
103 | return query_rand_uint(drbg, #name); \ | |
104 | } | |
3f078163 P |
105 | DRBG_UINT(reseed_counter) |
106 | ||
7d615e21 | 107 | static PROV_DRBG *prov_rand(EVP_RAND_CTX *drbg) |
d1768e82 | 108 | { |
7d615e21 | 109 | return (PROV_DRBG *)drbg->data; |
d1768e82 DMSP |
110 | } |
111 | ||
7d615e21 | 112 | static void set_reseed_counter(EVP_RAND_CTX *drbg, unsigned int n) |
3f078163 P |
113 | { |
114 | PROV_DRBG *p = prov_rand(drbg); | |
115 | ||
116 | p->reseed_counter = n; | |
117 | } | |
118 | ||
7d615e21 | 119 | static void inc_reseed_counter(EVP_RAND_CTX *drbg) |
3f078163 P |
120 | { |
121 | set_reseed_counter(drbg, reseed_counter(drbg) + 1); | |
122 | } | |
123 | ||
7d615e21 | 124 | static time_t reseed_time(EVP_RAND_CTX *drbg) |
3f078163 P |
125 | { |
126 | OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END }; | |
127 | time_t t; | |
128 | ||
129 | *params = OSSL_PARAM_construct_time_t(OSSL_DRBG_PARAM_RESEED_TIME, &t); | |
7d615e21 | 130 | if (EVP_RAND_get_ctx_params(drbg, params)) |
3f078163 P |
131 | return t; |
132 | return 0; | |
133 | } | |
134 | ||
3f078163 P |
135 | /* |
136 | * When building the FIPS module, it isn't possible to disable the continuous | |
137 | * RNG tests. Tests that require this are skipped. | |
138 | */ | |
139 | static int crngt_skip(void) | |
140 | { | |
141 | #ifdef FIPS_MODULE | |
142 | return 1; | |
143 | #else | |
144 | return 0; | |
145 | #endif | |
146 | } | |
147 | ||
d69226a3 P |
148 | /* |
149 | * Disable CRNG testing if it is enabled. | |
3f078163 P |
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. | |
d69226a3 | 153 | */ |
7d615e21 | 154 | static int disable_crngt(EVP_RAND_CTX *drbg) |
12fb8c3d | 155 | { |
12fb8c3d RS |
156 | return 1; |
157 | } | |
158 | ||
159 | /* | |
7d615e21 | 160 | * Generates random output using rand_bytes() and rand_priv_bytes() |
a93ba405 DMSP |
161 | * and checks whether the three shared DRBGs were reseeded as |
162 | * expected. | |
163 | * | |
164 | * |expect_success|: expected outcome (as reported by RAND_status()) | |
ce3080e9 | 165 | * |primary|, |public|, |private|: pointers to the three shared DRBGs |
09e76c5d | 166 | * |public_random|, |private_random|: generated random output |
a93ba405 DMSP |
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 | |
09e76c5d | 171 | * |reseed_when|: if nonzero, used instead of time(NULL) to set the |
2bb1b5dd | 172 | * |before_reseed| time. |
a93ba405 DMSP |
173 | */ |
174 | static int test_drbg_reseed(int expect_success, | |
7d615e21 P |
175 | EVP_RAND_CTX *primary, |
176 | EVP_RAND_CTX *public, | |
177 | EVP_RAND_CTX *private, | |
09e76c5d DMSP |
178 | unsigned char *public_random, |
179 | unsigned char *private_random, | |
ce3080e9 | 180 | int expect_primary_reseed, |
a93ba405 | 181 | int expect_public_reseed, |
2bb1b5dd | 182 | int expect_private_reseed, |
3f078163 | 183 | time_t reseed_when |
a93ba405 DMSP |
184 | ) |
185 | { | |
08a65d96 | 186 | time_t before_reseed, after_reseed; |
a93ba405 | 187 | int expected_state = (expect_success ? DRBG_READY : DRBG_ERROR); |
ce3080e9 | 188 | unsigned int primary_reseed, public_reseed, private_reseed; |
09e76c5d DMSP |
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; | |
a93ba405 DMSP |
196 | |
197 | /* | |
198 | * step 1: check preconditions | |
199 | */ | |
200 | ||
201 | /* Test whether seed propagation is enabled */ | |
ce3080e9 | 202 | if (!TEST_int_ne(primary_reseed = reseed_counter(primary), 0) |
3f078163 P |
203 | || !TEST_int_ne(public_reseed = reseed_counter(public), 0) |
204 | || !TEST_int_ne(private_reseed = reseed_counter(private), 0)) | |
a93ba405 DMSP |
205 | return 0; |
206 | ||
207 | /* | |
208 | * step 2: generate random output | |
209 | */ | |
210 | ||
3f078163 P |
211 | if (reseed_when == 0) |
212 | reseed_when = time(NULL); | |
2bb1b5dd | 213 | |
a93ba405 | 214 | /* Generate random output from the public and private DRBG */ |
ce3080e9 | 215 | before_reseed = expect_primary_reseed == 1 ? reseed_when : 0; |
09e76c5d DMSP |
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)) | |
a93ba405 | 220 | return 0; |
08a65d96 | 221 | after_reseed = time(NULL); |
a93ba405 DMSP |
222 | |
223 | ||
224 | /* | |
225 | * step 3: check postconditions | |
226 | */ | |
75e2c877 | 227 | |
a93ba405 | 228 | /* Test whether reseeding succeeded as expected */ |
7d615e21 P |
229 | if (!TEST_int_eq(state(primary), expected_state) |
230 | || !TEST_int_eq(state(public), expected_state) | |
3f078163 | 231 | || !TEST_int_eq(state(private), expected_state)) |
75e2c877 | 232 | return 0; |
a93ba405 | 233 | |
ce3080e9 P |
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)) | |
a93ba405 DMSP |
237 | return 0; |
238 | } | |
239 | ||
240 | if (expect_public_reseed >= 0) { | |
241 | /* Test whether public DRBG was reseeded as expected */ | |
3f078163 P |
242 | if (!TEST_int_ge(reseed_counter(public), public_reseed) |
243 | || !TEST_uint_ge(reseed_counter(public), | |
ce3080e9 | 244 | reseed_counter(primary))) |
a93ba405 DMSP |
245 | return 0; |
246 | } | |
247 | ||
248 | if (expect_private_reseed >= 0) { | |
249 | /* Test whether public DRBG was reseeded as expected */ | |
3f078163 P |
250 | if (!TEST_int_ge(reseed_counter(private), private_reseed) |
251 | || !TEST_uint_ge(reseed_counter(private), | |
ce3080e9 | 252 | reseed_counter(primary))) |
a93ba405 DMSP |
253 | return 0; |
254 | } | |
255 | ||
256 | if (expect_success == 1) { | |
ce3080e9 P |
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)) | |
08a65d96 DMSP |
260 | return 0; |
261 | ||
ce3080e9 P |
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))) | |
08a65d96 | 265 | return 0; |
a93ba405 DMSP |
266 | } else { |
267 | ERR_clear_error(); | |
268 | } | |
269 | ||
75e2c877 RS |
270 | return 1; |
271 | } | |
272 | ||
84952925 DMSP |
273 | |
274 | #if defined(OPENSSL_SYS_UNIX) | |
09e76c5d DMSP |
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 | ||
84952925 | 290 | /* |
09e76c5d DMSP |
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. | |
84952925 | 295 | */ |
09e76c5d | 296 | static int compare_drbg_fork_result(const void * left, const void * right) |
84952925 | 297 | { |
09e76c5d DMSP |
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 | */ | |
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 | */ | |
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]; | |
84952925 | 337 | pid_t pid; |
09e76c5d DMSP |
338 | unsigned char random[2 * RANDOM_SIZE]; |
339 | ||
340 | if (!TEST_int_ge(pipe(fd), 0)) | |
341 | return 0; | |
84952925 | 342 | |
09e76c5d DMSP |
343 | if (!TEST_int_ge(pid = fork(), 0)) { |
344 | close(fd[0]); | |
345 | close(fd[1]); | |
84952925 | 346 | return 0; |
09e76c5d DMSP |
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 | ||
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 | sprintf(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; | |
84952925 | 429 | |
09e76c5d | 430 | presult += 2; |
84952925 DMSP |
431 | } |
432 | ||
09e76c5d DMSP |
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 | ||
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_true(RAND_bytes(random, 1) && RAND_priv_bytes(random, 1))) | |
537 | success = 0; | |
538 | ||
539 | return success; | |
84952925 DMSP |
540 | } |
541 | #endif | |
542 | ||
a93ba405 DMSP |
543 | /* |
544 | * Test whether the default rand_method (RAND_OpenSSL()) is | |
545 | * setup correctly, in particular whether reseeding works | |
546 | * as designed. | |
547 | */ | |
09e76c5d | 548 | static int test_rand_reseed(void) |
a93ba405 | 549 | { |
7d615e21 | 550 | EVP_RAND_CTX *primary, *public, *private; |
a93ba405 | 551 | unsigned char rand_add_buf[256]; |
3f078163 | 552 | int rv = 0; |
2bb1b5dd | 553 | time_t before_reseed; |
a93ba405 | 554 | |
3f078163 P |
555 | if (crngt_skip()) |
556 | return TEST_skip("CRNGT cannot be disabled"); | |
557 | ||
a93ba405 DMSP |
558 | /* Check whether RAND_OpenSSL() is the default method */ |
559 | if (!TEST_ptr_eq(RAND_get_rand_method(), RAND_OpenSSL())) | |
560 | return 0; | |
561 | ||
562 | /* All three DRBGs should be non-null */ | |
7d615e21 P |
563 | if (!TEST_ptr(primary = RAND_get0_primary(NULL)) |
564 | || !TEST_ptr(public = RAND_get0_public(NULL)) | |
565 | || !TEST_ptr(private = RAND_get0_private(NULL))) | |
a93ba405 DMSP |
566 | return 0; |
567 | ||
ce3080e9 | 568 | /* There should be three distinct DRBGs, two of them chained to primary */ |
a93ba405 | 569 | if (!TEST_ptr_ne(public, private) |
ce3080e9 P |
570 | || !TEST_ptr_ne(public, primary) |
571 | || !TEST_ptr_ne(private, primary) | |
7d615e21 P |
572 | || !TEST_ptr_eq(prov_rand(public)->parent, prov_rand(primary)) |
573 | || !TEST_ptr_eq(prov_rand(private)->parent, prov_rand(primary))) | |
a93ba405 DMSP |
574 | return 0; |
575 | ||
ce3080e9 P |
576 | /* Disable CRNG testing for the primary DRBG */ |
577 | if (!TEST_true(disable_crngt(primary))) | |
d69226a3 P |
578 | return 0; |
579 | ||
59f124f9 | 580 | /* uninstantiate the three global DRBGs */ |
7d615e21 P |
581 | EVP_RAND_uninstantiate(primary); |
582 | EVP_RAND_uninstantiate(private); | |
583 | EVP_RAND_uninstantiate(public); | |
a93ba405 | 584 | |
59f124f9 DMSP |
585 | |
586 | /* | |
587 | * Test initial seeding of shared DRBGs | |
588 | */ | |
09e76c5d DMSP |
589 | if (!TEST_true(test_drbg_reseed(1, |
590 | primary, public, private, | |
591 | NULL, NULL, | |
592 | 1, 1, 1, 0))) | |
59f124f9 | 593 | goto error; |
59f124f9 DMSP |
594 | |
595 | ||
a93ba405 | 596 | /* |
59f124f9 | 597 | * Test initial state of shared DRBGs |
a93ba405 | 598 | */ |
09e76c5d DMSP |
599 | if (!TEST_true(test_drbg_reseed(1, |
600 | primary, public, private, | |
601 | NULL, NULL, | |
602 | 0, 0, 0, 0))) | |
a93ba405 | 603 | goto error; |
a93ba405 DMSP |
604 | |
605 | /* | |
606 | * Test whether the public and private DRBG are both reseeded when their | |
ce3080e9 | 607 | * reseed counters differ from the primary's reseed counter. |
a93ba405 | 608 | */ |
ce3080e9 | 609 | inc_reseed_counter(primary); |
09e76c5d DMSP |
610 | if (!TEST_true(test_drbg_reseed(1, |
611 | primary, public, private, | |
612 | NULL, NULL, | |
613 | 0, 1, 1, 0))) | |
a93ba405 | 614 | goto error; |
a93ba405 DMSP |
615 | |
616 | /* | |
617 | * Test whether the public DRBG is reseeded when its reseed counter differs | |
ce3080e9 | 618 | * from the primary's reseed counter. |
a93ba405 | 619 | */ |
ce3080e9 | 620 | inc_reseed_counter(primary); |
3f078163 | 621 | inc_reseed_counter(private); |
09e76c5d DMSP |
622 | if (!TEST_true(test_drbg_reseed(1, |
623 | primary, public, private, | |
624 | NULL, NULL, | |
625 | 0, 1, 0, 0))) | |
a93ba405 | 626 | goto error; |
a93ba405 DMSP |
627 | |
628 | /* | |
629 | * Test whether the private DRBG is reseeded when its reseed counter differs | |
ce3080e9 | 630 | * from the primary's reseed counter. |
a93ba405 | 631 | */ |
ce3080e9 | 632 | inc_reseed_counter(primary); |
3f078163 | 633 | inc_reseed_counter(public); |
09e76c5d DMSP |
634 | if (!TEST_true(test_drbg_reseed(1, |
635 | primary, public, private, | |
636 | NULL, NULL, | |
637 | 0, 0, 1, 0))) | |
a93ba405 | 638 | goto error; |
a93ba405 | 639 | |
a93ba405 DMSP |
640 | /* fill 'randomness' buffer with some arbitrary data */ |
641 | memset(rand_add_buf, 'r', sizeof(rand_add_buf)); | |
642 | ||
f844f9eb | 643 | #ifndef FIPS_MODULE |
a93ba405 | 644 | /* |
2bb1b5dd BE |
645 | * Test whether all three DRBGs are reseeded by RAND_add(). |
646 | * The before_reseed time has to be measured here and passed into the | |
ce3080e9 | 647 | * test_drbg_reseed() test, because the primary DRBG gets already reseeded |
2bb1b5dd | 648 | * in RAND_add(), whence the check for the condition |
ce3080e9 | 649 | * before_reseed <= reseed_time(primary) will fail if the time value happens |
2bb1b5dd | 650 | * to increase between the RAND_add() and the test_drbg_reseed() call. |
a93ba405 | 651 | */ |
2bb1b5dd | 652 | before_reseed = time(NULL); |
a93ba405 | 653 | RAND_add(rand_add_buf, sizeof(rand_add_buf), sizeof(rand_add_buf)); |
09e76c5d DMSP |
654 | if (!TEST_true(test_drbg_reseed(1, |
655 | primary, public, private, | |
656 | NULL, NULL, | |
657 | 1, 1, 1, | |
2bb1b5dd | 658 | before_reseed))) |
a93ba405 | 659 | goto error; |
f844f9eb | 660 | #else /* FIPS_MODULE */ |
3a50a8a9 DMSP |
661 | /* |
662 | * In FIPS mode, random data provided by the application via RAND_add() | |
663 | * is not considered a trusted entropy source. It is only treated as | |
664 | * additional_data and no reseeding is forced. This test assures that | |
665 | * no reseeding occurs. | |
666 | */ | |
667 | before_reseed = time(NULL); | |
668 | RAND_add(rand_add_buf, sizeof(rand_add_buf), sizeof(rand_add_buf)); | |
09e76c5d DMSP |
669 | if (!TEST_true(test_drbg_reseed(1, |
670 | primary, public, private, | |
671 | NULL, NULL, | |
672 | 0, 0, 0, | |
3a50a8a9 DMSP |
673 | before_reseed))) |
674 | goto error; | |
3a50a8a9 | 675 | #endif |
a93ba405 DMSP |
676 | |
677 | rv = 1; | |
678 | ||
679 | error: | |
3f078163 | 680 | return rv; |
a93ba405 DMSP |
681 | } |
682 | ||
440bce8f | 683 | #if defined(OPENSSL_THREADS) |
43687d68 DMSP |
684 | static int multi_thread_rand_bytes_succeeded = 1; |
685 | static int multi_thread_rand_priv_bytes_succeeded = 1; | |
440bce8f | 686 | |
7d615e21 P |
687 | static int set_reseed_time_interval(EVP_RAND_CTX *drbg, int t) |
688 | { | |
689 | OSSL_PARAM params[2]; | |
690 | ||
691 | params[0] = OSSL_PARAM_construct_int(OSSL_DRBG_PARAM_RESEED_TIME_INTERVAL, | |
692 | &t); | |
693 | params[1] = OSSL_PARAM_construct_end(); | |
694 | return EVP_RAND_set_ctx_params(drbg, params); | |
695 | } | |
696 | ||
440bce8f KR |
697 | static void run_multi_thread_test(void) |
698 | { | |
699 | unsigned char buf[256]; | |
700 | time_t start = time(NULL); | |
7d615e21 | 701 | EVP_RAND_CTX *public = NULL, *private = NULL; |
440bce8f | 702 | |
7d615e21 P |
703 | if (!TEST_ptr(public = RAND_get0_public(NULL)) |
704 | || !TEST_ptr(private = RAND_get0_private(NULL)) | |
705 | || !TEST_true(set_reseed_time_interval(private, 1)) | |
706 | || !TEST_true(set_reseed_time_interval(public, 1))) { | |
7ecd6c51 BE |
707 | multi_thread_rand_bytes_succeeded = 0; |
708 | return; | |
709 | } | |
440bce8f KR |
710 | |
711 | do { | |
7d615e21 | 712 | if (rand_bytes(buf, sizeof(buf)) <= 0) |
43687d68 | 713 | multi_thread_rand_bytes_succeeded = 0; |
7d615e21 | 714 | if (rand_priv_bytes(buf, sizeof(buf)) <= 0) |
43687d68 | 715 | multi_thread_rand_priv_bytes_succeeded = 0; |
440bce8f | 716 | } |
7d615e21 | 717 | while (time(NULL) - start < 5); |
440bce8f KR |
718 | } |
719 | ||
720 | # if defined(OPENSSL_SYS_WINDOWS) | |
721 | ||
722 | typedef HANDLE thread_t; | |
723 | ||
724 | static DWORD WINAPI thread_run(LPVOID arg) | |
725 | { | |
726 | run_multi_thread_test(); | |
03cdfe1e RL |
727 | /* |
728 | * Because we're linking with a static library, we must stop each | |
729 | * thread explicitly, or so says OPENSSL_thread_stop(3) | |
730 | */ | |
731 | OPENSSL_thread_stop(); | |
440bce8f KR |
732 | return 0; |
733 | } | |
734 | ||
735 | static int run_thread(thread_t *t) | |
736 | { | |
737 | *t = CreateThread(NULL, 0, thread_run, NULL, 0, NULL); | |
738 | return *t != NULL; | |
739 | } | |
740 | ||
741 | static int wait_for_thread(thread_t thread) | |
742 | { | |
743 | return WaitForSingleObject(thread, INFINITE) == 0; | |
744 | } | |
745 | ||
746 | # else | |
747 | ||
748 | typedef pthread_t thread_t; | |
749 | ||
750 | static void *thread_run(void *arg) | |
751 | { | |
752 | run_multi_thread_test(); | |
03cdfe1e RL |
753 | /* |
754 | * Because we're linking with a static library, we must stop each | |
755 | * thread explicitly, or so says OPENSSL_thread_stop(3) | |
756 | */ | |
757 | OPENSSL_thread_stop(); | |
440bce8f KR |
758 | return NULL; |
759 | } | |
760 | ||
761 | static int run_thread(thread_t *t) | |
762 | { | |
763 | return pthread_create(t, NULL, thread_run, NULL) == 0; | |
764 | } | |
765 | ||
766 | static int wait_for_thread(thread_t thread) | |
767 | { | |
768 | return pthread_join(thread, NULL) == 0; | |
769 | } | |
770 | ||
771 | # endif | |
772 | ||
773 | /* | |
774 | * The main thread will also run the test, so we'll have THREADS+1 parallel | |
775 | * tests running | |
776 | */ | |
43687d68 | 777 | # define THREADS 3 |
440bce8f KR |
778 | |
779 | static int test_multi_thread(void) | |
780 | { | |
781 | thread_t t[THREADS]; | |
782 | int i; | |
783 | ||
784 | for (i = 0; i < THREADS; i++) | |
785 | run_thread(&t[i]); | |
786 | run_multi_thread_test(); | |
787 | for (i = 0; i < THREADS; i++) | |
788 | wait_for_thread(t[i]); | |
43687d68 DMSP |
789 | |
790 | if (!TEST_true(multi_thread_rand_bytes_succeeded)) | |
791 | return 0; | |
792 | if (!TEST_true(multi_thread_rand_priv_bytes_succeeded)) | |
793 | return 0; | |
794 | ||
440bce8f KR |
795 | return 1; |
796 | } | |
797 | #endif | |
12fb8c3d | 798 | |
7d615e21 P |
799 | static EVP_RAND_CTX *new_drbg(EVP_RAND_CTX *parent) |
800 | { | |
801 | OSSL_PARAM params[2]; | |
802 | EVP_RAND *rand = NULL; | |
803 | EVP_RAND_CTX *drbg = NULL; | |
804 | ||
805 | params[0] = OSSL_PARAM_construct_utf8_string(OSSL_DRBG_PARAM_CIPHER, | |
806 | "AES-256-CTR", 0); | |
807 | params[1] = OSSL_PARAM_construct_end(); | |
808 | ||
809 | if (!TEST_ptr(rand = EVP_RAND_fetch(NULL, "CTR-DRBG", NULL)) | |
810 | || !TEST_ptr(drbg = EVP_RAND_CTX_new(rand, parent)) | |
811 | || !TEST_true(EVP_RAND_set_ctx_params(drbg, params))) { | |
c23add36 | 812 | EVP_RAND_CTX_free(drbg); |
7d615e21 P |
813 | drbg = NULL; |
814 | } | |
c23add36 | 815 | EVP_RAND_free(rand); |
7d615e21 P |
816 | return drbg; |
817 | } | |
818 | ||
09e76c5d | 819 | static int test_rand_prediction_resistance(void) |
65175163 | 820 | { |
7d615e21 | 821 | EVP_RAND_CTX *x = NULL, *y = NULL, *z = NULL; |
65175163 | 822 | unsigned char buf1[51], buf2[sizeof(buf1)]; |
ce3080e9 | 823 | int ret = 0, xreseed, yreseed, zreseed; |
65175163 | 824 | |
3f078163 P |
825 | if (crngt_skip()) |
826 | return TEST_skip("CRNGT cannot be disabled"); | |
827 | ||
65175163 | 828 | /* Initialise a three long DRBG chain */ |
7d615e21 | 829 | if (!TEST_ptr(x = new_drbg(NULL)) |
ce3080e9 | 830 | || !TEST_true(disable_crngt(x)) |
7d615e21 P |
831 | || !TEST_true(EVP_RAND_instantiate(x, 0, 0, NULL, 0)) |
832 | || !TEST_ptr(y = new_drbg(x)) | |
833 | || !TEST_true(EVP_RAND_instantiate(y, 0, 0, NULL, 0)) | |
834 | || !TEST_ptr(z = new_drbg(y)) | |
835 | || !TEST_true(EVP_RAND_instantiate(z, 0, 0, NULL, 0))) | |
65175163 P |
836 | goto err; |
837 | ||
ce3080e9 P |
838 | /* |
839 | * During a normal reseed, only the last DRBG in the chain should | |
840 | * be reseeded. | |
841 | */ | |
842 | inc_reseed_counter(y); | |
843 | xreseed = reseed_counter(x); | |
844 | yreseed = reseed_counter(y); | |
845 | zreseed = reseed_counter(z); | |
7d615e21 | 846 | if (!TEST_true(EVP_RAND_reseed(z, 0, NULL, 0, NULL, 0)) |
ce3080e9 P |
847 | || !TEST_int_eq(reseed_counter(x), xreseed) |
848 | || !TEST_int_eq(reseed_counter(y), yreseed) | |
849 | || !TEST_int_gt(reseed_counter(z), zreseed)) | |
65175163 P |
850 | goto err; |
851 | ||
852 | /* | |
853 | * When prediction resistance is requested, the request should be | |
ce3080e9 | 854 | * propagated to the primary, so that the entire DRBG chain reseeds. |
65175163 | 855 | */ |
ce3080e9 | 856 | zreseed = reseed_counter(z); |
7d615e21 | 857 | if (!TEST_true(EVP_RAND_reseed(z, 1, NULL, 0, NULL, 0)) |
ce3080e9 P |
858 | || !TEST_int_gt(reseed_counter(x), xreseed) |
859 | || !TEST_int_gt(reseed_counter(y), yreseed) | |
860 | || !TEST_int_gt(reseed_counter(z), zreseed)) | |
65175163 P |
861 | goto err; |
862 | ||
ce3080e9 P |
863 | /* |
864 | * During a normal generate, only the last DRBG should be reseed */ | |
865 | inc_reseed_counter(y); | |
866 | xreseed = reseed_counter(x); | |
867 | yreseed = reseed_counter(y); | |
868 | zreseed = reseed_counter(z); | |
7d615e21 | 869 | if (!TEST_true(EVP_RAND_generate(z, buf1, sizeof(buf1), 0, 0, NULL, 0)) |
ce3080e9 P |
870 | || !TEST_int_eq(reseed_counter(x), xreseed) |
871 | || !TEST_int_eq(reseed_counter(y), yreseed) | |
872 | || !TEST_int_gt(reseed_counter(z), zreseed)) | |
65175163 P |
873 | goto err; |
874 | ||
875 | /* | |
876 | * When a prediction resistant generate is requested, the request | |
ce3080e9 | 877 | * should be propagated to the primary, reseeding the entire DRBG chain. |
65175163 | 878 | */ |
ce3080e9 | 879 | zreseed = reseed_counter(z); |
7d615e21 | 880 | if (!TEST_true(EVP_RAND_generate(z, buf2, sizeof(buf2), 0, 1, NULL, 0)) |
ce3080e9 P |
881 | || !TEST_int_gt(reseed_counter(x), xreseed) |
882 | || !TEST_int_gt(reseed_counter(y), yreseed) | |
883 | || !TEST_int_gt(reseed_counter(z), zreseed) | |
65175163 P |
884 | || !TEST_mem_ne(buf1, sizeof(buf1), buf2, sizeof(buf2))) |
885 | goto err; | |
886 | ||
ce3080e9 P |
887 | /* Verify that a normal reseed still only reseeds the last DRBG */ |
888 | inc_reseed_counter(y); | |
889 | xreseed = reseed_counter(x); | |
890 | yreseed = reseed_counter(y); | |
891 | zreseed = reseed_counter(z); | |
7d615e21 | 892 | if (!TEST_true(EVP_RAND_reseed(z, 0, NULL, 0, NULL, 0)) |
ce3080e9 P |
893 | || !TEST_int_eq(reseed_counter(x), xreseed) |
894 | || !TEST_int_eq(reseed_counter(y), yreseed) | |
895 | || !TEST_int_gt(reseed_counter(z), zreseed)) | |
65175163 P |
896 | goto err; |
897 | ||
898 | ret = 1; | |
899 | err: | |
7d615e21 P |
900 | EVP_RAND_CTX_free(z); |
901 | EVP_RAND_CTX_free(y); | |
902 | EVP_RAND_CTX_free(x); | |
65175163 P |
903 | return ret; |
904 | } | |
905 | ||
ad887416 | 906 | int setup_tests(void) |
12fb8c3d | 907 | { |
09e76c5d DMSP |
908 | ADD_TEST(test_rand_reseed); |
909 | #if defined(OPENSSL_SYS_UNIX) | |
910 | ADD_ALL_TESTS(test_rand_fork_safety, RANDOM_SIZE); | |
911 | #endif | |
912 | ADD_TEST(test_rand_prediction_resistance); | |
440bce8f KR |
913 | #if defined(OPENSSL_THREADS) |
914 | ADD_TEST(test_multi_thread); | |
915 | #endif | |
ad887416 | 916 | return 1; |
12fb8c3d | 917 | } |