ssleay_rand_add returns a value in 1.1.0
[openssl.git] / crypto / rand / md_rand.c
index 4e581f3917318c982de9f34b6f2f34d99fdedcbf..3584cee3b68a1c63dee6e0c95f85937f95404401 100644 (file)
  *
  */
 
+#define OPENSSL_FIPSAPI
+
 #ifdef MD_RAND_DEBUG
 # ifndef NDEBUG
 #   define NDEBUG
 
 #include "e_os.h"
 
+#if !(defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYSNAME_DSPBIOS))
+# include <sys/time.h>
+#endif
+#if defined(OPENSSL_SYS_VXWORKS)
+# include <time.h>
+#endif
+
+#include <openssl/crypto.h>
 #include <openssl/rand.h>
 #include "rand_lcl.h"
 
-#include <openssl/crypto.h>
 #include <openssl/err.h>
 
+#ifdef OPENSSL_FIPS
+#include <openssl/fips.h>
+#endif
+
 #ifdef BN_DEBUG
 # define PREDICT
 #endif
@@ -154,16 +167,19 @@ int rand_predictable=0;
 
 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);
+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);
 
-RAND_METHOD rand_ssleay_meth={
+static RAND_METHOD rand_ssleay_meth={
        ssleay_rand_seed,
-       ssleay_rand_bytes,
+       ssleay_rand_nopseudo_bytes,
        ssleay_rand_cleanup,
        ssleay_rand_add,
        ssleay_rand_pseudo_bytes,
@@ -196,6 +212,9 @@ static int ssleay_rand_add(const void *buf, int num, double add)
        int do_not_lock;
        int rv = 0;
 
+       if (!num)
+               return 1;
+
        /*
         * (Based on the rand(3) manpage)
         *
@@ -340,7 +359,7 @@ static int ssleay_rand_seed(const void *buf, int num)
        return ssleay_rand_add(buf, num, (double)num);
        }
 
-static int ssleay_rand_bytes(unsigned char *buf, int num)
+static int ssleay_rand_bytes(unsigned char *buf, int num, int pseudo)
        {
        static volatile int stirred_pool = 0;
        int i,j,k,st_num,st_idx;
@@ -352,7 +371,28 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
 #ifndef GETPID_IS_MEANINGLESS
        pid_t curr_pid = getpid();
 #endif
+       time_t curr_time = time(NULL);
        int do_stir_pool = 0;
+/* time value for various platforms */
+#ifdef OPENSSL_SYS_WIN32
+       FILETIME tv;
+# ifdef _WIN32_WCE
+       SYSTEMTIME t;
+       GetSystemTime(&t);
+       SystemTimeToFileTime(&t, &tv);
+# else
+       GetSystemTimeAsFileTime(&tv);
+# endif
+#elif defined(OPENSSL_SYS_VXWORKS)
+       struct timespec tv;
+       clock_gettime(CLOCK_REALTIME, &ts);
+#elif defined(OPENSSL_SYSNAME_DSPBIOS)
+       unsigned long long tv, OPENSSL_rdtsc();
+       tv = OPENSSL_rdtsc();
+#else
+       struct timeval tv;
+       gettimeofday(&tv, NULL);
+#endif
 
 #ifdef PREDICT
        if (rand_predictable)
@@ -481,23 +521,38 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
 #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))
+                               goto err;
+                       if (!MD_Update(&m,(unsigned char*)&tv,
+                                      sizeof tv))
+                               goto err;
+                       curr_time = 0;
+                       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)))
                        goto err;
 
 #ifndef PURIFY /* purify complains */
-               /* DO NOT REMOVE THE FOLLOWING CALL TO MD_Update()! */
+               /* 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;
-               /* We know that line may cause programs such as
-                  purify and valgrind to complain about use of
-                  uninitialized data.  */
 #endif
 
                k=(st_idx+MD_DIGEST_LENGTH/2)-st_num;
@@ -539,7 +594,9 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
        EVP_MD_CTX_cleanup(&m);
        if (ok)
                return(1);
-       else
+       else if (pseudo)
+               return 0;
+       else 
                {
                RANDerr(RAND_F_SSLEAY_RAND_BYTES,RAND_R_PRNG_NOT_SEEDED);
                ERR_add_error_data(1, "You need to read the OpenSSL FAQ, "
@@ -553,22 +610,16 @@ static int ssleay_rand_bytes(unsigned char *buf, int num)
 
        }
 
+static int ssleay_rand_nopseudo_bytes(unsigned char *buf, int num)
+       {
+       return ssleay_rand_bytes(buf, num, 0);
+       }
+
 /* pseudo-random bytes that are guaranteed to be unique but not
    unpredictable */
 static int ssleay_rand_pseudo_bytes(unsigned char *buf, int num) 
        {
-       int ret;
-       unsigned long err;
-
-       ret = RAND_bytes(buf, num);
-       if (ret == 0)
-               {
-               err = ERR_peek_error();
-               if (ERR_GET_LIB(err) == ERR_LIB_RAND &&
-                   ERR_GET_REASON(err) == RAND_R_PRNG_NOT_SEEDED)
-                       ERR_clear_error();
-               }
-       return (ret);
+       return ssleay_rand_bytes(buf, num, 1);
        }
 
 static int ssleay_rand_status(void)
@@ -618,3 +669,79 @@ static int ssleay_rand_status(void)
        
        return ret;
        }
+
+/* rand_hw_seed: get seed data from any available hardware RNG.
+ * only currently supports rdrand.
+ */
+
+/* Adapted from eng_rdrand.c */
+
+#if (defined(__i386)   || defined(__i386__)   || defined(_M_IX86) || \
+     defined(__x86_64) || defined(__x86_64__) || \
+     defined(_M_AMD64) || defined (_M_X64)) && defined(OPENSSL_CPUID_OBJ)
+
+#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)
+       {
+       int i;
+       if (!(OPENSSL_ia32cap_P[1] & (1<<(62-32))))
+               return;
+       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));
+               }
+       }
+
+/* XOR an existing buffer with random data */
+
+void rand_hw_xor(unsigned char *buf, size_t num)
+       {
+       size_t rnd;
+       if (!(OPENSSL_ia32cap_P[1] & (1<<(62-32))))
+               return;
+       while (num >= sizeof(size_t))
+               {
+               rnd = OPENSSL_ia32_rdrand();
+               if (rnd == 0)
+                       return;
+               *((size_t *)buf) ^= rnd;
+               buf += sizeof(size_t);
+               num -= sizeof(size_t);
+               }
+       if (num)
+               {
+               rnd = OPENSSL_ia32_rdrand();
+               if (rnd == 0)
+                       return;
+               while(num)
+                       {
+                       *buf ^= rnd & 0xff;
+                       rnd >>= 8;
+                       buf++;
+                       num--;
+                       }
+               }
+       }
+
+
+#else
+
+static void rand_hw_seed(EVP_MD_CTX *ctx)
+       {
+       return;
+       }
+
+void rand_hw_xor(unsigned char *buf, size_t num)
+       {
+       return;
+       }
+
+#endif