Make the rand_crng code OPENSSL_CTX aware
[openssl.git] / crypto / rand / rand_crng_test.c
index 74a64ee53193ac89a50ac7353a553dc81d9338d1..11d85f395d7e796798367a8c33583fb914c63629 100644 (file)
  */
 
 #include <string.h>
+#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;
+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 *) = &rand_crngt_get_entropy_cb;
+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)
+static void rand_crng_ossl_ctx_free(void *vcrngt_glob)
 {
-    size_t n;
-    unsigned char *p;
-
-    while ((n = rand_pool_acquire_entropy(crngt_pool)) != 0)
-        if (n >= CRNGT_BUFSIZ) {
-            p = rand_pool_detach(crngt_pool);
-            memcpy(crngt_prev, p, CRNGT_BUFSIZ);
-            rand_pool_reattach(crngt_pool, p);
-            return 1;
-        }
-    return 0;
+    CRNG_TEST_GLOBAL *crngt_glob = vcrngt_glob;
 
-}
-void rand_crngt_cleanup(void)
-{
-    rand_pool_free(crngt_pool);
-    OPENSSL_secure_free(crngt_prev);
-    crngt_pool = NULL;
-    crngt_prev = 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)
 {
-    if ((crngt_pool = rand_pool_new(0, CRNGT_BUFSIZ, CRNGT_BUFSIZ)) == NULL)
-        return 0;
-    if ((crngt_prev = OPENSSL_secure_malloc(CRNGT_BUFSIZ)) != NULL
-        && crngt_get_entropy(crngt_prev))
-        return 1;
-    rand_crngt_cleanup();
-    return 0;
-}
+    unsigned char buf[CRNGT_BUFSIZ];
+    CRNG_TEST_GLOBAL *crngt_glob = OPENSSL_zalloc(sizeof(*crngt_glob));
 
-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);
+    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 crngt_glob;
+    }
+    rand_pool_free(crngt_glob->crngt_pool);
+    OPENSSL_free(crngt_glob);
+    return NULL;
 }
 
-int rand_crngt_single_init(void)
+static const OPENSSL_CTX_METHOD rand_crng_ossl_ctx_method = {
+    rand_crng_ossl_ctx_new,
+    rand_crng_ossl_ctx_free,
+};
+
+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,
@@ -74,12 +95,16 @@ size_t rand_crngt_get_entropy(RAND_DRBG *drbg,
                               int entropy, size_t min_len, size_t max_len,
                               int prediction_resistance)
 {
-    unsigned char buf[CRNGT_BUFSIZ];
+    unsigned char buf[CRNGT_BUFSIZ], md[EVP_MAX_MD_SIZE];
+    unsigned int sz;
     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)
@@ -87,17 +112,18 @@ 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)
-            || memcmp(crngt_prev, buf, CRNGT_BUFSIZ) == 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, buf, CRNGT_BUFSIZ);
+        memcpy(crngt_glob->crngt_prev, md, sz);
         t += s;
         attempts++;
     }
     r = t;
     *pout = rand_pool_detach(pool);
 err:
+    OPENSSL_cleanse(buf, sizeof(buf));
     rand_pool_free(pool);
     return r;
 }