Store EC_KEY's private key as an EC_SCALAR.

This isn't strictly necessary now that BIGNUMs are safe, but we get to
rely on type-system annotations from EC_SCALAR. Additionally,
EC_POINT_mul depends on BN_div, while the EC_SCALAR version does not.

Change-Id: I75e6967f3d35aef17278b94862f4e506baff5c23
Reviewed-on: https://boringssl-review.googlesource.com/26424
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/crypto/ec_extra/ec_asn1.c b/crypto/ec_extra/ec_asn1.c
index c125af2..bde6d0b 100644
--- a/crypto/ec_extra/ec_asn1.c
+++ b/crypto/ec_extra/ec_asn1.c
@@ -86,6 +86,7 @@
   // Parse the optional parameters field.
   EC_GROUP *inner_group = NULL;
   EC_KEY *ret = NULL;
+  BIGNUM *priv_key = NULL;
   if (CBS_peek_asn1_tag(&ec_private_key, kParametersTag)) {
     // Per SEC 1, as an alternative to omitting it, one is allowed to specify
     // this field and put in a NULL to mean inheriting this value. This was
@@ -126,15 +127,10 @@
   // Although RFC 5915 specifies the length of the key, OpenSSL historically
   // got this wrong, so accept any length. See upstream's
   // 30cd4ff294252c4b6a4b69cbef6a5b4117705d22.
-  ret->priv_key =
-      BN_bin2bn(CBS_data(&private_key), CBS_len(&private_key), NULL);
+  priv_key = BN_bin2bn(CBS_data(&private_key), CBS_len(&private_key), NULL);
   ret->pub_key = EC_POINT_new(group);
-  if (ret->priv_key == NULL || ret->pub_key == NULL) {
-    goto err;
-  }
-
-  if (BN_cmp(ret->priv_key, EC_GROUP_get0_order(group)) >= 0) {
-    OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
+  if (priv_key == NULL || ret->pub_key == NULL ||
+      !EC_KEY_set_private_key(ret, priv_key)) {
     goto err;
   }
 
@@ -163,7 +159,8 @@
         (point_conversion_form_t)(CBS_data(&public_key)[0] & ~0x01);
   } else {
     // Compute the public key instead.
-    if (!EC_POINT_mul(group, ret->pub_key, ret->priv_key, NULL, NULL, NULL)) {
+    if (!ec_point_mul_scalar(group, ret->pub_key, &ret->priv_key->scalar, NULL,
+                             NULL, NULL)) {
       goto err;
     }
     // Remember the original private-key-only encoding.
@@ -181,11 +178,13 @@
     goto err;
   }
 
+  BN_free(priv_key);
   EC_GROUP_free(inner_group);
   return ret;
 
 err:
   EC_KEY_free(ret);
+  BN_free(priv_key);
   EC_GROUP_free(inner_group);
   return NULL;
 }
@@ -203,7 +202,7 @@
       !CBB_add_asn1(&ec_private_key, &private_key, CBS_ASN1_OCTETSTRING) ||
       !BN_bn2cbb_padded(&private_key,
                         BN_num_bytes(EC_GROUP_get0_order(key->group)),
-                        key->priv_key)) {
+                        EC_KEY_get0_private_key(key))) {
     OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR);
     return 0;
   }
diff --git a/crypto/ecdh/ecdh.c b/crypto/ecdh/ecdh.c
index f38de2f..7634ba5 100644
--- a/crypto/ecdh/ecdh.c
+++ b/crypto/ecdh/ecdh.c
@@ -74,6 +74,7 @@
 #include <openssl/err.h>
 #include <openssl/mem.h>
 
+#include "../fipsmodule/ec/internal.h"
 #include "../internal.h"
 
 
@@ -81,11 +82,11 @@
                      const EC_KEY *priv_key,
                      void *(*kdf)(const void *in, size_t inlen, void *out,
                                   size_t *outlen)) {
-  const BIGNUM *const priv = EC_KEY_get0_private_key(priv_key);
-  if (priv == NULL) {
+  if (priv_key->priv_key == NULL) {
     OPENSSL_PUT_ERROR(ECDH, ECDH_R_NO_PRIVATE_VALUE);
     return -1;
   }
+  const EC_SCALAR *const priv = &priv_key->priv_key->scalar;
 
   BN_CTX *ctx = BN_CTX_new();
   if (ctx == NULL) {
@@ -104,7 +105,7 @@
     goto err;
   }
 
-  if (!EC_POINT_mul(group, tmp, NULL, pub_key, priv, ctx)) {
+  if (!ec_point_mul_scalar(group, tmp, NULL, pub_key, priv, ctx)) {
     OPENSSL_PUT_ERROR(ECDH, ECDH_R_POINT_ARITHMETIC_FAILURE);
     goto err;
   }
diff --git a/crypto/fipsmodule/bn/random.c b/crypto/fipsmodule/bn/random.c
index 733520d..c6f9f08 100644
--- a/crypto/fipsmodule/bn/random.c
+++ b/crypto/fipsmodule/bn/random.c
@@ -120,8 +120,6 @@
 #include "../rand/internal.h"
 
 
-static const uint8_t kDefaultAdditionalData[32] = {0};
-
 int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
   uint8_t *buf = NULL;
   int ret = 0, bit, bytes, mask;
@@ -278,6 +276,7 @@
 
 int BN_rand_range_ex(BIGNUM *r, BN_ULONG min_inclusive,
                      const BIGNUM *max_exclusive) {
+  static const uint8_t kDefaultAdditionalData[32] = {0};
   if (!bn_wexpand(r, max_exclusive->width) ||
       !bn_rand_range_words(r->d, min_inclusive, max_exclusive->d,
                            max_exclusive->width, kDefaultAdditionalData)) {
diff --git a/crypto/fipsmodule/ec/ec_key.c b/crypto/fipsmodule/ec/ec_key.c
index b56139d..a6d4697 100644
--- a/crypto/fipsmodule/ec/ec_key.c
+++ b/crypto/fipsmodule/ec/ec_key.c
@@ -84,6 +84,25 @@
 
 DEFINE_STATIC_EX_DATA_CLASS(g_ec_ex_data_class);
 
+static EC_WRAPPED_SCALAR *ec_wrapped_scalar_new(const EC_GROUP *group) {
+  EC_WRAPPED_SCALAR *wrapped = OPENSSL_malloc(sizeof(EC_WRAPPED_SCALAR));
+  if (wrapped == NULL) {
+    OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
+    return NULL;
+  }
+
+  OPENSSL_memset(wrapped, 0, sizeof(EC_WRAPPED_SCALAR));
+  wrapped->bignum.d = wrapped->scalar.words;
+  wrapped->bignum.width = group->order.width;
+  wrapped->bignum.dmax = group->order.width;
+  wrapped->bignum.flags = BN_FLG_STATIC_DATA;
+  return wrapped;
+}
+
+static void ec_wrapped_scalar_free(EC_WRAPPED_SCALAR *scalar) {
+  OPENSSL_free(scalar);
+}
+
 EC_KEY *EC_KEY_new(void) { return EC_KEY_new_method(NULL); }
 
 EC_KEY *EC_KEY_new_method(const ENGINE *engine) {
@@ -151,7 +170,7 @@
 
   EC_GROUP_free(r->group);
   EC_POINT_free(r->pub_key);
-  BN_clear_free(r->priv_key);
+  ec_wrapped_scalar_free(r->priv_key);
   BN_free(r->fixed_k);
 
   CRYPTO_free_ex_data(g_ec_ex_data_class_bss_get(), r, &r->ex_data);
@@ -175,7 +194,7 @@
       (src->pub_key != NULL &&
        !EC_KEY_set_public_key(ret, src->pub_key)) ||
       (src->priv_key != NULL &&
-       !EC_KEY_set_private_key(ret, src->priv_key))) {
+       !EC_KEY_set_private_key(ret, EC_KEY_get0_private_key(src)))) {
     EC_KEY_free(ret);
     return NULL;
   }
@@ -215,7 +234,7 @@
 }
 
 const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
-  return key->priv_key;
+  return key->priv_key != NULL ? &key->priv_key->bignum : NULL;
 }
 
 int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) {
@@ -224,14 +243,18 @@
     return 0;
   }
 
-  if (BN_is_negative(priv_key) ||
-      BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0) {
-    OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
+  EC_WRAPPED_SCALAR *scalar = ec_wrapped_scalar_new(key->group);
+  if (scalar == NULL) {
     return 0;
   }
-  BN_clear_free(key->priv_key);
-  key->priv_key = BN_dup(priv_key);
-  return (key->priv_key == NULL) ? 0 : 1;
+  if (!ec_bignum_to_scalar(key->group, &scalar->scalar, priv_key)) {
+    OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
+    ec_wrapped_scalar_free(scalar);
+    return 0;
+  }
+  ec_wrapped_scalar_free(key->priv_key);
+  key->priv_key = scalar;
+  return 1;
 }
 
 const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) {
@@ -296,15 +319,11 @@
   }
   // in case the priv_key is present :
   // check if generator * priv_key == pub_key
-  if (eckey->priv_key) {
-    if (BN_is_negative(eckey->priv_key) ||
-        BN_cmp(eckey->priv_key, EC_GROUP_get0_order(eckey->group)) >= 0) {
-      OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
-      goto err;
-    }
+  if (eckey->priv_key != NULL) {
     point = EC_POINT_new(eckey->group);
     if (point == NULL ||
-        !EC_POINT_mul(eckey->group, point, eckey->priv_key, NULL, NULL, ctx)) {
+        !ec_point_mul_scalar(eckey->group, point, &eckey->priv_key->scalar,
+                             NULL, NULL, ctx)) {
       OPENSSL_PUT_ERROR(EC, ERR_R_EC_LIB);
       goto err;
     }
@@ -375,65 +394,37 @@
   return ok;
 }
 
-int EC_KEY_generate_key(EC_KEY *eckey) {
-  int ok = 0;
-  BIGNUM *priv_key = NULL;
-  EC_POINT *pub_key = NULL;
-
-  if (!eckey || !eckey->group) {
+int EC_KEY_generate_key(EC_KEY *key) {
+  if (key == NULL || key->group == NULL) {
     OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER);
     return 0;
   }
 
-  if (eckey->priv_key == NULL) {
-    priv_key = BN_new();
-    if (priv_key == NULL) {
-      goto err;
-    }
-  } else {
-    priv_key = eckey->priv_key;
-  }
-
-  const BIGNUM *order = EC_GROUP_get0_order(eckey->group);
-
-  // Check that the size of the group order is FIPS compliant (FIPS 186-4
-  // B.4.2).
-  if (BN_num_bits(order) < 160) {
+  // Check that the group order is FIPS compliant (FIPS 186-4 B.4.2).
+  if (BN_num_bits(EC_GROUP_get0_order(key->group)) < 160) {
     OPENSSL_PUT_ERROR(EC, EC_R_INVALID_GROUP_ORDER);
-    goto err;
+    return 0;
   }
 
-  // Generate the private key by testing candidates (FIPS 186-4 B.4.2).
-  if (!BN_rand_range_ex(priv_key, 1, order)) {
-    goto err;
-  }
-
-  if (eckey->pub_key == NULL) {
-    pub_key = EC_POINT_new(eckey->group);
-    if (pub_key == NULL) {
-      goto err;
-    }
-  } else {
-    pub_key = eckey->pub_key;
-  }
-
-  if (!EC_POINT_mul(eckey->group, pub_key, priv_key, NULL, NULL, NULL)) {
-    goto err;
-  }
-
-  eckey->priv_key = priv_key;
-  eckey->pub_key = pub_key;
-
-  ok = 1;
-
-err:
-  if (eckey->pub_key == NULL) {
+  static const uint8_t kDefaultAdditionalData[32] = {0};
+  EC_WRAPPED_SCALAR *priv_key = ec_wrapped_scalar_new(key->group);
+  EC_POINT *pub_key = EC_POINT_new(key->group);
+  if (priv_key == NULL || pub_key == NULL ||
+      // Generate the private key by testing candidates (FIPS 186-4 B.4.2).
+      !ec_random_nonzero_scalar(key->group, &priv_key->scalar,
+                                kDefaultAdditionalData) ||
+      !ec_point_mul_scalar(key->group, pub_key, &priv_key->scalar, NULL, NULL,
+                           NULL)) {
     EC_POINT_free(pub_key);
+    ec_wrapped_scalar_free(priv_key);
+    return 0;
   }
-  if (eckey->priv_key == NULL) {
-    BN_free(priv_key);
-  }
-  return ok;
+
+  ec_wrapped_scalar_free(key->priv_key);
+  key->priv_key = priv_key;
+  EC_POINT_free(key->pub_key);
+  key->pub_key = pub_key;
+  return 1;
 }
 
 int EC_KEY_generate_key_fips(EC_KEY *eckey) {
diff --git a/crypto/fipsmodule/ec/ec_test.cc b/crypto/fipsmodule/ec/ec_test.cc
index 923ce1e..5cce361 100644
--- a/crypto/fipsmodule/ec/ec_test.cc
+++ b/crypto/fipsmodule/ec/ec_test.cc
@@ -359,6 +359,14 @@
       EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
 }
 
+TEST(ECTest, EmptyKey) {
+  bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
+  ASSERT_TRUE(key);
+  EXPECT_FALSE(EC_KEY_get0_group(key.get()));
+  EXPECT_FALSE(EC_KEY_get0_public_key(key.get()));
+  EXPECT_FALSE(EC_KEY_get0_private_key(key.get()));
+}
+
 class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
 
 TEST_P(ECCurveTest, SetAffine) {
diff --git a/crypto/fipsmodule/ec/internal.h b/crypto/fipsmodule/ec/internal.h
index e1a3e71..75fe81c 100644
--- a/crypto/fipsmodule/ec/internal.h
+++ b/crypto/fipsmodule/ec/internal.h
@@ -277,11 +277,18 @@
 // x86-64 optimized P256. See http://eprint.iacr.org/2013/816.
 const EC_METHOD *EC_GFp_nistz256_method(void);
 
+// An EC_WRAPPED_SCALAR is an |EC_SCALAR| with a parallel |BIGNUM|
+// representation. It exists to support the |EC_KEY_get0_private_key| API.
+typedef struct {
+  BIGNUM bignum;
+  EC_SCALAR scalar;
+} EC_WRAPPED_SCALAR;
+
 struct ec_key_st {
   EC_GROUP *group;
 
   EC_POINT *pub_key;
-  BIGNUM *priv_key;
+  EC_WRAPPED_SCALAR *priv_key;
 
   // fixed_k may contain a specific value of 'k', to be used in ECDSA signing.
   // This is only for the FIPS power-on tests.
diff --git a/crypto/fipsmodule/ecdsa/ecdsa.c b/crypto/fipsmodule/ecdsa/ecdsa.c
index e010dbd..1d08123 100644
--- a/crypto/fipsmodule/ecdsa/ecdsa.c
+++ b/crypto/fipsmodule/ecdsa/ecdsa.c
@@ -392,17 +392,17 @@
   }
 
   const EC_GROUP *group = EC_KEY_get0_group(eckey);
-  const BIGNUM *priv_key_bn = EC_KEY_get0_private_key(eckey);
-  if (group == NULL || priv_key_bn == NULL) {
+  if (group == NULL || eckey->priv_key == NULL) {
     OPENSSL_PUT_ERROR(ECDSA, ERR_R_PASSED_NULL_PARAMETER);
     return NULL;
   }
   const BIGNUM *order = EC_GROUP_get0_order(group);
+  const EC_SCALAR *priv_key = &eckey->priv_key->scalar;
 
   int ok = 0;
   ECDSA_SIG *ret = ECDSA_SIG_new();
   BN_CTX *ctx = BN_CTX_new();
-  EC_SCALAR kinv_mont, priv_key, r_mont, s;
+  EC_SCALAR kinv_mont, r_mont, s;
   EC_LOOSE_SCALAR m, tmp;
   if (ret == NULL || ctx == NULL) {
     OPENSSL_PUT_ERROR(ECDSA, ERR_R_MALLOC_FAILURE);
@@ -410,14 +410,9 @@
   }
 
   digest_to_scalar(group, &m, digest, digest_len);
-  // TODO(davidben): Store the private key as an |EC_SCALAR| so this is obvious
-  // via the type system.
-  if (!ec_bignum_to_scalar_unchecked(group, &priv_key, priv_key_bn)) {
-    goto err;
-  }
   for (;;) {
     if (!ecdsa_sign_setup(eckey, ctx, &kinv_mont, &ret->r, digest, digest_len,
-                          &priv_key)) {
+                          priv_key)) {
       goto err;
     }
 
@@ -427,7 +422,7 @@
     if (!ec_bignum_to_scalar(group, &r_mont, ret->r) ||
         !bn_to_montgomery_small(r_mont.words, order->width, r_mont.words,
                                 order->width, group->order_mont) ||
-        !scalar_mod_mul_montgomery(group, &s, &priv_key, &r_mont)) {
+        !scalar_mod_mul_montgomery(group, &s, priv_key, &r_mont)) {
       goto err;
     }
 
@@ -455,7 +450,6 @@
   }
   BN_CTX_free(ctx);
   OPENSSL_cleanse(&kinv_mont, sizeof(kinv_mont));
-  OPENSSL_cleanse(&priv_key, sizeof(priv_key));
   OPENSSL_cleanse(&r_mont, sizeof(r_mont));
   OPENSSL_cleanse(&s, sizeof(s));
   OPENSSL_cleanse(&tmp, sizeof(tmp));