]>
Commit | Line | Data |
---|---|---|
12fb8c3d | 1 | /* |
48e5119a | 2 | * Copyright 2011-2018 The OpenSSL Project Authors. All Rights Reserved. |
12fb8c3d RS |
3 | * |
4 | * Licensed under the OpenSSL license (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 | #include <string.h> | |
176db6dc | 11 | #include "internal/nelem.h" |
12fb8c3d RS |
12 | #include <openssl/crypto.h> |
13 | #include <openssl/err.h> | |
14 | #include <openssl/rand.h> | |
15 | #include <openssl/obj_mac.h> | |
16 | #include <openssl/evp.h> | |
17 | #include <openssl/aes.h> | |
18 | #include "../crypto/rand/rand_lcl.h" | |
19 | ||
440bce8f KR |
20 | #if defined(_WIN32) |
21 | # include <windows.h> | |
22 | #endif | |
23 | ||
12fb8c3d RS |
24 | #include "testutil.h" |
25 | #include "drbgtest.h" | |
26 | ||
27 | typedef struct drbg_selftest_data_st { | |
28 | int post; | |
29 | int nid; | |
30 | unsigned int flags; | |
31 | ||
32 | /* KAT data for no PR */ | |
aa048aef DMSP |
33 | const unsigned char *entropy; |
34 | size_t entropylen; | |
12fb8c3d RS |
35 | const unsigned char *nonce; |
36 | size_t noncelen; | |
37 | const unsigned char *pers; | |
38 | size_t perslen; | |
39 | const unsigned char *adin; | |
40 | size_t adinlen; | |
aa048aef DMSP |
41 | const unsigned char *entropyreseed; |
42 | size_t entropyreseedlen; | |
12fb8c3d RS |
43 | const unsigned char *adinreseed; |
44 | size_t adinreseedlen; | |
45 | const unsigned char *adin2; | |
46 | size_t adin2len; | |
47 | const unsigned char *expected; | |
48 | size_t exlen; | |
49 | const unsigned char *kat2; | |
50 | size_t kat2len; | |
51 | ||
52 | /* KAT data for PR */ | |
aa048aef DMSP |
53 | const unsigned char *entropy_pr; |
54 | size_t entropylen_pr; | |
12fb8c3d RS |
55 | const unsigned char *nonce_pr; |
56 | size_t noncelen_pr; | |
57 | const unsigned char *pers_pr; | |
58 | size_t perslen_pr; | |
59 | const unsigned char *adin_pr; | |
60 | size_t adinlen_pr; | |
aa048aef DMSP |
61 | const unsigned char *entropypr_pr; |
62 | size_t entropyprlen_pr; | |
12fb8c3d RS |
63 | const unsigned char *ading_pr; |
64 | size_t adinglen_pr; | |
aa048aef DMSP |
65 | const unsigned char *entropyg_pr; |
66 | size_t entropyglen_pr; | |
12fb8c3d RS |
67 | const unsigned char *kat_pr; |
68 | size_t katlen_pr; | |
69 | const unsigned char *kat2_pr; | |
70 | size_t kat2len_pr; | |
71 | } DRBG_SELFTEST_DATA; | |
72 | ||
73 | #define make_drbg_test_data(nid, flag, pr, post) {\ | |
74 | post, nid, flag, \ | |
75 | pr##_entropyinput, sizeof(pr##_entropyinput), \ | |
76 | pr##_nonce, sizeof(pr##_nonce), \ | |
77 | pr##_personalizationstring, sizeof(pr##_personalizationstring), \ | |
78 | pr##_additionalinput, sizeof(pr##_additionalinput), \ | |
79 | pr##_entropyinputreseed, sizeof(pr##_entropyinputreseed), \ | |
80 | pr##_additionalinputreseed, sizeof(pr##_additionalinputreseed), \ | |
81 | pr##_additionalinput2, sizeof(pr##_additionalinput2), \ | |
82 | pr##_int_returnedbits, sizeof(pr##_int_returnedbits), \ | |
83 | pr##_returnedbits, sizeof(pr##_returnedbits), \ | |
84 | pr##_pr_entropyinput, sizeof(pr##_pr_entropyinput), \ | |
85 | pr##_pr_nonce, sizeof(pr##_pr_nonce), \ | |
86 | pr##_pr_personalizationstring, sizeof(pr##_pr_personalizationstring), \ | |
87 | pr##_pr_additionalinput, sizeof(pr##_pr_additionalinput), \ | |
88 | pr##_pr_entropyinputpr, sizeof(pr##_pr_entropyinputpr), \ | |
89 | pr##_pr_additionalinput2, sizeof(pr##_pr_additionalinput2), \ | |
90 | pr##_pr_entropyinputpr2, sizeof(pr##_pr_entropyinputpr2), \ | |
91 | pr##_pr_int_returnedbits, sizeof(pr##_pr_int_returnedbits), \ | |
92 | pr##_pr_returnedbits, sizeof(pr##_pr_returnedbits) \ | |
93 | } | |
94 | ||
8164d91d DMSP |
95 | #define make_drbg_test_data_use_df(nid, pr, p) \ |
96 | make_drbg_test_data(nid, 0, pr, p) | |
97 | ||
98 | #define make_drbg_test_data_no_df(nid, pr, p) \ | |
99 | make_drbg_test_data(nid, RAND_DRBG_FLAG_CTR_NO_DF, pr, p) | |
12fb8c3d RS |
100 | |
101 | static DRBG_SELFTEST_DATA drbg_test[] = { | |
8164d91d DMSP |
102 | make_drbg_test_data_no_df (NID_aes_128_ctr, aes_128_no_df, 0), |
103 | make_drbg_test_data_no_df (NID_aes_192_ctr, aes_192_no_df, 0), | |
104 | make_drbg_test_data_no_df (NID_aes_256_ctr, aes_256_no_df, 1), | |
105 | make_drbg_test_data_use_df(NID_aes_128_ctr, aes_128_use_df, 0), | |
106 | make_drbg_test_data_use_df(NID_aes_192_ctr, aes_192_use_df, 0), | |
107 | make_drbg_test_data_use_df(NID_aes_256_ctr, aes_256_use_df, 1), | |
12fb8c3d RS |
108 | }; |
109 | ||
110 | static int app_data_index; | |
111 | ||
112 | /* | |
75e2c877 | 113 | * Test context data, attached as EXDATA to the RAND_DRBG |
12fb8c3d RS |
114 | */ |
115 | typedef struct test_ctx_st { | |
aa048aef DMSP |
116 | const unsigned char *entropy; |
117 | size_t entropylen; | |
118 | int entropycnt; | |
12fb8c3d RS |
119 | const unsigned char *nonce; |
120 | size_t noncelen; | |
121 | int noncecnt; | |
122 | } TEST_CTX; | |
123 | ||
75e2c877 | 124 | static size_t kat_entropy(RAND_DRBG *drbg, unsigned char **pout, |
eb238134 KR |
125 | int entropy, size_t min_len, size_t max_len, |
126 | int prediction_resistance) | |
12fb8c3d | 127 | { |
75e2c877 | 128 | TEST_CTX *t = (TEST_CTX *)RAND_DRBG_get_ex_data(drbg, app_data_index); |
12fb8c3d | 129 | |
aa048aef DMSP |
130 | t->entropycnt++; |
131 | *pout = (unsigned char *)t->entropy; | |
132 | return t->entropylen; | |
12fb8c3d RS |
133 | } |
134 | ||
75e2c877 | 135 | static size_t kat_nonce(RAND_DRBG *drbg, unsigned char **pout, |
12fb8c3d RS |
136 | int entropy, size_t min_len, size_t max_len) |
137 | { | |
75e2c877 | 138 | TEST_CTX *t = (TEST_CTX *)RAND_DRBG_get_ex_data(drbg, app_data_index); |
12fb8c3d RS |
139 | |
140 | t->noncecnt++; | |
141 | *pout = (unsigned char *)t->nonce; | |
142 | return t->noncelen; | |
143 | } | |
144 | ||
75e2c877 | 145 | static int uninstantiate(RAND_DRBG *drbg) |
12fb8c3d | 146 | { |
75e2c877 | 147 | int ret = drbg == NULL ? 1 : RAND_DRBG_uninstantiate(drbg); |
12fb8c3d RS |
148 | |
149 | ERR_clear_error(); | |
150 | return ret; | |
151 | } | |
152 | ||
153 | /* | |
154 | * Do a single KAT test. Return 0 on failure. | |
155 | */ | |
156 | static int single_kat(DRBG_SELFTEST_DATA *td) | |
157 | { | |
75e2c877 | 158 | RAND_DRBG *drbg = NULL; |
12fb8c3d RS |
159 | TEST_CTX t; |
160 | int failures = 0; | |
161 | unsigned char buff[1024]; | |
162 | ||
163 | /* | |
164 | * Test without PR: Instantiate DRBG with test entropy, nonce and | |
165 | * personalisation string. | |
166 | */ | |
75e2c877 | 167 | if (!TEST_ptr(drbg = RAND_DRBG_new(td->nid, td->flags, NULL))) |
12fb8c3d | 168 | return 0; |
75e2c877 | 169 | if (!TEST_true(RAND_DRBG_set_callbacks(drbg, kat_entropy, NULL, |
12fb8c3d RS |
170 | kat_nonce, NULL))) { |
171 | failures++; | |
172 | goto err; | |
173 | } | |
174 | memset(&t, 0, sizeof(t)); | |
aa048aef DMSP |
175 | t.entropy = td->entropy; |
176 | t.entropylen = td->entropylen; | |
12fb8c3d RS |
177 | t.nonce = td->nonce; |
178 | t.noncelen = td->noncelen; | |
75e2c877 | 179 | RAND_DRBG_set_ex_data(drbg, app_data_index, &t); |
12fb8c3d | 180 | |
75e2c877 RS |
181 | if (!TEST_true(RAND_DRBG_instantiate(drbg, td->pers, td->perslen)) |
182 | || !TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0, | |
12fb8c3d RS |
183 | td->adin, td->adinlen)) |
184 | || !TEST_mem_eq(td->expected, td->exlen, buff, td->exlen)) | |
185 | failures++; | |
186 | ||
187 | /* Reseed DRBG with test entropy and additional input */ | |
aa048aef DMSP |
188 | t.entropy = td->entropyreseed; |
189 | t.entropylen = td->entropyreseedlen; | |
eb238134 | 190 | if (!TEST_true(RAND_DRBG_reseed(drbg, td->adinreseed, td->adinreseedlen, 0) |
75e2c877 | 191 | || !TEST_true(RAND_DRBG_generate(drbg, buff, td->kat2len, 0, |
12fb8c3d RS |
192 | td->adin2, td->adin2len)) |
193 | || !TEST_mem_eq(td->kat2, td->kat2len, buff, td->kat2len))) | |
194 | failures++; | |
75e2c877 | 195 | uninstantiate(drbg); |
12fb8c3d RS |
196 | |
197 | /* | |
198 | * Now test with PR: Instantiate DRBG with test entropy, nonce and | |
199 | * personalisation string. | |
200 | */ | |
75e2c877 RS |
201 | if (!TEST_true(RAND_DRBG_set(drbg, td->nid, td->flags)) |
202 | || !TEST_true(RAND_DRBG_set_callbacks(drbg, kat_entropy, NULL, | |
12fb8c3d RS |
203 | kat_nonce, NULL))) |
204 | failures++; | |
75e2c877 | 205 | RAND_DRBG_set_ex_data(drbg, app_data_index, &t); |
aa048aef DMSP |
206 | t.entropy = td->entropy_pr; |
207 | t.entropylen = td->entropylen_pr; | |
12fb8c3d RS |
208 | t.nonce = td->nonce_pr; |
209 | t.noncelen = td->noncelen_pr; | |
aa048aef | 210 | t.entropycnt = 0; |
12fb8c3d | 211 | t.noncecnt = 0; |
75e2c877 | 212 | if (!TEST_true(RAND_DRBG_instantiate(drbg, td->pers_pr, td->perslen_pr))) |
12fb8c3d RS |
213 | failures++; |
214 | ||
215 | /* | |
216 | * Now generate with PR: we need to supply entropy as this will | |
217 | * perform a reseed operation. | |
218 | */ | |
aa048aef DMSP |
219 | t.entropy = td->entropypr_pr; |
220 | t.entropylen = td->entropyprlen_pr; | |
75e2c877 | 221 | if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->katlen_pr, 1, |
12fb8c3d RS |
222 | td->adin_pr, td->adinlen_pr)) |
223 | || !TEST_mem_eq(td->kat_pr, td->katlen_pr, buff, td->katlen_pr)) | |
224 | failures++; | |
225 | ||
226 | /* | |
227 | * Now generate again with PR: supply new entropy again. | |
228 | */ | |
aa048aef DMSP |
229 | t.entropy = td->entropyg_pr; |
230 | t.entropylen = td->entropyglen_pr; | |
12fb8c3d | 231 | |
75e2c877 | 232 | if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->kat2len_pr, 1, |
12fb8c3d RS |
233 | td->ading_pr, td->adinglen_pr)) |
234 | || !TEST_mem_eq(td->kat2_pr, td->kat2len_pr, | |
235 | buff, td->kat2len_pr)) | |
236 | failures++; | |
237 | ||
238 | err: | |
75e2c877 RS |
239 | uninstantiate(drbg); |
240 | RAND_DRBG_free(drbg); | |
12fb8c3d RS |
241 | return failures == 0; |
242 | } | |
243 | ||
244 | /* | |
245 | * Initialise a DRBG based on selftest data | |
246 | */ | |
75e2c877 | 247 | static int init(RAND_DRBG *drbg, DRBG_SELFTEST_DATA *td, TEST_CTX *t) |
12fb8c3d | 248 | { |
75e2c877 RS |
249 | if (!TEST_true(RAND_DRBG_set(drbg, td->nid, td->flags)) |
250 | || !TEST_true(RAND_DRBG_set_callbacks(drbg, kat_entropy, NULL, | |
12fb8c3d RS |
251 | kat_nonce, NULL))) |
252 | return 0; | |
75e2c877 | 253 | RAND_DRBG_set_ex_data(drbg, app_data_index, t); |
aa048aef DMSP |
254 | t->entropy = td->entropy; |
255 | t->entropylen = td->entropylen; | |
12fb8c3d RS |
256 | t->nonce = td->nonce; |
257 | t->noncelen = td->noncelen; | |
aa048aef | 258 | t->entropycnt = 0; |
12fb8c3d RS |
259 | t->noncecnt = 0; |
260 | return 1; | |
261 | } | |
262 | ||
263 | /* | |
264 | * Initialise and instantiate DRBG based on selftest data | |
265 | */ | |
75e2c877 | 266 | static int instantiate(RAND_DRBG *drbg, DRBG_SELFTEST_DATA *td, |
12fb8c3d RS |
267 | TEST_CTX *t) |
268 | { | |
75e2c877 RS |
269 | if (!TEST_true(init(drbg, td, t)) |
270 | || !TEST_true(RAND_DRBG_instantiate(drbg, td->pers, td->perslen))) | |
12fb8c3d RS |
271 | return 0; |
272 | return 1; | |
273 | } | |
274 | ||
275 | /* | |
276 | * Perform extensive error checking as required by SP800-90. | |
277 | * Induce several failure modes and check an error condition is set. | |
278 | */ | |
279 | static int error_check(DRBG_SELFTEST_DATA *td) | |
280 | { | |
75e2c877 RS |
281 | static char zero[sizeof(RAND_DRBG)]; |
282 | RAND_DRBG *drbg = NULL; | |
12fb8c3d RS |
283 | TEST_CTX t; |
284 | unsigned char buff[1024]; | |
a93ba405 | 285 | unsigned int generate_counter_tmp; |
12fb8c3d RS |
286 | int ret = 0; |
287 | ||
75e2c877 | 288 | if (!TEST_ptr(drbg = RAND_DRBG_new(0, 0, NULL))) |
12fb8c3d RS |
289 | goto err; |
290 | ||
291 | /* | |
292 | * Personalisation string tests | |
293 | */ | |
294 | ||
295 | /* Test detection of too large personlisation string */ | |
75e2c877 | 296 | if (!init(drbg, td, &t) |
aa048aef | 297 | || RAND_DRBG_instantiate(drbg, td->pers, drbg->max_perslen + 1) > 0) |
12fb8c3d RS |
298 | goto err; |
299 | ||
300 | /* | |
301 | * Entropy source tests | |
302 | */ | |
303 | ||
304 | /* Test entropy source failure detecion: i.e. returns no data */ | |
aa048aef | 305 | t.entropylen = 0; |
75e2c877 | 306 | if (TEST_int_le(RAND_DRBG_instantiate(drbg, td->pers, td->perslen), 0)) |
12fb8c3d RS |
307 | goto err; |
308 | ||
309 | /* Try to generate output from uninstantiated DRBG */ | |
75e2c877 | 310 | if (!TEST_false(RAND_DRBG_generate(drbg, buff, td->exlen, 0, |
12fb8c3d | 311 | td->adin, td->adinlen)) |
75e2c877 | 312 | || !uninstantiate(drbg)) |
12fb8c3d RS |
313 | goto err; |
314 | ||
315 | /* Test insufficient entropy */ | |
aa048aef | 316 | t.entropylen = drbg->min_entropylen - 1; |
75e2c877 RS |
317 | if (!init(drbg, td, &t) |
318 | || RAND_DRBG_instantiate(drbg, td->pers, td->perslen) > 0 | |
319 | || !uninstantiate(drbg)) | |
12fb8c3d RS |
320 | goto err; |
321 | ||
322 | /* Test too much entropy */ | |
aa048aef | 323 | t.entropylen = drbg->max_entropylen + 1; |
75e2c877 RS |
324 | if (!init(drbg, td, &t) |
325 | || RAND_DRBG_instantiate(drbg, td->pers, td->perslen) > 0 | |
326 | || !uninstantiate(drbg)) | |
12fb8c3d RS |
327 | goto err; |
328 | ||
329 | /* | |
330 | * Nonce tests | |
331 | */ | |
332 | ||
333 | /* Test too small nonce */ | |
aa048aef DMSP |
334 | if (drbg->min_noncelen) { |
335 | t.noncelen = drbg->min_noncelen - 1; | |
75e2c877 RS |
336 | if (!init(drbg, td, &t) |
337 | || RAND_DRBG_instantiate(drbg, td->pers, td->perslen) > 0 | |
338 | || !uninstantiate(drbg)) | |
12fb8c3d RS |
339 | goto err; |
340 | } | |
341 | ||
342 | /* Test too large nonce */ | |
aa048aef DMSP |
343 | if (drbg->max_noncelen) { |
344 | t.noncelen = drbg->max_noncelen + 1; | |
75e2c877 RS |
345 | if (!init(drbg, td, &t) |
346 | || RAND_DRBG_instantiate(drbg, td->pers, td->perslen) > 0 | |
347 | || !uninstantiate(drbg)) | |
12fb8c3d RS |
348 | goto err; |
349 | } | |
350 | ||
351 | /* Instantiate with valid data, Check generation is now OK */ | |
75e2c877 RS |
352 | if (!instantiate(drbg, td, &t) |
353 | || !TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0, | |
12fb8c3d RS |
354 | td->adin, td->adinlen))) |
355 | goto err; | |
356 | ||
357 | /* Request too much data for one request */ | |
75e2c877 | 358 | if (!TEST_false(RAND_DRBG_generate(drbg, buff, drbg->max_request + 1, 0, |
12fb8c3d RS |
359 | td->adin, td->adinlen))) |
360 | goto err; | |
361 | ||
362 | /* Try too large additional input */ | |
75e2c877 | 363 | if (!TEST_false(RAND_DRBG_generate(drbg, buff, td->exlen, 0, |
aa048aef | 364 | td->adin, drbg->max_adinlen + 1))) |
12fb8c3d RS |
365 | goto err; |
366 | ||
367 | /* | |
368 | * Check prediction resistance request fails if entropy source | |
369 | * failure. | |
370 | */ | |
aa048aef | 371 | t.entropylen = 0; |
75e2c877 | 372 | if (TEST_false(RAND_DRBG_generate(drbg, buff, td->exlen, 1, |
12fb8c3d | 373 | td->adin, td->adinlen)) |
75e2c877 | 374 | || !uninstantiate(drbg)) |
12fb8c3d RS |
375 | goto err; |
376 | ||
4468b6ed | 377 | /* Instantiate again with valid data */ |
75e2c877 | 378 | if (!instantiate(drbg, td, &t)) |
12fb8c3d | 379 | goto err; |
a93ba405 DMSP |
380 | generate_counter_tmp = drbg->generate_counter; |
381 | drbg->generate_counter = drbg->reseed_interval; | |
12fb8c3d RS |
382 | |
383 | /* Generate output and check entropy has been requested for reseed */ | |
aa048aef | 384 | t.entropycnt = 0; |
75e2c877 | 385 | if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0, |
12fb8c3d | 386 | td->adin, td->adinlen)) |
aa048aef | 387 | || !TEST_int_eq(t.entropycnt, 1) |
a93ba405 | 388 | || !TEST_int_eq(drbg->generate_counter, generate_counter_tmp + 1) |
75e2c877 | 389 | || !uninstantiate(drbg)) |
12fb8c3d RS |
390 | goto err; |
391 | ||
392 | /* | |
393 | * Check prediction resistance request fails if entropy source | |
394 | * failure. | |
395 | */ | |
aa048aef | 396 | t.entropylen = 0; |
75e2c877 | 397 | if (!TEST_false(RAND_DRBG_generate(drbg, buff, td->exlen, 1, |
12fb8c3d | 398 | td->adin, td->adinlen)) |
75e2c877 | 399 | || !uninstantiate(drbg)) |
12fb8c3d RS |
400 | goto err; |
401 | ||
402 | /* Test reseed counter works */ | |
75e2c877 | 403 | if (!instantiate(drbg, td, &t)) |
12fb8c3d | 404 | goto err; |
a93ba405 DMSP |
405 | generate_counter_tmp = drbg->generate_counter; |
406 | drbg->generate_counter = drbg->reseed_interval; | |
12fb8c3d RS |
407 | |
408 | /* Generate output and check entropy has been requested for reseed */ | |
aa048aef | 409 | t.entropycnt = 0; |
75e2c877 | 410 | if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0, |
12fb8c3d | 411 | td->adin, td->adinlen)) |
aa048aef | 412 | || !TEST_int_eq(t.entropycnt, 1) |
a93ba405 | 413 | || !TEST_int_eq(drbg->generate_counter, generate_counter_tmp + 1) |
75e2c877 | 414 | || !uninstantiate(drbg)) |
12fb8c3d RS |
415 | goto err; |
416 | ||
417 | /* | |
418 | * Explicit reseed tests | |
419 | */ | |
420 | ||
421 | /* Test explicit reseed with too large additional input */ | |
75e2c877 | 422 | if (!init(drbg, td, &t) |
eb238134 | 423 | || RAND_DRBG_reseed(drbg, td->adin, drbg->max_adinlen + 1, 0) > 0) |
12fb8c3d RS |
424 | goto err; |
425 | ||
426 | /* Test explicit reseed with entropy source failure */ | |
aa048aef | 427 | t.entropylen = 0; |
eb238134 | 428 | if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) |
75e2c877 | 429 | || !uninstantiate(drbg)) |
12fb8c3d RS |
430 | goto err; |
431 | ||
432 | /* Test explicit reseed with too much entropy */ | |
75e2c877 | 433 | if (!init(drbg, td, &t)) |
12fb8c3d | 434 | goto err; |
aa048aef | 435 | t.entropylen = drbg->max_entropylen + 1; |
eb238134 | 436 | if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) |
75e2c877 | 437 | || !uninstantiate(drbg)) |
12fb8c3d RS |
438 | goto err; |
439 | ||
440 | /* Test explicit reseed with too little entropy */ | |
75e2c877 | 441 | if (!init(drbg, td, &t)) |
12fb8c3d | 442 | goto err; |
aa048aef | 443 | t.entropylen = drbg->min_entropylen - 1; |
eb238134 | 444 | if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) |
75e2c877 | 445 | || !uninstantiate(drbg)) |
12fb8c3d RS |
446 | goto err; |
447 | ||
448 | /* Standard says we have to check uninstantiate really zeroes */ | |
8212d505 | 449 | if (!TEST_mem_eq(zero, sizeof(drbg->data), &drbg->data, sizeof(drbg->data))) |
12fb8c3d RS |
450 | goto err; |
451 | ||
452 | ret = 1; | |
453 | ||
454 | err: | |
75e2c877 RS |
455 | uninstantiate(drbg); |
456 | RAND_DRBG_free(drbg); | |
12fb8c3d RS |
457 | return ret; |
458 | } | |
459 | ||
460 | static int test_kats(int i) | |
461 | { | |
462 | DRBG_SELFTEST_DATA *td = &drbg_test[i]; | |
463 | int rv = 0; | |
464 | ||
465 | if (!single_kat(td)) | |
466 | goto err; | |
467 | rv = 1; | |
468 | ||
469 | err: | |
470 | return rv; | |
471 | } | |
472 | ||
473 | static int test_error_checks(int i) | |
474 | { | |
475 | DRBG_SELFTEST_DATA *td = &drbg_test[i]; | |
476 | int rv = 0; | |
477 | ||
478 | if (error_check(td)) | |
479 | goto err; | |
480 | rv = 1; | |
481 | ||
482 | err: | |
483 | return rv; | |
484 | } | |
485 | ||
a93ba405 DMSP |
486 | /* |
487 | * Hook context data, attached as EXDATA to the RAND_DRBG | |
488 | */ | |
489 | typedef struct hook_ctx_st { | |
490 | RAND_DRBG *drbg; | |
491 | /* | |
492 | * Currently, all DRBGs use the same get_entropy() callback. | |
493 | * The tests however, don't assume this and store | |
494 | * the original callback for every DRBG separately. | |
495 | */ | |
496 | RAND_DRBG_get_entropy_fn get_entropy; | |
497 | /* forces a failure of the get_entropy() call if nonzero */ | |
498 | int fail; | |
499 | /* counts successful reseeds */ | |
500 | int reseed_count; | |
501 | } HOOK_CTX; | |
502 | ||
503 | static HOOK_CTX master_ctx, public_ctx, private_ctx; | |
504 | ||
505 | static HOOK_CTX *get_hook_ctx(RAND_DRBG *drbg) | |
506 | { | |
507 | return (HOOK_CTX *)RAND_DRBG_get_ex_data(drbg, app_data_index); | |
508 | } | |
509 | ||
510 | /* Intercepts and counts calls to the get_entropy() callback */ | |
511 | static size_t get_entropy_hook(RAND_DRBG *drbg, unsigned char **pout, | |
eb238134 KR |
512 | int entropy, size_t min_len, size_t max_len, |
513 | int prediction_resistance) | |
a93ba405 DMSP |
514 | { |
515 | size_t ret; | |
516 | HOOK_CTX *ctx = get_hook_ctx(drbg); | |
517 | ||
518 | if (ctx->fail != 0) | |
519 | return 0; | |
520 | ||
eb238134 KR |
521 | ret = ctx->get_entropy(drbg, pout, entropy, min_len, max_len, |
522 | prediction_resistance); | |
a93ba405 DMSP |
523 | |
524 | if (ret != 0) | |
525 | ctx->reseed_count++; | |
526 | return ret; | |
527 | } | |
528 | ||
529 | /* Installs a hook for the get_entropy() callback of the given drbg */ | |
530 | static void hook_drbg(RAND_DRBG *drbg, HOOK_CTX *ctx) | |
531 | { | |
532 | memset(ctx, 0, sizeof(*ctx)); | |
533 | ctx->drbg = drbg; | |
534 | ctx->get_entropy = drbg->get_entropy; | |
535 | drbg->get_entropy = get_entropy_hook; | |
536 | RAND_DRBG_set_ex_data(drbg, app_data_index, ctx); | |
537 | } | |
538 | ||
539 | /* Installs the hook for the get_entropy() callback of the given drbg */ | |
540 | static void unhook_drbg(RAND_DRBG *drbg) | |
541 | { | |
542 | HOOK_CTX *ctx = get_hook_ctx(drbg); | |
543 | ||
544 | drbg->get_entropy = ctx->get_entropy; | |
545 | CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DRBG, drbg, &drbg->ex_data); | |
546 | } | |
75e2c877 | 547 | |
a93ba405 DMSP |
548 | /* Resets the given hook context */ |
549 | static void reset_hook_ctx(HOOK_CTX *ctx) | |
75e2c877 | 550 | { |
a93ba405 DMSP |
551 | ctx->fail = 0; |
552 | ctx->reseed_count = 0; | |
553 | } | |
554 | ||
555 | /* Resets all drbg hook contexts */ | |
556 | static void reset_drbg_hook_ctx() | |
557 | { | |
558 | reset_hook_ctx(&master_ctx); | |
559 | reset_hook_ctx(&public_ctx); | |
560 | reset_hook_ctx(&private_ctx); | |
561 | } | |
562 | ||
563 | /* | |
564 | * Generates random output using RAND_bytes() and RAND_priv_bytes() | |
565 | * and checks whether the three shared DRBGs were reseeded as | |
566 | * expected. | |
567 | * | |
568 | * |expect_success|: expected outcome (as reported by RAND_status()) | |
569 | * |master|, |public|, |private|: pointers to the three shared DRBGs | |
570 | * |expect_xxx_reseed| = | |
571 | * 1: it is expected that the specified DRBG is reseeded | |
572 | * 0: it is expected that the specified DRBG is not reseeded | |
573 | * -1: don't check whether the specified DRBG was reseeded or not | |
574 | */ | |
575 | static int test_drbg_reseed(int expect_success, | |
576 | RAND_DRBG *master, | |
577 | RAND_DRBG *public, | |
578 | RAND_DRBG *private, | |
579 | int expect_master_reseed, | |
580 | int expect_public_reseed, | |
581 | int expect_private_reseed | |
582 | ) | |
583 | { | |
584 | unsigned char buf[32]; | |
08a65d96 | 585 | time_t before_reseed, after_reseed; |
a93ba405 DMSP |
586 | int expected_state = (expect_success ? DRBG_READY : DRBG_ERROR); |
587 | ||
588 | /* | |
589 | * step 1: check preconditions | |
590 | */ | |
591 | ||
592 | /* Test whether seed propagation is enabled */ | |
593 | if (!TEST_int_ne(master->reseed_counter, 0) | |
594 | || !TEST_int_ne(public->reseed_counter, 0) | |
595 | || !TEST_int_ne(private->reseed_counter, 0)) | |
596 | return 0; | |
597 | ||
598 | /* Check whether the master DRBG's reseed counter is the largest one */ | |
599 | if (!TEST_int_le(public->reseed_counter, master->reseed_counter) | |
600 | || !TEST_int_le(private->reseed_counter, master->reseed_counter)) | |
601 | return 0; | |
602 | ||
603 | /* | |
604 | * step 2: generate random output | |
605 | */ | |
606 | ||
607 | /* Generate random output from the public and private DRBG */ | |
08a65d96 | 608 | before_reseed = expect_master_reseed == 1 ? time(NULL) : 0; |
a93ba405 DMSP |
609 | if (!TEST_int_eq(RAND_bytes(buf, sizeof(buf)), expect_success) |
610 | || !TEST_int_eq(RAND_priv_bytes(buf, sizeof(buf)), expect_success)) | |
611 | return 0; | |
08a65d96 | 612 | after_reseed = time(NULL); |
a93ba405 DMSP |
613 | |
614 | ||
615 | /* | |
616 | * step 3: check postconditions | |
617 | */ | |
75e2c877 | 618 | |
a93ba405 DMSP |
619 | /* Test whether reseeding succeeded as expected */ |
620 | if (!TEST_int_eq(master->state, expected_state) | |
621 | || !TEST_int_eq(public->state, expected_state) | |
622 | || !TEST_int_eq(private->state, expected_state)) | |
75e2c877 | 623 | return 0; |
a93ba405 DMSP |
624 | |
625 | if (expect_master_reseed >= 0) { | |
626 | /* Test whether master DRBG was reseeded as expected */ | |
627 | if (!TEST_int_eq(master_ctx.reseed_count, expect_master_reseed)) | |
628 | return 0; | |
629 | } | |
630 | ||
631 | if (expect_public_reseed >= 0) { | |
632 | /* Test whether public DRBG was reseeded as expected */ | |
633 | if (!TEST_int_eq(public_ctx.reseed_count, expect_public_reseed)) | |
634 | return 0; | |
635 | } | |
636 | ||
637 | if (expect_private_reseed >= 0) { | |
638 | /* Test whether public DRBG was reseeded as expected */ | |
639 | if (!TEST_int_eq(private_ctx.reseed_count, expect_private_reseed)) | |
640 | return 0; | |
641 | } | |
642 | ||
643 | if (expect_success == 1) { | |
644 | /* Test whether all three reseed counters are synchronized */ | |
645 | if (!TEST_int_eq(public->reseed_counter, master->reseed_counter) | |
646 | || !TEST_int_eq(private->reseed_counter, master->reseed_counter)) | |
647 | return 0; | |
08a65d96 DMSP |
648 | |
649 | /* Test whether reseed time of master DRBG is set correctly */ | |
650 | if (!TEST_time_t_le(before_reseed, master->reseed_time) | |
651 | || !TEST_time_t_le(master->reseed_time, after_reseed)) | |
652 | return 0; | |
653 | ||
654 | /* Test whether reseed times of child DRBGs are synchronized with master */ | |
655 | if (!TEST_time_t_ge(public->reseed_time, master->reseed_time) | |
656 | || !TEST_time_t_ge(private->reseed_time, master->reseed_time)) | |
657 | return 0; | |
a93ba405 DMSP |
658 | } else { |
659 | ERR_clear_error(); | |
660 | } | |
661 | ||
75e2c877 RS |
662 | return 1; |
663 | } | |
664 | ||
a93ba405 DMSP |
665 | /* |
666 | * Test whether the default rand_method (RAND_OpenSSL()) is | |
667 | * setup correctly, in particular whether reseeding works | |
668 | * as designed. | |
669 | */ | |
670 | static int test_rand_reseed(void) | |
671 | { | |
672 | RAND_DRBG *master, *public, *private; | |
673 | unsigned char rand_add_buf[256]; | |
674 | int rv=0; | |
675 | ||
676 | /* Check whether RAND_OpenSSL() is the default method */ | |
677 | if (!TEST_ptr_eq(RAND_get_rand_method(), RAND_OpenSSL())) | |
678 | return 0; | |
679 | ||
680 | /* All three DRBGs should be non-null */ | |
681 | if (!TEST_ptr(master = RAND_DRBG_get0_master()) | |
682 | || !TEST_ptr(public = RAND_DRBG_get0_public()) | |
683 | || !TEST_ptr(private = RAND_DRBG_get0_private())) | |
684 | return 0; | |
685 | ||
686 | /* There should be three distinct DRBGs, two of them chained to master */ | |
687 | if (!TEST_ptr_ne(public, private) | |
688 | || !TEST_ptr_ne(public, master) | |
689 | || !TEST_ptr_ne(private, master) | |
690 | || !TEST_ptr_eq(public->parent, master) | |
691 | || !TEST_ptr_eq(private->parent, master)) | |
692 | return 0; | |
693 | ||
694 | /* Install hooks for the following tests */ | |
695 | hook_drbg(master, &master_ctx); | |
696 | hook_drbg(public, &public_ctx); | |
697 | hook_drbg(private, &private_ctx); | |
698 | ||
699 | /* | |
700 | * Test initial state of shared DRBs | |
701 | */ | |
702 | if (!TEST_true(test_drbg_reseed(1, master, public, private, 0, 0, 0))) | |
703 | goto error; | |
704 | reset_drbg_hook_ctx(); | |
705 | ||
706 | /* | |
707 | * Test whether the public and private DRBG are both reseeded when their | |
708 | * reseed counters differ from the master's reseed counter. | |
709 | */ | |
710 | master->reseed_counter++; | |
711 | if (!TEST_true(test_drbg_reseed(1, master, public, private, 0, 1, 1))) | |
712 | goto error; | |
713 | reset_drbg_hook_ctx(); | |
714 | ||
715 | /* | |
716 | * Test whether the public DRBG is reseeded when its reseed counter differs | |
717 | * from the master's reseed counter. | |
718 | */ | |
719 | master->reseed_counter++; | |
720 | private->reseed_counter++; | |
721 | if (!TEST_true(test_drbg_reseed(1, master, public, private, 0, 1, 0))) | |
722 | goto error; | |
723 | reset_drbg_hook_ctx(); | |
724 | ||
725 | /* | |
726 | * Test whether the private DRBG is reseeded when its reseed counter differs | |
727 | * from the master's reseed counter. | |
728 | */ | |
729 | master->reseed_counter++; | |
730 | public->reseed_counter++; | |
731 | if (!TEST_true(test_drbg_reseed(1, master, public, private, 0, 0, 1))) | |
732 | goto error; | |
733 | reset_drbg_hook_ctx(); | |
734 | ||
735 | ||
736 | /* fill 'randomness' buffer with some arbitrary data */ | |
737 | memset(rand_add_buf, 'r', sizeof(rand_add_buf)); | |
738 | ||
739 | /* | |
740 | * Test whether all three DRBGs are reseeded by RAND_add() | |
741 | */ | |
742 | RAND_add(rand_add_buf, sizeof(rand_add_buf), sizeof(rand_add_buf)); | |
743 | if (!TEST_true(test_drbg_reseed(1, master, public, private, 1, 1, 1))) | |
744 | goto error; | |
745 | reset_drbg_hook_ctx(); | |
746 | ||
747 | ||
748 | /* | |
749 | * Test whether none of the DRBGs is reseed if the master fails to reseed | |
750 | */ | |
751 | master_ctx.fail = 1; | |
752 | master->reseed_counter++; | |
753 | RAND_add(rand_add_buf, sizeof(rand_add_buf), sizeof(rand_add_buf)); | |
754 | if (!TEST_true(test_drbg_reseed(0, master, public, private, 0, 0, 0))) | |
755 | goto error; | |
756 | reset_drbg_hook_ctx(); | |
757 | ||
758 | rv = 1; | |
759 | ||
760 | error: | |
761 | /* Remove hooks */ | |
762 | unhook_drbg(master); | |
763 | unhook_drbg(public); | |
764 | unhook_drbg(private); | |
765 | ||
766 | return rv; | |
767 | } | |
768 | ||
440bce8f KR |
769 | #if defined(OPENSSL_THREADS) |
770 | ||
771 | static void run_multi_thread_test(void) | |
772 | { | |
773 | unsigned char buf[256]; | |
774 | time_t start = time(NULL); | |
775 | RAND_DRBG *public, *private; | |
776 | ||
777 | public = RAND_DRBG_get0_public(); | |
778 | private = RAND_DRBG_get0_private(); | |
779 | RAND_DRBG_set_reseed_time_interval(public, 1); | |
780 | RAND_DRBG_set_reseed_time_interval(private, 1); | |
781 | ||
782 | do { | |
783 | RAND_bytes(buf, sizeof(buf)); | |
784 | RAND_priv_bytes(buf, sizeof(buf)); | |
785 | } | |
786 | while(time(NULL) - start < 5); | |
787 | } | |
788 | ||
789 | # if defined(OPENSSL_SYS_WINDOWS) | |
790 | ||
791 | typedef HANDLE thread_t; | |
792 | ||
793 | static DWORD WINAPI thread_run(LPVOID arg) | |
794 | { | |
795 | run_multi_thread_test(); | |
796 | return 0; | |
797 | } | |
798 | ||
799 | static int run_thread(thread_t *t) | |
800 | { | |
801 | *t = CreateThread(NULL, 0, thread_run, NULL, 0, NULL); | |
802 | return *t != NULL; | |
803 | } | |
804 | ||
805 | static int wait_for_thread(thread_t thread) | |
806 | { | |
807 | return WaitForSingleObject(thread, INFINITE) == 0; | |
808 | } | |
809 | ||
810 | # else | |
811 | ||
812 | typedef pthread_t thread_t; | |
813 | ||
814 | static void *thread_run(void *arg) | |
815 | { | |
816 | run_multi_thread_test(); | |
817 | return NULL; | |
818 | } | |
819 | ||
820 | static int run_thread(thread_t *t) | |
821 | { | |
822 | return pthread_create(t, NULL, thread_run, NULL) == 0; | |
823 | } | |
824 | ||
825 | static int wait_for_thread(thread_t thread) | |
826 | { | |
827 | return pthread_join(thread, NULL) == 0; | |
828 | } | |
829 | ||
830 | # endif | |
831 | ||
832 | /* | |
833 | * The main thread will also run the test, so we'll have THREADS+1 parallel | |
834 | * tests running | |
835 | */ | |
836 | #define THREADS 3 | |
837 | ||
838 | static int test_multi_thread(void) | |
839 | { | |
840 | thread_t t[THREADS]; | |
841 | int i; | |
842 | ||
843 | for (i = 0; i < THREADS; i++) | |
844 | run_thread(&t[i]); | |
845 | run_multi_thread_test(); | |
846 | for (i = 0; i < THREADS; i++) | |
847 | wait_for_thread(t[i]); | |
848 | return 1; | |
849 | } | |
850 | #endif | |
12fb8c3d | 851 | |
ad887416 | 852 | int setup_tests(void) |
12fb8c3d | 853 | { |
12fb8c3d RS |
854 | app_data_index = RAND_DRBG_get_ex_new_index(0L, NULL, NULL, NULL, NULL); |
855 | ||
856 | ADD_ALL_TESTS(test_kats, OSSL_NELEM(drbg_test)); | |
857 | ADD_ALL_TESTS(test_error_checks, OSSL_NELEM(drbg_test)); | |
a93ba405 | 858 | ADD_TEST(test_rand_reseed); |
440bce8f KR |
859 | #if defined(OPENSSL_THREADS) |
860 | ADD_TEST(test_multi_thread); | |
861 | #endif | |
ad887416 | 862 | return 1; |
12fb8c3d | 863 | } |