/* * Uninstantiate |drbg| and free all memory. */ void RAND_DRBG_free(RAND_DRBG *drbg) { if (drbg == NULL) return; if (drbg->meth != NULL) drbg->meth->uninstantiate(drbg); rand_pool_free(drbg->adin_pool); CRYPTO_THREAD_lock_free(drbg->lock); CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DRBG, drbg, &drbg->ex_data); if (drbg->secure) OPENSSL_secure_clear_free(drbg, sizeof(*drbg)); else OPENSSL_clear_free(drbg, sizeof(*drbg)); }
/* * Set/initialize |drbg| to be of type |type|, with optional |flags|. * * If |type| and |flags| are zero, use the defaults * * Returns 1 on success, 0 on failure. */ int RAND_DRBG_set(RAND_DRBG *drbg, int type, unsigned int flags) { int ret = 1; if (type == 0 && flags == 0) { type = rand_drbg_type[RAND_DRBG_TYPE_MASTER]; flags = rand_drbg_flags[RAND_DRBG_TYPE_MASTER]; } /* If set is called multiple times - clear the old one */ if (drbg->type != 0 && (type != drbg->type || flags != drbg->flags)) { drbg->meth->uninstantiate(drbg); rand_pool_free(drbg->adin_pool); drbg->adin_pool = NULL; } drbg->state = DRBG_UNINITIALISED; drbg->flags = flags; drbg->type = type; if (type == 0) { /* Uninitialized; that's okay. */ drbg->meth = NULL; return 1; } else if (is_ctr(type)) { ret = drbg_ctr_init(drbg); } else if (is_digest(type)) { if (flags & RAND_DRBG_FLAG_HMAC) ret = drbg_hmac_init(drbg); else ret = drbg_hash_init(drbg); } else { drbg->type = 0; drbg->flags = 0; drbg->meth = NULL; RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_UNSUPPORTED_DRBG_TYPE); return 0; } if (ret == 0) { drbg->state = DRBG_ERROR; RANDerr(RAND_F_RAND_DRBG_SET, RAND_R_ERROR_INITIALISING_DRBG); } return ret; }
/* * Restart |drbg|, using the specified entropy or additional input * * Tries its best to get the drbg instantiated by all means, * regardless of its current state. * * Optionally, a |buffer| of |len| random bytes can be passed, * which is assumed to contain at least |entropy| bits of entropy. * * If |entropy| > 0, the buffer content is used as entropy input. * * If |entropy| == 0, the buffer content is used as additional input * * Returns 1 on success, 0 on failure. * * This function is used internally only. */ int rand_drbg_restart(RAND_DRBG *drbg, const unsigned char *buffer, size_t len, size_t entropy) { int reseeded = 0; const unsigned char *adin = NULL; size_t adinlen = 0; if (drbg->pool != NULL) { RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); rand_pool_free(drbg->pool); drbg->pool = NULL; } if (buffer != NULL) { if (entropy > 0) { if (drbg->max_entropylen < len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_INPUT_TOO_LONG); return 0; } if (entropy > 8 * len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ENTROPY_OUT_OF_RANGE); return 0; } /* will be picked up by the rand_drbg_get_entropy() callback */ drbg->pool = rand_pool_new(entropy, len, len); if (drbg->pool == NULL) return 0; rand_pool_add(drbg->pool, buffer, len, entropy); } else { if (drbg->max_adinlen < len) { RANDerr(RAND_F_RAND_DRBG_RESTART, RAND_R_ADDITIONAL_INPUT_TOO_LONG); return 0; } adin = buffer; adinlen = len; } } /* repair error state */ if (drbg->state == DRBG_ERROR) RAND_DRBG_uninstantiate(drbg); /* repair uninitialized state */ if (drbg->state == DRBG_UNINITIALISED) { /* reinstantiate drbg */ RAND_DRBG_instantiate(drbg, (const unsigned char *) ossl_pers_string, sizeof(ossl_pers_string) - 1); /* already reseeded. prevent second reseeding below */ reseeded = (drbg->state == DRBG_READY); } /* refresh current state if entropy or additional input has been provided */ if (drbg->state == DRBG_READY) { if (adin != NULL) { /* * mix in additional input without reseeding * * Similar to RAND_DRBG_reseed(), but the provided additional * data |adin| is mixed into the current state without pulling * entropy from the trusted entropy source using get_entropy(). * This is not a reseeding in the strict sense of NIST SP 800-90A. */ drbg->meth->reseed(drbg, adin, adinlen, NULL, 0); } else if (reseeded == 0) { /* do a full reseeding if it has not been done yet above */ RAND_DRBG_reseed(drbg, NULL, 0, 0); } } /* check whether a given entropy pool was cleared properly during reseed */ if (drbg->pool != NULL) { drbg->state = DRBG_ERROR; RANDerr(RAND_F_RAND_DRBG_RESTART, ERR_R_INTERNAL_ERROR); rand_pool_free(drbg->pool); drbg->pool = NULL; return 0; } return drbg->state == DRBG_READY; }
/* * Instantiate |drbg|, after it has been initialized. Use |pers| and * |perslen| as prediction-resistance input. * * Requires that drbg->lock is already locked for write, if non-null. * * Returns 1 on success, 0 on failure. */ int RAND_DRBG_instantiate(RAND_DRBG *drbg, const unsigned char *pers, size_t perslen) { unsigned char *nonce = NULL, *entropy = NULL; size_t noncelen = 0, entropylen = 0; if (perslen > drbg->max_perslen) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_PERSONALISATION_STRING_TOO_LONG); goto end; } if (drbg->meth == NULL) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); goto end; } if (drbg->state != DRBG_UNINITIALISED) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, drbg->state == DRBG_ERROR ? RAND_R_IN_ERROR_STATE : RAND_R_ALREADY_INSTANTIATED); goto end; } drbg->state = DRBG_ERROR; if (drbg->get_entropy != NULL) entropylen = drbg->get_entropy(drbg, &entropy, drbg->strength, drbg->min_entropylen, drbg->max_entropylen, 0); if (entropylen < drbg->min_entropylen || entropylen > drbg->max_entropylen) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY); goto end; } if (drbg->max_noncelen > 0 && drbg->get_nonce != NULL) { noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2, drbg->min_noncelen, drbg->max_noncelen); if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE); goto end; } } if (!drbg->meth->instantiate(drbg, entropy, entropylen, nonce, noncelen, pers, perslen)) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_INSTANTIATING_DRBG); goto end; } drbg->state = DRBG_READY; drbg->generate_counter = 0; drbg->reseed_time = time(NULL); if (drbg->reseed_counter > 0) { if (drbg->parent == NULL) drbg->reseed_counter++; else drbg->reseed_counter = drbg->parent->reseed_counter; } end: if (entropy != NULL && drbg->cleanup_entropy != NULL) drbg->cleanup_entropy(drbg, entropy, entropylen); if (nonce != NULL && drbg->cleanup_nonce!= NULL ) drbg->cleanup_nonce(drbg, nonce, noncelen); if (drbg->pool != NULL) { if (drbg->state == DRBG_READY) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED); drbg->state = DRBG_ERROR; } rand_pool_free(drbg->pool); drbg->pool = NULL; } if (drbg->state == DRBG_READY) return 1; return 0; }
/* * Instantiate |drbg|, after it has been initialized. Use |pers| and * |perslen| as prediction-resistance input. * * Requires that drbg->lock is already locked for write, if non-null. * * Returns 1 on success, 0 on failure. */ int RAND_DRBG_instantiate(RAND_DRBG *drbg, const unsigned char *pers, size_t perslen) { unsigned char *nonce = NULL, *entropy = NULL; size_t noncelen = 0, entropylen = 0; size_t min_entropy = drbg->strength; size_t min_entropylen = drbg->min_entropylen; size_t max_entropylen = drbg->max_entropylen; if (perslen > drbg->max_perslen) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_PERSONALISATION_STRING_TOO_LONG); goto end; } if (drbg->meth == NULL) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_NO_DRBG_IMPLEMENTATION_SELECTED); goto end; } if (drbg->state != DRBG_UNINITIALISED) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, drbg->state == DRBG_ERROR ? RAND_R_IN_ERROR_STATE : RAND_R_ALREADY_INSTANTIATED); goto end; } drbg->state = DRBG_ERROR; /* * NIST SP800-90Ar1 section 9.1 says you can combine getting the entropy * and nonce in 1 call by increasing the entropy with 50% and increasing * the minimum length to accomadate the length of the nonce. * We do this in case a nonce is require and get_nonce is NULL. */ if (drbg->min_noncelen > 0 && drbg->get_nonce == NULL) { min_entropy += drbg->strength / 2; min_entropylen += drbg->min_noncelen; max_entropylen += drbg->max_noncelen; } if (drbg->get_entropy != NULL) entropylen = drbg->get_entropy(drbg, &entropy, min_entropy, min_entropylen, max_entropylen, 0); if (entropylen < min_entropylen || entropylen > max_entropylen) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_ENTROPY); goto end; } if (drbg->min_noncelen > 0 && drbg->get_nonce != NULL) { noncelen = drbg->get_nonce(drbg, &nonce, drbg->strength / 2, drbg->min_noncelen, drbg->max_noncelen); if (noncelen < drbg->min_noncelen || noncelen > drbg->max_noncelen) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_RETRIEVING_NONCE); goto end; } } if (!drbg->meth->instantiate(drbg, entropy, entropylen, nonce, noncelen, pers, perslen)) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_INSTANTIATING_DRBG); goto end; } drbg->state = DRBG_READY; drbg->generate_counter = 0; drbg->reseed_time = time(NULL); if (drbg->reseed_counter > 0) { if (drbg->parent == NULL) drbg->reseed_counter++; else drbg->reseed_counter = drbg->parent->reseed_counter; } end: if (entropy != NULL && drbg->cleanup_entropy != NULL) drbg->cleanup_entropy(drbg, entropy, entropylen); if (nonce != NULL && drbg->cleanup_nonce!= NULL ) drbg->cleanup_nonce(drbg, nonce, noncelen); if (drbg->pool != NULL) { if (drbg->state == DRBG_READY) { RANDerr(RAND_F_RAND_DRBG_INSTANTIATE, RAND_R_ERROR_ENTROPY_POOL_WAS_IGNORED); drbg->state = DRBG_ERROR; } rand_pool_free(drbg->pool); drbg->pool = NULL; } if (drbg->state == DRBG_READY) return 1; return 0; }