Clear some more false positives from constant-time validation

Mostly bits of DSA and RSA keygen, flagged when we make the PRNG output
secret by default. There's still a ton of RSA to resolve, mostly because
our constant-time bignum strategy does not interact well with valgrind
when handling RSA's secret-value / public-bit-length situation. Also
RSA's ASN.1 serialization is unavoidably leaky.

Bug: 676
Change-Id: I08d273959065c4db6fd44180a6ac56a82f862fe8
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/65447
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/dsa/dsa.c b/crypto/dsa/dsa.c
index 1881e6a..a35b384 100644
--- a/crypto/dsa/dsa.c
+++ b/crypto/dsa/dsa.c
@@ -274,6 +274,8 @@
         if (!RAND_bytes(seed, qsize)) {
           goto err;
         }
+        // DSA parameters are public.
+        CONSTTIME_DECLASSIFY(seed, qsize);
       } else {
         // If we come back through, use random seed next time.
         seed_in = NULL;
@@ -513,6 +515,9 @@
     goto err;
   }
 
+  // The public key is computed from the private key, but is public.
+  bn_declassify(pub_key);
+
   dsa->priv_key = priv_key;
   dsa->pub_key = pub_key;
   ok = 1;
@@ -649,6 +654,10 @@
     goto err;
   }
 
+  // The signature is computed from the private key, but is public.
+  bn_declassify(r);
+  bn_declassify(s);
+
   // Redo if r or s is zero as required by FIPS 186-3: this is
   // very unlikely.
   if (BN_is_zero(r) || BN_is_zero(s)) {
@@ -900,15 +909,19 @@
                               ctx) ||
       // Compute r = (g^k mod p) mod q
       !BN_mod_exp_mont_consttime(r, dsa->g, &k, dsa->p, ctx,
-                                 dsa->method_mont_p) ||
-      // Note |BN_mod| below is not constant-time and may leak information about
-      // |r|. |dsa->p| may be significantly larger than |dsa->q|, so this is not
-      // easily performed in constant-time with Montgomery reduction.
-      //
-      // However, |r| at this point is g^k (mod p). It is almost the value of
-      // |r| revealed in the signature anyway (g^k (mod p) (mod q)), going from
-      // it to |k| would require computing a discrete log.
-      !BN_mod(r, r, dsa->q, ctx) ||
+                                 dsa->method_mont_p)) {
+    OPENSSL_PUT_ERROR(DSA, ERR_R_BN_LIB);
+    goto err;
+  }
+  // Note |BN_mod| below is not constant-time and may leak information about
+  // |r|. |dsa->p| may be significantly larger than |dsa->q|, so this is not
+  // easily performed in constant-time with Montgomery reduction.
+  //
+  // However, |r| at this point is g^k (mod p). It is almost the value of |r|
+  // revealed in the signature anyway (g^k (mod p) (mod q)), going from it to
+  // |k| would require computing a discrete log.
+  bn_declassify(r);
+  if (!BN_mod(r, r, dsa->q, ctx) ||
       // Compute part of 's = inv(k) (m + xr) mod q' using Fermat's Little
       // Theorem.
       !bn_mod_inverse_prime(kinv, &k, dsa->q, ctx, dsa->method_mont_q)) {
diff --git a/crypto/dsa/dsa_asn1.c b/crypto/dsa/dsa_asn1.c
index 1985bb4..1caf4ae 100644
--- a/crypto/dsa/dsa_asn1.c
+++ b/crypto/dsa/dsa_asn1.c
@@ -119,8 +119,9 @@
   if (dsa->priv_key != NULL) {
     // The private key is a non-zero element of the scalar field, determined by
     // |q|.
-    if (BN_is_negative(dsa->priv_key) || BN_is_zero(dsa->priv_key) ||
-        BN_cmp(dsa->priv_key, dsa->q) >= 0) {
+    if (BN_is_negative(dsa->priv_key) ||
+        constant_time_declassify_int(BN_is_zero(dsa->priv_key)) ||
+        constant_time_declassify_int(BN_cmp(dsa->priv_key, dsa->q) >= 0)) {
       OPENSSL_PUT_ERROR(DSA, DSA_R_INVALID_PARAMETERS);
       return 0;
     }
diff --git a/crypto/fipsmodule/bn/gcd_extra.c b/crypto/fipsmodule/bn/gcd_extra.c
index b4fe00e..76f337c 100644
--- a/crypto/fipsmodule/bn/gcd_extra.c
+++ b/crypto/fipsmodule/bn/gcd_extra.c
@@ -314,7 +314,10 @@
   }
 
   assert(BN_is_zero(v));
-  if (!BN_is_one(u)) {
+  // While the inputs and output are secret, this function considers whether the
+  // input was invertible to be public. It is used as part of RSA key
+  // generation, where inputs are chosen to already be invertible.
+  if (constant_time_declassify_int(!BN_is_one(u))) {
     *out_no_inverse = 1;
     OPENSSL_PUT_ERROR(BN, BN_R_NO_INVERSE);
     goto err;
diff --git a/crypto/fipsmodule/bn/prime.c b/crypto/fipsmodule/bn/prime.c
index fb30768..5af6387 100644
--- a/crypto/fipsmodule/bn/prime.c
+++ b/crypto/fipsmodule/bn/prime.c
@@ -487,7 +487,10 @@
 static int bn_trial_division(uint16_t *out, const BIGNUM *bn) {
   const size_t num_primes = num_trial_division_primes(bn);
   for (size_t i = 1; i < num_primes; i++) {
-    if (bn_mod_u16_consttime(bn, kPrimes[i]) == 0) {
+    // During RSA key generation, |bn| may be secret, but only if |bn| was
+    // prime, so it is safe to leak failed trial divisions.
+    if (constant_time_declassify_int(bn_mod_u16_consttime(bn, kPrimes[i]) ==
+                                     0)) {
       *out = kPrimes[i];
       return 1;
     }
@@ -573,7 +576,8 @@
   // To avoid leaking |a|, we run the loop to |w_bits| and mask off all
   // iterations once |j| = |a|.
   for (int j = 1; j < miller_rabin->w_bits; j++) {
-    if (constant_time_eq_int(j, miller_rabin->a) & ~is_possibly_prime) {
+    if (constant_time_declassify_w(constant_time_eq_int(j, miller_rabin->a) &
+                                   ~is_possibly_prime)) {
       // If the loop is done and we haven't seen z = 1 or z = w-1 yet, the
       // value is composite and we can break in variable time.
       break;
@@ -593,12 +597,14 @@
     // Step 4.5.3. If z = 1 and the loop is not done, the previous value of z
     // was not -1. There are no non-trivial square roots of 1 modulo a prime, so
     // w is composite and we may exit in variable time.
-    if (BN_equal_consttime(z, miller_rabin->one_mont) & ~is_possibly_prime) {
+    if (constant_time_declassify_w(
+            BN_equal_consttime(z, miller_rabin->one_mont) &
+            ~is_possibly_prime)) {
       break;
     }
   }
 
-  *out_is_possibly_prime = is_possibly_prime & 1;
+  *out_is_possibly_prime = constant_time_declassify_w(is_possibly_prime) & 1;
   ret = 1;
 
 err:
@@ -736,8 +742,9 @@
   crypto_word_t uniform_iterations = 0;
   // Using |constant_time_lt_w| seems to prevent the compiler from optimizing
   // this into two jumps.
-  for (int i = 1; (i <= BN_PRIME_CHECKS_BLINDED) |
-                  constant_time_lt_w(uniform_iterations, checks);
+  for (int i = 1; constant_time_declassify_w(
+           (i <= BN_PRIME_CHECKS_BLINDED) |
+           constant_time_lt_w(uniform_iterations, checks));
        i++) {
     // Step 4.1-4.2
     int is_uniform;
diff --git a/crypto/fipsmodule/ec/ec_key.c b/crypto/fipsmodule/ec/ec_key.c
index 7b7d396..3b650d7 100644
--- a/crypto/fipsmodule/ec/ec_key.c
+++ b/crypto/fipsmodule/ec/ec_key.c
@@ -242,7 +242,10 @@
     return 0;
   }
   if (!ec_bignum_to_scalar(key->group, &scalar->scalar, priv_key) ||
-      ec_scalar_is_zero(key->group, &scalar->scalar)) {
+      // Zero is not a valid private key, so it is safe to leak the result of
+      // this comparison.
+      constant_time_declassify_int(
+          ec_scalar_is_zero(key->group, &scalar->scalar))) {
     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_PRIVATE_KEY);
     ec_wrapped_scalar_free(scalar);
     return 0;
diff --git a/crypto/fipsmodule/ec/scalar.c b/crypto/fipsmodule/ec/scalar.c
index a86ee0f..b05d508 100644
--- a/crypto/fipsmodule/ec/scalar.c
+++ b/crypto/fipsmodule/ec/scalar.c
@@ -23,8 +23,12 @@
 
 int ec_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
                         const BIGNUM *in) {
+  // Scalars, which are often secret, must be reduced modulo the order. Those
+  // that are not will be discarded, so leaking the result of the comparison is
+  // safe.
   if (!bn_copy_words(out->words, group->order.N.width, in) ||
-      !bn_less_than_words(out->words, group->order.N.d, group->order.N.width)) {
+      !constant_time_declassify_int(bn_less_than_words(
+          out->words, group->order.N.d, group->order.N.width))) {
     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR);
     return 0;
   }
diff --git a/crypto/fipsmodule/rsa/rsa.c b/crypto/fipsmodule/rsa/rsa.c
index 1a9f050..b524e77 100644
--- a/crypto/fipsmodule/rsa/rsa.c
+++ b/crypto/fipsmodule/rsa/rsa.c
@@ -758,7 +758,8 @@
 static int check_mod_inverse(int *out_ok, const BIGNUM *a, const BIGNUM *ainv,
                              const BIGNUM *m, unsigned m_min_bits,
                              BN_CTX *ctx) {
-  if (BN_is_negative(ainv) || BN_cmp(ainv, m) >= 0) {
+  if (BN_is_negative(ainv) ||
+      constant_time_declassify_int(BN_cmp(ainv, m) >= 0)) {
     *out_ok = 0;
     return 1;
   }
@@ -772,7 +773,7 @@
             bn_mul_consttime(tmp, a, ainv, ctx) &&
             bn_div_consttime(NULL, tmp, tmp, m, m_min_bits, ctx);
   if (ret) {
-    *out_ok = BN_is_one(tmp);
+    *out_ok = constant_time_declassify_int(BN_is_one(tmp));
   }
   BN_CTX_end(ctx);
   return ret;
@@ -831,8 +832,10 @@
   // bounds, to avoid a DoS vector in |bn_mul_consttime| below. Note that
   // n was bound by |rsa_check_public_key|. This also implicitly checks p and q
   // are odd, which is a necessary condition for Montgomery reduction.
-  if (BN_is_negative(key->p) || BN_cmp(key->p, key->n) >= 0 ||
-      BN_is_negative(key->q) || BN_cmp(key->q, key->n) >= 0) {
+  if (BN_is_negative(key->p) ||
+      constant_time_declassify_int(BN_cmp(key->p, key->n) >= 0) ||
+      BN_is_negative(key->q) ||
+      constant_time_declassify_int(BN_cmp(key->q, key->n) >= 0)) {
     OPENSSL_PUT_ERROR(RSA, RSA_R_N_NOT_EQUAL_P_Q);
     goto out;
   }
@@ -863,7 +866,8 @@
     goto out;
   }
 
-  if (!BN_is_one(&tmp) || !BN_is_one(&de)) {
+  if (constant_time_declassify_int(!BN_is_one(&tmp)) ||
+      constant_time_declassify_int(!BN_is_one(&de))) {
     OPENSSL_PUT_ERROR(RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1);
     goto out;
   }
diff --git a/crypto/fipsmodule/rsa/rsa_impl.c b/crypto/fipsmodule/rsa/rsa_impl.c
index f2dc7fe..6f9c3bb 100644
--- a/crypto/fipsmodule/rsa/rsa_impl.c
+++ b/crypto/fipsmodule/rsa/rsa_impl.c
@@ -1003,20 +1003,25 @@
     // retrying. That is, we reject a negligible fraction of primes that are
     // within the FIPS bound, but we will never accept a prime outside the
     // bound, ensuring the resulting RSA key is the right size.
-    if (BN_cmp(out, sqrt2) <= 0) {
+    //
+    // Values over the threshold are discarded, so it is safe to leak this
+    // comparison.
+    if (constant_time_declassify_int(BN_cmp(out, sqrt2) <= 0)) {
       continue;
     }
 
     // RSA key generation's bottleneck is discarding composites. If it fails
     // trial division, do not bother computing a GCD or performing Miller-Rabin.
     if (!bn_odd_number_is_obviously_composite(out)) {
-      // Check gcd(out-1, e) is one (steps 4.5 and 5.6).
+      // Check gcd(out-1, e) is one (steps 4.5 and 5.6). Leaking the final
+      // result of this comparison is safe because, if not relatively prime, the
+      // value will be discarded.
       int relatively_prime;
-      if (!BN_sub(tmp, out, BN_value_one()) ||
+      if (!bn_usub_consttime(tmp, out, BN_value_one()) ||
           !bn_is_relatively_prime(&relatively_prime, tmp, e, ctx)) {
         goto err;
       }
-      if (relatively_prime) {
+      if (constant_time_declassify_int(relatively_prime)) {
         // Test |out| for primality (steps 4.5.1 and 5.6.1).
         int is_probable_prime;
         if (!BN_primality_test(&is_probable_prime, out,
@@ -1174,8 +1179,9 @@
     }
 
     // Retry if |rsa->d| <= 2^|prime_bits|. See appendix B.3.1's guidance on
-    // values for d.
-  } while (BN_cmp(rsa->d, pow2_prime_bits) <= 0);
+    // values for d. When we retry, p and q are discarded, so it is safe to leak
+    // this comparison.
+  } while (constant_time_declassify_int(BN_cmp(rsa->d, pow2_prime_bits) <= 0));
 
   assert(BN_num_bits(pm1) == (unsigned)prime_bits);
   assert(BN_num_bits(qm1) == (unsigned)prime_bits);
@@ -1189,6 +1195,9 @@
   }
   bn_set_minimal_width(rsa->n);
 
+  // |rsa->n| is computed from the private key, but is public.
+  bn_declassify(rsa->n);
+
   // Sanity-check that |rsa->n| has the specified size. This is implied by
   // |generate_prime|'s bounds.
   if (BN_num_bits(rsa->n) != (unsigned)bits) {