Make the predictable numbers start from 1
[openssl.git] / crypto / rand / md_rand.c
index 698a63892eb4c4f3e43044da2ce01f97fa29054d..88820bbb917674e18644d308d862c6ec30d612e2 100644 (file)
-/* crypto/rand/md_rand.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
- */
-/* ====================================================================
- * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in
- *    the documentation and/or other materials provided with the
- *    distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- *    software must display the following acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- *    endorse or promote products derived from this software without
- *    prior written permission. For written permission, please contact
- *    openssl-core@openssl.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- *    nor may "OpenSSL" appear in their names without prior written
- *    permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- *    acknowledgment:
- *    "This product includes software developed by the OpenSSL Project
- *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com).  This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com).
+/*
+ * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
  *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
  */
 
-#ifdef MD_RAND_DEBUG
-# ifndef NDEBUG
-#  define NDEBUG
-# endif
-#endif
-
-#include <assert.h>
 #include <stdio.h>
 #include <string.h>
 
 # include <time.h>
 #endif
 
+#include <openssl/opensslconf.h>
 #include <openssl/crypto.h>
 #include <openssl/rand.h>
 #include <openssl/async.h>
 
 #include <openssl/err.h>
 
+#include <internal/thread_once.h>
+
 #ifdef OPENSSL_FIPS
 # include <openssl/fips.h>
 #endif
 
-#ifdef BN_DEBUG
+#if defined(BN_DEBUG) || defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
 # define PREDICT
 #endif
 
 /* #define PREDICT      1 */
 
 #define STATE_SIZE      1023
-static int state_num = 0, state_index = 0;
+static size_t state_num = 0, state_index = 0;
 static unsigned char state[STATE_SIZE + MD_DIGEST_LENGTH];
 static unsigned char md[MD_DIGEST_LENGTH];
 static long md_count[2] = { 0, 0 };
@@ -154,25 +48,28 @@ static long md_count[2] = { 0, 0 };
 static double entropy = 0;
 static int initialized = 0;
 
-static unsigned int crypto_lock_rand = 0; /* may be set only when a thread
-                                           * holds CRYPTO_LOCK_RAND (to
-                                           * prevent double locking) */
-/* access to lockin_thread is synchronized by CRYPTO_LOCK_RAND2 */
+static CRYPTO_RWLOCK *rand_lock = NULL;
+static CRYPTO_RWLOCK *rand_tmp_lock = NULL;
+static CRYPTO_ONCE rand_lock_init = CRYPTO_ONCE_STATIC_INIT;
+
+/* May be set only when a thread holds rand_lock (to prevent double locking) */
+static unsigned int crypto_lock_rand = 0;
+/* access to locking_threadid is synchronized by rand_tmp_lock */
 /* valid iff crypto_lock_rand is set */
-static CRYPTO_THREADID locking_threadid;
+static CRYPTO_THREAD_ID locking_threadid;
 
 #ifdef PREDICT
 int rand_predictable = 0;
 #endif
 
-static void rand_hw_seed(EVP_MD_CTX *ctx);
+static int rand_hw_seed(EVP_MD_CTX *ctx);
 
 static void rand_cleanup(void);
 static int rand_seed(const void *buf, int num);
 static int rand_add(const void *buf, int num, double add_entropy);
 static int rand_bytes(unsigned char *buf, int num, int pseudo);
 static int rand_nopseudo_bytes(unsigned char *buf, int num);
-#ifndef OPENSSL_NO_DEPRECATED
+#if OPENSSL_API_COMPAT < 0x10100000L
 static int rand_pseudo_bytes(unsigned char *buf, int num);
 #endif
 static int rand_status(void);
@@ -182,7 +79,7 @@ static RAND_METHOD rand_meth = {
     rand_nopseudo_bytes,
     rand_cleanup,
     rand_add,
-#ifndef OPENSSL_NO_DEPRECATED
+#if OPENSSL_API_COMPAT < 0x10100000L
     rand_pseudo_bytes,
 #else
     NULL,
@@ -190,6 +87,14 @@ static RAND_METHOD rand_meth = {
     rand_status
 };
 
+DEFINE_RUN_ONCE_STATIC(do_rand_lock_init)
+{
+    OPENSSL_init_crypto(0, NULL);
+    rand_lock = CRYPTO_THREAD_lock_new();
+    rand_tmp_lock = CRYPTO_THREAD_lock_new();
+    return rand_lock != NULL && rand_tmp_lock != NULL;
+}
+
 RAND_METHOD *RAND_OpenSSL(void)
 {
     return (&rand_meth);
@@ -205,6 +110,8 @@ static void rand_cleanup(void)
     md_count[1] = 0;
     entropy = 0;
     initialized = 0;
+    CRYPTO_THREAD_lock_free(rand_lock);
+    CRYPTO_THREAD_lock_free(rand_tmp_lock);
 }
 
 static int rand_add(const void *buf, int num, double add)
@@ -212,7 +119,7 @@ static int rand_add(const void *buf, int num, double add)
     int i, j, k, st_idx;
     long md_c[2];
     unsigned char local_md[MD_DIGEST_LENGTH];
-    EVP_MD_CTX m;
+    EVP_MD_CTX *m;
     int do_not_lock;
     int rv = 0;
 
@@ -234,19 +141,24 @@ static int rand_add(const void *buf, int num, double add)
      * hash function.
      */
 
-    EVP_MD_CTX_init(&m);
+    m = EVP_MD_CTX_new();
+    if (m == NULL)
+        goto err;
+
+    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
+        goto err;
+
     /* check if we already have the lock */
     if (crypto_lock_rand) {
-        CRYPTO_THREADID cur;
-        CRYPTO_THREADID_current(&cur);
-        CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
-        do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
-        CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
+        CRYPTO_THREAD_ID cur = CRYPTO_THREAD_get_current_id();
+        CRYPTO_THREAD_read_lock(rand_tmp_lock);
+        do_not_lock = CRYPTO_THREAD_compare_id(locking_threadid, cur);
+        CRYPTO_THREAD_unlock(rand_tmp_lock);
     } else
         do_not_lock = 0;
 
     if (!do_not_lock)
-        CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+        CRYPTO_THREAD_write_lock(rand_lock);
     st_idx = state_index;
 
     /*
@@ -278,27 +190,27 @@ static int rand_add(const void *buf, int num, double add)
     md_count[1] += (num / MD_DIGEST_LENGTH) + (num % MD_DIGEST_LENGTH > 0);
 
     if (!do_not_lock)
-        CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+        CRYPTO_THREAD_unlock(rand_lock);
 
     for (i = 0; i < num; i += MD_DIGEST_LENGTH) {
         j = (num - i);
         j = (j > MD_DIGEST_LENGTH) ? MD_DIGEST_LENGTH : j;
 
-        if (!MD_Init(&m))
+        if (!MD_Init(m))
             goto err;
-        if (!MD_Update(&m, local_md, MD_DIGEST_LENGTH))
+        if (!MD_Update(m, local_md, MD_DIGEST_LENGTH))
             goto err;
         k = (st_idx + j) - STATE_SIZE;
         if (k > 0) {
-            if (!MD_Update(&m, &(state[st_idx]), j - k))
+            if (!MD_Update(m, &(state[st_idx]), j - k))
                 goto err;
-            if (!MD_Update(&m, &(state[0]), k))
+            if (!MD_Update(m, &(state[0]), k))
                 goto err;
-        } else if (!MD_Update(&m, &(state[st_idx]), j))
+        } else if (!MD_Update(m, &(state[st_idx]), j))
             goto err;
 
         /* DO NOT REMOVE THE FOLLOWING CALL TO MD_Update()! */
-        if (!MD_Update(&m, buf, j))
+        if (!MD_Update(m, buf, j))
             goto err;
         /*
          * We know that line may cause programs such as purify and valgrind
@@ -308,9 +220,9 @@ static int rand_add(const void *buf, int num, double add)
          * insecure keys.
          */
 
-        if (!MD_Update(&m, (unsigned char *)&(md_c[0]), sizeof(md_c)))
+        if (!MD_Update(m, (unsigned char *)&(md_c[0]), sizeof(md_c)))
             goto err;
-        if (!MD_Final(&m, local_md))
+        if (!MD_Final(m, local_md))
             goto err;
         md_c[1]++;
 
@@ -320,7 +232,7 @@ static int rand_add(const void *buf, int num, double add)
             /*
              * Parallel threads may interfere with this, but always each byte
              * of the new state is the XOR of some previous value of its and
-             * local_md (itermediate values may be lost). Alway using locking
+             * local_md (intermediate values may be lost). Alway using locking
              * could hurt performance more than necessary given that
              * conflicts occur only when the total seeding is longer than the
              * random state.
@@ -332,7 +244,7 @@ static int rand_add(const void *buf, int num, double add)
     }
 
     if (!do_not_lock)
-        CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+        CRYPTO_THREAD_write_lock(rand_lock);
     /*
      * Don't just copy back local_md into md -- this could mean that other
      * thread's seeding remains without effect (except for the incremented
@@ -345,14 +257,11 @@ static int rand_add(const void *buf, int num, double add)
     if (entropy < ENTROPY_NEEDED) /* stop counting when we have enough */
         entropy += add;
     if (!do_not_lock)
-        CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+        CRYPTO_THREAD_unlock(rand_lock);
 
-#if !defined(OPENSSL_THREADS) && !defined(OPENSSL_SYS_WIN32)
-    assert(md_c[1] == md_count[1]);
-#endif
     rv = 1;
  err:
-    EVP_MD_CTX_cleanup(&m);
+    EVP_MD_CTX_free(m);
     return rv;
 }
 
@@ -364,12 +273,12 @@ static int rand_seed(const void *buf, int num)
 static int rand_bytes(unsigned char *buf, int num, int pseudo)
 {
     static volatile int stirred_pool = 0;
-    int i, j, k, st_num, st_idx;
-    int num_ceil;
+    int i, j, k;
+    size_t num_ceil, st_idx, st_num;
     int ok;
     long md_c[2];
     unsigned char local_md[MD_DIGEST_LENGTH];
-    EVP_MD_CTX m;
+    EVP_MD_CTX *m;
 #ifndef GETPID_IS_MEANINGLESS
     pid_t curr_pid = getpid();
 #endif
@@ -398,7 +307,7 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
 
 #ifdef PREDICT
     if (rand_predictable) {
-        static unsigned char val = 0;
+        unsigned char val = 1;
 
         for (i = 0; i < num; i++)
             buf[i] = val++;
@@ -409,7 +318,10 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
     if (num <= 0)
         return 1;
 
-    EVP_MD_CTX_init(&m);
+    m = EVP_MD_CTX_new();
+    if (m == NULL)
+        goto err_mem;
+
     /* round upwards to multiple of MD_DIGEST_LENGTH/2 */
     num_ceil =
         (1 + (num - 1) / (MD_DIGEST_LENGTH / 2)) * (MD_DIGEST_LENGTH / 2);
@@ -432,7 +344,10 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
      * global 'md'.
      */
 
-    CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
+        goto err_mem;
+
+    CRYPTO_THREAD_write_lock(rand_lock);
     /*
      * We could end up in an async engine while holding this lock so ensure
      * we don't pause and cause a deadlock
@@ -440,9 +355,9 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
     ASYNC_block_pause();
 
     /* prevent rand_bytes() from trying to obtain the lock again */
-    CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
-    CRYPTO_THREADID_current(&locking_threadid);
-    CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
+    CRYPTO_THREAD_write_lock(rand_tmp_lock);
+    locking_threadid = CRYPTO_THREAD_get_current_id();
+    CRYPTO_THREAD_unlock(rand_tmp_lock);
     crypto_lock_rand = 1;
 
     if (!initialized) {
@@ -517,55 +432,44 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
     /* before unlocking, we must clear 'crypto_lock_rand' */
     crypto_lock_rand = 0;
     ASYNC_unblock_pause();
-    CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+    CRYPTO_THREAD_unlock(rand_lock);
 
     while (num > 0) {
         /* num_ceil -= MD_DIGEST_LENGTH/2 */
         j = (num >= MD_DIGEST_LENGTH / 2) ? MD_DIGEST_LENGTH / 2 : num;
         num -= j;
-        if (!MD_Init(&m))
+        if (!MD_Init(m))
             goto err;
 #ifndef GETPID_IS_MEANINGLESS
         if (curr_pid) {         /* just in the first iteration to save time */
-            if (!MD_Update(&m, (unsigned char *)&curr_pid, sizeof curr_pid))
+            if (!MD_Update(m, (unsigned char *)&curr_pid, sizeof curr_pid))
                 goto err;
             curr_pid = 0;
         }
 #endif
         if (curr_time) {        /* just in the first iteration to save time */
-            if (!MD_Update(&m, (unsigned char *)&curr_time, sizeof curr_time))
+            if (!MD_Update(m, (unsigned char *)&curr_time, sizeof curr_time))
                 goto err;
-            if (!MD_Update(&m, (unsigned char *)&tv, sizeof tv))
+            if (!MD_Update(m, (unsigned char *)&tv, sizeof tv))
                 goto err;
             curr_time = 0;
-            rand_hw_seed(&m);
+            if (!rand_hw_seed(m))
+                goto err;
         }
-        if (!MD_Update(&m, local_md, MD_DIGEST_LENGTH))
-            goto err;
-        if (!MD_Update(&m, (unsigned char *)&(md_c[0]), sizeof(md_c)))
+        if (!MD_Update(m, local_md, MD_DIGEST_LENGTH))
             goto err;
-
-#ifndef PURIFY                  /* purify complains */
-        /*
-         * The following line uses the supplied buffer as a small source of
-         * entropy: since this buffer is often uninitialised it may cause
-         * programs such as purify or valgrind to complain. So for those
-         * builds it is not used: the removal of such a small source of
-         * entropy has negligible impact on security.
-         */
-        if (!MD_Update(&m, buf, j))
+        if (!MD_Update(m, (unsigned char *)&(md_c[0]), sizeof(md_c)))
             goto err;
-#endif
 
         k = (st_idx + MD_DIGEST_LENGTH / 2) - st_num;
         if (k > 0) {
-            if (!MD_Update(&m, &(state[st_idx]), MD_DIGEST_LENGTH / 2 - k))
+            if (!MD_Update(m, &(state[st_idx]), MD_DIGEST_LENGTH / 2 - k))
                 goto err;
-            if (!MD_Update(&m, &(state[0]), k))
+            if (!MD_Update(m, &(state[0]), k))
                 goto err;
-        } else if (!MD_Update(&m, &(state[st_idx]), MD_DIGEST_LENGTH / 2))
+        } else if (!MD_Update(m, &(state[st_idx]), MD_DIGEST_LENGTH / 2))
             goto err;
-        if (!MD_Final(&m, local_md))
+        if (!MD_Final(m, local_md))
             goto err;
 
         for (i = 0; i < MD_DIGEST_LENGTH / 2; i++) {
@@ -578,23 +482,23 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
         }
     }
 
-    if (!MD_Init(&m)
-        || !MD_Update(&m, (unsigned char *)&(md_c[0]), sizeof(md_c))
-        || !MD_Update(&m, local_md, MD_DIGEST_LENGTH))
+    if (!MD_Init(m)
+        || !MD_Update(m, (unsigned char *)&(md_c[0]), sizeof(md_c))
+        || !MD_Update(m, local_md, MD_DIGEST_LENGTH))
         goto err;
-    CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+    CRYPTO_THREAD_write_lock(rand_lock);
     /*
      * Prevent deadlocks if we end up in an async engine
      */
     ASYNC_block_pause();
-    if (!MD_Update(&m, md, MD_DIGEST_LENGTH) || !MD_Final(&m, md)) {
-        CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+    if (!MD_Update(m, md, MD_DIGEST_LENGTH) || !MD_Final(m, md)) {
+        CRYPTO_THREAD_unlock(rand_lock);
         goto err;
     }
     ASYNC_unblock_pause();
-    CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+    CRYPTO_THREAD_unlock(rand_lock);
 
-    EVP_MD_CTX_cleanup(&m);
+    EVP_MD_CTX_free(m);
     if (ok)
         return (1);
     else if (pseudo)
@@ -602,12 +506,16 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
     else {
         RANDerr(RAND_F_RAND_BYTES, RAND_R_PRNG_NOT_SEEDED);
         ERR_add_error_data(1, "You need to read the OpenSSL FAQ, "
-                           "http://www.openssl.org/support/faq.html");
+                           "https://www.openssl.org/docs/faq.html");
         return (0);
     }
  err:
-    EVP_MD_CTX_cleanup(&m);
     RANDerr(RAND_F_RAND_BYTES, ERR_R_EVP_LIB);
+    EVP_MD_CTX_free(m);
+    return 0;
+ err_mem:
+    RANDerr(RAND_F_RAND_BYTES, ERR_R_MALLOC_FAILURE);
+    EVP_MD_CTX_free(m);
     return 0;
 
 }
@@ -617,7 +525,7 @@ static int rand_nopseudo_bytes(unsigned char *buf, int num)
     return rand_bytes(buf, num, 0);
 }
 
-#ifndef OPENSSL_NO_DEPRECATED
+#if OPENSSL_API_COMPAT < 0x10100000L
 /*
  * pseudo-random bytes that are guaranteed to be unique but not unpredictable
  */
@@ -629,24 +537,27 @@ static int rand_pseudo_bytes(unsigned char *buf, int num)
 
 static int rand_status(void)
 {
-    CRYPTO_THREADID cur;
+    CRYPTO_THREAD_ID cur;
     int ret;
     int do_not_lock;
 
-    CRYPTO_THREADID_current(&cur);
+    if (!RUN_ONCE(&rand_lock_init, do_rand_lock_init))
+        return 0;
+
+    cur = CRYPTO_THREAD_get_current_id();
     /*
      * check if we already have the lock (could happen if a RAND_poll()
      * implementation calls RAND_status())
      */
     if (crypto_lock_rand) {
-        CRYPTO_r_lock(CRYPTO_LOCK_RAND2);
-        do_not_lock = !CRYPTO_THREADID_cmp(&locking_threadid, &cur);
-        CRYPTO_r_unlock(CRYPTO_LOCK_RAND2);
+        CRYPTO_THREAD_read_lock(rand_tmp_lock);
+        do_not_lock = CRYPTO_THREAD_compare_id(locking_threadid, cur);
+        CRYPTO_THREAD_unlock(rand_tmp_lock);
     } else
         do_not_lock = 0;
 
     if (!do_not_lock) {
-        CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+        CRYPTO_THREAD_write_lock(rand_lock);
         /*
          * Prevent deadlocks in case we end up in an async engine
          */
@@ -655,9 +566,9 @@ static int rand_status(void)
         /*
          * prevent rand_bytes() from trying to obtain the lock again
          */
-        CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
-        CRYPTO_THREADID_cpy(&locking_threadid, &cur);
-        CRYPTO_w_unlock(CRYPTO_LOCK_RAND2);
+        CRYPTO_THREAD_write_lock(rand_tmp_lock);
+        locking_threadid = cur;
+        CRYPTO_THREAD_unlock(rand_tmp_lock);
         crypto_lock_rand = 1;
     }
 
@@ -673,7 +584,7 @@ static int rand_status(void)
         crypto_lock_rand = 0;
 
         ASYNC_unblock_pause();
-        CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+        CRYPTO_THREAD_unlock(rand_lock);
     }
 
     return ret;
@@ -688,25 +599,28 @@ static int rand_status(void)
 
 #if (defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
      defined(__x86_64) || defined(__x86_64__) || \
-     defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ)
+     defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ) \
+     && !defined(OPENSSL_NO_RDRAND)
 
 # define RDRAND_CALLS    4
 
 size_t OPENSSL_ia32_rdrand(void);
 extern unsigned int OPENSSL_ia32cap_P[];
 
-static void rand_hw_seed(EVP_MD_CTX *ctx)
+static int rand_hw_seed(EVP_MD_CTX *ctx)
 {
     int i;
     if (!(OPENSSL_ia32cap_P[1] & (1 << (62 - 32))))
-        return;
+        return 1;
     for (i = 0; i < RDRAND_CALLS; i++) {
         size_t rnd;
         rnd = OPENSSL_ia32_rdrand();
         if (rnd == 0)
-            return;
-        MD_Update(ctx, (unsigned char *)&rnd, sizeof(size_t));
+            return 1;
+        if (!MD_Update(ctx, (unsigned char *)&rnd, sizeof(size_t)))
+            return 0;
     }
+    return 1;
 }
 
 /* XOR an existing buffer with random data */
@@ -739,9 +653,9 @@ void rand_hw_xor(unsigned char *buf, size_t num)
 
 #else
 
-static void rand_hw_seed(EVP_MD_CTX *ctx)
+static int rand_hw_seed(EVP_MD_CTX *ctx)
 {
-    return;
+    return 1;
 }
 
 void rand_hw_xor(unsigned char *buf, size_t num)