Move much of rand/ into the FIPS module.

Support for platforms that we don't support FIPS on doesn't need to be
in the module. Also, functions for dealing with whether fork-unsafe
buffering is enabled are left out because they aren't implementing any
cryptography and they use global r/w state, making their inclusion
painful.

Change-Id: I71a0123db6f5449e9dfc7ec7dea0944428e661aa
Reviewed-on: https://boringssl-review.googlesource.com/15084
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt
index 6991ac9..be36c4b 100644
--- a/crypto/CMakeLists.txt
+++ b/crypto/CMakeLists.txt
@@ -90,7 +90,7 @@
 # Level 1, depends only on 0.*
 add_subdirectory(digest_extra)
 add_subdirectory(cipher)
-add_subdirectory(rand)
+add_subdirectory(rand_extra)
 add_subdirectory(bio)
 add_subdirectory(bn)
 add_subdirectory(obj)
@@ -177,7 +177,7 @@
   $<TARGET_OBJECTS:buf>
   $<TARGET_OBJECTS:bn>
   $<TARGET_OBJECTS:bio>
-  $<TARGET_OBJECTS:rand>
+  $<TARGET_OBJECTS:rand_extra>
   $<TARGET_OBJECTS:obj>
   $<TARGET_OBJECTS:asn1>
   $<TARGET_OBJECTS:engine>
@@ -245,7 +245,7 @@
   ec/ec_test.cc
   err/err_test.cc
   evp/evp_extra_test.cc
-  rand/ctrdrbg_test.cc
+  fipsmodule/rand/ctrdrbg_test.cc
   rsa/rsa_test.cc
 
   $<TARGET_OBJECTS:gtest_main>
diff --git a/crypto/bn/random.c b/crypto/bn/random.c
index 55eca80..4b3da75 100644
--- a/crypto/bn/random.c
+++ b/crypto/bn/random.c
@@ -117,7 +117,7 @@
 #include <openssl/type_check.h>
 
 #include "../internal.h"
-#include "../rand/internal.h"
+#include "../fipsmodule/rand/internal.h"
 
 
 static const uint8_t kZeroAdditionalData[32] = {0};
diff --git a/crypto/fipsmodule/CMakeLists.txt b/crypto/fipsmodule/CMakeLists.txt
index 375a3db..4c20218 100644
--- a/crypto/fipsmodule/CMakeLists.txt
+++ b/crypto/fipsmodule/CMakeLists.txt
@@ -14,6 +14,7 @@
     vpaes-x86_64.${ASM_EXT}
     aesni-gcm-x86_64.${ASM_EXT}
     ghash-x86_64.${ASM_EXT}
+    rdrand-x86_64.${ASM_EXT}
   )
 endif()
 
@@ -85,6 +86,7 @@
 perlasm(ghash-x86.${ASM_EXT} modes/asm/ghash-x86.pl)
 perlasm(md5-586.${ASM_EXT} md5/asm/md5-586.pl)
 perlasm(md5-x86_64.${ASM_EXT} md5/asm/md5-x86_64.pl)
+perlasm(rdrand-x86_64.${ASM_EXT} rand/asm/rdrand-x86_64.pl)
 perlasm(sha1-586.${ASM_EXT} sha/asm/sha1-586.pl)
 perlasm(sha1-armv4-large.${ASM_EXT} sha/asm/sha1-armv4-large.pl)
 perlasm(sha1-armv8.${ASM_EXT} sha/asm/sha1-armv8.pl)
@@ -198,3 +200,14 @@
 
 target_link_libraries(gcm_test crypto)
 add_dependencies(all_tests gcm_test)
+
+add_executable(
+  ctrdrbg_vector_test
+
+  rand/ctrdrbg_vector_test.cc
+
+  $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(ctrdrbg_vector_test crypto)
+add_dependencies(all_tests ctrdrbg_vector_test)
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c
index b93ab83..e90f0a4 100644
--- a/crypto/fipsmodule/bcm.c
+++ b/crypto/fipsmodule/bcm.c
@@ -12,6 +12,10 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
+#if !defined(_GNU_SOURCE)
+#define _GNU_SOURCE  /* needed for syscall() on Linux. */
+#endif
+
 #include <openssl/aead.h>
 #include <openssl/aes.h>
 #include <openssl/base.h>
@@ -19,13 +23,13 @@
 #include <openssl/bytestring.h>
 #include <openssl/crypto.h>
 #include <openssl/des.h>
-#include <openssl/ec_key.h>
 #include <openssl/ecdsa.h>
+#include <openssl/ec_key.h>
 #include <openssl/hmac.h>
 #include <openssl/rsa.h>
 
 #include "../internal.h"
-#include "../rand/internal.h"
+#include "rand/internal.h"
 
 #include "aes/aes.c"
 #include "aes/key_wrap.c"
@@ -41,6 +45,9 @@
 #include "modes/gcm.c"
 #include "modes/ofb.c"
 #include "modes/polyval.c"
+#include "rand/ctrdrbg.c"
+#include "rand/rand.c"
+#include "rand/urandom.c"
 #include "sha/sha1-altivec.c"
 #include "sha/sha1.c"
 #include "sha/sha256.c"
diff --git a/crypto/fipsmodule/delocate.h b/crypto/fipsmodule/delocate.h
index 676073c..f4ee3c8 100644
--- a/crypto/fipsmodule/delocate.h
+++ b/crypto/fipsmodule/delocate.h
@@ -21,13 +21,24 @@
 
 
 #if defined(BORINGSSL_FIPS)
-#define DEFINE_BSS_GET(type, name)            \
+#define DEFINE_BSS_GET(type, name)        \
   static type name __attribute__((used)); \
   type *name##_bss_get(void);
+/* For FIPS builds we require that CRYPTO_ONCE_INIT be zero. */
+#define DEFINE_STATIC_ONCE(name) DEFINE_BSS_GET(CRYPTO_once_t, name)
+/* For FIPS builds we require that CRYPTO_STATIC_MUTEX_INIT be zero. */
+#define DEFINE_STATIC_MUTEX(name) \
+  DEFINE_BSS_GET(struct CRYPTO_STATIC_MUTEX, name)
 #else
 #define DEFINE_BSS_GET(type, name) \
-  static type name;            \
+  static type name;                \
   static type *name##_bss_get(void) { return &name; }
+#define DEFINE_STATIC_ONCE(name)                \
+  static CRYPTO_once_t name = CRYPTO_ONCE_INIT; \
+  static CRYPTO_once_t *name##_bss_get(void) { return &name; }
+#define DEFINE_STATIC_MUTEX(name)                                    \
+  static struct CRYPTO_STATIC_MUTEX name = CRYPTO_STATIC_MUTEX_INIT; \
+  static struct CRYPTO_STATIC_MUTEX *name##_bss_get(void) { return &name; }
 #endif
 
 /* DEFINE_METHOD_FUNCTION defines a function named |name| which returns a
@@ -53,7 +64,7 @@
  * order is undefined. See FIPS.md for more details. */
 #define DEFINE_METHOD_FUNCTION(type, name)                                    \
   DEFINE_BSS_GET(type, name##_storage)                                        \
-  DEFINE_BSS_GET(CRYPTO_once_t, name##_once)                                  \
+  DEFINE_STATIC_ONCE(name##_once)                                             \
   static void name##_do_init(type *out);                                      \
   static void name##_init(void) { name##_do_init(name##_storage_bss_get()); } \
   const type *name(void) {                                                    \
diff --git a/crypto/rand/asm/rdrand-x86_64.pl b/crypto/fipsmodule/rand/asm/rdrand-x86_64.pl
similarity index 96%
rename from crypto/rand/asm/rdrand-x86_64.pl
rename to crypto/fipsmodule/rand/asm/rdrand-x86_64.pl
index c32a55c..3583d4c 100644
--- a/crypto/rand/asm/rdrand-x86_64.pl
+++ b/crypto/fipsmodule/rand/asm/rdrand-x86_64.pl
@@ -19,7 +19,7 @@
 if ($flavour =~ /\./) { $output = $flavour; undef $flavour; }
 
 $0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1;
-( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
+( $xlate="${dir}../../../perlasm/x86_64-xlate.pl" and -f $xlate) or
 die "can't locate x86_64-xlate.pl";
 
 open OUT,"| \"$^X\" $xlate $flavour $output";
diff --git a/crypto/rand/ctrdrbg.c b/crypto/fipsmodule/rand/ctrdrbg.c
similarity index 99%
rename from crypto/rand/ctrdrbg.c
rename to crypto/fipsmodule/rand/ctrdrbg.c
index 2b22f5d..5920837 100644
--- a/crypto/rand/ctrdrbg.c
+++ b/crypto/fipsmodule/rand/ctrdrbg.c
@@ -18,7 +18,7 @@
 #include <openssl/mem.h>
 
 #include "internal.h"
-#include "../cipher/internal.h"
+#include "../../cipher/internal.h"
 
 
 /* Section references in this file refer to SP 800-90Ar1:
diff --git a/crypto/rand/ctrdrbg_test.cc b/crypto/fipsmodule/rand/ctrdrbg_test.cc
similarity index 98%
rename from crypto/rand/ctrdrbg_test.cc
rename to crypto/fipsmodule/rand/ctrdrbg_test.cc
index 2ff1027..a35e6b0 100644
--- a/crypto/rand/ctrdrbg_test.cc
+++ b/crypto/fipsmodule/rand/ctrdrbg_test.cc
@@ -18,7 +18,7 @@
 #include <openssl/sha.h>
 
 #include "internal.h"
-#include "../test/test_util.h"
+#include "../../test/test_util.h"
 
 
 TEST(CTRDRBGTest, Basic) {
diff --git a/crypto/rand/ctrdrbg_vector_test.cc b/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc
similarity index 97%
rename from crypto/rand/ctrdrbg_vector_test.cc
rename to crypto/fipsmodule/rand/ctrdrbg_vector_test.cc
index 7c93861..4680e6e 100644
--- a/crypto/rand/ctrdrbg_vector_test.cc
+++ b/crypto/fipsmodule/rand/ctrdrbg_vector_test.cc
@@ -17,8 +17,8 @@
 #include <openssl/crypto.h>
 
 #include "internal.h"
-#include "../test/test_util.h"
-#include "../test/file_test.h"
+#include "../../test/test_util.h"
+#include "../../test/file_test.h"
 
 
 static bool TestCTRDRBG(FileTest *t, void *arg) {
diff --git a/crypto/rand/ctrdrbg_vectors.txt b/crypto/fipsmodule/rand/ctrdrbg_vectors.txt
similarity index 100%
rename from crypto/rand/ctrdrbg_vectors.txt
rename to crypto/fipsmodule/rand/ctrdrbg_vectors.txt
diff --git a/crypto/rand/internal.h b/crypto/fipsmodule/rand/internal.h
similarity index 97%
rename from crypto/rand/internal.h
rename to crypto/fipsmodule/rand/internal.h
index 349daf0..f569c38 100644
--- a/crypto/rand/internal.h
+++ b/crypto/fipsmodule/rand/internal.h
@@ -17,8 +17,8 @@
 
 #include <openssl/aes.h>
 
-#include "../internal.h"
-#include "../fipsmodule/modes/internal.h"
+#include "../../internal.h"
+#include "../modes/internal.h"
 
 #if defined(__cplusplus)
 extern "C" {
diff --git a/crypto/rand/rand.c b/crypto/fipsmodule/rand/rand.c
similarity index 88%
rename from crypto/rand/rand.c
rename to crypto/fipsmodule/rand/rand.c
index 028979a..e42ad46 100644
--- a/crypto/rand/rand.c
+++ b/crypto/fipsmodule/rand/rand.c
@@ -23,7 +23,7 @@
 #include <openssl/mem.h>
 
 #include "internal.h"
-#include "../internal.h"
+#include "../../internal.h"
 
 
 /* It's assumed that the operating system always has an unfailing source of
@@ -261,53 +261,3 @@
 int RAND_pseudo_bytes(uint8_t *buf, size_t len) {
   return RAND_bytes(buf, len);
 }
-
-void RAND_seed(const void *buf, int num) {
-  /* OpenSSH calls |RAND_seed| before jailing on the assumption that any needed
-   * file descriptors etc will be opened. */
-  uint8_t unused;
-  RAND_bytes(&unused, sizeof(unused));
-}
-
-int RAND_load_file(const char *path, long num) {
-  if (num < 0) {  /* read the "whole file" */
-    return 1;
-  } else if (num <= INT_MAX) {
-    return (int) num;
-  } else {
-    return INT_MAX;
-  }
-}
-
-const char *RAND_file_name(char *buf, size_t num) { return NULL; }
-
-void RAND_add(const void *buf, int num, double entropy) {}
-
-int RAND_egd(const char *path) {
-  return 255;
-}
-
-int RAND_poll(void) {
-  return 1;
-}
-
-int RAND_status(void) {
-  return 1;
-}
-
-static const struct rand_meth_st kSSLeayMethod = {
-  RAND_seed,
-  RAND_bytes,
-  RAND_cleanup,
-  RAND_add,
-  RAND_pseudo_bytes,
-  RAND_status,
-};
-
-RAND_METHOD *RAND_SSLeay(void) {
-  return (RAND_METHOD*) &kSSLeayMethod;
-}
-
-void RAND_set_rand_method(const RAND_METHOD *method) {}
-
-void RAND_cleanup(void) {}
diff --git a/crypto/rand/urandom.c b/crypto/fipsmodule/rand/urandom.c
similarity index 67%
rename from crypto/rand/urandom.c
rename to crypto/fipsmodule/rand/urandom.c
index f3aab44..474c4bc 100644
--- a/crypto/rand/urandom.c
+++ b/crypto/fipsmodule/rand/urandom.c
@@ -12,10 +12,6 @@
  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
 
-#if !defined(_GNU_SOURCE)
-#define _GNU_SOURCE  /* needed for syscall() on Linux. */
-#endif
-
 #include <openssl/rand.h>
 
 #if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_FUCHSIA) && \
@@ -38,7 +34,8 @@
 #include <openssl/mem.h>
 
 #include "internal.h"
-#include "../internal.h"
+#include "../delocate.h"
+#include "../../internal.h"
 
 
 #if defined(OPENSSL_LINUX)
@@ -78,30 +75,42 @@
 
 #endif  /* OPENSSL_LINUX */
 
-/* requested_lock is used to protect the |*_requested| variables. */
-static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT;
+/* rand_lock is used to protect the |*_requested| variables. */
+DEFINE_STATIC_MUTEX(rand_lock);
 
 /* The following constants are magic values of |urandom_fd|. */
-static const int kUnset = -2;
+static const int kUnset = 0;
 static const int kHaveGetrandom = -3;
 
 /* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by
- * |requested_lock|. */
-static int urandom_fd_requested = -2 /* kUnset */;
+ * |rand_lock|. */
+DEFINE_BSS_GET(int, urandom_fd_requested);
 
 /* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */
-static int urandom_fd = -2 /* kUnset */;
+DEFINE_BSS_GET(int, urandom_fd);
 
-static CRYPTO_once_t once = CRYPTO_ONCE_INIT;
+DEFINE_STATIC_ONCE(rand_once);
+
+#if defined(USE_SYS_getrandom) || defined(BORINGSSL_FIPS)
+/* message writes |msg| to stderr. We use this because referencing |stderr|
+ * with |fprintf| generates relocations, which is a problem inside the FIPS
+ * module. */
+static void message(const char *msg) {
+  ssize_t r;
+  do {
+    r = write(2, msg, strlen(msg));
+  } while (r == -1 && errno == EINTR);
+}
+#endif
 
 /* init_once initializes the state of this module to values previously
  * requested. This is the only function that modifies |urandom_fd| and
  * |urandom_buffering|, whose values may be read safely after calling the
  * once. */
 static void init_once(void) {
-  CRYPTO_STATIC_MUTEX_lock_read(&requested_lock);
-  int fd = urandom_fd_requested;
-  CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock);
+  CRYPTO_STATIC_MUTEX_lock_read(rand_lock_bss_get());
+  int fd = *urandom_fd_requested_bss_get();
+  CRYPTO_STATIC_MUTEX_unlock_read(rand_lock_bss_get());
 
 #if defined(USE_SYS_getrandom)
   uint8_t dummy;
@@ -109,20 +118,21 @@
       syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
 
   if (getrandom_ret == 1) {
-    urandom_fd = kHaveGetrandom;
+    *urandom_fd_bss_get() = kHaveGetrandom;
     return;
   } else if (getrandom_ret == -1 && errno == EAGAIN) {
-    fprintf(stderr,
-            "getrandom indicates that the entropy pool has not been "
-            "initialized. Rather than continue with poor entropy, this process "
-            "will block until entropy is available.\n");
+    message(
+        "getrandom indicates that the entropy pool has not been initialized. "
+        "Rather than continue with poor entropy, this process will block until "
+        "entropy is available.\n");
+
     do {
       getrandom_ret =
           syscall(SYS_getrandom, &dummy, sizeof(dummy), 0 /* no flags */);
     } while (getrandom_ret == -1 && errno == EINTR);
 
     if (getrandom_ret == 1) {
-      urandom_fd = kHaveGetrandom;
+      *urandom_fd_bss_get() = kHaveGetrandom;
       return;
     }
   }
@@ -138,6 +148,19 @@
     abort();
   }
 
+  assert(kUnset == 0);
+  if (fd == kUnset) {
+    /* Because we want to keep |urandom_fd| in the BSS, we have to initialise
+     * it to zero. But zero is a valid file descriptor too. Thus if open
+     * returns zero for /dev/urandom, we dup it to get a non-zero number. */
+    fd = dup(fd);
+    close(kUnset);
+
+    if (fd <= 0) {
+      abort();
+    }
+  }
+
 #if defined(BORINGSSL_FIPS)
   /* In FIPS mode we ensure that the kernel has sufficient entropy before
    * continuing. This is automatically handled by getrandom, which requires
@@ -147,9 +170,9 @@
   for (;;) {
     int entropy_bits;
     if (ioctl(fd, RNDGETENTCNT, &entropy_bits)) {
-      fprintf(stderr,
-              "RNDGETENTCNT on /dev/urandom failed. We cannot continue in this "
-              "case when in FIPS mode.\n");
+      message(
+          "RNDGETENTCNT on /dev/urandom failed. We cannot continue in this "
+          "case when in FIPS mode.\n");
       abort();
     }
 
@@ -159,10 +182,10 @@
     }
 
     if (first_iteration) {
-      fprintf(stderr,
-              "The kernel entropy pool contains too few bits: have %d, want "
-              "%d. This process is built in FIPS mode and will block until "
-              "sufficient entropy is available.\n", entropy_bits, kBitsNeeded);
+      message(
+          "The kernel entropy pool contains too few bits. This process is "
+          "built in FIPS mode and will block until sufficient entropy is "
+          "available.\n");
     }
     first_iteration = 0;
 
@@ -182,7 +205,7 @@
       abort();
     }
   }
-  urandom_fd = fd;
+  *urandom_fd_bss_get() = fd;
 }
 
 void RAND_set_urandom_fd(int fd) {
@@ -191,14 +214,27 @@
     abort();
   }
 
-  CRYPTO_STATIC_MUTEX_lock_write(&requested_lock);
-  urandom_fd_requested = fd;
-  CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock);
+  assert(kUnset == 0);
+  if (fd == kUnset) {
+    /* Because we want to keep |urandom_fd| in the BSS, we have to initialise
+     * it to zero. But zero is a valid file descriptor too. Thus if dup
+     * returned zero we dup it again to get a non-zero number. */
+    fd = dup(fd);
+    close(kUnset);
 
-  CRYPTO_once(&once, init_once);
-  if (urandom_fd == kHaveGetrandom) {
+    if (fd <= 0) {
+      abort();
+    }
+  }
+
+  CRYPTO_STATIC_MUTEX_lock_write(rand_lock_bss_get());
+  *urandom_fd_requested_bss_get() = fd;
+  CRYPTO_STATIC_MUTEX_unlock_write(rand_lock_bss_get());
+
+  CRYPTO_once(rand_once_bss_get(), init_once);
+  if (*urandom_fd_bss_get() == kHaveGetrandom) {
     close(fd);
-  } else if (urandom_fd != fd) {
+  } else if (*urandom_fd_bss_get() != fd) {
     abort();  // Already initialized.
   }
 }
@@ -215,7 +251,7 @@
   while (len > 0) {
     ssize_t r;
 
-    if (urandom_fd == kHaveGetrandom) {
+    if (*urandom_fd_bss_get() == kHaveGetrandom) {
 #if defined(USE_SYS_getrandom)
       do {
         r = syscall(SYS_getrandom, out, len, 0 /* no flags */);
@@ -236,7 +272,7 @@
 #endif
     } else {
       do {
-        r = read(urandom_fd, out, len);
+        r = read(*urandom_fd_bss_get(), out, len);
       } while (r == -1 && errno == EINTR);
     }
 
@@ -256,7 +292,7 @@
     return;
   }
 
-  CRYPTO_once(&once, init_once);
+  CRYPTO_once(rand_once_bss_get(), init_once);
 
   if (!fill_with_entropy(out, requested)) {
     abort();
diff --git a/crypto/rand/CMakeLists.txt b/crypto/rand/CMakeLists.txt
deleted file mode 100644
index c2b1fda..0000000
--- a/crypto/rand/CMakeLists.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-include_directories(../../include)
-
-if (${ARCH} STREQUAL "x86_64")
-  set(
-    RAND_ARCH_SOURCES
-
-    rdrand-x86_64.${ASM_EXT}
-  )
-endif()
-
-add_library(
-  rand
-
-  OBJECT
-
-  ctrdrbg.c
-  deterministic.c
-  forkunsafe.c
-  fuchsia.c
-  rand.c
-  urandom.c
-  windows.c
-
-  ${RAND_ARCH_SOURCES}
-)
-
-perlasm(rdrand-x86_64.${ASM_EXT} asm/rdrand-x86_64.pl)
-
-add_executable(
-  ctrdrbg_vector_test
-
-  ctrdrbg_vector_test.cc
-
-  $<TARGET_OBJECTS:test_support>
-)
-
-target_link_libraries(ctrdrbg_vector_test crypto)
-add_dependencies(all_tests ctrdrbg_vector_test)
diff --git a/crypto/rand_extra/CMakeLists.txt b/crypto/rand_extra/CMakeLists.txt
new file mode 100644
index 0000000..2841ef6
--- /dev/null
+++ b/crypto/rand_extra/CMakeLists.txt
@@ -0,0 +1,12 @@
+include_directories(../../include)
+
+add_library(
+  rand_extra
+
+  OBJECT
+
+  forkunsafe.c
+  fuchsia.c
+  rand_extra.c
+  windows.c
+)
diff --git a/crypto/rand/deterministic.c b/crypto/rand_extra/deterministic.c
similarity index 97%
rename from crypto/rand/deterministic.c
rename to crypto/rand_extra/deterministic.c
index 8c754c1..5d3a9ce 100644
--- a/crypto/rand/deterministic.c
+++ b/crypto/rand_extra/deterministic.c
@@ -20,8 +20,8 @@
 
 #include <openssl/chacha.h>
 
-#include "internal.h"
 #include "../internal.h"
+#include "../fipsmodule/rand/internal.h"
 
 
 /* g_num_calls is the number of calls to |CRYPTO_sysrand| that have occurred.
diff --git a/crypto/rand/forkunsafe.c b/crypto/rand_extra/forkunsafe.c
similarity index 97%
rename from crypto/rand/forkunsafe.c
rename to crypto/rand_extra/forkunsafe.c
index e9badc9..1a3977f 100644
--- a/crypto/rand/forkunsafe.c
+++ b/crypto/rand_extra/forkunsafe.c
@@ -16,7 +16,7 @@
 
 #include <stdlib.h>
 
-#include "internal.h"
+#include "../fipsmodule/rand/internal.h"
 
 
 /* g_buffering_enabled is true if fork-unsafe buffering has been enabled. */
diff --git a/crypto/rand/fuchsia.c b/crypto/rand_extra/fuchsia.c
similarity index 96%
rename from crypto/rand/fuchsia.c
rename to crypto/rand_extra/fuchsia.c
index 2e138d0..fae2989 100644
--- a/crypto/rand/fuchsia.c
+++ b/crypto/rand_extra/fuchsia.c
@@ -21,7 +21,7 @@
 
 #include <magenta/syscalls.h>
 
-#include "internal.h"
+#include "../fipsmodule/rand/internal.h"
 
 void CRYPTO_sysrand(uint8_t *out, size_t requested) {
   while (requested > 0) {
diff --git a/crypto/rand_extra/rand_extra.c b/crypto/rand_extra/rand_extra.c
new file mode 100644
index 0000000..8fce3c8
--- /dev/null
+++ b/crypto/rand_extra/rand_extra.c
@@ -0,0 +1,68 @@
+/* Copyright (c) 2017, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/rand.h>
+
+#include <limits.h>
+
+
+void RAND_seed(const void *buf, int num) {
+  /* OpenSSH calls |RAND_seed| before jailing on the assumption that any needed
+   * file descriptors etc will be opened. */
+  uint8_t unused;
+  RAND_bytes(&unused, sizeof(unused));
+}
+
+int RAND_load_file(const char *path, long num) {
+  if (num < 0) {  /* read the "whole file" */
+    return 1;
+  } else if (num <= INT_MAX) {
+    return (int) num;
+  } else {
+    return INT_MAX;
+  }
+}
+
+const char *RAND_file_name(char *buf, size_t num) { return NULL; }
+
+void RAND_add(const void *buf, int num, double entropy) {}
+
+int RAND_egd(const char *path) {
+  return 255;
+}
+
+int RAND_poll(void) {
+  return 1;
+}
+
+int RAND_status(void) {
+  return 1;
+}
+
+static const struct rand_meth_st kSSLeayMethod = {
+  RAND_seed,
+  RAND_bytes,
+  RAND_cleanup,
+  RAND_add,
+  RAND_pseudo_bytes,
+  RAND_status,
+};
+
+RAND_METHOD *RAND_SSLeay(void) {
+  return (RAND_METHOD*) &kSSLeayMethod;
+}
+
+void RAND_set_rand_method(const RAND_METHOD *method) {}
+
+void RAND_cleanup(void) {}
diff --git a/crypto/rand/windows.c b/crypto/rand_extra/windows.c
similarity index 97%
rename from crypto/rand/windows.c
rename to crypto/rand_extra/windows.c
index f47182d..fb94847 100644
--- a/crypto/rand/windows.c
+++ b/crypto/rand_extra/windows.c
@@ -32,7 +32,7 @@
 
 OPENSSL_MSVC_PRAGMA(warning(pop))
 
-#include "internal.h"
+#include "../fipsmodule/rand/internal.h"
 
 
 void CRYPTO_sysrand(uint8_t *out, size_t requested) {
diff --git a/crypto/thread_test.c b/crypto/thread_test.c
index 714bef7..4763fd3 100644
--- a/crypto/thread_test.c
+++ b/crypto/thread_test.c
@@ -103,6 +103,9 @@
 static CRYPTO_once_t once_init_value = CRYPTO_ONCE_INIT;
 static CRYPTO_once_t once_bss;
 
+static struct CRYPTO_STATIC_MUTEX mutex_init_value = CRYPTO_STATIC_MUTEX_INIT;
+static struct CRYPTO_STATIC_MUTEX mutex_bss;
+
 static int test_once(void) {
   if (g_once_init_called != 0) {
     fprintf(stderr, "g_once_init_called was non-zero at start.\n");
@@ -127,13 +130,20 @@
   }
 
   if (FIPS_mode()) {
-    /* Our FIPS tooling currently requires that |CRYPTO_ONCE_INIT| is all
-     * zeros, so the |CRYPTO_once_t| is placed in the bss. */
+    /* Our FIPS tooling currently requires that |CRYPTO_ONCE_INIT| and
+     * |CRYPTO_STATIC_MUTEX_INIT| are all zeros and so can be placed in the BSS
+     * section. */
     if (OPENSSL_memcmp((void *)&once_init_value, (void *)&once_bss,
                        sizeof(CRYPTO_once_t)) != 0) {
       fprintf(stderr, "CRYPTO_ONCE_INIT did not expand to all zeros.\n");
       return 0;
     }
+
+    if (OPENSSL_memcmp((void *)&mutex_init_value, (void *)&mutex_bss,
+                       sizeof(struct CRYPTO_STATIC_MUTEX)) != 0) {
+      fprintf(stderr, "CRYPTO_STATIC_MUTEX did not expand to all zeros.\n");
+      return 0;
+    }
   }
 
   return 1;
diff --git a/util/all_tests.json b/util/all_tests.json
index ff82a6d..f34e7c4 100644
--- a/util/all_tests.json
+++ b/util/all_tests.json
@@ -54,7 +54,7 @@
 	["crypto/pkcs8/pkcs8_test"],
 	["crypto/poly1305/poly1305_test", "crypto/poly1305/poly1305_tests.txt"],
 	["crypto/pool/pool_test"],
-	["crypto/rand/ctrdrbg_vector_test", "crypto/rand/ctrdrbg_vectors.txt"],
+	["crypto/fipsmodule/ctrdrbg_vector_test", "crypto/fipsmodule/rand/ctrdrbg_vectors.txt"],
 	["crypto/refcount_test"],
 	["crypto/thread_test"],
 	["crypto/x509/x509_test"],