]>
Commit | Line | Data |
---|---|---|
12fb8c3d RS |
1 | /* |
2 | * Copyright 2011-2017 The OpenSSL Project Authors. All Rights Reserved. | |
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> | |
11 | #include "e_os.h" | |
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 | ||
20 | #include "testutil.h" | |
21 | #include "drbgtest.h" | |
22 | ||
23 | typedef struct drbg_selftest_data_st { | |
24 | int post; | |
25 | int nid; | |
26 | unsigned int flags; | |
27 | ||
28 | /* KAT data for no PR */ | |
29 | const unsigned char *ent; | |
30 | size_t entlen; | |
31 | const unsigned char *nonce; | |
32 | size_t noncelen; | |
33 | const unsigned char *pers; | |
34 | size_t perslen; | |
35 | const unsigned char *adin; | |
36 | size_t adinlen; | |
37 | const unsigned char *entreseed; | |
38 | size_t entreseedlen; | |
39 | const unsigned char *adinreseed; | |
40 | size_t adinreseedlen; | |
41 | const unsigned char *adin2; | |
42 | size_t adin2len; | |
43 | const unsigned char *expected; | |
44 | size_t exlen; | |
45 | const unsigned char *kat2; | |
46 | size_t kat2len; | |
47 | ||
48 | /* KAT data for PR */ | |
49 | const unsigned char *ent_pr; | |
50 | size_t entlen_pr; | |
51 | const unsigned char *nonce_pr; | |
52 | size_t noncelen_pr; | |
53 | const unsigned char *pers_pr; | |
54 | size_t perslen_pr; | |
55 | const unsigned char *adin_pr; | |
56 | size_t adinlen_pr; | |
57 | const unsigned char *entpr_pr; | |
58 | size_t entprlen_pr; | |
59 | const unsigned char *ading_pr; | |
60 | size_t adinglen_pr; | |
61 | const unsigned char *entg_pr; | |
62 | size_t entglen_pr; | |
63 | const unsigned char *kat_pr; | |
64 | size_t katlen_pr; | |
65 | const unsigned char *kat2_pr; | |
66 | size_t kat2len_pr; | |
67 | } DRBG_SELFTEST_DATA; | |
68 | ||
69 | #define make_drbg_test_data(nid, flag, pr, post) {\ | |
70 | post, nid, flag, \ | |
71 | pr##_entropyinput, sizeof(pr##_entropyinput), \ | |
72 | pr##_nonce, sizeof(pr##_nonce), \ | |
73 | pr##_personalizationstring, sizeof(pr##_personalizationstring), \ | |
74 | pr##_additionalinput, sizeof(pr##_additionalinput), \ | |
75 | pr##_entropyinputreseed, sizeof(pr##_entropyinputreseed), \ | |
76 | pr##_additionalinputreseed, sizeof(pr##_additionalinputreseed), \ | |
77 | pr##_additionalinput2, sizeof(pr##_additionalinput2), \ | |
78 | pr##_int_returnedbits, sizeof(pr##_int_returnedbits), \ | |
79 | pr##_returnedbits, sizeof(pr##_returnedbits), \ | |
80 | pr##_pr_entropyinput, sizeof(pr##_pr_entropyinput), \ | |
81 | pr##_pr_nonce, sizeof(pr##_pr_nonce), \ | |
82 | pr##_pr_personalizationstring, sizeof(pr##_pr_personalizationstring), \ | |
83 | pr##_pr_additionalinput, sizeof(pr##_pr_additionalinput), \ | |
84 | pr##_pr_entropyinputpr, sizeof(pr##_pr_entropyinputpr), \ | |
85 | pr##_pr_additionalinput2, sizeof(pr##_pr_additionalinput2), \ | |
86 | pr##_pr_entropyinputpr2, sizeof(pr##_pr_entropyinputpr2), \ | |
87 | pr##_pr_int_returnedbits, sizeof(pr##_pr_int_returnedbits), \ | |
88 | pr##_pr_returnedbits, sizeof(pr##_pr_returnedbits) \ | |
89 | } | |
90 | ||
91 | #define make_drbg_test_data_df(nid, pr, p) \ | |
92 | make_drbg_test_data(nid, RAND_DRBG_FLAG_CTR_USE_DF, pr, p) | |
93 | ||
94 | static DRBG_SELFTEST_DATA drbg_test[] = { | |
95 | make_drbg_test_data_df(NID_aes_128_ctr, aes_128_use_df, 0), | |
96 | make_drbg_test_data_df(NID_aes_192_ctr, aes_192_use_df, 0), | |
97 | make_drbg_test_data_df(NID_aes_256_ctr, aes_256_use_df, 1), | |
98 | make_drbg_test_data (NID_aes_128_ctr, 0, aes_128_no_df, 0), | |
99 | make_drbg_test_data (NID_aes_192_ctr, 0, aes_192_no_df, 0), | |
100 | make_drbg_test_data (NID_aes_256_ctr, 0, aes_256_no_df, 1), | |
101 | }; | |
102 | ||
103 | static int app_data_index; | |
104 | ||
105 | /* | |
106 | * Test context data, attached as appdata to the DRBG_CTX | |
107 | */ | |
108 | typedef struct test_ctx_st { | |
109 | const unsigned char *ent; | |
110 | size_t entlen; | |
111 | int entcnt; | |
112 | const unsigned char *nonce; | |
113 | size_t noncelen; | |
114 | int noncecnt; | |
115 | } TEST_CTX; | |
116 | ||
117 | static size_t kat_entropy(DRBG_CTX *dctx, unsigned char **pout, | |
118 | int entropy, size_t min_len, size_t max_len) | |
119 | { | |
120 | TEST_CTX *t = (TEST_CTX *)RAND_DRBG_get_ex_data(dctx, app_data_index); | |
121 | ||
122 | t->entcnt++; | |
123 | *pout = (unsigned char *)t->ent; | |
124 | return t->entlen; | |
125 | } | |
126 | ||
127 | static size_t kat_nonce(DRBG_CTX *dctx, unsigned char **pout, | |
128 | int entropy, size_t min_len, size_t max_len) | |
129 | { | |
130 | TEST_CTX *t = (TEST_CTX *)RAND_DRBG_get_ex_data(dctx, app_data_index); | |
131 | ||
132 | t->noncecnt++; | |
133 | *pout = (unsigned char *)t->nonce; | |
134 | return t->noncelen; | |
135 | } | |
136 | ||
137 | static int uninstantiate(DRBG_CTX *dctx) | |
138 | { | |
139 | int ret = dctx == NULL ? 1 : RAND_DRBG_uninstantiate(dctx); | |
140 | ||
141 | ERR_clear_error(); | |
142 | return ret; | |
143 | } | |
144 | ||
145 | /* | |
146 | * Do a single KAT test. Return 0 on failure. | |
147 | */ | |
148 | static int single_kat(DRBG_SELFTEST_DATA *td) | |
149 | { | |
150 | DRBG_CTX *dctx = NULL; | |
151 | TEST_CTX t; | |
152 | int failures = 0; | |
153 | unsigned char buff[1024]; | |
154 | ||
155 | /* | |
156 | * Test without PR: Instantiate DRBG with test entropy, nonce and | |
157 | * personalisation string. | |
158 | */ | |
159 | if (!TEST_ptr(dctx = RAND_DRBG_new(td->nid, td->flags, NULL))) | |
160 | return 0; | |
161 | if (!TEST_true(RAND_DRBG_set_callbacks(dctx, kat_entropy, NULL, | |
162 | kat_nonce, NULL))) { | |
163 | failures++; | |
164 | goto err; | |
165 | } | |
166 | memset(&t, 0, sizeof(t)); | |
167 | t.ent = td->ent; | |
168 | t.entlen = td->entlen; | |
169 | t.nonce = td->nonce; | |
170 | t.noncelen = td->noncelen; | |
171 | RAND_DRBG_set_ex_data(dctx, app_data_index, &t); | |
172 | ||
173 | if (!TEST_true(RAND_DRBG_instantiate(dctx, td->pers, td->perslen)) | |
174 | || !TEST_true(RAND_DRBG_generate(dctx, buff, td->exlen, 0, | |
175 | td->adin, td->adinlen)) | |
176 | || !TEST_mem_eq(td->expected, td->exlen, buff, td->exlen)) | |
177 | failures++; | |
178 | ||
179 | /* Reseed DRBG with test entropy and additional input */ | |
180 | t.ent = td->entreseed; | |
181 | t.entlen = td->entreseedlen; | |
182 | if (!TEST_true(RAND_DRBG_reseed(dctx, td->adinreseed, td->adinreseedlen) | |
183 | || !TEST_true(RAND_DRBG_generate(dctx, buff, td->kat2len, 0, | |
184 | td->adin2, td->adin2len)) | |
185 | || !TEST_mem_eq(td->kat2, td->kat2len, buff, td->kat2len))) | |
186 | failures++; | |
187 | uninstantiate(dctx); | |
188 | ||
189 | /* | |
190 | * Now test with PR: Instantiate DRBG with test entropy, nonce and | |
191 | * personalisation string. | |
192 | */ | |
193 | if (!TEST_true(RAND_DRBG_set(dctx, td->nid, td->flags)) | |
194 | || !TEST_true(RAND_DRBG_set_callbacks(dctx, kat_entropy, NULL, | |
195 | kat_nonce, NULL))) | |
196 | failures++; | |
197 | RAND_DRBG_set_ex_data(dctx, app_data_index, &t); | |
198 | t.ent = td->ent_pr; | |
199 | t.entlen = td->entlen_pr; | |
200 | t.nonce = td->nonce_pr; | |
201 | t.noncelen = td->noncelen_pr; | |
202 | t.entcnt = 0; | |
203 | t.noncecnt = 0; | |
204 | if (!TEST_true(RAND_DRBG_instantiate(dctx, td->pers_pr, td->perslen_pr))) | |
205 | failures++; | |
206 | ||
207 | /* | |
208 | * Now generate with PR: we need to supply entropy as this will | |
209 | * perform a reseed operation. | |
210 | */ | |
211 | t.ent = td->entpr_pr; | |
212 | t.entlen = td->entprlen_pr; | |
213 | if (!TEST_true(RAND_DRBG_generate(dctx, buff, td->katlen_pr, 1, | |
214 | td->adin_pr, td->adinlen_pr)) | |
215 | || !TEST_mem_eq(td->kat_pr, td->katlen_pr, buff, td->katlen_pr)) | |
216 | failures++; | |
217 | ||
218 | /* | |
219 | * Now generate again with PR: supply new entropy again. | |
220 | */ | |
221 | t.ent = td->entg_pr; | |
222 | t.entlen = td->entglen_pr; | |
223 | ||
224 | if (!TEST_true(RAND_DRBG_generate(dctx, buff, td->kat2len_pr, 1, | |
225 | td->ading_pr, td->adinglen_pr)) | |
226 | || !TEST_mem_eq(td->kat2_pr, td->kat2len_pr, | |
227 | buff, td->kat2len_pr)) | |
228 | failures++; | |
229 | ||
230 | err: | |
231 | uninstantiate(dctx); | |
232 | RAND_DRBG_free(dctx); | |
233 | return failures == 0; | |
234 | } | |
235 | ||
236 | /* | |
237 | * Initialise a DRBG based on selftest data | |
238 | */ | |
239 | static int init(DRBG_CTX *dctx, DRBG_SELFTEST_DATA *td, TEST_CTX *t) | |
240 | { | |
241 | if (!TEST_true(RAND_DRBG_set(dctx, td->nid, td->flags)) | |
242 | || !TEST_true(RAND_DRBG_set_callbacks(dctx, kat_entropy, NULL, | |
243 | kat_nonce, NULL))) | |
244 | return 0; | |
245 | RAND_DRBG_set_ex_data(dctx, app_data_index, t); | |
246 | t->ent = td->ent; | |
247 | t->entlen = td->entlen; | |
248 | t->nonce = td->nonce; | |
249 | t->noncelen = td->noncelen; | |
250 | t->entcnt = 0; | |
251 | t->noncecnt = 0; | |
252 | return 1; | |
253 | } | |
254 | ||
255 | /* | |
256 | * Initialise and instantiate DRBG based on selftest data | |
257 | */ | |
258 | static int instantiate(DRBG_CTX *dctx, DRBG_SELFTEST_DATA *td, | |
259 | TEST_CTX *t) | |
260 | { | |
261 | if (!TEST_true(init(dctx, td, t)) | |
262 | || !TEST_true(RAND_DRBG_instantiate(dctx, td->pers, td->perslen))) | |
263 | return 0; | |
264 | return 1; | |
265 | } | |
266 | ||
267 | /* | |
268 | * Perform extensive error checking as required by SP800-90. | |
269 | * Induce several failure modes and check an error condition is set. | |
270 | */ | |
271 | static int error_check(DRBG_SELFTEST_DATA *td) | |
272 | { | |
273 | static char zero[sizeof(DRBG_CTX)]; | |
274 | DRBG_CTX *dctx = NULL; | |
275 | TEST_CTX t; | |
276 | unsigned char buff[1024]; | |
277 | unsigned int reseed_counter_tmp; | |
278 | int ret = 0; | |
279 | ||
280 | if (!TEST_ptr(dctx = RAND_DRBG_new(0, 0, NULL))) | |
281 | goto err; | |
282 | ||
283 | /* | |
284 | * Personalisation string tests | |
285 | */ | |
286 | ||
287 | /* Test detection of too large personlisation string */ | |
288 | if (!init(dctx, td, &t) | |
289 | || RAND_DRBG_instantiate(dctx, td->pers, dctx->max_pers + 1) > 0) | |
290 | goto err; | |
291 | ||
292 | /* | |
293 | * Entropy source tests | |
294 | */ | |
295 | ||
296 | /* Test entropy source failure detecion: i.e. returns no data */ | |
297 | t.entlen = 0; | |
298 | if (TEST_int_le(RAND_DRBG_instantiate(dctx, td->pers, td->perslen), 0)) | |
299 | goto err; | |
300 | ||
301 | /* Try to generate output from uninstantiated DRBG */ | |
302 | if (!TEST_false(RAND_DRBG_generate(dctx, buff, td->exlen, 0, | |
303 | td->adin, td->adinlen)) | |
304 | || !uninstantiate(dctx)) | |
305 | goto err; | |
306 | ||
307 | /* Test insufficient entropy */ | |
308 | t.entlen = dctx->min_entropy - 1; | |
309 | if (!init(dctx, td, &t) | |
310 | || RAND_DRBG_instantiate(dctx, td->pers, td->perslen) > 0 | |
311 | || !uninstantiate(dctx)) | |
312 | goto err; | |
313 | ||
314 | /* Test too much entropy */ | |
315 | t.entlen = dctx->max_entropy + 1; | |
316 | if (!init(dctx, td, &t) | |
317 | || RAND_DRBG_instantiate(dctx, td->pers, td->perslen) > 0 | |
318 | || !uninstantiate(dctx)) | |
319 | goto err; | |
320 | ||
321 | /* | |
322 | * Nonce tests | |
323 | */ | |
324 | ||
325 | /* Test too small nonce */ | |
4468b6ed | 326 | if (dctx->min_nonce) { |
12fb8c3d RS |
327 | t.noncelen = dctx->min_nonce - 1; |
328 | if (!init(dctx, td, &t) | |
329 | || RAND_DRBG_instantiate(dctx, td->pers, td->perslen) > 0 | |
330 | || !uninstantiate(dctx)) | |
331 | goto err; | |
332 | } | |
333 | ||
334 | /* Test too large nonce */ | |
335 | if (dctx->max_nonce) { | |
336 | t.noncelen = dctx->max_nonce + 1; | |
337 | if (!init(dctx, td, &t) | |
338 | || RAND_DRBG_instantiate(dctx, td->pers, td->perslen) > 0 | |
339 | || !uninstantiate(dctx)) | |
340 | goto err; | |
341 | } | |
342 | ||
343 | /* Instantiate with valid data, Check generation is now OK */ | |
344 | if (!instantiate(dctx, td, &t) | |
345 | || !TEST_true(RAND_DRBG_generate(dctx, buff, td->exlen, 0, | |
346 | td->adin, td->adinlen))) | |
347 | goto err; | |
348 | ||
349 | /* Request too much data for one request */ | |
350 | if (!TEST_false(RAND_DRBG_generate(dctx, buff, dctx->max_request + 1, 0, | |
351 | td->adin, td->adinlen))) | |
352 | goto err; | |
353 | ||
354 | /* Try too large additional input */ | |
355 | if (!TEST_false(RAND_DRBG_generate(dctx, buff, td->exlen, 0, | |
356 | td->adin, dctx->max_adin + 1))) | |
357 | goto err; | |
358 | ||
359 | /* | |
360 | * Check prediction resistance request fails if entropy source | |
361 | * failure. | |
362 | */ | |
363 | t.entlen = 0; | |
364 | if (TEST_false(RAND_DRBG_generate(dctx, buff, td->exlen, 1, | |
365 | td->adin, td->adinlen)) | |
366 | || !uninstantiate(dctx)) | |
367 | goto err; | |
368 | ||
4468b6ed | 369 | /* Instantiate again with valid data */ |
12fb8c3d RS |
370 | if (!instantiate(dctx, td, &t)) |
371 | goto err; | |
372 | reseed_counter_tmp = dctx->reseed_counter; | |
373 | dctx->reseed_counter = dctx->reseed_interval; | |
374 | ||
375 | /* Generate output and check entropy has been requested for reseed */ | |
376 | t.entcnt = 0; | |
377 | if (!TEST_true(RAND_DRBG_generate(dctx, buff, td->exlen, 0, | |
378 | td->adin, td->adinlen)) | |
379 | || !TEST_int_eq(t.entcnt, 1) | |
380 | || !TEST_int_eq(dctx->reseed_counter, reseed_counter_tmp + 1) | |
381 | || !uninstantiate(dctx)) | |
382 | goto err; | |
383 | ||
384 | /* | |
385 | * Check prediction resistance request fails if entropy source | |
386 | * failure. | |
387 | */ | |
388 | t.entlen = 0; | |
389 | if (!TEST_false(RAND_DRBG_generate(dctx, buff, td->exlen, 1, | |
390 | td->adin, td->adinlen)) | |
391 | || !uninstantiate(dctx)) | |
392 | goto err; | |
393 | ||
394 | /* Test reseed counter works */ | |
395 | if (!instantiate(dctx, td, &t)) | |
396 | goto err; | |
397 | reseed_counter_tmp = dctx->reseed_counter; | |
398 | dctx->reseed_counter = dctx->reseed_interval; | |
399 | ||
400 | /* Generate output and check entropy has been requested for reseed */ | |
401 | t.entcnt = 0; | |
402 | if (!TEST_true(RAND_DRBG_generate(dctx, buff, td->exlen, 0, | |
403 | td->adin, td->adinlen)) | |
404 | || !TEST_int_eq(t.entcnt, 1) | |
405 | || !TEST_int_eq(dctx->reseed_counter, reseed_counter_tmp + 1) | |
406 | || !uninstantiate(dctx)) | |
407 | goto err; | |
408 | ||
409 | /* | |
410 | * Explicit reseed tests | |
411 | */ | |
412 | ||
413 | /* Test explicit reseed with too large additional input */ | |
414 | if (!init(dctx, td, &t) | |
415 | || RAND_DRBG_reseed(dctx, td->adin, dctx->max_adin + 1) > 0) | |
416 | goto err; | |
417 | ||
418 | /* Test explicit reseed with entropy source failure */ | |
419 | t.entlen = 0; | |
420 | if (!TEST_int_le(RAND_DRBG_reseed(dctx, td->adin, td->adinlen), 0) | |
421 | || !uninstantiate(dctx)) | |
422 | goto err; | |
423 | ||
424 | /* Test explicit reseed with too much entropy */ | |
425 | if (!init(dctx, td, &t)) | |
426 | goto err; | |
427 | t.entlen = dctx->max_entropy + 1; | |
428 | if (!TEST_int_le(RAND_DRBG_reseed(dctx, td->adin, td->adinlen), 0) | |
429 | || !uninstantiate(dctx)) | |
430 | goto err; | |
431 | ||
432 | /* Test explicit reseed with too little entropy */ | |
433 | if (!init(dctx, td, &t)) | |
434 | goto err; | |
435 | t.entlen = dctx->min_entropy - 1; | |
436 | if (!TEST_int_le(RAND_DRBG_reseed(dctx, td->adin, td->adinlen), 0) | |
437 | || !uninstantiate(dctx)) | |
438 | goto err; | |
439 | ||
440 | /* Standard says we have to check uninstantiate really zeroes */ | |
441 | if (!TEST_mem_eq(zero, sizeof(dctx->ctr), &dctx->ctr, sizeof(dctx->ctr))) | |
442 | goto err; | |
443 | ||
444 | ret = 1; | |
445 | ||
446 | err: | |
447 | uninstantiate(dctx); | |
448 | RAND_DRBG_free(dctx); | |
449 | return ret; | |
450 | } | |
451 | ||
452 | static int test_kats(int i) | |
453 | { | |
454 | DRBG_SELFTEST_DATA *td = &drbg_test[i]; | |
455 | int rv = 0; | |
456 | ||
457 | if (!single_kat(td)) | |
458 | goto err; | |
459 | rv = 1; | |
460 | ||
461 | err: | |
462 | return rv; | |
463 | } | |
464 | ||
465 | static int test_error_checks(int i) | |
466 | { | |
467 | DRBG_SELFTEST_DATA *td = &drbg_test[i]; | |
468 | int rv = 0; | |
469 | ||
470 | if (error_check(td)) | |
471 | goto err; | |
472 | rv = 1; | |
473 | ||
474 | err: | |
475 | return rv; | |
476 | } | |
477 | ||
478 | ||
479 | int test_main(int argc, char *argv[]) | |
480 | { | |
481 | if (argc != 1) { | |
482 | TEST_error("Usage: %s", argv[0]); | |
483 | return EXIT_FAILURE; | |
484 | } | |
485 | app_data_index = RAND_DRBG_get_ex_new_index(0L, NULL, NULL, NULL, NULL); | |
486 | ||
487 | ADD_ALL_TESTS(test_kats, OSSL_NELEM(drbg_test)); | |
488 | ADD_ALL_TESTS(test_error_checks, OSSL_NELEM(drbg_test)); | |
489 | return run_tests(argv[0]); | |
490 | } |