rand: reference count the EVP_RAND contexts.
authorPauli <paul.dale@oracle.com>
Wed, 16 Sep 2020 01:10:01 +0000 (11:10 +1000)
committerPauli <paul.dale@oracle.com>
Tue, 22 Sep 2020 22:39:43 +0000 (08:39 +1000)
This is required before the RAND/DRBG framework can be made user mutable.

Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org>
(Merged from https://github.com/openssl/openssl/pull/12904)

crypto/evp/evp_local.h
crypto/evp/evp_rand.c
doc/man3/EVP_RAND.pod

index 3268aa4109132b8aead79c8e8d7fffd0be066161..285c69103b573e1a8930e5443a17aab191da7aa8 100644 (file)
@@ -69,6 +69,9 @@ struct evp_kdf_ctx_st {
 struct evp_rand_ctx_st {
     EVP_RAND *meth;             /* Method structure */
     void *data;                 /* Algorithm-specific data */
+    EVP_RAND_CTX *parent;       /* Parent EVP_RAND or NULL if none */
+    CRYPTO_REF_COUNT refcnt;    /* Context reference count */
+    CRYPTO_RWLOCK *refcnt_lock;
 } /* EVP_RAND_CTX */ ;
 
 struct evp_keymgmt_st {
index 0e5e8c11f9a505affd8fcd392160e25cce04b9d7..2e4edfff34674239b19503d811161e72bf6c2ffd 100644 (file)
@@ -308,6 +308,13 @@ int EVP_RAND_get_params(EVP_RAND *rand, OSSL_PARAM params[])
     return 1;
 }
 
+static int evp_rand_ctx_up_ref(EVP_RAND_CTX *ctx)
+{
+    int ref = 0;
+
+    return CRYPTO_UP_REF(&ctx->refcnt, &ref, ctx->refcnt_lock);
+}
+
 EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, EVP_RAND_CTX *parent)
 {
     EVP_RAND_CTX *ctx;
@@ -320,13 +327,21 @@ EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, EVP_RAND_CTX *parent)
     }
 
     ctx = OPENSSL_zalloc(sizeof(*ctx));
-    if (ctx == NULL) {
+    if (ctx == NULL || (ctx->refcnt_lock = CRYPTO_THREAD_lock_new()) == NULL) {
+        OPENSSL_free(ctx);
         EVPerr(0, ERR_R_MALLOC_FAILURE);
         return NULL;
     }
     if (parent != NULL) {
         if (!EVP_RAND_enable_locking(parent)) {
             EVPerr(0, EVP_R_UNABLE_TO_ENABLE_PARENT_LOCKING);
+            CRYPTO_THREAD_lock_free(ctx->refcnt_lock);
+            OPENSSL_free(ctx);
+            return NULL;
+        }
+        if (!evp_rand_ctx_up_ref(parent)) {
+            EVPerr(0, ERR_R_INTERNAL_ERROR);
+            CRYPTO_THREAD_lock_free(ctx->refcnt_lock);
             OPENSSL_free(ctx);
             return NULL;
         }
@@ -338,20 +353,33 @@ EVP_RAND_CTX *EVP_RAND_CTX_new(EVP_RAND *rand, EVP_RAND_CTX *parent)
             || !EVP_RAND_up_ref(rand)) {
         EVPerr(0, ERR_R_MALLOC_FAILURE);
         rand->freectx(ctx->data);
+        CRYPTO_THREAD_lock_free(ctx->refcnt_lock);
         OPENSSL_free(ctx);
+        EVP_RAND_CTX_free(parent);
         return NULL;
     }
     ctx->meth = rand;
+    ctx->parent = parent;
+    ctx->refcnt = 1;
     return ctx;
 }
 
 void EVP_RAND_CTX_free(EVP_RAND_CTX *ctx)
 {
     if (ctx != NULL) {
-        ctx->meth->freectx(ctx->data);
-        ctx->data = NULL;
-        EVP_RAND_free(ctx->meth);
-        OPENSSL_free(ctx);
+        int ref = 0;
+
+        CRYPTO_DOWN_REF(&ctx->refcnt, &ref, ctx->refcnt_lock);
+        if (ref <= 0) {
+            EVP_RAND_CTX *parent = ctx->parent;
+
+            ctx->meth->freectx(ctx->data);
+            ctx->data = NULL;
+            EVP_RAND_free(ctx->meth);
+            CRYPTO_THREAD_lock_free(ctx->refcnt_lock);
+            OPENSSL_free(ctx);
+            EVP_RAND_CTX_free(parent);
+        }
     }
 }
 
index dfd2a7eb4c0ee4b35c63abf5de2df51e50ac50d3..b7b836f03e15c0f8ac0bfb7a9efb858a23fed3ce 100644 (file)
@@ -85,6 +85,7 @@ cryptographically secure random bytes.
 B<EVP_RAND> is a type that holds the implementation of a RAND.
 
 B<EVP_RAND_CTX> is a context type that holds the algorithm inputs.
+B<EVP_RAND_CTX> structures are reference counted.
 
 =head2 Algorithm implementation fetching