static int rand_drbg_restart(PROV_DRBG *drbg);
+/*
+ * We interpret a call to this function as a hint only and ignore it. This
+ * occurs when the EVP layer thinks we should do some locking. In practice
+ * however we manage for ourselves when we take a lock or not on the basis
+ * of whether drbg->lock is present or not.
+ */
int ossl_drbg_lock(void *vctx)
{
- PROV_DRBG *drbg = vctx;
-
- if (drbg == NULL || drbg->lock == NULL)
- return 1;
- return CRYPTO_THREAD_write_lock(drbg->lock);
+ return 1;
}
+/* Interpreted as a hint only and ignored as for ossl_drbg_lock() */
void ossl_drbg_unlock(void *vctx)
{
- PROV_DRBG *drbg = vctx;
-
- if (drbg != NULL && drbg->lock != NULL)
- CRYPTO_THREAD_unlock(drbg->lock);
}
static int ossl_drbg_lock_parent(PROV_DRBG *drbg)
return 1;
}
-/*
- * Reseed |drbg|, mixing in the specified data
- *
- * Requires that drbg->lock is already locked for write, if non-null.
- *
- * Returns 1 on success, 0 on failure.
- */
-int ossl_prov_drbg_reseed(PROV_DRBG *drbg, int prediction_resistance,
- const unsigned char *ent, size_t ent_len,
- const unsigned char *adin, size_t adinlen)
+static int ossl_prov_drbg_reseed_unlocked(PROV_DRBG *drbg,
+ int prediction_resistance,
+ const unsigned char *ent,
+ size_t ent_len,
+ const unsigned char *adin,
+ size_t adinlen)
{
unsigned char *entropy = NULL;
size_t entropylen = 0;
return 0;
}
+/*
+ * Reseed |drbg|, mixing in the specified data
+ *
+ * Acquires the drbg->lock for writing, if non-null.
+ *
+ * Returns 1 on success, 0 on failure.
+ */
+int ossl_prov_drbg_reseed(PROV_DRBG *drbg, int prediction_resistance,
+ const unsigned char *ent, size_t ent_len,
+ const unsigned char *adin, size_t adinlen)
+{
+ int ret;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
+ return 0;
+
+ ret = ossl_prov_drbg_reseed_unlocked(drbg, prediction_resistance, ent,
+ ent_len, adin, adinlen);
+
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
+}
+
/*
* Generate |outlen| bytes into the buffer at |out|. Reseed if we need
* to or if |prediction_resistance| is set. Additional input can be
* sent in |adin| and |adinlen|.
*
- * Requires that drbg->lock is already locked for write, if non-null.
+ * Acquires the drbg->lock for writing if available
*
* Returns 1 on success, 0 on failure.
*
{
int fork_id;
int reseed_required = 0;
+ int ret = 0;
if (!ossl_prov_is_running())
return 0;
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
+ return 0;
+
if (drbg->state != EVP_RAND_STATE_READY) {
/* try to recover from previous errors */
rand_drbg_restart(drbg);
if (drbg->state == EVP_RAND_STATE_ERROR) {
ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE);
- return 0;
+ goto err;
}
if (drbg->state == EVP_RAND_STATE_UNINITIALISED) {
ERR_raise(ERR_LIB_PROV, PROV_R_NOT_INSTANTIATED);
- return 0;
+ goto err;
}
}
if (strength > drbg->strength) {
ERR_raise(ERR_LIB_PROV, PROV_R_INSUFFICIENT_DRBG_STRENGTH);
- return 0;
+ goto err;
}
if (outlen > drbg->max_request) {
ERR_raise(ERR_LIB_PROV, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG);
- return 0;
+ goto err;
}
if (adinlen > drbg->max_adinlen) {
ERR_raise(ERR_LIB_PROV, PROV_R_ADDITIONAL_INPUT_TOO_LONG);
- return 0;
+ goto err;
}
fork_id = openssl_get_fork_id();
reseed_required = 1;
if (reseed_required || prediction_resistance) {
- if (!ossl_prov_drbg_reseed(drbg, prediction_resistance, NULL, 0,
- adin, adinlen)) {
+ if (!ossl_prov_drbg_reseed_unlocked(drbg, prediction_resistance, NULL,
+ 0, adin, adinlen)) {
ERR_raise(ERR_LIB_PROV, PROV_R_RESEED_ERROR);
- return 0;
+ goto err;
}
adin = NULL;
adinlen = 0;
if (!drbg->generate(drbg, out, outlen, adin, adinlen)) {
drbg->state = EVP_RAND_STATE_ERROR;
ERR_raise(ERR_LIB_PROV, PROV_R_GENERATE_ERROR);
- return 0;
+ goto err;
}
drbg->generate_counter++;
- return 1;
+ ret = 1;
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
}
/*
OPENSSL_free(drbg);
}
+/*
+ * Helper function called by internal DRBG implementations. Assumes that at
+ * least a read lock has been taken on drbg->lock
+ */
int ossl_drbg_get_ctx_params(PROV_DRBG *drbg, OSSL_PARAM params[])
{
OSSL_PARAM *p;
static OSSL_FUNC_rand_get_ctx_params_fn drbg_ctr_get_ctx_params;
static OSSL_FUNC_rand_verify_zeroization_fn drbg_ctr_verify_zeroization;
+static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]);
+
/*
* The state of a DRBG AES-CTR.
*/
const OSSL_PARAM params[])
{
PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+ int ret = 0;
- if (!ossl_prov_is_running() || !drbg_ctr_set_ctx_params(drbg, params))
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
return 0;
- return ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance,
- pstr, pstr_len);
+
+ if (!ossl_prov_is_running()
+ || !drbg_ctr_set_ctx_params_locked(drbg, params))
+ goto err;
+ ret = ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance,
+ pstr, pstr_len);
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+ return ret;
}
static int drbg_ctr_reseed(PROV_DRBG *drbg,
static int drbg_ctr_uninstantiate_wrapper(void *vdrbg)
{
- return drbg_ctr_uninstantiate((PROV_DRBG *)vdrbg);
+ PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+ int ret;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
+ return 0;
+
+ ret = drbg_ctr_uninstantiate(drbg);
+
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
}
static int drbg_ctr_verify_zeroization(void *vdrbg)
{
PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
+ int ret = 0;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_read_lock(drbg->lock))
+ return 0;
PROV_DRBG_VERYIFY_ZEROIZATION(ctr->K);
PROV_DRBG_VERYIFY_ZEROIZATION(ctr->V);
PROV_DRBG_VERYIFY_ZEROIZATION(ctr->bltmp);
PROV_DRBG_VERYIFY_ZEROIZATION(ctr->KX);
if (ctr->bltmp_pos != 0)
- return 0;
- return 1;
+ goto err;
+
+ ret = 1;
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+ return ret;
}
static int drbg_ctr_init_lengths(PROV_DRBG *drbg)
PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)drbg->data;
OSSL_PARAM *p;
+ int ret = 0;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_read_lock(drbg->lock))
+ return 0;
p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_USE_DF);
if (p != NULL && !OSSL_PARAM_set_int(p, ctr->use_df))
- return 0;
+ goto err;
p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_CIPHER);
if (p != NULL) {
if (ctr->cipher_ctr == NULL
|| !OSSL_PARAM_set_utf8_string(p,
EVP_CIPHER_get0_name(ctr->cipher_ctr)))
- return 0;
+ goto err;
}
- return ossl_drbg_get_ctx_params(drbg, params);
+ ret = ossl_drbg_get_ctx_params(drbg, params);
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
}
static const OSSL_PARAM *drbg_ctr_gettable_ctx_params(ossl_unused void *vctx,
return known_gettable_ctx_params;
}
-static int drbg_ctr_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+static int drbg_ctr_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[])
{
PROV_DRBG *ctx = (PROV_DRBG *)vctx;
PROV_DRBG_CTR *ctr = (PROV_DRBG_CTR *)ctx->data;
return ossl_drbg_set_ctx_params(ctx, params);
}
+static int drbg_ctr_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_DRBG *drbg = (PROV_DRBG *)vctx;
+ int ret;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
+ return 0;
+
+ ret = drbg_ctr_set_ctx_params_locked(vctx, params);
+
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
+}
+
static const OSSL_PARAM *drbg_ctr_settable_ctx_params(ossl_unused void *vctx,
ossl_unused void *provctx)
{
static OSSL_FUNC_rand_get_ctx_params_fn drbg_hash_get_ctx_params;
static OSSL_FUNC_rand_verify_zeroization_fn drbg_hash_verify_zeroization;
+static int drbg_hash_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]);
+
/* 888 bits from SP800-90Ar1 10.1 table 2 */
#define HASH_PRNG_MAX_SEEDLEN (888/8)
const OSSL_PARAM params[])
{
PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+ int ret = 0;
- if (!ossl_prov_is_running() || !drbg_hash_set_ctx_params(drbg, params))
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
return 0;
- return ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance,
- pstr, pstr_len);
+
+ if (!ossl_prov_is_running()
+ || !drbg_hash_set_ctx_params_locked(drbg, params))
+ goto err;
+ ret = ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance,
+ pstr, pstr_len);
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+ return ret;
}
/*
static int drbg_hash_uninstantiate_wrapper(void *vdrbg)
{
- return drbg_hash_uninstantiate((PROV_DRBG *)vdrbg);
+ PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+ int ret;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
+ return 0;
+
+ ret = drbg_hash_uninstantiate(drbg);
+
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
}
static int drbg_hash_verify_zeroization(void *vdrbg)
{
PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data;
+ int ret = 0;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_read_lock(drbg->lock))
+ return 0;
PROV_DRBG_VERYIFY_ZEROIZATION(hash->V);
PROV_DRBG_VERYIFY_ZEROIZATION(hash->C);
PROV_DRBG_VERYIFY_ZEROIZATION(hash->vtmp);
- return 1;
+
+ ret = 1;
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+ return ret;
}
static int drbg_hash_new(PROV_DRBG *ctx)
PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)drbg->data;
const EVP_MD *md;
OSSL_PARAM *p;
+ int ret = 0;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_read_lock(drbg->lock))
+ return 0;
p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_DIGEST);
if (p != NULL) {
md = ossl_prov_digest_md(&hash->digest);
if (md == NULL || !OSSL_PARAM_set_utf8_string(p, EVP_MD_get0_name(md)))
- return 0;
+ goto err;
}
- return ossl_drbg_get_ctx_params(drbg, params);
+ ret = ossl_drbg_get_ctx_params(drbg, params);
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
}
static const OSSL_PARAM *drbg_hash_gettable_ctx_params(ossl_unused void *vctx,
return known_gettable_ctx_params;
}
-static int drbg_hash_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+static int drbg_hash_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[])
{
PROV_DRBG *ctx = (PROV_DRBG *)vctx;
PROV_DRBG_HASH *hash = (PROV_DRBG_HASH *)ctx->data;
return ossl_drbg_set_ctx_params(ctx, params);
}
+static int drbg_hash_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_DRBG *drbg = (PROV_DRBG *)vctx;
+ int ret;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
+ return 0;
+
+ ret = drbg_hash_set_ctx_params_locked(vctx, params);
+
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
+}
+
static const OSSL_PARAM *drbg_hash_settable_ctx_params(ossl_unused void *vctx,
ossl_unused void *p_ctx)
{
static OSSL_FUNC_rand_get_ctx_params_fn drbg_hmac_get_ctx_params;
static OSSL_FUNC_rand_verify_zeroization_fn drbg_hmac_verify_zeroization;
+static int drbg_hmac_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[]);
+
/*
* Called twice by SP800-90Ar1 10.1.2.2 HMAC_DRBG_Update_Process.
*
const OSSL_PARAM params[])
{
PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+ int ret = 0;
- if (!ossl_prov_is_running() || !drbg_hmac_set_ctx_params(drbg, params))
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
return 0;
- return ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance,
- pstr, pstr_len);
+
+ if (!ossl_prov_is_running()
+ || !drbg_hmac_set_ctx_params_locked(drbg, params))
+ goto err;
+ ret = ossl_prov_drbg_instantiate(drbg, strength, prediction_resistance,
+ pstr, pstr_len);
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+ return ret;
}
+
/*
* SP800-90Ar1 10.1.2.4 HMAC_DRBG_Reseed_Process:
*
static int drbg_hmac_uninstantiate_wrapper(void *vdrbg)
{
- return drbg_hmac_uninstantiate((PROV_DRBG *)vdrbg);
+ PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
+ int ret;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
+ return 0;
+
+ ret = drbg_hmac_uninstantiate(drbg);
+
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
}
static int drbg_hmac_verify_zeroization(void *vdrbg)
{
PROV_DRBG *drbg = (PROV_DRBG *)vdrbg;
PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)drbg->data;
+ int ret = 0;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_read_lock(drbg->lock))
+ return 0;
PROV_DRBG_VERYIFY_ZEROIZATION(hmac->K);
PROV_DRBG_VERYIFY_ZEROIZATION(hmac->V);
- return 1;
+
+ ret = 1;
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+ return ret;
}
static int drbg_hmac_new(PROV_DRBG *drbg)
const char *name;
const EVP_MD *md;
OSSL_PARAM *p;
+ int ret = 0;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_read_lock(drbg->lock))
+ return 0;
p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_MAC);
if (p != NULL) {
if (hmac->ctx == NULL)
- return 0;
+ goto err;
name = EVP_MAC_get0_name(EVP_MAC_CTX_get0_mac(hmac->ctx));
if (!OSSL_PARAM_set_utf8_string(p, name))
- return 0;
+ goto err;
}
p = OSSL_PARAM_locate(params, OSSL_DRBG_PARAM_DIGEST);
if (p != NULL) {
md = ossl_prov_digest_md(&hmac->digest);
if (md == NULL || !OSSL_PARAM_set_utf8_string(p, EVP_MD_get0_name(md)))
- return 0;
+ goto err;
}
- return ossl_drbg_get_ctx_params(drbg, params);
+ ret = ossl_drbg_get_ctx_params(drbg, params);
+ err:
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
}
static const OSSL_PARAM *drbg_hmac_gettable_ctx_params(ossl_unused void *vctx,
return known_gettable_ctx_params;
}
-static int drbg_hmac_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+static int drbg_hmac_set_ctx_params_locked(void *vctx, const OSSL_PARAM params[])
{
PROV_DRBG *ctx = (PROV_DRBG *)vctx;
PROV_DRBG_HMAC *hmac = (PROV_DRBG_HMAC *)ctx->data;
return ossl_drbg_set_ctx_params(ctx, params);
}
+static int drbg_hmac_set_ctx_params(void *vctx, const OSSL_PARAM params[])
+{
+ PROV_DRBG *drbg = (PROV_DRBG *)vctx;
+ int ret;
+
+ if (drbg->lock != NULL && !CRYPTO_THREAD_write_lock(drbg->lock))
+ return 0;
+
+ ret = drbg_hmac_set_ctx_params_locked(vctx, params);
+
+ if (drbg->lock != NULL)
+ CRYPTO_THREAD_unlock(drbg->lock);
+
+ return ret;
+}
+
static const OSSL_PARAM *drbg_hmac_settable_ctx_params(ossl_unused void *vctx,
ossl_unused void *p_ctx)
{
\
for (i = 0; i < OSSL_NELEM(v); i++) \
if ((v)[i] != 0) \
- return 0; \
+ goto err; \
}
/* locking api */