Split FIPS KATs into fast and slow groups.

The provision of FIPS that allowed the tests to be skipped based on a
flag-file has been removed in 140-3. Therefore we expect to run the fast
KATs on start-up, but to defer to slower ones until the functionality in
question is first used. So this change splits off the fast KATs and
removes support for skipping KATs based on a flag-file.

Change-Id: Ib24cb1739cfef93e4a1349d786a0257ee1083cfb
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51326
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/FIPS.md b/crypto/fipsmodule/FIPS.md
index d3b3890..29fc688 100644
--- a/crypto/fipsmodule/FIPS.md
+++ b/crypto/fipsmodule/FIPS.md
@@ -61,12 +61,6 @@
 
 FIPS requires that RNG state be zeroed when the process exits. In order to implement this, all per-thread RNG states are tracked in a linked list and a destructor function is included which clears them. In order for this to be safe in the presence of threads, a lock is used to stop all other threads from using the RNG once this process has begun. Thus the main thread exiting may cause other threads to deadlock, and drawing on entropy in a destructor function may also deadlock.
 
-## Self-test optimisation
-
-On Android, the self-tests are optimised in line with [IG](https://csrc.nist.gov/csrc/media/projects/cryptographic-module-validation-program/documents/fips140-2/fips1402ig.pdf) section 9.11. The module will always perform the integrity test at power-on, but the self-tests will test for the presence of a file named after the hex encoded, HMAC-SHA-256 hash of the module in `/dev/boringssl/selftest/`. If such a file is found then the self-tests are skipped. Otherwise, after the self-tests complete successfully, that file will be written. Any I/O errors are ignored and, if they occur when testing for the presence of the file, the module acts as if it's not present.
-
-It is intended that a `tmpfs` be mounted at that location in order to skip running the self tests for every process once they have already passed in a given instance of the operating system.
-
 ## Integrity Test
 
 FIPS-140 mandates that a module calculate an HMAC of its own code in a constructor function and compare the result to a known-good value. Typical code produced by a C compiler includes large numbers of relocations: places in the machine code where the linker needs to resolve and inject the final value of a symbolic expression. These relocations mean that the bytes that make up any specific bit of code generally aren't known until the final link has completed.
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c
index bab30cf..f83c6f5 100644
--- a/crypto/fipsmodule/bcm.c
+++ b/crypto/fipsmodule/bcm.c
@@ -239,15 +239,11 @@
   }
 
   OPENSSL_cleanse(result, sizeof(result)); // FIPS 140-3, AS05.10.
+#endif  // OPENSSL_ASAN
 
-  if (!boringssl_fips_self_test(BORINGSSL_bcm_text_hash, sizeof(result))) {
-    goto err;
-  }
-#else
   if (!BORINGSSL_self_test()) {
     goto err;
   }
-#endif  // OPENSSL_ASAN
 
   return;
 
diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c
index 9dacf91..da018f1 100644
--- a/crypto/fipsmodule/self_check/self_check.c
+++ b/crypto/fipsmodule/self_check/self_check.c
@@ -46,21 +46,6 @@
 
 #else
 
-#if defined(BORINGSSL_FIPS) && defined(OPENSSL_ANDROID)
-// FIPS builds on Android will test for flag files, named after the module hash,
-// in /dev/boringssl/selftest/. If such a flag file exists, it's assumed that
-// self-tests have already passed and thus do not need to be repeated. (The
-// integrity tests always run, however.)
-//
-// If self-tests complete successfully and the environment variable named in
-// |kFlagWriteEnableEnvVar| is present, then the flag file will be created. The
-// flag file isn't written without the environment variable being set in order
-// to avoid SELinux violations on Android.
-#define BORINGSSL_FIPS_SELF_TEST_FLAG_FILE
-static const char kFlagPrefix[] = "/dev/boringssl/selftest/";
-static const char kFlagWriteEnableEnvVar[] = "BORINGSSL_SELF_TEST_CREATE_FLAG";
-#endif
-
 static void hexdump(const uint8_t *in, size_t len) {
   for (size_t i = 0; i < len; i++) {
     fprintf(stderr, "%02x", in[i]);
@@ -288,42 +273,270 @@
   return NULL;
 }
 
-#if defined(OPENSSL_ANDROID)
-#define MODULE_DIGEST_SIZE SHA256_DIGEST_LENGTH
+static int boringssl_self_test_slow(void) {
+  static const uint8_t kExampleDigest[32] = {
+      0x37, 0xbd, 0x70, 0x53, 0x72, 0xfc, 0xd4, 0x03, 0x79, 0x70, 0xfb,
+      0x06, 0x95, 0xb1, 0x2a, 0x82, 0x48, 0xe1, 0x3e, 0xf2, 0x33, 0xfb,
+      0xef, 0x29, 0x81, 0x22, 0x45, 0x40, 0x43, 0x70, 0xce, 0x0f,
+  };
+  static const uint8_t kRSASignature[256] = {
+      0x62, 0x66, 0x4b, 0xe3, 0xb1, 0xd2, 0x83, 0xf1, 0xa8, 0x56, 0x2b, 0x33,
+      0x60, 0x1e, 0xdb, 0x1e, 0x06, 0xf7, 0xa7, 0x1e, 0xa8, 0xef, 0x03, 0x4d,
+      0x0c, 0xf6, 0x83, 0x75, 0x7a, 0xf0, 0x14, 0xc7, 0xe2, 0x94, 0x3a, 0xb5,
+      0x67, 0x56, 0xa5, 0x48, 0x7f, 0x3a, 0xa5, 0xbf, 0xf7, 0x1d, 0x44, 0xa6,
+      0x34, 0xed, 0x9b, 0xd6, 0x51, 0xaa, 0x2c, 0x4e, 0xce, 0x60, 0x5f, 0xe9,
+      0x0e, 0xd5, 0xcd, 0xeb, 0x23, 0x27, 0xf8, 0xfb, 0x45, 0xe5, 0x34, 0x63,
+      0x77, 0x7f, 0x2e, 0x80, 0xcf, 0x9d, 0x2e, 0xfc, 0xe2, 0x50, 0x75, 0x29,
+      0x46, 0xf4, 0xaf, 0x91, 0xed, 0x36, 0xe1, 0x5e, 0xef, 0x66, 0xa1, 0xff,
+      0x27, 0xfc, 0x87, 0x7e, 0x60, 0x84, 0x0f, 0x54, 0x51, 0x56, 0x0f, 0x68,
+      0x99, 0xc0, 0x3f, 0xeb, 0xa5, 0xa0, 0x46, 0xb0, 0x86, 0x02, 0xb0, 0xc8,
+      0xe8, 0x46, 0x13, 0x06, 0xcd, 0xb7, 0x8a, 0xd0, 0x3b, 0x46, 0xd0, 0x14,
+      0x64, 0x53, 0x9b, 0x5b, 0x5e, 0x02, 0x45, 0xba, 0x6e, 0x7e, 0x0a, 0xb9,
+      0x9e, 0x62, 0xb7, 0xd5, 0x7a, 0x87, 0xea, 0xd3, 0x24, 0xa5, 0xef, 0xb3,
+      0xdc, 0x05, 0x9c, 0x04, 0x60, 0x4b, 0xde, 0xa8, 0x90, 0x08, 0x7b, 0x6a,
+      0x5f, 0xb4, 0x3f, 0xda, 0xc5, 0x1f, 0x6e, 0xd6, 0x15, 0xde, 0x65, 0xa4,
+      0x6e, 0x62, 0x9d, 0x8f, 0xa8, 0xbe, 0x86, 0xf6, 0x09, 0x90, 0x40, 0xa5,
+      0xf4, 0x23, 0xc5, 0xf6, 0x38, 0x86, 0x0d, 0x1c, 0xed, 0x4a, 0x0a, 0xae,
+      0xa4, 0x26, 0xc2, 0x2e, 0xd3, 0x13, 0x66, 0x61, 0xea, 0x35, 0x01, 0x0e,
+      0x13, 0xda, 0x78, 0x20, 0xae, 0x59, 0x5f, 0x9b, 0xa9, 0x6c, 0xf9, 0x1b,
+      0xdf, 0x76, 0x53, 0xc8, 0xa7, 0xf5, 0x63, 0x6d, 0xf3, 0xff, 0xfd, 0xaf,
+      0x75, 0x4b, 0xac, 0x67, 0xb1, 0x3c, 0xbf, 0x5e, 0xde, 0x73, 0x02, 0x6d,
+      0xd2, 0x0c, 0xb1,
+#if !defined(BORINGSSL_FIPS_BREAK_RSA_SIG)
+      0x64
 #else
-#define MODULE_DIGEST_SIZE SHA512_DIGEST_LENGTH
+      0x00
 #endif
+  };
+  const uint8_t kECDSASigS[32] = {
+      0xa5, 0x93, 0xe0, 0x23, 0x91, 0xe7, 0x4b, 0x8d, 0x77, 0x25, 0xa6,
+      0xba, 0x4d, 0xd9, 0x86, 0x77, 0xda, 0x7d, 0x8f, 0xef, 0xc4, 0x1a,
+      0xf0, 0xcc, 0x81, 0xe5, 0xea, 0x3f, 0xc2, 0x41, 0x7f, 0xd8,
+  };
+  // kP256Point is SHA256("Primitive Z Computation KAT")×G within P-256.
+  const uint8_t kP256Point[65] = {
+      0x04, 0x4e, 0xc1, 0x94, 0x8c, 0x5c, 0xf4, 0x37, 0x35, 0x0d, 0xa3,
+      0xf9, 0x55, 0xf9, 0x8b, 0x26, 0x23, 0x5c, 0x43, 0xe0, 0x83, 0x51,
+      0x2b, 0x0d, 0x4b, 0x56, 0x24, 0xc3, 0xe4, 0xa5, 0xa8, 0xe2, 0xe9,
+      0x95, 0xf2, 0xc4, 0xb9, 0xb7, 0x48, 0x7d, 0x2a, 0xae, 0xc5, 0xc0,
+      0x0a, 0xcc, 0x1b, 0xd0, 0xec, 0xb8, 0xdc, 0xbe, 0x0c, 0xbe, 0x52,
+      0x79, 0x93, 0x7c, 0x0b, 0x92, 0x2b, 0x7f, 0x17, 0xa5, 0x80,
+  };
+  // kP256Scalar is SHA256("Primitive Z Computation KAT scalar").
+  const uint8_t kP256Scalar[32] = {
+      0xe7, 0x60, 0x44, 0x91, 0x26, 0x9a, 0xfb, 0x5b, 0x10, 0x2d, 0x6e,
+      0xa5, 0x2c, 0xb5, 0x9f, 0xeb, 0x70, 0xae, 0xde, 0x6c, 0xe3, 0xbf,
+      0xb3, 0xe0, 0x10, 0x54, 0x85, 0xab, 0xd8, 0x61, 0xd7, 0x7b,
+  };
+  // kP256PointResult is |kP256Scalar|×|kP256Point|.
+  const uint8_t kP256PointResult[65] = {
+      0x04, 0xf1, 0x63, 0x00, 0x88, 0xc5, 0xd5, 0xe9, 0x05, 0x52, 0xac,
+      0xb6, 0xec, 0x68, 0x76, 0xb8, 0x73, 0x7f, 0x0f, 0x72, 0x34, 0xe6,
+      0xbb, 0x30, 0x32, 0x22, 0x37, 0xb6, 0x2a, 0x80, 0xe8, 0x9e, 0x6e,
+      0x6f, 0x36, 0x02, 0xe7, 0x21, 0xd2, 0x31, 0xdb, 0x94, 0x63, 0xb7,
+      0xd8, 0x19, 0x0e, 0xc2, 0xc0, 0xa7, 0x2f, 0x15, 0x49, 0x1a, 0xa2,
+      0x7c, 0x41, 0x8f, 0xaf, 0x9c, 0x40, 0xaf, 0x2e, 0x4a,
+#if !defined(BORINGSSL_FIPS_BREAK_Z_COMPUTATION)
+      0x0c,
+#else
+      0x00,
+#endif
+  };
+  // kFFDHE2048PublicValueData is an arbitrary public value, mod
+  // kFFDHE2048Data. (The private key happens to be 4096.)
+  const BN_ULONG kFFDHE2048PublicValueData[] = {
+      TOBN(0x187be36b, 0xd38a4fa1), TOBN(0x0a152f39, 0x6458f3b8),
+      TOBN(0x0570187e, 0xc422eeb7), TOBN(0x18af7482, 0x91173f2a),
+      TOBN(0xe9fdac6a, 0xcff4eaaa), TOBN(0xf6afebb7, 0x6e589d6c),
+      TOBN(0xf92f8e9a, 0xb7e33fb0), TOBN(0x70acf2aa, 0x4cf36ddd),
+      TOBN(0x561ab426, 0xd07137fd), TOBN(0x5f57d037, 0x430ee91e),
+      TOBN(0xe3e768c8, 0x60d10b8a), TOBN(0xb14884d8, 0xa18af8ce),
+      TOBN(0xf8a98014, 0xa12b74e4), TOBN(0x748d407c, 0x3437b7a8),
+      TOBN(0x627588c4, 0x9875d5a7), TOBN(0xdd24a127, 0x53c8f09d),
+      TOBN(0x85a997d5, 0x0cd51aec), TOBN(0x44f0c619, 0xce348458),
+      TOBN(0x9b894b24, 0x5f6b69a1), TOBN(0xae1302f2, 0xf6d4777e),
+      TOBN(0xe6678eeb, 0x375db18e), TOBN(0x2674e1d6, 0x4fbcbdc8),
+      TOBN(0xb297a823, 0x6fa93d28), TOBN(0x6a12fb70, 0x7c8c0510),
+      TOBN(0x5c6d1aeb, 0xdb06f65b), TOBN(0xe8c2954e, 0x4c1804ca),
+      TOBN(0x06bdeac1, 0xf5500fa7), TOBN(0x6a315604, 0x189cd76b),
+      TOBN(0xbae7b0b3, 0x6e362dc0), TOBN(0xa57c73bd, 0xdc70fb82),
+      TOBN(0xfaff50d2, 0x9d573457), TOBN(0x352bd399, 0xbe84058e),
+  };
+  const uint8_t kDHOutput[2048 / 8] = {
+      0x2a, 0xe6, 0xd3, 0xa6, 0x13, 0x58, 0x8e, 0xce, 0x53, 0xaa, 0xf6, 0x5d,
+      0x9a, 0xae, 0x02, 0x12, 0xf5, 0x80, 0x3d, 0x06, 0x09, 0x76, 0xac, 0x57,
+      0x37, 0x9e, 0xab, 0x38, 0x62, 0x25, 0x05, 0x1d, 0xf3, 0xa9, 0x39, 0x60,
+      0xf6, 0xae, 0x90, 0xed, 0x1e, 0xad, 0x6e, 0xe9, 0xe3, 0xba, 0x27, 0xf6,
+      0xdb, 0x54, 0xdf, 0xe2, 0xbd, 0xbb, 0x7f, 0xf1, 0x81, 0xac, 0x1a, 0xfa,
+      0xdb, 0x87, 0x07, 0x98, 0x76, 0x90, 0x21, 0xf2, 0xae, 0xda, 0x0d, 0x84,
+      0x97, 0x64, 0x0b, 0xbf, 0xb8, 0x8d, 0x10, 0x46, 0xe2, 0xd5, 0xca, 0x1b,
+      0xbb, 0xe5, 0x37, 0xb2, 0x3b, 0x35, 0xd3, 0x1b, 0x65, 0xea, 0xae, 0xf2,
+      0x03, 0xe2, 0xb6, 0xde, 0x22, 0xb7, 0x86, 0x49, 0x79, 0xfe, 0xd7, 0x16,
+      0xf7, 0xdc, 0x9c, 0x59, 0xf5, 0xb7, 0x70, 0xc0, 0x53, 0x42, 0x6f, 0xb1,
+      0xd2, 0x4e, 0x00, 0x25, 0x4b, 0x2d, 0x5a, 0x9b, 0xd0, 0xe9, 0x27, 0x43,
+      0xcc, 0x00, 0x66, 0xea, 0x94, 0x7a, 0x0b, 0xb9, 0x89, 0x0c, 0x5e, 0x94,
+      0xb8, 0x3a, 0x78, 0x9c, 0x4d, 0x84, 0xe6, 0x32, 0x2c, 0x38, 0x7c, 0xf7,
+      0x43, 0x9c, 0xd8, 0xb8, 0x1c, 0xce, 0x24, 0x91, 0x20, 0x67, 0x7a, 0x54,
+      0x1f, 0x7e, 0x86, 0x7f, 0xa1, 0xc1, 0x03, 0x4e, 0x2c, 0x26, 0x71, 0xb2,
+      0x06, 0x30, 0xb3, 0x6c, 0x15, 0xcc, 0xac, 0x25, 0xe5, 0x37, 0x3f, 0x24,
+      0x8f, 0x2a, 0x89, 0x5e, 0x3d, 0x43, 0x94, 0xc9, 0x36, 0xae, 0x40, 0x00,
+      0x6a, 0x0d, 0xb0, 0x6e, 0x8b, 0x2e, 0x70, 0x57, 0xe1, 0x88, 0x53, 0xd6,
+      0x06, 0x80, 0x2a, 0x4e, 0x5a, 0xf0, 0x1e, 0xaa, 0xcb, 0xab, 0x06, 0x0e,
+      0x27, 0x0f, 0xd9, 0x88, 0xd9, 0x01, 0xe3, 0x07, 0xeb, 0xdf, 0xc3, 0x12,
+      0xe3, 0x40, 0x88, 0x7b, 0x5f, 0x59, 0x78, 0x6e, 0x26, 0x20, 0xc3, 0xdf,
+      0xc8, 0xe4, 0x5e,
+#if !defined(BORINGSSL_FIPS_BREAK_FFC_DH)
+      0xb8,
+#else
+      0x00,
+#endif
+  };
+  const uint8_t kECDSASigR[32] = {
+      0x67, 0x80, 0xc5, 0xfc, 0x70, 0x27, 0x5e, 0x2c, 0x70, 0x61, 0xa0,
+      0xe7, 0x87, 0x7b, 0xb1, 0x74, 0xde, 0xad, 0xeb, 0x98, 0x87, 0x02,
+      0x7f, 0x3f, 0xa8, 0x36, 0x54, 0x15, 0x8b, 0xa7, 0xf5,
+#if !defined(BORINGSSL_FIPS_BREAK_ECDSA_SIG)
+      0x0c,
+#else
+      0x00,
+#endif
+  };
 
-int boringssl_fips_self_test(
-    const uint8_t *module_hash, size_t module_hash_len) {
-#if defined(BORINGSSL_FIPS_SELF_TEST_FLAG_FILE)
-  char flag_path[sizeof(kFlagPrefix) + 2 * MODULE_DIGEST_SIZE];
-  if (module_hash_len != 0) {
-    if (module_hash_len != MODULE_DIGEST_SIZE) {
-      fprintf(stderr,
-              "module hash of length %zu does not match expected length %d\n",
-              module_hash_len, MODULE_DIGEST_SIZE);
-      BORINGSSL_FIPS_abort();
-    }
+  int ret = 0;
+  RSA *rsa_key = NULL;
+  EC_KEY *ec_key = NULL;
+  EC_GROUP *ec_group = NULL;
+  EC_POINT *ec_point_in = NULL;
+  EC_POINT *ec_point_out = NULL;
+  BIGNUM *ec_scalar = NULL;
+  ECDSA_SIG *sig = NULL;
+  uint8_t output[256];
 
-    // Test whether the flag file exists.
-    memcpy(flag_path, kFlagPrefix, sizeof(kFlagPrefix) - 1);
-    static const char kHexTable[17] = "0123456789abcdef";
-    for (size_t i = 0; i < MODULE_DIGEST_SIZE; i++) {
-      flag_path[sizeof(kFlagPrefix) - 1 + 2 * i] =
-          kHexTable[module_hash[i] >> 4];
-      flag_path[sizeof(kFlagPrefix) - 1 + 2 * i + 1] =
-          kHexTable[module_hash[i] & 15];
-    }
-    flag_path[sizeof(flag_path) - 1] = 0;
-
-    if (access(flag_path, F_OK) == 0) {
-      // Flag file found. Skip self-tests.
-      return 1;
-    }
+  rsa_key = self_test_rsa_key();
+  if (rsa_key == NULL) {
+    fprintf(stderr, "RSA KeyGen failed\n");
+    goto err;
   }
-#endif // BORINGSSL_FIPS_SELF_TEST_FLAG_FILE
 
+  // RSA Sign KAT
+  unsigned sig_len;
+
+  // Disable blinding for the power-on tests because it's not needed and
+  // triggers an entropy draw.
+  rsa_key->flags |= RSA_FLAG_NO_BLINDING;
+
+  if (!RSA_sign(NID_sha256, kExampleDigest, sizeof(kExampleDigest), output,
+                &sig_len, rsa_key) ||
+      !check_test(kRSASignature, output, sizeof(kRSASignature),
+                  "RSA Sign KAT")) {
+    fprintf(stderr, "RSA signing test failed.\n");
+    goto err;
+  }
+
+  // RSA Verify KAT
+  if (!RSA_verify(NID_sha256, kExampleDigest, sizeof(kExampleDigest),
+                  kRSASignature, sizeof(kRSASignature), rsa_key)) {
+    fprintf(stderr, "RSA Verify KAT failed.\n");
+    goto err;
+  }
+
+  ec_key = self_test_ecdsa_key();
+  if (ec_key == NULL) {
+    fprintf(stderr, "ECDSA KeyGen failed\n");
+    goto err;
+  }
+
+  // ECDSA Sign/Verify KAT
+
+  // The 'k' value for ECDSA is fixed to avoid an entropy draw.
+  uint8_t ecdsa_k[32] = {0};
+  ecdsa_k[31] = 42;
+
+  sig = ecdsa_sign_with_nonce_for_known_answer_test(
+      kExampleDigest, sizeof(kExampleDigest), ec_key, ecdsa_k,
+      sizeof(ecdsa_k));
+
+  uint8_t ecdsa_r_bytes[sizeof(kECDSASigR)];
+  uint8_t ecdsa_s_bytes[sizeof(kECDSASigS)];
+  if (sig == NULL ||
+      BN_num_bytes(sig->r) != sizeof(ecdsa_r_bytes) ||
+      !BN_bn2bin(sig->r, ecdsa_r_bytes) ||
+      BN_num_bytes(sig->s) != sizeof(ecdsa_s_bytes) ||
+      !BN_bn2bin(sig->s, ecdsa_s_bytes) ||
+      !check_test(kECDSASigR, ecdsa_r_bytes, sizeof(kECDSASigR), "ECDSA R") ||
+      !check_test(kECDSASigS, ecdsa_s_bytes, sizeof(kECDSASigS), "ECDSA S")) {
+    fprintf(stderr, "ECDSA signature KAT failed.\n");
+    goto err;
+  }
+
+  if (!ECDSA_do_verify(kExampleDigest, sizeof(kExampleDigest), sig,
+                       ec_key)) {
+    fprintf(stderr, "ECDSA verification KAT failed.\n");
+    goto err;
+  }
+
+  // Primitive Z Computation KAT (IG 9.6).
+  ec_group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+  if (ec_group == NULL) {
+    fprintf(stderr, "Failed to create P-256 group.\n");
+    goto err;
+  }
+  ec_point_in = EC_POINT_new(ec_group);
+  ec_point_out = EC_POINT_new(ec_group);
+  ec_scalar = BN_new();
+  uint8_t z_comp_result[65];
+  if (ec_point_in == NULL || ec_point_out == NULL || ec_scalar == NULL ||
+      !EC_POINT_oct2point(ec_group, ec_point_in, kP256Point, sizeof(kP256Point),
+                          NULL) ||
+      !BN_bin2bn(kP256Scalar, sizeof(kP256Scalar), ec_scalar) ||
+      !EC_POINT_mul(ec_group, ec_point_out, NULL, ec_point_in, ec_scalar,
+                    NULL) ||
+      !EC_POINT_point2oct(ec_group, ec_point_out, POINT_CONVERSION_UNCOMPRESSED,
+                          z_comp_result, sizeof(z_comp_result), NULL) ||
+      !check_test(kP256PointResult, z_comp_result, sizeof(z_comp_result),
+                  "Z Computation Result")) {
+    fprintf(stderr, "Z Computation KAT failed.\n");
+    goto err;
+  }
+
+  // FFC Diffie-Hellman KAT
+
+  BIGNUM *const ffdhe2048_value = BN_new();
+  DH *const dh = self_test_dh();
+  int dh_ok = 0;
+  if (ffdhe2048_value && dh) {
+    bn_set_static_words(ffdhe2048_value, kFFDHE2048PublicValueData,
+                        OPENSSL_ARRAY_SIZE(kFFDHE2048PublicValueData));
+
+    uint8_t dh_out[sizeof(kDHOutput)];
+    dh_ok =
+        sizeof(dh_out) == DH_size(dh) &&
+        DH_compute_key_padded(dh_out, ffdhe2048_value, dh) == sizeof(dh_out) &&
+        check_test(kDHOutput, dh_out, sizeof(dh_out), "FFC DH");
+  }
+
+  BN_free(ffdhe2048_value);
+  DH_free(dh);
+  if (!dh_ok) {
+    fprintf(stderr, "FFDH failed.\n");
+    goto err;
+  }
+
+  ret = 1;
+
+err:
+  RSA_free(rsa_key);
+  EC_KEY_free(ec_key);
+  EC_POINT_free(ec_point_in);
+  EC_POINT_free(ec_point_out);
+  EC_GROUP_free(ec_group);
+  BN_free(ec_scalar);
+  ECDSA_SIG_free(sig);
+
+  return ret;
+}
+
+int BORINGSSL_self_test(void) {
   static const uint8_t kAESKey[16] = "BoringCrypto Key";
   static const uint8_t kAESIV[16] = {0};
   static const uint8_t kPlaintext[64] =
@@ -387,35 +600,6 @@
       0x00
 #endif
   };
-  static const uint8_t kRSASignature[256] = {
-      0x62, 0x66, 0x4b, 0xe3, 0xb1, 0xd2, 0x83, 0xf1, 0xa8, 0x56, 0x2b, 0x33,
-      0x60, 0x1e, 0xdb, 0x1e, 0x06, 0xf7, 0xa7, 0x1e, 0xa8, 0xef, 0x03, 0x4d,
-      0x0c, 0xf6, 0x83, 0x75, 0x7a, 0xf0, 0x14, 0xc7, 0xe2, 0x94, 0x3a, 0xb5,
-      0x67, 0x56, 0xa5, 0x48, 0x7f, 0x3a, 0xa5, 0xbf, 0xf7, 0x1d, 0x44, 0xa6,
-      0x34, 0xed, 0x9b, 0xd6, 0x51, 0xaa, 0x2c, 0x4e, 0xce, 0x60, 0x5f, 0xe9,
-      0x0e, 0xd5, 0xcd, 0xeb, 0x23, 0x27, 0xf8, 0xfb, 0x45, 0xe5, 0x34, 0x63,
-      0x77, 0x7f, 0x2e, 0x80, 0xcf, 0x9d, 0x2e, 0xfc, 0xe2, 0x50, 0x75, 0x29,
-      0x46, 0xf4, 0xaf, 0x91, 0xed, 0x36, 0xe1, 0x5e, 0xef, 0x66, 0xa1, 0xff,
-      0x27, 0xfc, 0x87, 0x7e, 0x60, 0x84, 0x0f, 0x54, 0x51, 0x56, 0x0f, 0x68,
-      0x99, 0xc0, 0x3f, 0xeb, 0xa5, 0xa0, 0x46, 0xb0, 0x86, 0x02, 0xb0, 0xc8,
-      0xe8, 0x46, 0x13, 0x06, 0xcd, 0xb7, 0x8a, 0xd0, 0x3b, 0x46, 0xd0, 0x14,
-      0x64, 0x53, 0x9b, 0x5b, 0x5e, 0x02, 0x45, 0xba, 0x6e, 0x7e, 0x0a, 0xb9,
-      0x9e, 0x62, 0xb7, 0xd5, 0x7a, 0x87, 0xea, 0xd3, 0x24, 0xa5, 0xef, 0xb3,
-      0xdc, 0x05, 0x9c, 0x04, 0x60, 0x4b, 0xde, 0xa8, 0x90, 0x08, 0x7b, 0x6a,
-      0x5f, 0xb4, 0x3f, 0xda, 0xc5, 0x1f, 0x6e, 0xd6, 0x15, 0xde, 0x65, 0xa4,
-      0x6e, 0x62, 0x9d, 0x8f, 0xa8, 0xbe, 0x86, 0xf6, 0x09, 0x90, 0x40, 0xa5,
-      0xf4, 0x23, 0xc5, 0xf6, 0x38, 0x86, 0x0d, 0x1c, 0xed, 0x4a, 0x0a, 0xae,
-      0xa4, 0x26, 0xc2, 0x2e, 0xd3, 0x13, 0x66, 0x61, 0xea, 0x35, 0x01, 0x0e,
-      0x13, 0xda, 0x78, 0x20, 0xae, 0x59, 0x5f, 0x9b, 0xa9, 0x6c, 0xf9, 0x1b,
-      0xdf, 0x76, 0x53, 0xc8, 0xa7, 0xf5, 0x63, 0x6d, 0xf3, 0xff, 0xfd, 0xaf,
-      0x75, 0x4b, 0xac, 0x67, 0xb1, 0x3c, 0xbf, 0x5e, 0xde, 0x73, 0x02, 0x6d,
-      0xd2, 0x0c, 0xb1,
-#if !defined(BORINGSSL_FIPS_BREAK_RSA_SIG)
-      0x64
-#else
-      0x00
-#endif
-  };
   const uint8_t kDRBGEntropy[48] =
       "BCM Known Answer Test DBRG Initial Entropy      ";
   const uint8_t kDRBGPersonalization[18] = "BCMPersonalization";
@@ -443,50 +627,6 @@
       0xd5, 0xa8, 0x66, 0x16, 0xbd, 0x18, 0x3c, 0xf2, 0xaa, 0x7a, 0x2b,
       0x37, 0xf9, 0xab, 0x35, 0x64, 0x15, 0x01, 0x3f, 0xc4,
   };
-  const uint8_t kECDSASigR[32] = {
-      0x67, 0x80, 0xc5, 0xfc, 0x70, 0x27, 0x5e, 0x2c, 0x70, 0x61, 0xa0,
-      0xe7, 0x87, 0x7b, 0xb1, 0x74, 0xde, 0xad, 0xeb, 0x98, 0x87, 0x02,
-      0x7f, 0x3f, 0xa8, 0x36, 0x54, 0x15, 0x8b, 0xa7, 0xf5,
-#if !defined(BORINGSSL_FIPS_BREAK_ECDSA_SIG)
-      0x0c,
-#else
-      0x00,
-#endif
-  };
-  const uint8_t kECDSASigS[32] = {
-      0xa5, 0x93, 0xe0, 0x23, 0x91, 0xe7, 0x4b, 0x8d, 0x77, 0x25, 0xa6,
-      0xba, 0x4d, 0xd9, 0x86, 0x77, 0xda, 0x7d, 0x8f, 0xef, 0xc4, 0x1a,
-      0xf0, 0xcc, 0x81, 0xe5, 0xea, 0x3f, 0xc2, 0x41, 0x7f, 0xd8,
-  };
-  // kP256Point is SHA256("Primitive Z Computation KAT")×G within P-256.
-  const uint8_t kP256Point[65] = {
-      0x04, 0x4e, 0xc1, 0x94, 0x8c, 0x5c, 0xf4, 0x37, 0x35, 0x0d, 0xa3,
-      0xf9, 0x55, 0xf9, 0x8b, 0x26, 0x23, 0x5c, 0x43, 0xe0, 0x83, 0x51,
-      0x2b, 0x0d, 0x4b, 0x56, 0x24, 0xc3, 0xe4, 0xa5, 0xa8, 0xe2, 0xe9,
-      0x95, 0xf2, 0xc4, 0xb9, 0xb7, 0x48, 0x7d, 0x2a, 0xae, 0xc5, 0xc0,
-      0x0a, 0xcc, 0x1b, 0xd0, 0xec, 0xb8, 0xdc, 0xbe, 0x0c, 0xbe, 0x52,
-      0x79, 0x93, 0x7c, 0x0b, 0x92, 0x2b, 0x7f, 0x17, 0xa5, 0x80,
-  };
-  // kP256Scalar is SHA256("Primitive Z Computation KAT scalar").
-  const uint8_t kP256Scalar[32] = {
-      0xe7, 0x60, 0x44, 0x91, 0x26, 0x9a, 0xfb, 0x5b, 0x10, 0x2d, 0x6e,
-      0xa5, 0x2c, 0xb5, 0x9f, 0xeb, 0x70, 0xae, 0xde, 0x6c, 0xe3, 0xbf,
-      0xb3, 0xe0, 0x10, 0x54, 0x85, 0xab, 0xd8, 0x61, 0xd7, 0x7b,
-  };
-  // kP256PointResult is |kP256Scalar|×|kP256Point|.
-  const uint8_t kP256PointResult[65] = {
-      0x04, 0xf1, 0x63, 0x00, 0x88, 0xc5, 0xd5, 0xe9, 0x05, 0x52, 0xac,
-      0xb6, 0xec, 0x68, 0x76, 0xb8, 0x73, 0x7f, 0x0f, 0x72, 0x34, 0xe6,
-      0xbb, 0x30, 0x32, 0x22, 0x37, 0xb6, 0x2a, 0x80, 0xe8, 0x9e, 0x6e,
-      0x6f, 0x36, 0x02, 0xe7, 0x21, 0xd2, 0x31, 0xdb, 0x94, 0x63, 0xb7,
-      0xd8, 0x19, 0x0e, 0xc2, 0xc0, 0xa7, 0x2f, 0x15, 0x49, 0x1a, 0xa2,
-      0x7c, 0x41, 0x8f, 0xaf, 0x9c, 0x40, 0xaf, 0x2e, 0x4a,
-#if !defined(BORINGSSL_FIPS_BREAK_Z_COMPUTATION)
-      0x0c,
-#else
-      0x00,
-#endif
-  };
   const uint8_t kTLSOutput[32] = {
       0x67, 0x85, 0xde, 0x60, 0xfc, 0x0a, 0x83, 0xe9, 0xa2, 0x2a, 0xb3,
       0xf0, 0x27, 0x0c, 0xba, 0xf7, 0xfa, 0x82, 0x3d, 0x14, 0x77, 0x1d,
@@ -512,66 +652,8 @@
       0x31, 0x1e, 0x2b, 0x21, 0x41, 0x8d, 0x32, 0x81,
   };
 
-  // kFFDHE2048PublicValueData is an arbitrary public value, mod
-  // kFFDHE2048Data. (The private key happens to be 4096.)
-  static const BN_ULONG kFFDHE2048PublicValueData[] = {
-      TOBN(0x187be36b, 0xd38a4fa1), TOBN(0x0a152f39, 0x6458f3b8),
-      TOBN(0x0570187e, 0xc422eeb7), TOBN(0x18af7482, 0x91173f2a),
-      TOBN(0xe9fdac6a, 0xcff4eaaa), TOBN(0xf6afebb7, 0x6e589d6c),
-      TOBN(0xf92f8e9a, 0xb7e33fb0), TOBN(0x70acf2aa, 0x4cf36ddd),
-      TOBN(0x561ab426, 0xd07137fd), TOBN(0x5f57d037, 0x430ee91e),
-      TOBN(0xe3e768c8, 0x60d10b8a), TOBN(0xb14884d8, 0xa18af8ce),
-      TOBN(0xf8a98014, 0xa12b74e4), TOBN(0x748d407c, 0x3437b7a8),
-      TOBN(0x627588c4, 0x9875d5a7), TOBN(0xdd24a127, 0x53c8f09d),
-      TOBN(0x85a997d5, 0x0cd51aec), TOBN(0x44f0c619, 0xce348458),
-      TOBN(0x9b894b24, 0x5f6b69a1), TOBN(0xae1302f2, 0xf6d4777e),
-      TOBN(0xe6678eeb, 0x375db18e), TOBN(0x2674e1d6, 0x4fbcbdc8),
-      TOBN(0xb297a823, 0x6fa93d28), TOBN(0x6a12fb70, 0x7c8c0510),
-      TOBN(0x5c6d1aeb, 0xdb06f65b), TOBN(0xe8c2954e, 0x4c1804ca),
-      TOBN(0x06bdeac1, 0xf5500fa7), TOBN(0x6a315604, 0x189cd76b),
-      TOBN(0xbae7b0b3, 0x6e362dc0), TOBN(0xa57c73bd, 0xdc70fb82),
-      TOBN(0xfaff50d2, 0x9d573457), TOBN(0x352bd399, 0xbe84058e),
-  };
-
-  const uint8_t kDHOutput[2048 / 8] = {
-      0x2a, 0xe6, 0xd3, 0xa6, 0x13, 0x58, 0x8e, 0xce, 0x53, 0xaa, 0xf6, 0x5d,
-      0x9a, 0xae, 0x02, 0x12, 0xf5, 0x80, 0x3d, 0x06, 0x09, 0x76, 0xac, 0x57,
-      0x37, 0x9e, 0xab, 0x38, 0x62, 0x25, 0x05, 0x1d, 0xf3, 0xa9, 0x39, 0x60,
-      0xf6, 0xae, 0x90, 0xed, 0x1e, 0xad, 0x6e, 0xe9, 0xe3, 0xba, 0x27, 0xf6,
-      0xdb, 0x54, 0xdf, 0xe2, 0xbd, 0xbb, 0x7f, 0xf1, 0x81, 0xac, 0x1a, 0xfa,
-      0xdb, 0x87, 0x07, 0x98, 0x76, 0x90, 0x21, 0xf2, 0xae, 0xda, 0x0d, 0x84,
-      0x97, 0x64, 0x0b, 0xbf, 0xb8, 0x8d, 0x10, 0x46, 0xe2, 0xd5, 0xca, 0x1b,
-      0xbb, 0xe5, 0x37, 0xb2, 0x3b, 0x35, 0xd3, 0x1b, 0x65, 0xea, 0xae, 0xf2,
-      0x03, 0xe2, 0xb6, 0xde, 0x22, 0xb7, 0x86, 0x49, 0x79, 0xfe, 0xd7, 0x16,
-      0xf7, 0xdc, 0x9c, 0x59, 0xf5, 0xb7, 0x70, 0xc0, 0x53, 0x42, 0x6f, 0xb1,
-      0xd2, 0x4e, 0x00, 0x25, 0x4b, 0x2d, 0x5a, 0x9b, 0xd0, 0xe9, 0x27, 0x43,
-      0xcc, 0x00, 0x66, 0xea, 0x94, 0x7a, 0x0b, 0xb9, 0x89, 0x0c, 0x5e, 0x94,
-      0xb8, 0x3a, 0x78, 0x9c, 0x4d, 0x84, 0xe6, 0x32, 0x2c, 0x38, 0x7c, 0xf7,
-      0x43, 0x9c, 0xd8, 0xb8, 0x1c, 0xce, 0x24, 0x91, 0x20, 0x67, 0x7a, 0x54,
-      0x1f, 0x7e, 0x86, 0x7f, 0xa1, 0xc1, 0x03, 0x4e, 0x2c, 0x26, 0x71, 0xb2,
-      0x06, 0x30, 0xb3, 0x6c, 0x15, 0xcc, 0xac, 0x25, 0xe5, 0x37, 0x3f, 0x24,
-      0x8f, 0x2a, 0x89, 0x5e, 0x3d, 0x43, 0x94, 0xc9, 0x36, 0xae, 0x40, 0x00,
-      0x6a, 0x0d, 0xb0, 0x6e, 0x8b, 0x2e, 0x70, 0x57, 0xe1, 0x88, 0x53, 0xd6,
-      0x06, 0x80, 0x2a, 0x4e, 0x5a, 0xf0, 0x1e, 0xaa, 0xcb, 0xab, 0x06, 0x0e,
-      0x27, 0x0f, 0xd9, 0x88, 0xd9, 0x01, 0xe3, 0x07, 0xeb, 0xdf, 0xc3, 0x12,
-      0xe3, 0x40, 0x88, 0x7b, 0x5f, 0x59, 0x78, 0x6e, 0x26, 0x20, 0xc3, 0xdf,
-      0xc8, 0xe4, 0x5e,
-#if !defined(BORINGSSL_FIPS_BREAK_FFC_DH)
-      0xb8,
-#else
-      0x00,
-#endif
-  };
-
   EVP_AEAD_CTX aead_ctx;
   EVP_AEAD_CTX_zero(&aead_ctx);
-  RSA *rsa_key = NULL;
-  EC_KEY *ec_key = NULL;
-  EC_GROUP *ec_group = NULL;
-  EC_POINT *ec_point_in = NULL;
-  EC_POINT *ec_point_out = NULL;
-  BIGNUM *ec_scalar = NULL;
-  ECDSA_SIG *sig = NULL;
   int ret = 0;
 
   AES_KEY aes_key;
@@ -655,116 +737,6 @@
     goto err;
   }
 
-  rsa_key = self_test_rsa_key();
-  if (rsa_key == NULL) {
-    fprintf(stderr, "RSA KeyGen failed\n");
-    goto err;
-  }
-
-  // RSA Sign KAT
-  unsigned sig_len;
-
-  // Disable blinding for the power-on tests because it's not needed and
-  // triggers an entropy draw.
-  rsa_key->flags |= RSA_FLAG_NO_BLINDING;
-
-  if (!RSA_sign(NID_sha256, kPlaintextSHA256, sizeof(kPlaintextSHA256), output,
-                &sig_len, rsa_key) ||
-      !check_test(kRSASignature, output, sizeof(kRSASignature),
-                  "RSA Sign KAT")) {
-    fprintf(stderr, "RSA signing test failed.\n");
-    goto err;
-  }
-
-  // RSA Verify KAT
-  if (!RSA_verify(NID_sha256, kPlaintextSHA256, sizeof(kPlaintextSHA256),
-                  kRSASignature, sizeof(kRSASignature), rsa_key)) {
-    fprintf(stderr, "RSA Verify KAT failed.\n");
-    goto err;
-  }
-
-  ec_key = self_test_ecdsa_key();
-  if (ec_key == NULL) {
-    fprintf(stderr, "ECDSA KeyGen failed\n");
-    goto err;
-  }
-
-  // ECDSA Sign/Verify KAT
-
-  // The 'k' value for ECDSA is fixed to avoid an entropy draw.
-  uint8_t ecdsa_k[32] = {0};
-  ecdsa_k[31] = 42;
-
-  sig = ecdsa_sign_with_nonce_for_known_answer_test(
-      kPlaintextSHA256, sizeof(kPlaintextSHA256), ec_key, ecdsa_k,
-      sizeof(ecdsa_k));
-
-  uint8_t ecdsa_r_bytes[sizeof(kECDSASigR)];
-  uint8_t ecdsa_s_bytes[sizeof(kECDSASigS)];
-  if (sig == NULL ||
-      BN_num_bytes(sig->r) != sizeof(ecdsa_r_bytes) ||
-      !BN_bn2bin(sig->r, ecdsa_r_bytes) ||
-      BN_num_bytes(sig->s) != sizeof(ecdsa_s_bytes) ||
-      !BN_bn2bin(sig->s, ecdsa_s_bytes) ||
-      !check_test(kECDSASigR, ecdsa_r_bytes, sizeof(kECDSASigR), "ECDSA R") ||
-      !check_test(kECDSASigS, ecdsa_s_bytes, sizeof(kECDSASigS), "ECDSA S")) {
-    fprintf(stderr, "ECDSA signature KAT failed.\n");
-    goto err;
-  }
-
-  if (!ECDSA_do_verify(kPlaintextSHA256, sizeof(kPlaintextSHA256), sig,
-                       ec_key)) {
-    fprintf(stderr, "ECDSA verification KAT failed.\n");
-    goto err;
-  }
-
-  // Primitive Z Computation KAT (IG 9.6).
-  ec_group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
-  if (ec_group == NULL) {
-    fprintf(stderr, "Failed to create P-256 group.\n");
-    goto err;
-  }
-  ec_point_in = EC_POINT_new(ec_group);
-  ec_point_out = EC_POINT_new(ec_group);
-  ec_scalar = BN_new();
-  uint8_t z_comp_result[65];
-  if (ec_point_in == NULL || ec_point_out == NULL || ec_scalar == NULL ||
-      !EC_POINT_oct2point(ec_group, ec_point_in, kP256Point, sizeof(kP256Point),
-                          NULL) ||
-      !BN_bin2bn(kP256Scalar, sizeof(kP256Scalar), ec_scalar) ||
-      !EC_POINT_mul(ec_group, ec_point_out, NULL, ec_point_in, ec_scalar,
-                    NULL) ||
-      !EC_POINT_point2oct(ec_group, ec_point_out, POINT_CONVERSION_UNCOMPRESSED,
-                          z_comp_result, sizeof(z_comp_result), NULL) ||
-      !check_test(kP256PointResult, z_comp_result, sizeof(z_comp_result),
-                  "Z Computation Result")) {
-    fprintf(stderr, "Z Computation KAT failed.\n");
-    goto err;
-  }
-
-  // FFC Diffie-Hellman KAT
-
-  BIGNUM *const ffdhe2048_value = BN_new();
-  DH *const dh = self_test_dh();
-  int dh_ok = 0;
-  if (ffdhe2048_value && dh) {
-    bn_set_static_words(ffdhe2048_value, kFFDHE2048PublicValueData,
-                        OPENSSL_ARRAY_SIZE(kFFDHE2048PublicValueData));
-
-    uint8_t dh_out[sizeof(kDHOutput)];
-    dh_ok =
-        sizeof(dh_out) == DH_size(dh) &&
-        DH_compute_key_padded(dh_out, ffdhe2048_value, dh) == sizeof(dh_out) &&
-        check_test(kDHOutput, dh_out, sizeof(dh_out), "FFC DH");
-  }
-
-  BN_free(ffdhe2048_value);
-  DH_free(dh);
-  if (!dh_ok) {
-    fprintf(stderr, "FFDH failed.\n");
-    goto err;
-  }
-
   // DBRG KAT
   CTR_DRBG_STATE drbg;
   if (!CTR_DRBG_init(&drbg, kDRBGEntropy, kDRBGPersonalization,
@@ -800,33 +772,12 @@
     goto err;
   }
 
-  ret = 1;
-
-#if defined(BORINGSSL_FIPS_SELF_TEST_FLAG_FILE)
-  // Tests were successful. Write flag file if requested.
-  if (module_hash_len != 0 && getenv(kFlagWriteEnableEnvVar) != NULL) {
-    const int fd = open(flag_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-    if (fd >= 0) {
-      close(fd);
-    }
-  }
-#endif  // BORINGSSL_FIPS_SELF_TEST_FLAG_FILE
+  ret = boringssl_self_test_slow();
 
 err:
   EVP_AEAD_CTX_cleanup(&aead_ctx);
-  RSA_free(rsa_key);
-  EC_KEY_free(ec_key);
-  EC_POINT_free(ec_point_in);
-  EC_POINT_free(ec_point_out);
-  EC_GROUP_free(ec_group);
-  BN_free(ec_scalar);
-  ECDSA_SIG_free(sig);
 
   return ret;
 }
 
-int BORINGSSL_self_test(void) {
-  return boringssl_fips_self_test(NULL, 0);
-}
-
 #endif  // !_MSC_VER
diff --git a/crypto/internal.h b/crypto/internal.h
index 42f94d5..9d7b486 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -938,14 +938,6 @@
 void BORINGSSL_FIPS_abort(void) __attribute__((noreturn));
 #endif
 
-// boringssl_fips_self_test runs the FIPS KAT-based self tests. It returns one
-// on success and zero on error. The argument is the integrity hash of the FIPS
-// module and may be used to check and write flag files to suppress duplicate
-// self-tests. If |module_hash_len| is zero then no flag file will be checked
-// nor written and tests will always be run.
-int boringssl_fips_self_test(const uint8_t *module_hash,
-                             size_t module_hash_len);
-
 #if defined(BORINGSSL_FIPS_COUNTERS)
 void boringssl_fips_inc_counter(enum fips_counter_t counter);
 #else