Make the rand_crng code OPENSSL_CTX aware
authorMatt Caswell <matt@openssl.org>
Thu, 23 May 2019 15:51:55 +0000 (16:51 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 7 Jun 2019 11:04:34 +0000 (12:04 +0100)
This is in preparation for moving this code inside the FIPS module.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/9039)

crypto/rand/rand_crng_test.c
crypto/rand/rand_lcl.h
include/internal/cryptlib.h
test/drbgtest.c

index 1b4f167..11d85f3 100644 (file)
 #include <openssl/evp.h>
 #include "internal/rand_int.h"
 #include "internal/thread_once.h"
+#include "internal/cryptlib.h"
 #include "rand_lcl.h"
 
-static RAND_POOL *crngt_pool;
-static unsigned char crngt_prev[EVP_MAX_MD_SIZE];
+typedef struct crng_test_global_st {
+    unsigned char crngt_prev[EVP_MAX_MD_SIZE];
+    RAND_POOL *crngt_pool;
+} CRNG_TEST_GLOBAL;
 
-int (*crngt_get_entropy)(unsigned char *, unsigned char *, unsigned int *)
+int (*crngt_get_entropy)(OPENSSL_CTX *, unsigned char *, unsigned char *,
+                         unsigned int *)
     = &rand_crngt_get_entropy_cb;
 
-int rand_crngt_get_entropy_cb(unsigned char *buf, unsigned char *md,
-                              unsigned int *md_size)
+static void rand_crng_ossl_ctx_free(void *vcrngt_glob)
 {
-    int r;
-    size_t n;
-    unsigned char *p;
+    CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob;
 
-    n = rand_pool_acquire_entropy(crngt_pool);
-    if (n >= CRNGT_BUFSIZ) {
-        p = rand_pool_detach(crngt_pool);
-        r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, EVP_sha256(), NULL);
-        if (r != 0)
-            memcpy(buf, p, CRNGT_BUFSIZ);
-        rand_pool_reattach(crngt_pool, p);
-        return r;
-    }
-    return 0;
-}
-
-void rand_crngt_cleanup(void)
-{
-    rand_pool_free(crngt_pool);
-    crngt_pool = NULL;
+    rand_pool_free(crngt_glob->crngt_pool);
+    OPENSSL_free(crngt_glob);
 }
 
-int rand_crngt_init(void)
+static void *rand_crng_ossl_ctx_new(OPENSSL_CTX *ctx)
 {
     unsigned char buf[CRNGT_BUFSIZ];
+    CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob));
 
-    if ((crngt_pool = rand_pool_new(0, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL)
-        return 0;
-    if (crngt_get_entropy(buf, crngt_prev, NULL)) {
+    if (crngt_glob == NULL)
+        return NULL;
+
+    if ((crngt_glob->crngt_pool
+         = rand_pool_new(0, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL) {
+        OPENSSL_free(crngt_glob);
+        return NULL;
+    }
+    if (crngt_get_entropy(ctx, buf, crngt_glob->crngt_prev, NULL)) {
         OPENSSL_cleanse(buf, sizeof(buf));
-        return 1;
+        return crngt_glob;
     }
-    rand_crngt_cleanup();
-    return 0;
+    rand_pool_free(crngt_glob->crngt_pool);
+    OPENSSL_free(crngt_glob);
+    return NULL;
 }
 
-static CRYPTO_ONCE rand_crngt_init_flag = CRYPTO_ONCE_STATIC_INIT;
-DEFINE_RUN_ONCE_STATIC(do_rand_crngt_init)
-{
-    return OPENSSL_init_crypto(0, NULL)
-        && rand_crngt_init()
-        && OPENSSL_atexit(&rand_crngt_cleanup);
-}
+static const OPENSSL_CTX_METHOD rand_crng_ossl_ctx_method = {
+    rand_crng_ossl_ctx_new,
+    rand_crng_ossl_ctx_free,
+};
 
-int rand_crngt_single_init(void)
+int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx,
+                              unsigned char *buf,
+                              unsigned char *md,
+                              unsigned int *md_size)
 {
-    return RUN_ONCE(&rand_crngt_init_flag, do_rand_crngt_init);
+    int r;
+    size_t n;
+    unsigned char *p;
+    CRNG_TEST_GLOBAL *crngt_glob
+        = openssl_ctx_get_data(ctx, OPENSSL_CTX_RAND_CRNGT_INDEX,
+                               &rand_crng_ossl_ctx_method);
+
+    if (crngt_glob == NULL)
+        return 0;
+
+    n = rand_pool_acquire_entropy(crngt_glob->crngt_pool);
+    if (n >= CRNGT_BUFSIZ) {
+        p = rand_pool_detach(crngt_glob->crngt_pool);
+        r = EVP_Digest(p, CRNGT_BUFSIZ, md, md_size, EVP_sha256(), NULL);
+        if (r != 0)
+            memcpy(buf, p, CRNGT_BUFSIZ);
+        rand_pool_reattach(crngt_glob->crngt_pool, p);
+        return r;
+    }
+    return 0;
 }
 
 size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
@@ -86,8 +100,11 @@ size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
     RAND_POOL *pool;
     size_t q, r = 0, s, t = 0;
     int attempts = 3;
+    CRNG_TEST_GLOBAL *crngt_glob
+        = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_RAND_CRNGT_INDEX,
+                               &rand_crng_ossl_ctx_method);
 
-    if (!RUN_ONCE(&rand_crngt_init_flag, do_rand_crngt_init))
+    if (crngt_glob == NULL)
         return 0;
 
     if ((pool = rand_pool_new(entropy, min_len, max_len)) == NULL)
@@ -95,11 +112,11 @@ size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
 
     while ((q = rand_pool_bytes_needed(pool, 1)) > 0 && attempts-- > 0) {
         s = q > sizeof(buf) ? sizeof(buf) : q;
-        if (!crngt_get_entropy(buf, md, &sz)
-            || memcmp(crngt_prev, md, sz) == 0
+        if (!crngt_get_entropy(drbg->libctx, buf, md, &sz)
+            || memcmp(crngt_glob->crngt_prev, md, sz) == 0
             || !rand_pool_add(pool, buf, s, s * 8))
             goto err;
-        memcpy(crngt_prev, md, sz);
+        memcpy(crngt_glob->crngt_prev, md, sz);
         t += s;
         attempts++;
     }
index 4e1c9c0..97126bc 100644 (file)
@@ -336,18 +336,10 @@ int drbg_hmac_init(RAND_DRBG *drbg);
  * Entropy call back for the FIPS 140-2 section 4.9.2 Conditional Tests.
  * These need to be exposed for the unit tests.
  */
-int rand_crngt_get_entropy_cb(unsigned char *buf, unsigned char *md,
-                              unsigned int *md_size);
-extern int (*crngt_get_entropy)(unsigned char *buf, unsigned char *md,
+int rand_crngt_get_entropy_cb(OPENSSL_CTX *ctx, unsigned char *buf,
+                              unsigned char *md, unsigned int *md_size);
+extern int (*crngt_get_entropy)(OPENSSL_CTX *ctx, unsigned char *buf,
+                                unsigned char *md,
                                 unsigned int *md_size);
-int rand_crngt_init(void);
-void rand_crngt_cleanup(void);
-
-/*
- * Expose the run once initialisation function for the unit tests because.
- * they need to restart from scratch to validate the first block is skipped
- * properly.
- */
-int rand_crngt_single_init(void);
 
 #endif
index 9ec1a37..585263a 100644 (file)
@@ -147,7 +147,8 @@ typedef struct ossl_ex_data_global_st {
 # define OPENSSL_CTX_PROPERTY_STRING_INDEX          3
 # define OPENSSL_CTX_NAMEMAP_INDEX                  4
 # define OPENSSL_CTX_DRBG_INDEX                     5
-# define OPENSSL_CTX_MAX_INDEXES                    6
+# define OPENSSL_CTX_RAND_CRNGT_INDEX               6
+# define OPENSSL_CTX_MAX_INDEXES                    7
 
 typedef struct openssl_ctx_method {
     void *(*new_func)(OPENSSL_CTX *ctx);
index 9e0aba8..618403f 100644 (file)
@@ -1264,7 +1264,8 @@ static const size_t crngt_num_cases = 6;
 
 static size_t crngt_case, crngt_idx;
 
-static int crngt_entropy_cb(unsigned char *buf, unsigned char *md,
+static int crngt_entropy_cb(OPENSSL_CTX *ctx, unsigned char *buf,
+                            unsigned char *md,
                             unsigned int *md_size)
 {
     size_t i, z;
@@ -1288,19 +1289,16 @@ static int test_crngt(int n)
     size_t ent;
     int res = 0;
     int expect;
+    OPENSSL_CTX *ctx = OPENSSL_CTX_new();
 
-    if (!TEST_true(rand_crngt_single_init()))
-        return 0;
-    rand_crngt_cleanup();
-
-    if (!TEST_ptr(drbg = RAND_DRBG_new(dt->nid, dt->flags, NULL)))
+    if (!TEST_ptr(ctx))
         return 0;
+    if (!TEST_ptr(drbg = RAND_DRBG_new_ex(ctx, dt->nid, dt->flags, NULL)))
+        goto err;
     ent = (drbg->min_entropylen + CRNGT_BUFSIZ - 1) / CRNGT_BUFSIZ;
     crngt_case = n % crngt_num_cases;
     crngt_idx = 0;
     crngt_get_entropy = &crngt_entropy_cb;
-    if (!TEST_true(rand_crngt_init()))
-        goto err;
 #ifndef FIPS_MODE
     if (!TEST_true(RAND_DRBG_set_callbacks(drbg, &rand_crngt_get_entropy,
                                            &rand_crngt_cleanup_entropy,
@@ -1333,6 +1331,7 @@ err:
     uninstantiate(drbg);
     RAND_DRBG_free(drbg);
     crngt_get_entropy = &rand_crngt_get_entropy_cb;
+    OPENSSL_CTX_free(ctx);
     return res;
 }