Make RSA self-test lazy.

We need to ensure that all public functions that end up doing a
cryptographic RSA operation run the self-tests first. We could do that
by putting calls in the lower-most functions but the self-tests must run
operations without creating a cycle. Therefore calls are placed as low
down as possible except where it would conflict with the self-tests.
Some functions need to be split so that there's a private version that
doesn't require that the self tests have passed.

Here's the call-graph that I used for this:

                   ┌───────────────────────────┐
                   │      private_decrypt      │
                   └───────────────────────────┘
                     │
                     │
                     ▼
                   ┌───────────────────────────┐
                   │          decrypt          │
                   └───────────────────────────┘
                     │
                     │
                     ▼
                   ┌───────────────────────────┐
                   │      default_decrypt      │
                   └───────────────────────────┘
                     │
                     │
                     ▼
                   ┌───────────────────────────┐
                   │     private_transform     │   ◀┐
                   └───────────────────────────┘    │
                     │                              │
                     │                              │
                     ▼                              │
                   ┌───────────────────────────┐    │
                   │ default_private_transform │    │
                   └───────────────────────────┘    │
                   ┌───────────────────────────┐    │
                   │      private_encrypt      │    │
                   └───────────────────────────┘    │
  ┌───────────────┐  │                              │
  │ sign_pss_mgf1 │  │                              │
  └───────────────┘\ ▼                              │
  ┌────────┐       ┌───────────────────────────┐    │
  │  sign  │ ──▶   │         sign_raw          │    │
  └────────┘       └───────────────────────────┘    │
                     │                              │
                     │                              │
                     ▼                              │
                   ┌───────────────────────────┐    │
                   │     default_sign_raw      │   ─┘
                   └───────────────────────────┘
                 ┌−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−┐
                 ╎         Verification          ╎
                 ╎                               ╎
                 ╎ ┌───────────────────────────┐ ╎
                 ╎ │      public_decrypt       │ ╎
                 ╎ └───────────────────────────┘ ╎
                 ╎   │                           ╎
                 ╎   │                           ╎
                 ╎   │                           ╎
┌−−−−−−−−−−−−−−−−    │                           ╎
╎                    ▼                           ╎
╎ ┌────────┐       ┌───────────────────────────┐ ╎
╎ │ verify │ ────▶ │        verify_raw         │ ╎
╎ └────────┘       └───────────────────────────┘ ╎
╎                                                ╎
└−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−┘
                 ┌−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−┐
                 ╎          Encryption           ╎
                 ╎                               ╎
                 ╎ ┌───────────────────────────┐ ╎
                 ╎ │      public_encrypt       │ ╎
                 ╎ └───────────────────────────┘ ╎
                 ╎   │                           ╎
                 ╎   │                           ╎
                 ╎   ▼                           ╎
                 ╎ ┌───────────────────────────┐ ╎
                 ╎ │          encrypt          │ ╎
                 ╎ └───────────────────────────┘ ╎
                 ╎                               ╎
                 └−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−┘

Speed difference looks to be in the noise.

Before:

Did 19716 RSA 2048 signing operations in 10050000us (1961.8 ops/sec)
Did 712000 RSA 2048 verify (same key) operations in 10007156us (71149.1 ops/sec)
Did 590000 RSA 2048 verify (fresh key) operations in 10004296us (58974.7 ops/sec)
Did 101866 RSA 2048 private key parse operations in 10090285us (10095.5 ops/sec)
Did 2919 RSA 4096 signing operations in 10019359us (291.3 ops/sec)
Did 203000 RSA 4096 verify (same key) operations in 10008421us (20282.9 ops/sec)
Did 175000 RSA 4096 verify (fresh key) operations in 10026353us (17454.0 ops/sec)
Did 30900 RSA 4096 private key parse operations in 10090073us (3062.4 ops/sec)

After:

Did 19525 RSA 2048 signing operations in 10000499us (1952.4 ops/sec)
Did 706000 RSA 2048 verify (same key) operations in 10002172us (70584.7 ops/sec)
Did 588000 RSA 2048 verify (fresh key) operations in 10010856us (58736.2 ops/sec)
Did 101864 RSA 2048 private key parse operations in 10063474us (10122.2 ops/sec)
Did 2919 RSA 4096 signing operations in 10037480us (290.8 ops/sec)
Did 203000 RSA 4096 verify (same key) operations in 10026966us (20245.4 ops/sec)
Did 175000 RSA 4096 verify (fresh key) operations in 10032281us (17443.7 ops/sec)
Did 31416 RSA 4096 private key parse operations in 10031047us (3131.9 ops/sec)

Change-Id: I8dec8a33066717b7078f160e3f93c33cd354bb0c
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/51426
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c
index 4b0f7e1..505510c 100644
--- a/crypto/fipsmodule/bcm.c
+++ b/crypto/fipsmodule/bcm.c
@@ -252,7 +252,7 @@
   OPENSSL_cleanse(result, sizeof(result)); // FIPS 140-3, AS05.10.
 #endif  // OPENSSL_ASAN
 
-  if (!BORINGSSL_self_test()) {
+  if (!boringssl_self_test_startup()) {
     goto err;
   }
 
diff --git a/crypto/fipsmodule/rsa/internal.h b/crypto/fipsmodule/rsa/internal.h
index d9d6fac..1cb3b5f 100644
--- a/crypto/fipsmodule/rsa/internal.h
+++ b/crypto/fipsmodule/rsa/internal.h
@@ -124,6 +124,28 @@
 extern const size_t kBoringSSLRSASqrtTwoLen;
 
 
+// Functions that avoid self-tests.
+//
+// Self-tests need to call functions that don't try and ensure that the
+// self-tests have passed. These functions, in turn, need to limit themselves
+// to such functions too.
+//
+// These functions are the same as their public versions, but skip the self-test
+// check.
+
+int rsa_verify_no_self_test(int hash_nid, const uint8_t *digest,
+                            size_t digest_len, const uint8_t *sig,
+                            size_t sig_len, RSA *rsa);
+
+int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
+                                size_t max_out, const uint8_t *in,
+                                size_t in_len, int padding);
+
+int rsa_sign_no_self_test(int hash_nid, const uint8_t *digest,
+                          unsigned digest_len, uint8_t *out, unsigned *out_len,
+                          RSA *rsa);
+
+
 #if defined(__cplusplus)
 }  // extern C
 #endif
diff --git a/crypto/fipsmodule/rsa/rsa.c b/crypto/fipsmodule/rsa/rsa.c
index 83649d3..03acd27 100644
--- a/crypto/fipsmodule/rsa/rsa.c
+++ b/crypto/fipsmodule/rsa/rsa.c
@@ -304,8 +304,9 @@
   return out_len;
 }
 
-int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
-                 const uint8_t *in, size_t in_len, int padding) {
+static int rsa_sign_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
+                                     size_t max_out, const uint8_t *in,
+                                     size_t in_len, int padding) {
   if (rsa->meth->sign_raw) {
     return rsa->meth->sign_raw(rsa, out_len, out, max_out, in, in_len, padding);
   }
@@ -313,6 +314,13 @@
   return rsa_default_sign_raw(rsa, out_len, out, max_out, in, in_len, padding);
 }
 
+int RSA_sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
+                 const uint8_t *in, size_t in_len, int padding) {
+  boringssl_ensure_rsa_self_test();
+  return rsa_sign_raw_no_self_test(rsa, out_len, out, max_out, in, in_len,
+                                   padding);
+}
+
 int RSA_private_encrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
                         int padding) {
   size_t out_len;
@@ -524,8 +532,9 @@
   return 0;
 }
 
-int RSA_sign(int hash_nid, const uint8_t *digest, unsigned digest_len,
-             uint8_t *out, unsigned *out_len, RSA *rsa) {
+int rsa_sign_no_self_test(int hash_nid, const uint8_t *digest,
+                          unsigned digest_len, uint8_t *out, unsigned *out_len,
+                          RSA *rsa) {
   const unsigned rsa_size = RSA_size(rsa);
   int ret = 0;
   uint8_t *signed_msg = NULL;
@@ -540,8 +549,9 @@
   if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
                             &signed_msg_is_alloced, hash_nid, digest,
                             digest_len) ||
-      !RSA_sign_raw(rsa, &size_t_out_len, out, rsa_size, signed_msg,
-                    signed_msg_len, RSA_PKCS1_PADDING)) {
+      !rsa_sign_raw_no_self_test(rsa, &size_t_out_len, out, rsa_size,
+                                 signed_msg, signed_msg_len,
+                                 RSA_PKCS1_PADDING)) {
     goto err;
   }
 
@@ -555,6 +565,13 @@
   return ret;
 }
 
+int RSA_sign(int hash_nid, const uint8_t *digest, unsigned digest_len,
+             uint8_t *out, unsigned *out_len, RSA *rsa) {
+  boringssl_ensure_rsa_self_test();
+
+  return rsa_sign_no_self_test(hash_nid, digest, digest_len, out, out_len, rsa);
+}
+
 int RSA_sign_pss_mgf1(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
                       const uint8_t *digest, size_t digest_len,
                       const EVP_MD *md, const EVP_MD *mgf1_md, int salt_len) {
@@ -578,8 +595,9 @@
   return ret;
 }
 
-int RSA_verify(int hash_nid, const uint8_t *digest, size_t digest_len,
-               const uint8_t *sig, size_t sig_len, RSA *rsa) {
+int rsa_verify_no_self_test(int hash_nid, const uint8_t *digest,
+                            size_t digest_len, const uint8_t *sig,
+                            size_t sig_len, RSA *rsa) {
   if (rsa->n == NULL || rsa->e == NULL) {
     OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
     return 0;
@@ -603,12 +621,9 @@
     return 0;
   }
 
-  if (!RSA_verify_raw(rsa, &len, buf, rsa_size, sig, sig_len,
-                      RSA_PKCS1_PADDING)) {
-    goto out;
-  }
-
-  if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
+  if (!rsa_verify_raw_no_self_test(rsa, &len, buf, rsa_size, sig, sig_len,
+                                   RSA_PKCS1_PADDING) ||
+      !RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
                             &signed_msg_is_alloced, hash_nid, digest,
                             digest_len)) {
     goto out;
@@ -631,6 +646,13 @@
   return ret;
 }
 
+int RSA_verify(int hash_nid, const uint8_t *digest, size_t digest_len,
+               const uint8_t *sig, size_t sig_len, RSA *rsa) {
+  boringssl_ensure_rsa_self_test();
+  return rsa_verify_no_self_test(hash_nid, digest, digest_len, sig, sig_len,
+                                 rsa);
+}
+
 int RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *digest, size_t digest_len,
                         const EVP_MD *md, const EVP_MD *mgf1_md, int salt_len,
                         const uint8_t *sig, size_t sig_len) {
diff --git a/crypto/fipsmodule/rsa/rsa_impl.c b/crypto/fipsmodule/rsa/rsa_impl.c
index a6865c0..1046f35 100644
--- a/crypto/fipsmodule/rsa/rsa_impl.c
+++ b/crypto/fipsmodule/rsa/rsa_impl.c
@@ -261,6 +261,8 @@
 
 int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
                 const uint8_t *in, size_t in_len, int padding) {
+  boringssl_ensure_rsa_self_test();
+
   if (!rsa_check_public_key(rsa)) {
     return 0;
   }
@@ -528,6 +530,8 @@
 
 int rsa_default_decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
                         const uint8_t *in, size_t in_len, int padding) {
+  boringssl_ensure_rsa_self_test();
+
   const unsigned rsa_size = RSA_size(rsa);
   uint8_t *buf = NULL;
   int ret = 0;
@@ -593,8 +597,9 @@
 
 static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx);
 
-int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
-                   const uint8_t *in, size_t in_len, int padding) {
+int rsa_verify_raw_no_self_test(RSA *rsa, size_t *out_len, uint8_t *out,
+                                size_t max_out, const uint8_t *in,
+                                size_t in_len, int padding) {
   if (!rsa_check_public_key(rsa)) {
     return 0;
   }
@@ -686,6 +691,14 @@
   return ret;
 }
 
+int RSA_verify_raw(RSA *rsa, size_t *out_len, uint8_t *out,
+                                size_t max_out, const uint8_t *in,
+                                size_t in_len, int padding) {
+  boringssl_ensure_rsa_self_test();
+  return rsa_verify_raw_no_self_test(rsa, out_len, out, max_out, in, in_len,
+                                     padding);
+}
+
 int rsa_default_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
                                   size_t len) {
   if (rsa->n == NULL || rsa->d == NULL) {
@@ -1324,6 +1337,8 @@
 static int RSA_generate_key_ex_maybe_fips(RSA *rsa, int bits,
                                           const BIGNUM *e_value, BN_GENCB *cb,
                                           int check_fips) {
+  boringssl_ensure_rsa_self_test();
+
   RSA *tmp = NULL;
   uint32_t err;
   int ret = 0;
diff --git a/crypto/fipsmodule/self_check/self_check.c b/crypto/fipsmodule/self_check/self_check.c
index fe40d90..21e9e0a 100644
--- a/crypto/fipsmodule/self_check/self_check.c
+++ b/crypto/fipsmodule/self_check/self_check.c
@@ -296,27 +296,22 @@
   return NULL;
 }
 
-static int boringssl_self_test_slow(void) {
+
+// Lazy self-tests
+//
+// Self tests that are slow are deferred until the corresponding algorithm is
+// actually exercised, in FIPS mode. (In non-FIPS mode these tests are only run
+// when requested by |BORINGSSL_self_test|.)
+
+static int boringssl_self_test_rsa(void) {
   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;
-  DH *dh = NULL;
-  BIGNUM *ffdhe2048_value = NULL;
   uint8_t output[256];
 
-  rsa_key = self_test_rsa_key();
+  RSA *const rsa_key = self_test_rsa_key();
   if (rsa_key == NULL) {
-    fprintf(stderr, "RSA KeyGen failed\n");
+    fprintf(stderr, "RSA key construction failed\n");
     goto err;
   }
-  // Disable blinding for the power-on tests because it's not needed and
-  // triggers an entropy draw.
-  rsa_key->flags |= RSA_FLAG_NO_BLINDING;
 
   // RSA Sign KAT
 
@@ -351,8 +346,8 @@
   };
 
   unsigned sig_len;
-  if (!RSA_sign(NID_sha256, kRSASignDigest, sizeof(kRSASignDigest), output,
-                &sig_len, rsa_key) ||
+  if (!rsa_sign_no_self_test(NID_sha256, kRSASignDigest, sizeof(kRSASignDigest),
+                             output, &sig_len, rsa_key) ||
       !check_test(kRSASignSignature, output, sizeof(kRSASignSignature),
                   "RSA-sign KAT")) {
     fprintf(stderr, "RSA signing test failed.\n");
@@ -390,12 +385,53 @@
       0x4d, 0xbe, 0xa4, 0x16, 0x15, 0x34, 0x5c, 0x88, 0x53, 0x25, 0x92, 0x67,
       0x44, 0xa5, 0x39, 0x15,
   };
-  if (!RSA_verify(NID_sha256, kRSAVerifyDigest, sizeof(kRSAVerifyDigest),
-                  kRSAVerifySignature, sizeof(kRSAVerifySignature), rsa_key)) {
+  if (!rsa_verify_no_self_test(NID_sha256, kRSAVerifyDigest,
+                               sizeof(kRSAVerifyDigest), kRSAVerifySignature,
+                               sizeof(kRSAVerifySignature), rsa_key)) {
     fprintf(stderr, "RSA-verify KAT failed.\n");
     goto err;
   }
 
+  ret = 1;
+
+err:
+  RSA_free(rsa_key);
+
+  return ret;
+}
+
+#if defined(BORINGSSL_FIPS)
+
+static void run_self_test_rsa(void) {
+  if (!boringssl_self_test_rsa()) {
+    BORINGSSL_FIPS_abort();
+  }
+}
+
+DEFINE_STATIC_ONCE(g_self_test_once_rsa);
+
+void boringssl_ensure_rsa_self_test(void) {
+  CRYPTO_once(g_self_test_once_rsa_bss_get(), run_self_test_rsa);
+}
+
+#endif  // BORINGSSL_FIPS
+
+
+// Startup self tests.
+//
+// These tests are run at process start when in FIPS mode.
+
+static int boringssl_self_test_slow(void) {
+  int ret = 0;
+  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;
+  DH *dh = NULL;
+  BIGNUM *ffdhe2048_value = NULL;
+
   ec_key = self_test_ecdsa_key();
   if (ec_key == NULL) {
     fprintf(stderr, "ECDSA KeyGen failed\n");
@@ -572,7 +608,6 @@
   ret = 1;
 
 err:
-  RSA_free(rsa_key);
   EC_KEY_free(ec_key);
   EC_POINT_free(ec_point_in);
   EC_POINT_free(ec_point_out);
@@ -644,7 +679,7 @@
                     "HMAC-SHA-256 KAT");
 }
 
-int BORINGSSL_self_test(void) {
+static int boringssl_self_test_fast(void) {
   static const uint8_t kAESKey[16] = "BoringCrypto Key";
   static const uint8_t kAESIV[16] = {0};
 
@@ -862,7 +897,7 @@
     goto err;
   }
 
-  ret = boringssl_self_test_slow();
+  ret = 1;
 
 err:
   EVP_AEAD_CTX_cleanup(&aead_ctx);
@@ -870,4 +905,26 @@
   return ret;
 }
 
+int BORINGSSL_self_test(void) {
+  if (!boringssl_self_test_fast() ||
+      !boringssl_self_test_slow() ||
+      // When requested to run self tests, also run the lazy tests.
+      !boringssl_self_test_rsa()) {
+    return 0;
+  }
+
+  return 1;
+}
+
+#if defined(BORINGSSL_FIPS)
+int boringssl_self_test_startup(void) {
+  if (!boringssl_self_test_fast() ||
+      !boringssl_self_test_slow()) {
+    return 0;
+  }
+
+  return 1;
+}
+#endif
+
 #endif  // !_MSC_VER
diff --git a/crypto/internal.h b/crypto/internal.h
index fe2ba39..dac515c 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -938,6 +938,22 @@
 // process.
 void BORINGSSL_FIPS_abort(void) __attribute__((noreturn));
 
+// boringssl_self_test_startup runs all startup self tests and returns one on
+// success or zero on error. Startup self tests do not include lazy tests.
+// Call |BORINGSSL_self_test| to run every self test.
+int boringssl_self_test_startup(void);
+
+// boringssl_ensure_rsa_self_test checks whether the RSA self-test has been run
+// in this address space. If not, it runs it and crashes the address space if
+// unsuccessful.
+void boringssl_ensure_rsa_self_test(void);
+
+#else
+
+// Outside of FIPS mode, the lazy tests are no-ops.
+
+OPENSSL_INLINE void boringssl_ensure_rsa_self_test(void) {}
+
 #endif  // FIPS
 
 // boringssl_self_test_sha256 performs a SHA-256 KAT.