Fix: dummy definition of rand_hw_seed() should also return int
[openssl.git] / crypto / rand / md_rand.c
index c2dfce419a8e11993322c90ba071d83e9e582db8..9d39831cf231c5643bd16ff94bca8ad2c068987e 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>
 /* #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 +46,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 +77,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 +85,12 @@ static RAND_METHOD rand_meth = {
     rand_status
 };
 
+static void do_rand_lock_init(void)
+{
+    rand_lock = CRYPTO_THREAD_lock_new();
+    rand_tmp_lock = CRYPTO_THREAD_lock_new();
+}
+
 RAND_METHOD *RAND_OpenSSL(void)
 {
     return (&rand_meth);
@@ -205,6 +106,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)
@@ -238,18 +141,19 @@ static int rand_add(const void *buf, int num, double add)
     if (m == NULL)
         goto err;
 
+    CRYPTO_THREAD_run_once(&rand_lock_init, do_rand_lock_init);
+
     /* 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;
 
     /*
@@ -281,7 +185,7 @@ 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);
@@ -323,7 +227,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.
@@ -335,7 +239,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
@@ -348,11 +252,8 @@ 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_free(m);
@@ -367,8 +268,8 @@ 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];
@@ -438,7 +339,8 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
      * global 'md'.
      */
 
-    CRYPTO_w_lock(CRYPTO_LOCK_RAND);
+    CRYPTO_THREAD_run_once(&rand_lock_init, do_rand_lock_init);
+    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
@@ -446,9 +348,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) {
@@ -523,7 +425,7 @@ 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 */
@@ -544,25 +446,14 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
             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)))
             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))
-            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))
@@ -588,17 +479,17 @@ static int rand_bytes(unsigned char *buf, int num, int pseudo)
         || !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);
+        CRYPTO_THREAD_unlock(rand_lock);
         goto err;
     }
     ASYNC_unblock_pause();
-    CRYPTO_w_unlock(CRYPTO_LOCK_RAND);
+    CRYPTO_THREAD_unlock(rand_lock);
 
     EVP_MD_CTX_free(m);
     if (ok)
@@ -608,7 +499,7 @@ 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:
@@ -627,7 +518,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
  */
@@ -639,24 +530,25 @@ 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);
+    CRYPTO_THREAD_run_once(&rand_lock_init, do_rand_lock_init);
+    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
          */
@@ -665,9 +557,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;
     }
 
@@ -683,7 +575,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;
@@ -698,25 +590,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 */
@@ -749,9 +644,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)