md_rand: FAQ URL to use https and follow a redirect
[openssl.git] / crypto / rand / md_rand.c
index ef43966814c3ca254cb0adcc6db3721c4eba9875..c7be2783da40bddd77a02e432825d378966966cc 100644 (file)
@@ -1,4 +1,3 @@
-/* crypto/rand/md_rand.c */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
 # include <time.h>
 #endif
 
+#include <openssl/opensslconf.h>
 #include <openssl/crypto.h>
 #include <openssl/rand.h>
+#include <openssl/async.h>
 #include "rand_lcl.h"
 
 #include <openssl/err.h>
@@ -164,33 +165,37 @@ static CRYPTO_THREADID locking_threadid;
 int rand_predictable = 0;
 #endif
 
-const char RAND_version[] = "RAND" OPENSSL_VERSION_PTEXT;
-
 static void rand_hw_seed(EVP_MD_CTX *ctx);
 
-static void ssleay_rand_cleanup(void);
-static int ssleay_rand_seed(const void *buf, int num);
-static int ssleay_rand_add(const void *buf, int num, double add_entropy);
-static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo);
-static int ssleay_rand_nopseudo_bytes(unsigned char *buf, int num);
-static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num);
-static int ssleay_rand_status(void);
-
-static RAND_METHOD rand_ssleay_meth = {
-    ssleay_rand_seed,
-    ssleay_rand_nopseudo_bytes,
-    ssleay_rand_cleanup,
-    ssleay_rand_add,
-    ssleay_rand_pseudo_bytes,
-    ssleay_rand_status
+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);
+#if OPENSSL_API_COMPAT < 0x10100000L
+static int rand_pseudo_bytes(unsigned char *buf, int num);
+#endif
+static int rand_status(void);
+
+static RAND_METHOD rand_meth = {
+    rand_seed,
+    rand_nopseudo_bytes,
+    rand_cleanup,
+    rand_add,
+#if OPENSSL_API_COMPAT < 0x10100000L
+    rand_pseudo_bytes,
+#else
+    NULL,
+#endif
+    rand_status
 };
 
-RAND_METHOD *RAND_SSLeay(void)
+RAND_METHOD *RAND_OpenSSL(void)
 {
-    return (&rand_ssleay_meth);
+    return (&rand_meth);
 }
 
-static void ssleay_rand_cleanup(void)
+static void rand_cleanup(void)
 {
     OPENSSL_cleanse(state, sizeof(state));
     state_num = 0;
@@ -202,12 +207,12 @@ static void ssleay_rand_cleanup(void)
     initialized = 0;
 }
 
-static int ssleay_rand_add(const void *buf, int num, double add)
+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;
 
@@ -229,7 +234,10 @@ static int ssleay_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;
+
     /* check if we already have the lock */
     if (crypto_lock_rand) {
         CRYPTO_THREADID cur;
@@ -279,21 +287,21 @@ static int ssleay_rand_add(const void *buf, int num, double add)
         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
@@ -303,9 +311,9 @@ static int ssleay_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]++;
 
@@ -315,7 +323,7 @@ static int ssleay_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.
@@ -347,16 +355,16 @@ static int ssleay_rand_add(const void *buf, int num, double add)
 #endif
     rv = 1;
  err:
-    EVP_MD_CTX_cleanup(&m);
+    EVP_MD_CTX_free(m);
     return rv;
 }
 
-static int ssleay_rand_seed(const void *buf, int num)
+static int rand_seed(const void *buf, int num)
 {
-    return ssleay_rand_add(buf, num, (double)num);
+    return rand_add(buf, num, (double)num);
 }
 
-static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo)
+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;
@@ -364,7 +372,7 @@ static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo)
     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
@@ -404,7 +412,10 @@ static int ssleay_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);
@@ -428,8 +439,13 @@ static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo)
      */
 
     CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+    /*
+     * We could end up in an async engine while holding this lock so ensure
+     * we don't pause and cause a deadlock
+     */
+    ASYNC_block_pause();
 
-    /* prevent ssleay_rand_bytes() from trying to obtain the lock again */
+    /* 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);
@@ -466,7 +482,7 @@ static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo)
          * In the output function only half of 'md' remains secret, so we
          * better make sure that the required entropy gets 'evenly
          * distributed' through 'state', our randomness pool. The input
-         * function (ssleay_rand_add) chains all of 'md', which makes it more
+         * function (rand_add) chains all of 'md', which makes it more
          * suitable for this purpose.
          */
 
@@ -478,9 +494,9 @@ static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo)
 #define DUMMY_SEED "...................." /* at least MD_DIGEST_LENGTH */
             /*
              * Note that the seed does not matter, it's just that
-             * ssleay_rand_add expects to have something to hash.
+             * rand_add expects to have something to hash.
              */
-            ssleay_rand_add(DUMMY_SEED, MD_DIGEST_LENGTH, 0.0);
+            rand_add(DUMMY_SEED, MD_DIGEST_LENGTH, 0.0);
             n -= MD_DIGEST_LENGTH;
         }
         if (ok)
@@ -506,55 +522,44 @@ static int ssleay_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);
 
     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);
+            rand_hw_seed(m);
         }
-        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++) {
@@ -567,49 +572,60 @@ static int ssleay_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);
-    if (!MD_Update(&m, md, MD_DIGEST_LENGTH) || !MD_Final(&m, md)) {
+    /*
+     * 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);
         goto err;
     }
+    ASYNC_unblock_pause();
     CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
 
-    EVP_MD_CTX_cleanup(&m);
+    EVP_MD_CTX_free(m);
     if (ok)
         return (1);
     else if (pseudo)
         return 0;
     else {
-        RANDerr(RAND_F_SSLEAY_RAND_BYTES, RAND_R_PRNG_NOT_SEEDED);
+        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_SSLEAY_RAND_BYTES, ERR_R_EVP_LIB);
+    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;
 
 }
 
-static int ssleay_rand_nopseudo_bytes(unsigned char *buf, int num)
+static int rand_nopseudo_bytes(unsigned char *buf, int num)
 {
-    return ssleay_rand_bytes(buf, num, 0);
+    return rand_bytes(buf, num, 0);
 }
 
+#if OPENSSL_API_COMPAT < 0x10100000L
 /*
  * pseudo-random bytes that are guaranteed to be unique but not unpredictable
  */
-static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num)
+static int rand_pseudo_bytes(unsigned char *buf, int num)
 {
-    return ssleay_rand_bytes(buf, num, 1);
+    return rand_bytes(buf, num, 1);
 }
+#endif
 
-static int ssleay_rand_status(void)
+static int rand_status(void)
 {
     CRYPTO_THREADID cur;
     int ret;
@@ -629,9 +645,13 @@ static int ssleay_rand_status(void)
 
     if (!do_not_lock) {
         CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+        /*
+         * Prevent deadlocks in case we end up in an async engine
+         */
+        ASYNC_block_pause();
 
         /*
-         * prevent ssleay_rand_bytes() from trying to obtain the lock again
+         * prevent rand_bytes() from trying to obtain the lock again
          */
         CRYPTO_w_lock(CRYPTO_LOCK_RAND2);
         CRYPTO_THREADID_cpy(&locking_threadid, &cur);
@@ -650,6 +670,7 @@ static int ssleay_rand_status(void)
         /* before unlocking, we must clear 'crypto_lock_rand' */
         crypto_lock_rand = 0;
 
+        ASYNC_unblock_pause();
         CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
     }
 
@@ -665,7 +686,8 @@ static int ssleay_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