]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Refactor the DRBG implementations to manage locking themselves
authorMatt Caswell <matt@openssl.org>
Mon, 15 May 2023 10:33:01 +0000 (11:33 +0100)
committerPauli <pauli@openssl.org>
Thu, 1 Jun 2023 21:30:04 +0000 (07:30 +1000)
Previously the EVP layer would call lock and unlock functions on the
underlying DRBG implementation to say when a lock should be acquired and
released. This gives the DRBG implementation no say as to what kind of
lock should obtained (e.g. read/write) or even whether a lock is actually
needed or not.

In reality we know whether a DRBG is supposed to be in locking mode or
not because the "enable_locking()" function will have been called if
locks should be used. Therefore we re-interpret the lock and unlock
functions as "hints" from the EVP layer which we ignore. Instead we
acquire locks only when we need them. By knowing the context we can obtain
either a read or a write lock as appropriate.

This may mean that in some rare cases we acquire the locks more than once
for a single EVP call, if the EVP call makes several calls to the underlying
DRBG. But in practice almost all EVP calls only make one such call.
EVP_RAND_generate() is an example of a call where multiple DRBG calls may
be made. One of these gets the "max_request" parameter (which is constant
for all of our own DRBGs) and it may make several calls to the DRBG generate
call - but only if the requested size is very large which will rarely be
the case.

Partially fixes #20286

Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Todd Short <todd.short@me.com>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/20970)

providers/implementations/rands/drbg.c
providers/implementations/rands/drbg_ctr.c
providers/implementations/rands/drbg_hash.c
providers/implementations/rands/drbg_hmac.c
providers/implementations/rands/drbg_local.h

index a41b994a055e90449b909d65094106c109025d31..4b16873724249b0c2f243dc93b4f72fdcae7f0ff 100644 (file)
@@ -45,21 +45,20 @@ static const OSSL_DISPATCH *find_call(const OSSL_DISPATCH *dispatch,
 
 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)
@@ -484,16 +483,12 @@ int ossl_prov_drbg_uninstantiate(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;
@@ -595,12 +590,37 @@ int ossl_prov_drbg_reseed(PROV_DRBG *drbg, int prediction_resistance,
     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.
  *
@@ -611,35 +631,39 @@ int ossl_prov_drbg_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen,
 {
     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();
@@ -664,10 +688,10 @@ int ossl_prov_drbg_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen,
         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;
@@ -676,12 +700,17 @@ int ossl_prov_drbg_generate(PROV_DRBG *drbg, unsigned char *out, size_t outlen,
     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;
 }
 
 /*
@@ -848,6 +877,10 @@ void ossl_rand_drbg_free(PROV_DRBG *drbg)
     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;
index 07825957989a20294ecc9e8866ad6ec98b3a3d62..40d7dbe86d622acfa6fb4d5472836ae22a85e056 100644 (file)
@@ -33,6 +33,8 @@ static OSSL_FUNC_rand_gettable_ctx_params_fn drbg_ctr_gettable_ctx_params;
 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.
  */
@@ -330,11 +332,20 @@ static int drbg_ctr_instantiate_wrapper(void *vdrbg, unsigned int strength,
                                         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,
@@ -473,21 +484,41 @@ static int drbg_ctr_uninstantiate(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)
@@ -627,20 +658,29 @@ static int drbg_ctr_get_ctx_params(void *vdrbg, OSSL_PARAM params[])
     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,
@@ -655,7 +695,7 @@ 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;
@@ -712,6 +752,22 @@ static int drbg_ctr_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     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)
 {
index b2017a4f06ed7965492bdd180c33e05432e5c8a0..a911840c9b15a4535b043cfd317ca0d4ace5dcc3 100644 (file)
@@ -35,6 +35,8 @@ static OSSL_FUNC_rand_gettable_ctx_params_fn drbg_hash_gettable_ctx_params;
 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)
 
@@ -270,11 +272,20 @@ static int drbg_hash_instantiate_wrapper(void *vdrbg, unsigned int strength,
                                          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;
 }
 
 /*
@@ -371,18 +382,38 @@ static int drbg_hash_uninstantiate(PROV_DRBG *drbg)
 
 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)
@@ -432,15 +463,24 @@ static int drbg_hash_get_ctx_params(void *vdrbg, OSSL_PARAM params[])
     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,
@@ -454,7 +494,7 @@ 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;
@@ -487,6 +527,22 @@ static int drbg_hash_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     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)
 {
index 0e4bc8082a4911fe13e74879ee9581ca3d9bdbd4..4c6482894bba820041d2a262efe7a6fcbade7077 100644 (file)
@@ -32,6 +32,8 @@ static OSSL_FUNC_rand_gettable_ctx_params_fn drbg_hmac_gettable_ctx_params;
 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.
  *
@@ -143,13 +145,23 @@ static int drbg_hmac_instantiate_wrapper(void *vdrbg, unsigned int strength,
                                          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:
  *
@@ -263,17 +275,37 @@ static int drbg_hmac_uninstantiate(PROV_DRBG *drbg)
 
 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)
@@ -324,24 +356,33 @@ static int drbg_hmac_get_ctx_params(void *vdrbg, OSSL_PARAM params[])
     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,
@@ -356,7 +397,7 @@ 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;
@@ -389,6 +430,22 @@ static int drbg_hmac_set_ctx_params(void *vctx, const OSSL_PARAM params[])
     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)
 {
index 776b44882c5197ab38dcc71ee72bf8f9d76d2ea8..c3df1bc9627798189123198dda83a228369680da 100644 (file)
@@ -212,7 +212,7 @@ OSSL_FUNC_rand_clear_seed_fn ossl_drbg_clear_seed;
                                             \
         for (i = 0; i < OSSL_NELEM(v); i++) \
             if ((v)[i] != 0)                \
-                return 0;                   \
+                goto err;                   \
     }
 
 /* locking api */