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(¶ms, &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