Test: link drbgtest statically against libcrypto
[oweals/openssl.git] / crypto / rand / rand_unix.c
index 74cc9e146fdf2030eff8cf8bfe4bca93b0aad0d7..cb3a6b24ab04c3280f2cd3c9c75eda4c828b0818 100644 (file)
@@ -77,6 +77,17 @@ static uint64_t get_timer_bits(void);
 # endif
 #endif /* defined(OPENSSL_SYS_UNIX) || defined(__DJGPP__) */
 
+#if defined(OPENSSL_RAND_SEED_NONE)
+/* none means none. this simplifies the following logic */
+# undef OPENSSL_RAND_SEED_OS
+# undef OPENSSL_RAND_SEED_GETRANDOM
+# undef OPENSSL_RAND_SEED_LIBRANDOM
+# undef OPENSSL_RAND_SEED_DEVRANDOM
+# undef OPENSSL_RAND_SEED_RDTSC
+# undef OPENSSL_RAND_SEED_RDCPU
+# undef OPENSSL_RAND_SEED_EGD
+#endif
+
 #if (defined(OPENSSL_SYS_VXWORKS) || defined(OPENSSL_SYS_UEFI)) && \
         !defined(OPENSSL_RAND_SEED_NONE)
 # error "UEFI and VXWorks only support seeding NONE"
@@ -86,8 +97,6 @@ static uint64_t get_timer_bits(void);
     || defined(OPENSSL_SYS_VMS) || defined(OPENSSL_SYS_VXWORKS) \
     || defined(OPENSSL_SYS_UEFI))
 
-static ssize_t syscall_random(void *buf, size_t buflen);
-
 # if defined(OPENSSL_SYS_VOS)
 
 #  ifndef OPENSSL_RAND_SEED_OS
@@ -244,6 +253,7 @@ static ssize_t sysctl_random(char *buf, size_t buflen)
 }
 #  endif
 
+#  if defined(OPENSSL_RAND_SEED_GETRANDOM)
 /*
  * syscall_random(): Try to get random data using a system call
  * returns the number of bytes returned in buf, or < 0 on error.
@@ -254,7 +264,7 @@ static ssize_t syscall_random(void *buf, size_t buflen)
      * Note: 'buflen' equals the size of the buffer which is used by the
      * get_entropy() callback of the RAND_DRBG. It is roughly bounded by
      *
-     *   2 * DRBG_MINMAX_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^13
+     *   2 * RAND_POOL_FACTOR * (RAND_DRBG_STRENGTH / 8) = 2^14
      *
      * which is way below the OSSL_SSIZE_MAX limit. Therefore sign conversion
      * between size_t and ssize_t is safe even without a range check.
@@ -302,8 +312,9 @@ static ssize_t syscall_random(void *buf, size_t buflen)
     return -1;
 #  endif
 }
+#  endif    /* defined(OPENSSL_RAND_SEED_GETRANDOM) */
 
-#if  !defined(OPENSSL_RAND_SEED_NONE) && defined(OPENSSL_RAND_SEED_DEVRANDOM)
+#  if defined(OPENSSL_RAND_SEED_DEVRANDOM)
 static const char *random_device_paths[] = { DEVRANDOM };
 static struct random_device {
     int fd;
@@ -410,9 +421,7 @@ void rand_pool_keep_random_devices_open(int keep)
     keep_random_devices_open = keep;
 }
 
-#  else     /* defined(OPENSSL_RAND_SEED_NONE)
-             * || !defined(OPENSSL_RAND_SEED_DEVRANDOM)
-             */
+#  else     /* !defined(OPENSSL_RAND_SEED_DEVRANDOM) */
 
 int rand_pool_init(void)
 {
@@ -427,9 +436,7 @@ void rand_pool_keep_random_devices_open(int keep)
 {
 }
 
-#  endif    /* !defined(OPENSSL_RAND_SEED_NONE)
-             * && defined(OPENSSL_RAND_SEED_DEVRANDOM)
-             */
+#  endif    /* defined(OPENSSL_RAND_SEED_DEVRANDOM) */
 
 /*
  * Try the various seeding methods in turn, exit when successful.
@@ -450,25 +457,33 @@ void rand_pool_keep_random_devices_open(int keep)
  */
 size_t rand_pool_acquire_entropy(RAND_POOL *pool)
 {
-#  ifdef OPENSSL_RAND_SEED_NONE
+#  if defined(OPENSSL_RAND_SEED_NONE)
     return rand_pool_entropy_available(pool);
 #  else
     size_t bytes_needed;
     size_t entropy_available = 0;
     unsigned char *buffer;
 
-#   ifdef OPENSSL_RAND_SEED_GETRANDOM
-    bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
-    buffer = rand_pool_add_begin(pool, bytes_needed);
-    if (buffer != NULL) {
-        size_t bytes = 0;
-
-        if (syscall_random(buffer, bytes_needed) == (int)bytes_needed)
-            bytes = bytes_needed;
+#   if defined(OPENSSL_RAND_SEED_GETRANDOM)
+    {
+        ssize_t bytes;
+        /* Maximum allowed number of consecutive unsuccessful attempts */
+        int attempts = 3;
 
-        rand_pool_add_end(pool, bytes, 8 * bytes);
-        entropy_available = rand_pool_entropy_available(pool);
+        bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
+        while (bytes_needed != 0 && attempts-- > 0) {
+            buffer = rand_pool_add_begin(pool, bytes_needed);
+            bytes = syscall_random(buffer, bytes_needed);
+            if (bytes > 0) {
+                rand_pool_add_end(pool, bytes, 8 * bytes);
+                bytes_needed -= bytes;
+                attempts = 3; /* reset counter after successful attempt */
+            } else if (bytes < 0 && errno != EINTR) {
+                break;
+            }
+        }
     }
+    entropy_available = rand_pool_entropy_available(pool);
     if (entropy_available > 0)
         return entropy_available;
 #   endif
@@ -479,28 +494,33 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool)
     }
 #   endif
 
-#   ifdef OPENSSL_RAND_SEED_DEVRANDOM
+#   if defined(OPENSSL_RAND_SEED_DEVRANDOM)
     bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
     {
         size_t i;
 
         for (i = 0; bytes_needed > 0 && i < OSSL_NELEM(random_device_paths); i++) {
+            ssize_t bytes = 0;
+            /* Maximum allowed number of consecutive unsuccessful attempts */
+            int attempts = 3;
             const int fd = get_random_device(i);
 
             if (fd == -1)
                 continue;
-            buffer = rand_pool_add_begin(pool, bytes_needed);
-            if (buffer != NULL) {
-                const ssize_t n = read(fd, buffer, bytes_needed);
 
-                if (n <= 0) {
-                    close_random_device(i);
-                    continue;
-                }
+            while (bytes_needed != 0 && attempts-- > 0) {
+                buffer = rand_pool_add_begin(pool, bytes_needed);
+                bytes = read(fd, buffer, bytes_needed);
 
-                rand_pool_add_end(pool, n, 8 * n);
+                if (bytes > 0) {
+                    rand_pool_add_end(pool, bytes, 8 * bytes);
+                    bytes_needed -= bytes;
+                    attempts = 3; /* reset counter after successful attempt */
+                } else if (bytes < 0 && errno != EINTR) {
+                    break;
+                }
             }
-            if (!keep_random_devices_open)
+            if (bytes < 0 || !keep_random_devices_open)
                 close_random_device(i);
 
             bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
@@ -511,19 +531,19 @@ size_t rand_pool_acquire_entropy(RAND_POOL *pool)
     }
 #   endif
 
-#   ifdef OPENSSL_RAND_SEED_RDTSC
+#   if defined(OPENSSL_RAND_SEED_RDTSC)
     entropy_available = rand_acquire_entropy_from_tsc(pool);
     if (entropy_available > 0)
         return entropy_available;
 #   endif
 
-#   ifdef OPENSSL_RAND_SEED_RDCPU
+#   if defined(OPENSSL_RAND_SEED_RDCPU)
     entropy_available = rand_acquire_entropy_from_cpu(pool);
     if (entropy_available > 0)
         return entropy_available;
 #   endif
 
-#   ifdef OPENSSL_RAND_SEED_EGD
+#   if defined(OPENSSL_RAND_SEED_EGD)
     bytes_needed = rand_pool_bytes_needed(pool, 1 /*entropy_factor*/);
     if (bytes_needed > 0) {
         static const char *paths[] = { DEVRANDOM_EGD, NULL };
@@ -564,7 +584,7 @@ int rand_pool_add_nonce_data(RAND_POOL *pool)
 
     /*
      * Add process id, thread id, and a high resolution timestamp to
-     * ensure that the nonce is unique whith high probability for
+     * ensure that the nonce is unique with high probability for
      * different process instances.
      */
     data.pid = getpid();