Move the rand_nonce_lock code into drbg_lib.c
authorMatt Caswell <matt@openssl.org>
Fri, 24 May 2019 15:36:44 +0000 (16:36 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 7 Jun 2019 11:04:42 +0000 (12:04 +0100)
It was previously rand_lib but it makes more sense in drbg_lib.c since
all the functions that use this lock are only ever called from drbg_lib.c

We add some FIPS_MODE defines in preparation for later moving this code
into the FIPS module.

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

crypto/init.c
crypto/rand/drbg_lib.c
crypto/rand/rand_lib.c
include/internal/cryptlib.h

index 6a1f5ea..e73c9ba 100644 (file)
@@ -852,5 +852,6 @@ void OPENSSL_fork_parent(void)
 void OPENSSL_fork_child(void)
 {
     rand_fork();
+    /* TODO(3.0): Inform all providers about a fork event */
 }
 #endif
index eece882..26e2ccb 100644 (file)
@@ -69,6 +69,11 @@ typedef struct drbg_global_st {
     CRYPTO_THREAD_LOCAL private_drbg;
 } DRBG_GLOBAL;
 
+typedef struct drbg_nonce_global_st {
+    CRYPTO_RWLOCK *rand_nonce_lock;
+    int rand_nonce_count;
+} DRBG_NONCE_GLOBAL;
+
 /* NIST SP 800-90A DRBG recommends the use of a personalization string. */
 static const char ossl_pers_string[] = DRBG_DEFAULT_PERS_STRING;
 
@@ -142,6 +147,149 @@ static int is_digest(int type)
     }
 }
 
+/*
+ * Initialize the OPENSSL_CTX global DRBGs on first use.
+ * Returns the allocated global data on success or NULL on failure.
+ */
+static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx)
+{
+    DRBG_GLOBAL *dgbl = OPENSSL_zalloc(sizeof(*dgbl));
+
+    if (dgbl == NULL)
+        return NULL;
+
+    if (!CRYPTO_THREAD_init_local(&dgbl->private_drbg, NULL))
+        goto err1;
+
+    if (!CRYPTO_THREAD_init_local(&dgbl->public_drbg, NULL))
+        goto err2;
+
+    dgbl->master_drbg = drbg_setup(libctx, NULL, RAND_DRBG_TYPE_MASTER);
+    if (dgbl->master_drbg == NULL)
+        goto err3;
+
+    return dgbl;
+
+ err3:
+    CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
+ err2:
+    CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
+ err1:
+    OPENSSL_free(dgbl);
+    return NULL;
+}
+
+static void drbg_ossl_ctx_free(void *vdgbl)
+{
+    DRBG_GLOBAL *dgbl = vdgbl;
+
+    RAND_DRBG_free(dgbl->master_drbg);
+    CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
+    CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
+
+    OPENSSL_free(dgbl);
+}
+
+static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = {
+    drbg_ossl_ctx_new,
+    drbg_ossl_ctx_free,
+};
+
+/*
+ * drbg_ossl_ctx_new() calls drgb_setup() which calls rand_drbg_get_nonce()
+ * which needs to get the rand_nonce_lock out of the OPENSSL_CTX...but since
+ * drbg_ossl_ctx_new() hasn't finished running yet we need the rand_nonce_lock
+ * to be in a different global data object. Otherwise we will go into an
+ * infinite recursion loop.
+ */
+static void *drbg_nonce_ossl_ctx_new(OPENSSL_CTX *libctx)
+{
+    DRBG_NONCE_GLOBAL *dngbl = OPENSSL_zalloc(sizeof(*dngbl));
+
+    if (dngbl == NULL)
+        return NULL;
+
+    dngbl->rand_nonce_lock = CRYPTO_THREAD_lock_new();
+    if (dngbl->rand_nonce_lock == NULL) {
+        OPENSSL_free(dngbl);
+        return NULL;
+    }
+
+    return dngbl;
+}
+
+static void drbg_nonce_ossl_ctx_free(void *vdngbl)
+{
+    DRBG_NONCE_GLOBAL *dngbl = vdngbl;
+
+    CRYPTO_THREAD_lock_free(dngbl->rand_nonce_lock);
+
+    OPENSSL_free(dngbl);
+}
+
+static const OPENSSL_CTX_METHOD drbg_nonce_ossl_ctx_method = {
+    drbg_nonce_ossl_ctx_new,
+    drbg_nonce_ossl_ctx_free,
+};
+
+static DRBG_GLOBAL *drbg_get_global(OPENSSL_CTX *libctx)
+{
+    return openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_INDEX,
+                                &drbg_ossl_ctx_method);
+}
+
+/* Implements the get_nonce() callback (see RAND_DRBG_set_callbacks()) */
+size_t rand_drbg_get_nonce(RAND_DRBG *drbg,
+                           unsigned char **pout,
+                           int entropy, size_t min_len, size_t max_len)
+{
+    size_t ret = 0;
+    RAND_POOL *pool;
+    DRBG_NONCE_GLOBAL *dngbl
+        = openssl_ctx_get_data(drbg->libctx, OPENSSL_CTX_DRBG_NONCE_INDEX,
+                               &drbg_nonce_ossl_ctx_method);
+    struct {
+        void *instance;
+        int count;
+    } data;
+
+    if (dngbl == NULL)
+        return 0;
+
+    memset(&data, 0, sizeof(data));
+    pool = rand_pool_new(0, min_len, max_len);
+    if (pool == NULL)
+        return 0;
+
+    if (rand_pool_add_nonce_data(pool) == 0)
+        goto err;
+
+    data.instance = drbg;
+    CRYPTO_atomic_add(&dngbl->rand_nonce_count, 1, &data.count,
+                      dngbl->rand_nonce_lock);
+
+    if (rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0) == 0)
+        goto err;
+
+    ret   = rand_pool_length(pool);
+    *pout = rand_pool_detach(pool);
+
+ err:
+    rand_pool_free(pool);
+
+    return ret;
+}
+
+/*
+ * Implements the cleanup_nonce() callback (see RAND_DRBG_set_callbacks())
+ *
+ */
+void rand_drbg_cleanup_nonce(RAND_DRBG *drbg,
+                             unsigned char *out, size_t outlen)
+{
+    OPENSSL_secure_clear_free(out, outlen);
+}
+
 /*
  * Set/initialize |drbg| to be of type |type|, with optional |flags|.
  *
@@ -989,62 +1137,10 @@ err:
     return NULL;
 }
 
-/*
- * Initialize the OPENSSL_CTX global DRBGs on first use.
- * Returns the allocated global data on success or NULL on failure.
- */
-static void *drbg_ossl_ctx_new(OPENSSL_CTX *libctx)
-{
-    DRBG_GLOBAL *dgbl = OPENSSL_zalloc(sizeof(*dgbl));
-
-    if (dgbl == NULL)
-        return NULL;
-
-    if (!CRYPTO_THREAD_init_local(&dgbl->private_drbg, NULL))
-        goto err1;
-
-    if (!CRYPTO_THREAD_init_local(&dgbl->public_drbg, NULL))
-        goto err2;
-
-    dgbl->master_drbg = drbg_setup(libctx, NULL, RAND_DRBG_TYPE_MASTER);
-    if (dgbl->master_drbg == NULL)
-        goto err3;
-
-    return dgbl;
-
- err3:
-    CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
- err2:
-    CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
- err1:
-    OPENSSL_free(dgbl);
-    return NULL;
-}
-
-static void drbg_ossl_ctx_free(void *vdgbl)
-{
-    DRBG_GLOBAL *dgbl = vdgbl;
-
-    RAND_DRBG_free(dgbl->master_drbg);
-    CRYPTO_THREAD_cleanup_local(&dgbl->private_drbg);
-    CRYPTO_THREAD_cleanup_local(&dgbl->public_drbg);
-
-    OPENSSL_free(dgbl);
-}
-
-static const OPENSSL_CTX_METHOD drbg_ossl_ctx_method = {
-    drbg_ossl_ctx_new,
-    drbg_ossl_ctx_free,
-};
-
-static DRBG_GLOBAL *drbg_get_global(OPENSSL_CTX *libctx)
-{
-    return openssl_ctx_get_data(libctx, OPENSSL_CTX_DRBG_INDEX,
-                                &drbg_ossl_ctx_method);
-}
-
 void drbg_delete_thread_state(void)
 {
+    /* TODO(3.0): Other PRs will pass the ctx as a param to this function */
+    OPENSSL_CTX *ctx = NULL;
     DRBG_GLOBAL *dgbl = drbg_get_global(ctx);
     RAND_DRBG *drbg;
 
@@ -1287,5 +1383,9 @@ RAND_METHOD rand_meth = {
 
 RAND_METHOD *RAND_OpenSSL(void)
 {
+#ifndef FIPS_MODE
     return &rand_meth;
+#else
+    return NULL;
+#endif
 }
index 2b77960..45742f5 100644 (file)
 #include "rand_lcl.h"
 #include "e_os.h"
 
-#ifndef OPENSSL_NO_ENGINE
+#ifndef FIPS_MODE
+# ifndef OPENSSL_NO_ENGINE
 /* non-NULL if default_RAND_meth is ENGINE-provided */
 static ENGINE *funct_ref;
 static CRYPTO_RWLOCK *rand_engine_lock;
-#endif
+# endif
 static CRYPTO_RWLOCK *rand_meth_lock;
 static const RAND_METHOD *default_RAND_meth;
 static CRYPTO_ONCE rand_init = CRYPTO_ONCE_STATIC_INIT;
 
-int rand_fork_count;
-
-static CRYPTO_RWLOCK *rand_nonce_lock;
-static int rand_nonce_count;
-
 static int rand_inited = 0;
+#endif /* FIPS_MODE */
+
+int rand_fork_count;
 
 #ifdef OPENSSL_RAND_SEED_RDTSC
 /*
@@ -208,56 +207,6 @@ void rand_drbg_cleanup_entropy(RAND_DRBG *drbg,
         OPENSSL_secure_clear_free(out, outlen);
 }
 
-
-/*
- * Implements the get_nonce() callback (see RAND_DRBG_set_callbacks())
- *
- */
-size_t rand_drbg_get_nonce(RAND_DRBG *drbg,
-                           unsigned char **pout,
-                           int entropy, size_t min_len, size_t max_len)
-{
-    size_t ret = 0;
-    RAND_POOL *pool;
-
-    struct {
-        void * instance;
-        int count;
-    } data;
-
-    memset(&data, 0, sizeof(data));
-    pool = rand_pool_new(0, min_len, max_len);
-    if (pool == NULL)
-        return 0;
-
-    if (rand_pool_add_nonce_data(pool) == 0)
-        goto err;
-
-    data.instance = drbg;
-    CRYPTO_atomic_add(&rand_nonce_count, 1, &data.count, rand_nonce_lock);
-
-    if (rand_pool_add(pool, (unsigned char *)&data, sizeof(data), 0) == 0)
-        goto err;
-
-    ret   = rand_pool_length(pool);
-    *pout = rand_pool_detach(pool);
-
- err:
-    rand_pool_free(pool);
-
-    return ret;
-}
-
-/*
- * Implements the cleanup_nonce() callback (see RAND_DRBG_set_callbacks())
- *
- */
-void rand_drbg_cleanup_nonce(RAND_DRBG *drbg,
-                             unsigned char *out, size_t outlen)
-{
-    OPENSSL_secure_clear_free(out, outlen);
-}
-
 /*
  * Generate additional data that can be used for the drbg. The data does
  * not need to contain entropy, but it's useful if it contains at least
@@ -292,39 +241,32 @@ void rand_fork(void)
     rand_fork_count++;
 }
 
+#ifndef FIPS_MODE
 DEFINE_RUN_ONCE_STATIC(do_rand_init)
 {
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
     rand_engine_lock = CRYPTO_THREAD_lock_new();
     if (rand_engine_lock == NULL)
         return 0;
-#endif
+# endif
 
     rand_meth_lock = CRYPTO_THREAD_lock_new();
     if (rand_meth_lock == NULL)
-        goto err1;
-
-    rand_nonce_lock = CRYPTO_THREAD_lock_new();
-    if (rand_nonce_lock == NULL)
-        goto err2;
+        goto err;
 
     if (!rand_pool_init())
-        goto err3;
+        goto err;
 
     rand_inited = 1;
     return 1;
 
-err3:
-    CRYPTO_THREAD_lock_free(rand_nonce_lock);
-    rand_nonce_lock = NULL;
-err2:
+ err:
     CRYPTO_THREAD_lock_free(rand_meth_lock);
     rand_meth_lock = NULL;
-err1:
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
     CRYPTO_THREAD_lock_free(rand_engine_lock);
     rand_engine_lock = NULL;
-#endif
+# endif
     return 0;
 }
 
@@ -339,17 +281,16 @@ void rand_cleanup_int(void)
         meth->cleanup();
     RAND_set_rand_method(NULL);
     rand_pool_cleanup();
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
     CRYPTO_THREAD_lock_free(rand_engine_lock);
     rand_engine_lock = NULL;
-#endif
+# endif
     CRYPTO_THREAD_lock_free(rand_meth_lock);
     rand_meth_lock = NULL;
-    CRYPTO_THREAD_lock_free(rand_nonce_lock);
-    rand_nonce_lock = NULL;
     rand_inited = 0;
 }
 
+/* TODO(3.0): Do we need to handle this somehow in the FIPS module? */
 /*
  * RAND_close_seed_files() ensures that any seed file decriptors are
  * closed after use.
@@ -371,8 +312,6 @@ int RAND_poll(void)
 {
     int ret = 0;
 
-    RAND_POOL *pool = NULL;
-
     const RAND_METHOD *meth = RAND_get_rand_method();
 
     if (meth == RAND_OpenSSL()) {
@@ -389,6 +328,8 @@ int RAND_poll(void)
         return ret;
 
     } else {
+        RAND_POOL *pool = NULL;
+
         /* fill random pool and seed the current legacy RNG */
         pool = rand_pool_new(RAND_DRBG_STRENGTH,
                              (RAND_DRBG_STRENGTH + 7) / 8,
@@ -406,12 +347,14 @@ int RAND_poll(void)
             goto err;
 
         ret = 1;
+
+     err:
+        rand_pool_free(pool);
     }
 
-err:
-    rand_pool_free(pool);
     return ret;
 }
+#endif /* FIPS_MODE */
 
 /*
  * Allocate memory and initialize a new random pool
@@ -708,23 +651,28 @@ int rand_pool_add_end(RAND_POOL *pool, size_t len, size_t entropy)
     return 1;
 }
 
+#ifndef FIPS_MODE
 int RAND_set_rand_method(const RAND_METHOD *meth)
 {
     if (!RUN_ONCE(&rand_init, do_rand_init))
         return 0;
 
     CRYPTO_THREAD_write_lock(rand_meth_lock);
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
     ENGINE_finish(funct_ref);
     funct_ref = NULL;
-#endif
+# endif
     default_RAND_meth = meth;
     CRYPTO_THREAD_unlock(rand_meth_lock);
     return 1;
 }
+#endif
 
 const RAND_METHOD *RAND_get_rand_method(void)
 {
+#ifdef FIPS_MODE
+    return NULL;
+#else
     const RAND_METHOD *tmp_meth = NULL;
 
     if (!RUN_ONCE(&rand_init, do_rand_init))
@@ -732,7 +680,7 @@ const RAND_METHOD *RAND_get_rand_method(void)
 
     CRYPTO_THREAD_write_lock(rand_meth_lock);
     if (default_RAND_meth == NULL) {
-#ifndef OPENSSL_NO_ENGINE
+# ifndef OPENSSL_NO_ENGINE
         ENGINE *e;
 
         /* If we have an engine that can do RAND, use it. */
@@ -744,16 +692,17 @@ const RAND_METHOD *RAND_get_rand_method(void)
             ENGINE_finish(e);
             default_RAND_meth = &rand_meth;
         }
-#else
+# else
         default_RAND_meth = &rand_meth;
-#endif
+# endif
     }
     tmp_meth = default_RAND_meth;
     CRYPTO_THREAD_unlock(rand_meth_lock);
     return tmp_meth;
+#endif
 }
 
-#ifndef OPENSSL_NO_ENGINE
+#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE)
 int RAND_set_rand_engine(ENGINE *engine)
 {
     const RAND_METHOD *tmp_meth = NULL;
@@ -802,9 +751,9 @@ void RAND_add(const void *buf, int num, double randomness)
  */
 int RAND_priv_bytes(unsigned char *buf, int num)
 {
-    const RAND_METHOD *meth = RAND_get_rand_method();
     RAND_DRBG *drbg;
     int ret;
+    const RAND_METHOD *meth = RAND_get_rand_method();
 
     if (meth != RAND_OpenSSL())
         return RAND_bytes(buf, num);
@@ -827,7 +776,7 @@ int RAND_bytes(unsigned char *buf, int num)
     return -1;
 }
 
-#if !OPENSSL_API_1_1_0
+#if !OPENSSL_API_1_1_0 && !defined(FIPS_MODE)
 int RAND_pseudo_bytes(unsigned char *buf, int num)
 {
     const RAND_METHOD *meth = RAND_get_rand_method();
index 585263a..d76f9e1 100644 (file)
@@ -147,8 +147,9 @@ 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_RAND_CRNGT_INDEX               6
-# define OPENSSL_CTX_MAX_INDEXES                    7
+# define OPENSSL_CTX_DRBG_NONCE_INDEX               6
+# define OPENSSL_CTX_RAND_CRNGT_INDEX               7
+# define OPENSSL_CTX_MAX_INDEXES                    8
 
 typedef struct openssl_ctx_method {
     void *(*new_func)(OPENSSL_CTX *ctx);