/* * Allocate memory and initialize a new DRBG. The DRBG is allocated on * the secure heap if |secure| is nonzero and the secure heap is enabled. * The |parent|, if not NULL, will be used as random source for reseeding. * * Returns a pointer to the new DRBG instance on success, NULL on failure. */ static RAND_DRBG *rand_drbg_new(int secure, int type, unsigned int flags, RAND_DRBG *parent) { RAND_DRBG *drbg = secure ? OPENSSL_secure_zalloc(sizeof(*drbg)) : OPENSSL_zalloc(sizeof(*drbg)); if (drbg == NULL) { RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); return NULL; } drbg->secure = secure && CRYPTO_secure_allocated(drbg); drbg->fork_count = rand_fork_count; drbg->parent = parent; if (parent == NULL) { drbg->reseed_interval = master_reseed_interval; drbg->reseed_time_interval = master_reseed_time_interval; } else { drbg->reseed_interval = slave_reseed_interval; drbg->reseed_time_interval = slave_reseed_time_interval; } if (RAND_DRBG_set(drbg, type, flags) == 0) goto err; if (parent != NULL) { rand_drbg_lock(parent); if (drbg->strength > parent->strength) { /* * We currently don't support the algorithm from NIST SP 800-90C * 10.1.2 to use a weaker DRBG as source */ rand_drbg_unlock(parent); RANDerr(RAND_F_RAND_DRBG_NEW, RAND_R_PARENT_STRENGTH_TOO_WEAK); goto err; } rand_drbg_unlock(parent); } if (!RAND_DRBG_set_callbacks(drbg, rand_drbg_get_entropy, rand_drbg_cleanup_entropy, NULL, NULL)) goto err; return drbg; err: if (drbg->secure) OPENSSL_secure_free(drbg); else OPENSSL_free(drbg); return NULL; }
/* * Allocates a new global DRBG on the secure heap (if enabled) and * initializes it with default settings. * A global lock for the DRBG is created with the given name. * * Returns a pointer to the new DRBG instance on success, NULL on failure. */ static RAND_DRBG *drbg_setup(const char *name, RAND_DRBG *parent) { RAND_DRBG *drbg; if (name == NULL) { RANDerr(RAND_F_DRBG_SETUP, ERR_R_INTERNAL_ERROR); return NULL; } drbg = OPENSSL_secure_zalloc(sizeof(RAND_DRBG)); if (drbg == NULL) return NULL; drbg->lock = CRYPTO_THREAD_glock_new(name); if (drbg->lock == NULL) { RANDerr(RAND_F_DRBG_SETUP, RAND_R_FAILED_TO_CREATE_LOCK); goto err; } if (RAND_DRBG_set(drbg, RAND_DRBG_NID, RAND_DRBG_FLAG_CTR_USE_DF) != 1) goto err; if (RAND_DRBG_set_callbacks(drbg, rand_drbg_get_entropy, rand_drbg_cleanup_entropy, NULL, NULL) != 1) goto err; if (parent == NULL) { drbg->reseed_interval = MASTER_RESEED_INTERVAL; drbg->reseed_time_interval = MASTER_RESEED_TIME_INTERVAL; } else { drbg->parent = parent; drbg->reseed_interval = SLAVE_RESEED_INTERVAL; drbg->reseed_time_interval = SLAVE_RESEED_TIME_INTERVAL; } /* enable seed propagation */ drbg->reseed_counter = 1; /* * Ignore instantiation error so support just-in-time instantiation. * * The state of the drbg will be checked in RAND_DRBG_generate() and * an automatic recovery is attempted. */ RAND_DRBG_instantiate(drbg, (const unsigned char *) ossl_pers_string, sizeof(ossl_pers_string) - 1); return drbg; err: drbg_cleanup(drbg); return NULL; }
/* * Initialise a DRBG based on selftest data */ static int init(RAND_DRBG *drbg, DRBG_SELFTEST_DATA *td, TEST_CTX *t) { if (!TEST_true(RAND_DRBG_set(drbg, td->nid, td->flags)) || !TEST_true(RAND_DRBG_set_callbacks(drbg, kat_entropy, NULL, kat_nonce, NULL))) return 0; RAND_DRBG_set_ex_data(drbg, app_data_index, t); t->entropy = td->entropy; t->entropylen = td->entropylen; t->nonce = td->nonce; t->noncelen = td->noncelen; t->entropycnt = 0; t->noncecnt = 0; return 1; }
/* * Set up a global DRBG. */ static int setup_drbg(RAND_DRBG *drbg) { int ret = 1; drbg->lock = CRYPTO_THREAD_lock_new(); ret &= drbg->lock != NULL; drbg->size = RANDOMNESS_NEEDED; drbg->secure = CRYPTO_secure_malloc_initialized(); drbg->randomness = NULL; /* If you change these parameters, see RANDOMNESS_NEEDED */ ret &= RAND_DRBG_set(drbg, NID_aes_128_ctr, RAND_DRBG_FLAG_CTR_USE_DF) == 1; ret &= RAND_DRBG_set_callbacks(drbg, drbg_entropy_from_system, drbg_release_entropy, NULL, NULL) == 1; return ret; }
/* * Disable CRNG testing if it is enabled. * If the DRBG is ready or in an error state, this means an instantiate cycle * for which the default personalisation string is used. */ static int disable_crngt(RAND_DRBG *drbg) { static const char pers[] = DRBG_DEFAULT_PERS_STRING; const int instantiate = drbg->state != DRBG_UNINITIALISED; if (drbg->get_entropy != rand_crngt_get_entropy) return 1; if ((instantiate && !RAND_DRBG_uninstantiate(drbg)) || !TEST_true(RAND_DRBG_set_callbacks(drbg, &rand_drbg_get_entropy, &rand_drbg_cleanup_entropy, &rand_drbg_get_nonce, &rand_drbg_cleanup_nonce)) || (instantiate && !RAND_DRBG_instantiate(drbg, (const unsigned char *)pers, sizeof(pers) - 1))) return 0; return 1; }
/* * Allocate memory and initialize a new DRBG. The |parent|, if not * NULL, will be used to auto-seed this RAND_DRBG as needed. * * Returns a pointer to the new DRBG instance on success, NULL on failure. */ RAND_DRBG *RAND_DRBG_new(int type, unsigned int flags, RAND_DRBG *parent) { RAND_DRBG *drbg = OPENSSL_zalloc(sizeof(*drbg)); if (drbg == NULL) { RANDerr(RAND_F_RAND_DRBG_NEW, ERR_R_MALLOC_FAILURE); goto err; } drbg->fork_count = rand_fork_count; drbg->parent = parent; if (RAND_DRBG_set(drbg, type, flags) == 0) goto err; if (!RAND_DRBG_set_callbacks(drbg, rand_drbg_get_entropy, rand_drbg_cleanup_entropy, NULL, NULL)) goto err; return drbg; err: OPENSSL_free(drbg); return NULL; }
/* * 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; }