Decouple crypto/ec from the OID table.

Instead, embed the (very short) encoding of the OID into built_in_curve.

BUG=chromium:499653

Change-Id: I0db36f83c71fbd3321831f54fa5022f8304b30cd
Reviewed-on: https://boringssl-review.googlesource.com/7564
Reviewed-by: Steven Valdez <svaldez@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c
index 478e80e..8f3fa6e 100644
--- a/crypto/ec/ec.c
+++ b/crypto/ec/ec.c
@@ -228,10 +228,25 @@
 #endif
 
 const struct built_in_curve OPENSSL_built_in_curves[] = {
-    {NID_secp521r1, &P521, 0},
-    {NID_secp384r1, &P384, 0},
     {
-        NID_X9_62_prime256v1, &P256,
+        NID_secp521r1,
+        /* 1.3.132.0.35 */
+        {0x2b, 0x81, 0x04, 0x00, 0x23}, 5,
+        &P521,
+        NULL,
+      },
+    {
+        NID_secp384r1,
+        /* 1.3.132.0.34 */
+        {0x2b, 0x81, 0x04, 0x00, 0x22}, 5,
+        &P384,
+        NULL,
+    },
+    {
+        NID_X9_62_prime256v1,
+        /* 1.2.840.10045.3.1.7 */
+        {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}, 8,
+        &P256,
 #if defined(BORINGSSL_USE_INT128_CODE)
 #if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
     !defined(OPENSSL_SMALL)
@@ -240,18 +255,21 @@
         EC_GFp_nistp256_method,
 #endif
 #else
-        0,
+        NULL,
 #endif
     },
     {
-        NID_secp224r1, &P224,
+        NID_secp224r1,
+        /* 1.3.132.0.33 */
+        {0x2b, 0x81, 0x04, 0x00, 0x21}, 5,
+        &P224,
 #if defined(BORINGSSL_USE_INT128_CODE) && !defined(OPENSSL_SMALL)
         EC_GFp_nistp224_method,
 #else
-        0,
+        NULL,
 #endif
     },
-    {NID_undef, 0, 0},
+    {NID_undef, {0}, 0, NULL, NULL},
 };
 
 /* built_in_curve_scalar_field_monts contains Montgomery contexts for
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index 0535a79..f31e158 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -60,7 +60,7 @@
 #include <openssl/bn.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
 
 #include "internal.h"
 #include "../bytestring/internal.h"
@@ -207,14 +207,9 @@
   }
 
   if (!(enc_flags & EC_PKEY_NO_PARAMETERS)) {
-    int curve_nid = EC_GROUP_get_curve_name(key->group);
-    if (curve_nid == NID_undef) {
-      OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
-      return 0;
-    }
     CBB child;
     if (!CBB_add_asn1(&ec_private_key, &child, kParametersTag) ||
-        !OBJ_nid2cbb(&child, curve_nid) ||
+        !EC_KEY_marshal_curve_name(&child, key->group) ||
         !CBB_flush(&ec_private_key)) {
       OPENSSL_PUT_ERROR(EC, EC_R_ENCODE_ERROR);
       return 0;
@@ -260,6 +255,9 @@
   return 1;
 }
 
+/* kPrimeFieldOID is the encoding of 1.2.840.10045.1.1. */
+static const uint8_t kPrimeField[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01};
+
 static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a,
                                       CBS *out_b, CBS *out_base_x,
                                       CBS *out_base_y, CBS *out_order) {
@@ -272,7 +270,8 @@
       version != 1 ||
       !CBS_get_asn1(&params, &field_id, CBS_ASN1_SEQUENCE) ||
       !CBS_get_asn1(&field_id, &field_type, CBS_ASN1_OBJECT) ||
-      OBJ_cbs2nid(&field_type) != NID_X9_62_prime_field ||
+      CBS_len(&field_type) != sizeof(kPrimeField) ||
+      memcmp(CBS_data(&field_type), kPrimeField, sizeof(kPrimeField)) != 0 ||
       !CBS_get_asn1(&field_id, out_prime, CBS_ASN1_INTEGER) ||
       !is_unsigned_integer(out_prime) ||
       CBS_len(&field_id) != 0 ||
@@ -324,51 +323,86 @@
   return CBS_mem_equal(&a_copy, b, b_len);
 }
 
-EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) {
-  if (CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) {
-    /* OpenSSL sometimes produces ECPrivateKeys with explicitly-encoded versions
-     * of named curves.
-     *
-     * TODO(davidben): Remove support for this. */
-    CBS prime, a, b, base_x, base_y, order;
-    if (!parse_explicit_prime_curve(cbs, &prime, &a, &b, &base_x, &base_y,
-                                    &order)) {
-      return NULL;
-    }
-
-    /* Look for a matching prime curve. */
-    unsigned i;
-    for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
-      const struct built_in_curve *curve = &OPENSSL_built_in_curves[i];
-      const unsigned param_len = curve->data->param_len;
-      /* |curve->data->data| is ordered p, a, b, x, y, order, each component
-       * zero-padded up to the field length. Although SEC 1 states that the
-       * Field-Element-to-Octet-String conversion also pads, OpenSSL mis-encodes
-       * |a| and |b|, so this comparison must allow omitting leading zeros.
-       * (This is relevant for P-521 whose |b| has a leading 0.) */
-      if (integers_equal(&prime, curve->data->data, param_len) &&
-          integers_equal(&a, curve->data->data + param_len, param_len) &&
-          integers_equal(&b, curve->data->data + param_len * 2, param_len) &&
-          integers_equal(&base_x, curve->data->data + param_len * 3,
-                         param_len) &&
-          integers_equal(&base_y, curve->data->data + param_len * 4,
-                         param_len) &&
-          integers_equal(&order, curve->data->data + param_len * 5,
-                         param_len)) {
-        return EC_GROUP_new_by_curve_name(curve->nid);
-      }
-    }
-
-    OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
-    return NULL;
-  }
-
+EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs) {
   CBS named_curve;
   if (!CBS_get_asn1(cbs, &named_curve, CBS_ASN1_OBJECT)) {
     OPENSSL_PUT_ERROR(EC, EC_R_DECODE_ERROR);
     return NULL;
   }
-  return EC_GROUP_new_by_curve_name(OBJ_cbs2nid(&named_curve));
+
+  /* Look for a matching curve. */
+  unsigned i;
+  for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
+    const struct built_in_curve *curve = &OPENSSL_built_in_curves[i];
+    if (CBS_len(&named_curve) == curve->oid_len &&
+        memcmp(CBS_data(&named_curve), curve->oid, curve->oid_len) == 0) {
+      return EC_GROUP_new_by_curve_name(curve->nid);
+    }
+  }
+
+  OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
+  return NULL;
+}
+
+int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group) {
+  int nid = EC_GROUP_get_curve_name(group);
+  if (nid == NID_undef) {
+    OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
+    return 0;
+  }
+
+  unsigned i;
+  for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
+    const struct built_in_curve *curve = &OPENSSL_built_in_curves[i];
+    if (curve->nid == nid) {
+      CBB child;
+      return CBB_add_asn1(cbb, &child, CBS_ASN1_OBJECT) &&
+             CBB_add_bytes(&child, curve->oid, curve->oid_len) &&
+             CBB_flush(cbb);
+    }
+  }
+
+  OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
+  return 0;
+}
+
+EC_GROUP *EC_KEY_parse_parameters(CBS *cbs) {
+  if (!CBS_peek_asn1_tag(cbs, CBS_ASN1_SEQUENCE)) {
+    return EC_KEY_parse_curve_name(cbs);
+  }
+
+  /* OpenSSL sometimes produces ECPrivateKeys with explicitly-encoded versions
+   * of named curves.
+   *
+   * TODO(davidben): Remove support for this. */
+  CBS prime, a, b, base_x, base_y, order;
+  if (!parse_explicit_prime_curve(cbs, &prime, &a, &b, &base_x, &base_y,
+                                  &order)) {
+    return NULL;
+  }
+
+  /* Look for a matching prime curve. */
+  unsigned i;
+  for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
+    const struct built_in_curve *curve = &OPENSSL_built_in_curves[i];
+    const unsigned param_len = curve->data->param_len;
+    /* |curve->data->data| is ordered p, a, b, x, y, order, each component
+     * zero-padded up to the field length. Although SEC 1 states that the
+     * Field-Element-to-Octet-String conversion also pads, OpenSSL mis-encodes
+     * |a| and |b|, so this comparison must allow omitting leading zeros. (This
+     * is relevant for P-521 whose |b| has a leading 0.) */
+    if (integers_equal(&prime, curve->data->data, param_len) &&
+        integers_equal(&a, curve->data->data + param_len, param_len) &&
+        integers_equal(&b, curve->data->data + param_len * 2, param_len) &&
+        integers_equal(&base_x, curve->data->data + param_len * 3, param_len) &&
+        integers_equal(&base_y, curve->data->data + param_len * 4, param_len) &&
+        integers_equal(&order, curve->data->data + param_len * 5, param_len)) {
+      return EC_GROUP_new_by_curve_name(curve->nid);
+    }
+  }
+
+  OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
+  return NULL;
 }
 
 EC_KEY *d2i_ECPrivateKey(EC_KEY **out, const uint8_t **inp, long len) {
@@ -441,15 +475,9 @@
     return -1;
   }
 
-  int curve_nid = EC_GROUP_get_curve_name(key->group);
-  if (curve_nid == NID_undef) {
-    OPENSSL_PUT_ERROR(EC, EC_R_UNKNOWN_GROUP);
-    return -1;
-  }
-
   CBB cbb;
   if (!CBB_init(&cbb, 0) ||
-      !OBJ_nid2cbb(&cbb, curve_nid)) {
+      !EC_KEY_marshal_curve_name(&cbb, key->group)) {
     CBB_cleanup(&cbb);
     return -1;
   }
diff --git a/crypto/ec/internal.h b/crypto/ec/internal.h
index bb9fc9e..f2cbb96 100644
--- a/crypto/ec/internal.h
+++ b/crypto/ec/internal.h
@@ -271,6 +271,8 @@
 
 struct built_in_curve {
   int nid;
+  uint8_t oid[8];
+  uint8_t oid_len;
   const struct curve_data *data;
   const EC_METHOD *(*method)(void);
 };
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
index 4e51440..d81e54d 100644
--- a/crypto/evp/p_ec_asn1.c
+++ b/crypto/evp/p_ec_asn1.c
@@ -69,11 +69,6 @@
 static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) {
   const EC_KEY *ec_key = key->pkey.ec;
   const EC_GROUP *group = EC_KEY_get0_group(ec_key);
-  int curve_nid = EC_GROUP_get_curve_name(group);
-  if (curve_nid == NID_undef) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
-    return 0;
-  }
   const EC_POINT *public_key = EC_KEY_get0_public_key(ec_key);
 
   /* See RFC 5480, section 2. */
@@ -81,7 +76,7 @@
   if (!CBB_add_asn1(out, &spki, CBS_ASN1_SEQUENCE) ||
       !CBB_add_asn1(&spki, &algorithm, CBS_ASN1_SEQUENCE) ||
       !OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) ||
-      !OBJ_nid2cbb(&algorithm, curve_nid) ||
+      !EC_KEY_marshal_curve_name(&algorithm, group) ||
       !CBB_add_asn1(&spki, &key_bitstring, CBS_ASN1_BITSTRING) ||
       !CBB_add_u8(&key_bitstring, 0 /* padding */) ||
       !EC_POINT_point2cbb(&key_bitstring, group, public_key,
@@ -98,31 +93,32 @@
   /* See RFC 5480, section 2. */
 
   /* The parameters are a named curve. */
-  CBS named_curve;
-  if (!CBS_get_asn1(params, &named_curve, CBS_ASN1_OBJECT) ||
-      CBS_len(params) != 0) {
+  EC_GROUP *group = EC_KEY_parse_curve_name(params);
+  if (group == NULL || CBS_len(params) != 0) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     return 0;
   }
 
-  EC_KEY *eckey = EC_KEY_new_by_curve_name(OBJ_cbs2nid(&named_curve));
-  if (eckey == NULL) {
-    return 0;
+  EC_POINT *point = NULL;
+  EC_KEY *eckey = EC_KEY_new();
+  if (eckey == NULL || !EC_KEY_set_group(eckey, group)) {
+    goto err;
   }
 
-  EC_POINT *point = EC_POINT_new(EC_KEY_get0_group(eckey));
+  point = EC_POINT_new(group);
   if (point == NULL ||
-      !EC_POINT_oct2point(EC_KEY_get0_group(eckey), point, CBS_data(key),
-                          CBS_len(key), NULL) ||
+      !EC_POINT_oct2point(group, point, CBS_data(key), CBS_len(key), NULL) ||
       !EC_KEY_set_public_key(eckey, point)) {
     goto err;
   }
 
+  EC_GROUP_free(group);
   EC_POINT_free(point);
   EVP_PKEY_assign_EC_KEY(out, eckey);
   return 1;
 
 err:
+  EC_GROUP_free(group);
   EC_POINT_free(point);
   EC_KEY_free(eckey);
   return 0;
@@ -166,11 +162,6 @@
 
 static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) {
   const EC_KEY *ec_key = key->pkey.ec;
-  int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
-  if (curve_nid == NID_undef) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
-    return 0;
-  }
 
   /* Omit the redundant copy of the curve name. This contradicts RFC 5915 but
    * aligns with PKCS #11. SEC 1 only says they may be omitted if known by other
@@ -184,7 +175,7 @@
       !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
       !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
       !OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) ||
-      !OBJ_nid2cbb(&algorithm, curve_nid) ||
+      !EC_KEY_marshal_curve_name(&algorithm, EC_KEY_get0_group(ec_key)) ||
       !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
       !EC_KEY_marshal_private_key(&private_key, ec_key, enc_flags) ||
       !CBB_flush(out)) {
diff --git a/include/openssl/ec_key.h b/include/openssl/ec_key.h
index 2742355..b9b19bc 100644
--- a/include/openssl/ec_key.h
+++ b/include/openssl/ec_key.h
@@ -192,10 +192,21 @@
 OPENSSL_EXPORT int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key,
                                               unsigned enc_flags);
 
+/* EC_KEY_parse_parameters parses a DER-encoded OBJECT IDENTIFIER as a curve
+ * name from |cbs| and advances |cbs|. It returns a newly-allocated |EC_GROUP|
+ * or NULL on error. */
+OPENSSL_EXPORT EC_GROUP *EC_KEY_parse_curve_name(CBS *cbs);
+
+/* EC_KEY_marshal_curve_name marshals |group| as a DER-encoded OBJECT IDENTIFIER
+ * and appends the result to |cbb|. It returns one on success and zero on
+ * failure. */
+OPENSSL_EXPORT int EC_KEY_marshal_curve_name(CBB *cbb, const EC_GROUP *group);
+
 /* EC_KEY_parse_parameters parses a DER-encoded ECParameters structure (RFC
  * 5480) from |cbs| and advances |cbs|. It returns a newly-allocated |EC_GROUP|
  * or NULL on error. It supports the namedCurve and specifiedCurve options, but
- * use of specifiedCurve is deprecated. */
+ * use of specifiedCurve is deprecated. Use |EC_KEY_parse_curve_name|
+ * instead. */
 OPENSSL_EXPORT EC_GROUP *EC_KEY_parse_parameters(CBS *cbs);
 
 
@@ -279,7 +290,7 @@
  * allocated and the previous one is freed. On successful exit, |*inp| is
  * advanced past the DER structure. It returns the result or NULL on error.
  *
- * Use EC_KEY_parse_parameters instead. */
+ * Use |EC_KEY_parse_parameters| or |EC_KEY_parse_curve_name| instead. */
 OPENSSL_EXPORT EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp,
                                         long len);
 
@@ -288,7 +299,7 @@
  * |*outp| is advanced just past the output. It returns the number of bytes in
  * the result, whether written or not, or a negative value on error.
  *
- * Use |OBJ_nid2cbb| and |EC_GROUP_get_curve_name| instead. */
+ * Use |EC_KEY_marshal_curve_name| instead. */
 OPENSSL_EXPORT int i2d_ECParameters(const EC_KEY *key, uint8_t **outp);
 
 /* o2i_ECPublicKey parses an EC point from |len| bytes at |*inp| into