/* * Do a single KAT test. Return 0 on failure. */ static int single_kat(DRBG_SELFTEST_DATA *td) { RAND_DRBG *drbg = NULL; TEST_CTX t; int failures = 0; unsigned char buff[1024]; /* * Test without PR: Instantiate DRBG with test entropy, nonce and * personalisation string. */ if (!TEST_ptr(drbg = RAND_DRBG_new(td->nid, td->flags, NULL))) return 0; if (!TEST_true(RAND_DRBG_set_callbacks(drbg, kat_entropy, NULL, kat_nonce, NULL))) { failures++; goto err; } memset(&t, 0, sizeof(t)); t.entropy = td->entropy; t.entropylen = td->entropylen; t.nonce = td->nonce; t.noncelen = td->noncelen; RAND_DRBG_set_ex_data(drbg, app_data_index, &t); if (!TEST_true(RAND_DRBG_instantiate(drbg, td->pers, td->perslen)) || !TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0, td->adin, td->adinlen)) || !TEST_mem_eq(td->expected, td->exlen, buff, td->exlen)) failures++; /* Reseed DRBG with test entropy and additional input */ t.entropy = td->entropyreseed; t.entropylen = td->entropyreseedlen; if (!TEST_true(RAND_DRBG_reseed(drbg, td->adinreseed, td->adinreseedlen, 0) || !TEST_true(RAND_DRBG_generate(drbg, buff, td->kat2len, 0, td->adin2, td->adin2len)) || !TEST_mem_eq(td->kat2, td->kat2len, buff, td->kat2len))) failures++; uninstantiate(drbg); /* * Now test with PR: Instantiate DRBG with test entropy, nonce and * personalisation string. */ if (!TEST_true(RAND_DRBG_set(drbg, td->nid, td->flags)) || !TEST_true(RAND_DRBG_set_callbacks(drbg, kat_entropy, NULL, kat_nonce, NULL))) failures++; RAND_DRBG_set_ex_data(drbg, app_data_index, &t); t.entropy = td->entropy_pr; t.entropylen = td->entropylen_pr; t.nonce = td->nonce_pr; t.noncelen = td->noncelen_pr; t.entropycnt = 0; t.noncecnt = 0; if (!TEST_true(RAND_DRBG_instantiate(drbg, td->pers_pr, td->perslen_pr))) failures++; /* * Now generate with PR: we need to supply entropy as this will * perform a reseed operation. */ t.entropy = td->entropypr_pr; t.entropylen = td->entropyprlen_pr; if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->katlen_pr, 1, td->adin_pr, td->adinlen_pr)) || !TEST_mem_eq(td->kat_pr, td->katlen_pr, buff, td->katlen_pr)) failures++; /* * Now generate again with PR: supply new entropy again. */ t.entropy = td->entropyg_pr; t.entropylen = td->entropyglen_pr; if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->kat2len_pr, 1, td->ading_pr, td->adinglen_pr)) || !TEST_mem_eq(td->kat2_pr, td->kat2len_pr, buff, td->kat2len_pr)) failures++; err: uninstantiate(drbg); RAND_DRBG_free(drbg); return failures == 0; }
/* * Perform extensive error checking as required by SP800-90. * Induce several failure modes and check an error condition is set. */ static int error_check(DRBG_SELFTEST_DATA *td) { static char zero[sizeof(RAND_DRBG)]; RAND_DRBG *drbg = NULL; TEST_CTX t; unsigned char buff[1024]; unsigned int reseed_counter_tmp; int ret = 0; if (!TEST_ptr(drbg = RAND_DRBG_new(td->nid, td->flags, NULL)) || !TEST_true(disable_crngt(drbg))) goto err; /* * Personalisation string tests */ /* Test detection of too large personlisation string */ if (!init(drbg, td, &t) || RAND_DRBG_instantiate(drbg, td->pers, drbg->max_perslen + 1) > 0) goto err; /* * Entropy source tests */ /* Test entropy source failure detection: i.e. returns no data */ t.entropylen = 0; if (TEST_int_le(RAND_DRBG_instantiate(drbg, td->pers, td->perslen), 0)) goto err; /* Try to generate output from uninstantiated DRBG */ if (!TEST_false(RAND_DRBG_generate(drbg, buff, td->exlen, 0, td->adin, td->adinlen)) || !uninstantiate(drbg)) goto err; /* Test insufficient entropy */ t.entropylen = drbg->min_entropylen - 1; if (!init(drbg, td, &t) || RAND_DRBG_instantiate(drbg, td->pers, td->perslen) > 0 || !uninstantiate(drbg)) goto err; /* Test too much entropy */ t.entropylen = drbg->max_entropylen + 1; if (!init(drbg, td, &t) || RAND_DRBG_instantiate(drbg, td->pers, td->perslen) > 0 || !uninstantiate(drbg)) goto err; /* * Nonce tests */ /* Test too small nonce */ if (drbg->min_noncelen) { t.noncelen = drbg->min_noncelen - 1; if (!init(drbg, td, &t) || RAND_DRBG_instantiate(drbg, td->pers, td->perslen) > 0 || !uninstantiate(drbg)) goto err; } /* Test too large nonce */ if (drbg->max_noncelen) { t.noncelen = drbg->max_noncelen + 1; if (!init(drbg, td, &t) || RAND_DRBG_instantiate(drbg, td->pers, td->perslen) > 0 || !uninstantiate(drbg)) goto err; } /* Instantiate with valid data, Check generation is now OK */ if (!instantiate(drbg, td, &t) || !TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0, td->adin, td->adinlen))) goto err; /* Request too much data for one request */ if (!TEST_false(RAND_DRBG_generate(drbg, buff, drbg->max_request + 1, 0, td->adin, td->adinlen))) goto err; /* Try too large additional input */ if (!TEST_false(RAND_DRBG_generate(drbg, buff, td->exlen, 0, td->adin, drbg->max_adinlen + 1))) goto err; /* * Check prediction resistance request fails if entropy source * failure. */ t.entropylen = 0; if (TEST_false(RAND_DRBG_generate(drbg, buff, td->exlen, 1, td->adin, td->adinlen)) || !uninstantiate(drbg)) goto err; /* Instantiate again with valid data */ if (!instantiate(drbg, td, &t)) goto err; reseed_counter_tmp = drbg->reseed_gen_counter; drbg->reseed_gen_counter = drbg->reseed_interval; /* Generate output and check entropy has been requested for reseed */ t.entropycnt = 0; if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0, td->adin, td->adinlen)) || !TEST_int_eq(t.entropycnt, 1) || !TEST_int_eq(drbg->reseed_gen_counter, reseed_counter_tmp + 1) || !uninstantiate(drbg)) goto err; /* * Check prediction resistance request fails if entropy source * failure. */ t.entropylen = 0; if (!TEST_false(RAND_DRBG_generate(drbg, buff, td->exlen, 1, td->adin, td->adinlen)) || !uninstantiate(drbg)) goto err; /* Test reseed counter works */ if (!instantiate(drbg, td, &t)) goto err; reseed_counter_tmp = drbg->reseed_gen_counter; drbg->reseed_gen_counter = drbg->reseed_interval; /* Generate output and check entropy has been requested for reseed */ t.entropycnt = 0; if (!TEST_true(RAND_DRBG_generate(drbg, buff, td->exlen, 0, td->adin, td->adinlen)) || !TEST_int_eq(t.entropycnt, 1) || !TEST_int_eq(drbg->reseed_gen_counter, reseed_counter_tmp + 1) || !uninstantiate(drbg)) goto err; /* * Explicit reseed tests */ /* Test explicit reseed with too large additional input */ if (!instantiate(drbg, td, &t) || RAND_DRBG_reseed(drbg, td->adin, drbg->max_adinlen + 1, 0) > 0) goto err; /* Test explicit reseed with entropy source failure */ t.entropylen = 0; if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) || !uninstantiate(drbg)) goto err; /* Test explicit reseed with too much entropy */ if (!instantiate(drbg, td, &t)) goto err; t.entropylen = drbg->max_entropylen + 1; if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) || !uninstantiate(drbg)) goto err; /* Test explicit reseed with too little entropy */ if (!instantiate(drbg, td, &t)) goto err; t.entropylen = drbg->min_entropylen - 1; if (!TEST_int_le(RAND_DRBG_reseed(drbg, td->adin, td->adinlen, 0), 0) || !uninstantiate(drbg)) goto err; /* Standard says we have to check uninstantiate really zeroes */ if (!TEST_mem_eq(zero, sizeof(drbg->data), &drbg->data, sizeof(drbg->data))) goto err; ret = 1; err: uninstantiate(drbg); RAND_DRBG_free(drbg); return ret; }