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>
This commit is contained in:
David Benjamin 2016-03-25 18:07:15 -04:00
parent 981936791e
commit 0d76c402b8
5 changed files with 136 additions and 86 deletions

View File

@ -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

View File

@ -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 @@ 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(&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 @@ 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;
}

View File

@ -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);
};

View File

@ -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)) {

View File

@ -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