BN_mod_exp_mont_consttime: check for zero modulus.

Don't dereference |d| when |top| is zero. Also test that various BIGNUM
methods behave correctly on zero/even inputs.

(Imported from upstream's cf633fa00244e39eea2f2c0b623f7d5bbefa904e.)

We already had the BN_div and BN_MONT_CTX_set tests, but align them with
upstream's for consistency.

Change-Id: Ice5d04f559b4d5672e23c400637c07d8ee401727
Reviewed-on: https://boringssl-review.googlesource.com/5783
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/bn/bn_test.cc b/crypto/bn/bn_test.cc
index c7ea9cc..276f683 100644
--- a/crypto/bn/bn_test.cc
+++ b/crypto/bn/bn_test.cc
@@ -423,6 +423,16 @@
     return false;
   }
 
+  if (!BN_one(a.get())) {
+    return false;
+  }
+  BN_zero(b.get());
+  if (BN_div(d.get(), c.get(), a.get(), b.get(), ctx)) {
+    fprintf(stderr, "Division by zero succeeded!\n");
+    return false;
+  }
+  ERR_clear_error();
+
   for (int i = 0; i < num0 + num1; i++) {
     if (i < num1) {
       if (!BN_rand(a.get(), 400, 0, 0) ||
@@ -491,14 +501,6 @@
     return false;
   }
 
-  // Test the BN_div checks for division by zero.
-  BN_zero(b.get());
-  if (BN_div(d.get(), c.get(), a.get(), b.get(), ctx)) {
-    fprintf(stderr, "Divided by zero!\n");
-    return false;
-  }
-  ERR_clear_error();
-
   return true;
 }
 
@@ -881,8 +883,27 @@
   ScopedBIGNUM B(BN_new());
   ScopedBIGNUM n(BN_new());
   ScopedBN_MONT_CTX mont(BN_MONT_CTX_new());
-  if (!a || !b || !c || !d || !A || !B || !n || !mont ||
-      !BN_rand(a.get(), 100, 0, 0) ||
+  if (!a || !b || !c || !d || !A || !B || !n || !mont) {
+    return false;
+  }
+
+  BN_zero(n.get());
+  if (BN_MONT_CTX_set(mont.get(), n.get(), ctx)) {
+    fprintf(stderr, "BN_MONT_CTX_set succeeded for zero modulus!\n");
+    return false;
+  }
+  ERR_clear_error();
+
+  if (!BN_set_word(n.get(), 16)) {
+    return false;
+  }
+  if (BN_MONT_CTX_set(mont.get(), n.get(), ctx)) {
+    fprintf(stderr, "BN_MONT_CTX_set succeeded for even modulus!\n");
+    return false;
+  }
+  ERR_clear_error();
+
+  if (!BN_rand(a.get(), 100, 0, 0) ||
       !BN_rand(b.get(), 100, 0, 0)) {
     return false;
   }
@@ -923,13 +944,6 @@
     }
   }
 
-  BN_zero(n.get());
-  if (BN_MONT_CTX_set(mont.get(), n.get(), ctx)) {
-    fprintf(stderr, "Division by zero!\n");
-    return false;
-  }
-  ERR_clear_error();
-
   return true;
 }
 
@@ -983,6 +997,16 @@
     return false;
   }
 
+  if (!BN_one(a.get()) || !BN_one(b.get())) {
+    return false;
+  }
+  BN_zero(c.get());
+  if (BN_mod_mul(e.get(), a.get(), b.get(), c.get(), ctx)) {
+    fprintf(stderr, "BN_mod_mul with zero modulus succeeded!\n");
+    return false;
+  }
+  ERR_clear_error();
+
   for (int j = 0; j < 3; j++) {
     if (!BN_rand(c.get(), 1024, 0, 0)) {
       return false;
@@ -1037,8 +1061,21 @@
   ScopedBIGNUM c(BN_new());
   ScopedBIGNUM d(BN_new());
   ScopedBIGNUM e(BN_new());
-  if (!a || !b || !c || !d || !e ||
-      !BN_rand(c.get(), 30, 0, 1)) {  // must be odd for montgomery
+  if (!a || !b || !c || !d || !e) {
+    return false;
+  }
+
+  if (!BN_one(a.get()) || !BN_one(b.get())) {
+    return false;
+  }
+  BN_zero(c.get());
+  if (BN_mod_exp(d.get(), a.get(), b.get(), c.get(), ctx)) {
+    fprintf(stderr, "BN_mod_exp with zero modulus succeeded!\n");
+    return 0;
+  }
+  ERR_clear_error();
+
+  if (!BN_rand(c.get(), 30, 0, 1)) {  // must be odd for montgomery
     return false;
   }
   for (int i = 0; i < num2; i++) {
@@ -1077,8 +1114,32 @@
   ScopedBIGNUM c(BN_new());
   ScopedBIGNUM d(BN_new());
   ScopedBIGNUM e(BN_new());
-  if (!a || !b || !c || !d || !e ||
-      !BN_rand(c.get(), 30, 0, 1)) {  // must be odd for montgomery
+  if (!a || !b || !c || !d || !e) {
+    return false;
+  }
+
+  if (!BN_one(a.get()) || !BN_one(b.get())) {
+    return false;
+  }
+  BN_zero(c.get());
+  if (BN_mod_exp_mont_consttime(d.get(), a.get(), b.get(), c.get(), ctx,
+                                nullptr)) {
+    fprintf(stderr, "BN_mod_exp_mont_consttime with zero modulus succeeded!\n");
+    return 0;
+  }
+  ERR_clear_error();
+
+  if (!BN_set_word(c.get(), 16)) {
+    return false;
+  }
+  if (BN_mod_exp_mont_consttime(d.get(), a.get(), b.get(), c.get(), ctx,
+                                nullptr)) {
+    fprintf(stderr, "BN_mod_exp_mont_consttime with even modulus succeeded!\n");
+    return 0;
+  }
+  ERR_clear_error();
+
+  if (!BN_rand(c.get(), 30, 0, 1)) {  // must be odd for montgomery
     return false;
   }
   for (int i = 0; i < num2; i++) {
diff --git a/crypto/bn/exponentiation.c b/crypto/bn/exponentiation.c
index a829810..6c5e11b 100644
--- a/crypto/bn/exponentiation.c
+++ b/crypto/bn/exponentiation.c
@@ -862,12 +862,13 @@
   unsigned char *powerbuf = NULL;
   BIGNUM tmp, am;
 
-  top = m->top;
-
-  if (!(m->d[0] & 1)) {
+  if (!BN_is_odd(m)) {
     OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
     return 0;
   }
+
+  top = m->top;
+
   bits = BN_num_bits(p);
   if (bits == 0) {
     ret = BN_one(rr);