diff --git a/crypto/ec/ec.c b/crypto/ec/ec.c index 478e80ed..8f3fa6e1 100644 --- a/crypto/ec/ec.c +++ b/crypto/ec/ec.c @@ -228,10 +228,25 @@ static const struct curve_data P521 = { #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 @@ const struct built_in_curve OPENSSL_built_in_curves[] = { 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 0535a79f..f31e1587 100644 --- a/crypto/ec/ec_asn1.c +++ b/crypto/ec/ec_asn1.c @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include "internal.h" #include "../bytestring/internal.h" @@ -207,14 +207,9 @@ int EC_KEY_marshal_private_key(CBB *cbb, const EC_KEY *key, } 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 @@ static int is_unsigned_integer(const CBS *cbs) { 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 @@ static int parse_explicit_prime_curve(CBS *in, CBS *out_prime, CBS *out_a, 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 @@ static int integers_equal(const CBS *a, const uint8_t *b, size_t b_len) { 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 @@ int i2d_ECParameters(const EC_KEY *key, uint8_t **outp) { 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 bb9fc9ee..f2cbb961 100644 --- a/crypto/ec/internal.h +++ b/crypto/ec/internal.h @@ -271,6 +271,8 @@ struct curve_data { 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 4e51440a..d81e54d8 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 @@ static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) { 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 @@ static int eckey_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { /* 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_decode(EVP_PKEY *out, CBS *params, CBS *key) { 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 @@ static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) { !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 27423558..b9b19bc6 100644 --- a/include/openssl/ec_key.h +++ b/include/openssl/ec_key.h @@ -192,10 +192,21 @@ OPENSSL_EXPORT EC_KEY *EC_KEY_parse_private_key(CBS *cbs, 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 @@ OPENSSL_EXPORT int i2d_ECPrivateKey(const EC_KEY *key, uint8_t **outp); * 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 @@ OPENSSL_EXPORT EC_KEY *d2i_ECParameters(EC_KEY **out_key, const uint8_t **inp, * |*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