ec: recognise known parameters when written in full.

Some EC ASN.1 structures are using a named curve, but include the full
parameters anyway. With this change, BoringSSL will recognise the order
of the curve.

Change-Id: Iff057178453f9fdc98c8c03bcabbccef89709887
Reviewed-on: https://boringssl-review.googlesource.com/1270
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c
index ef022bc..5e3325d 100644
--- a/crypto/ec/ec.c
+++ b/crypto/ec/ec.c
@@ -75,21 +75,6 @@
 #include "internal.h"
 
 
-/* curve_data contains data about a built-in elliptic curve. */
-struct curve_data {
-  /* comment is a human-readable string describing the curve. */
-  const char *comment;
-  /* param_len is the number of bytes needed to store a field element. */
-  uint8_t param_len;
-  /* cofactor is the cofactor of the group (i.e. the number of elements in the
-   * group divided by the size of the main subgroup. */
-  uint8_t cofactor; /* promoted to BN_ULONG */
-  /* data points to an array of 6*|param_len| bytes which hold the field
-   * elements of the following (in big-endian order): prime, a, b, generator x,
-   * generator y, order. */
-  const uint8_t data[];
-};
-
 static const struct curve_data P224 = {
     "NIST P-224",
     28,
@@ -231,13 +216,7 @@
      0xA5, 0xD0, 0x3B, 0xB5, 0xC9, 0xB8, 0x89, 0x9C, 0x47, 0xAE, 0xBB, 0x6F,
      0xB7, 0x1E, 0x91, 0x38, 0x64, 0x09}};
 
-struct built_in_curve {
-  int nid;
-  const struct curve_data *data;
-  const EC_METHOD *(*method)(void);
-};
-
-static const struct built_in_curve built_in_curves[] = {
+const struct built_in_curve OPENSSL_built_in_curves[] = {
   {NID_secp224r1, &P224, 0},
   {NID_X9_62_prime256v1, &P256, 0},
   {NID_secp384r1, &P384, 0},
@@ -401,8 +380,8 @@
   const struct built_in_curve *curve;
   EC_GROUP *ret = NULL;
 
-  for (i = 0; built_in_curves[i].nid != NID_undef; i++) {
-    curve = &built_in_curves[i];
+  for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
+    curve = &OPENSSL_built_in_curves[i];
     if (curve->nid == nid) {
       ret = ec_group_new_from_data(curve);
       break;
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index 35fff74..7920ae8 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -190,19 +190,39 @@
 
 EC_GROUP *ec_asn1_pkparameters2group(const ECPKPARAMETERS *params) {
   EC_GROUP *ret = NULL;
-  int nid = 0;
+  int nid = NID_undef;
 
   if (params == NULL) {
     OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_MISSING_PARAMETERS);
     return NULL;
   }
 
-  if (params->type != 0) {
+  if (params->type == 0) {
+    nid = OBJ_obj2nid(params->value.named_curve);
+  } else if (params->type == 1) {
+    /* We don't support arbitary curves so we attempt to recognise it from the
+     * group order. */
+    const ECPARAMETERS *ecparams = params->value.parameters;
+    unsigned i;
+    const struct built_in_curve *curve;
+
+    for (i = 0; OPENSSL_built_in_curves[i].nid != NID_undef; i++) {
+      curve = &OPENSSL_built_in_curves[i];
+      const unsigned param_len = curve->data->param_len;
+      if (ecparams->order->length == param_len &&
+          memcmp(ecparams->order->data, &curve->data->data[param_len * 5],
+                 param_len) == 0) {
+        nid = curve->nid;
+        break;
+      }
+    }
+  }
+
+  if (nid == NID_undef) {
     OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group, EC_R_NON_NAMED_CURVE);
     return NULL;
   }
 
-  nid = OBJ_obj2nid(params->value.named_curve);
   ret = EC_GROUP_new_by_curve_name(nid);
   if (ret == NULL) {
     OPENSSL_PUT_ERROR(EC, ec_asn1_pkparameters2group,
diff --git a/crypto/ec/internal.h b/crypto/ec/internal.h
index dc79186..76c3a80 100644
--- a/crypto/ec/internal.h
+++ b/crypto/ec/internal.h
@@ -349,6 +349,30 @@
   CRYPTO_EX_DATA ex_data;
 } /* EC_KEY */;
 
+/* curve_data contains data about a built-in elliptic curve. */
+struct curve_data {
+  /* comment is a human-readable string describing the curve. */
+  const char *comment;
+  /* param_len is the number of bytes needed to store a field element. */
+  uint8_t param_len;
+  /* cofactor is the cofactor of the group (i.e. the number of elements in the
+   * group divided by the size of the main subgroup. */
+  uint8_t cofactor; /* promoted to BN_ULONG */
+  /* data points to an array of 6*|param_len| bytes which hold the field
+   * elements of the following (in big-endian order): prime, a, b, generator x,
+   * generator y, order. */
+  const uint8_t data[];
+};
+
+struct built_in_curve {
+  int nid;
+  const struct curve_data *data;
+  const EC_METHOD *(*method)(void);
+};
+
+/* OPENSSL_built_in_curves is terminated with an entry where |nid| is
+ * |NID_undef|. */
+extern const struct built_in_curve OPENSSL_built_in_curves[];
 
 #if defined(__cplusplus)
 }  /* extern C */