Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions crypto/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ add_library(
ecdh_extra/ecdh_extra.c
ecdsa_extra/ecdsa_asn1.c
ec_extra/ec_asn1.c
ec_extra/ec_brainpool.c
ec_extra/ec_derive.c
ec_extra/hash_to_curve.c
err/err.c
Expand Down
9 changes: 6 additions & 3 deletions crypto/ec_extra/ec_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,14 @@ static const CBS_ASN1_TAG kPublicKeyTag =
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;

// TODO(https://crbug.com/boringssl/497): Allow parsers to specify a list of
// acceptable groups, so parsers don't have to pull in all four.
// acceptable groups, so parsers don't have to pull in all ten.
typedef const EC_GROUP *(*ec_group_func)(void);
static const ec_group_func kAllGroups[] = {
&EC_group_p224, &EC_group_p256, &EC_group_p384,
&EC_group_p521, &EC_group_secp256k1,
&EC_group_p224, &EC_group_p256,
&EC_group_p384, &EC_group_p521,
&EC_group_secp256k1, &EC_group_brainpoolP224r1,
&EC_group_brainpoolP256r1, &EC_group_brainpoolP320r1,
&EC_group_brainpoolP384r1, &EC_group_brainpoolP512r1,
};

EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
Expand Down
254 changes: 254 additions & 0 deletions crypto/ec_extra/ec_brainpool.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC

// Brainpool elliptic curve groups from RFC 5639.
// These curves are not FIPS-approved and are therefore defined outside
// the FIPS module boundary (crypto/fipsmodule/).

#include <openssl/ec.h>

#include <string.h>

#include <openssl/mem.h>
#include <openssl/nid.h>

#include "../fipsmodule/bn/internal.h"
#include "../fipsmodule/ec/internal.h"
#include "../internal.h"
#include "internal.h"

#include "../fipsmodule/ec/builtin_curves.h"

// DEFINE_METHOD_FUNCTION (from delocate.h) cannot be used outside the FIPS
// module because it relies on delocated BSS storage within bcm.o. Since
// Brainpool curves are not FIPS-approved, we use an equivalent lazy-init
// pattern directly.
#define DEFINE_CURVE_DATA(type, name) \
Comment thread
manastasova marked this conversation as resolved.
static type name##_storage; \
static CRYPTO_once_t name##_once = CRYPTO_ONCE_INIT; \
static void name##_do_init(type *out); \
static void name##_init(void) { name##_do_init(&name##_storage); } \
const type *name(void) { \
CRYPTO_once(&name##_once, name##_init); \
return (const type *)&name##_storage; \
} \
static void name##_do_init(type *out)


// Duplicated from crypto/fipsmodule/ec/ec.c to avoid exposing
// FIPS-internal helpers across the module boundary.
static void ec_group_init_static_mont(BN_MONT_CTX *mont, size_t num_words,
const BN_ULONG *modulus,
const BN_ULONG *rr, uint64_t n0) {
bn_set_static_words(&mont->N, modulus, num_words);
bn_set_static_words(&mont->RR, rr, num_words);
#if defined(OPENSSL_64_BIT)
mont->n0[0] = n0;
#elif defined(OPENSSL_32_BIT)
mont->n0[0] = (uint32_t)n0;
mont->n0[1] = (uint32_t)(n0 >> 32);
#else
#error "unknown word length"
#endif
}

// Brainpool curves have arbitrary a coefficients (not -3 like NIST curves,
// not 0 like secp256k1), so a is provided in precomputed Montgomery form.
static void ec_group_set_a_mont(EC_GROUP *group, const BN_ULONG *mont_a,
size_t num_bytes) {
group->a_is_minus3 = 0;
OPENSSL_memset(group->a.words, 0, sizeof(EC_FELEM));
OPENSSL_memcpy(group->a.words, mont_a, num_bytes);
}

DEFINE_CURVE_DATA(EC_GROUP, EC_group_brainpoolP224r1) {
out->curve_name = NID_brainpoolP224r1;
out->comment = "brainpoolP224r1";
// OID 1.3.36.3.3.2.8.1.1.5 — RFC 5639, Section 4.1
static const uint8_t kOID[] = {0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01,
0x01, 0x05};
OPENSSL_memcpy(out->oid, kOID, sizeof(kOID));
out->oid_len = sizeof(kOID);

ec_group_init_static_mont(
&out->field, OPENSSL_ARRAY_SIZE(kbrainpoolP224r1Field),
kbrainpoolP224r1Field, kbrainpoolP224r1FieldRR, kbrainpoolP224r1FieldN0);
ec_group_init_static_mont(
&out->order, OPENSSL_ARRAY_SIZE(kbrainpoolP224r1Order),
kbrainpoolP224r1Order, kbrainpoolP224r1OrderRR, kbrainpoolP224r1OrderN0);

out->meth = EC_GFp_mont_method();
out->generator.group = out;
OPENSSL_memcpy(out->generator.raw.X.words, kbrainpoolP224r1MontGX,
sizeof(kbrainpoolP224r1MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kbrainpoolP224r1MontGY,
sizeof(kbrainpoolP224r1MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kbrainpoolP224r1FieldR,
sizeof(kbrainpoolP224r1FieldR));
OPENSSL_memcpy(out->b.words, kbrainpoolP224r1MontB,
sizeof(kbrainpoolP224r1MontB));

ec_group_set_a_mont(out, kbrainpoolP224r1MontA,
sizeof(kbrainpoolP224r1MontA));
out->has_order = 1;
out->field_greater_than_order = 1;
out->conv_form = POINT_CONVERSION_UNCOMPRESSED;
out->mutable_ec_group = 0;
}

DEFINE_CURVE_DATA(EC_GROUP, EC_group_brainpoolP256r1) {
out->curve_name = NID_brainpoolP256r1;
out->comment = "brainpoolP256r1";
// OID 1.3.36.3.3.2.8.1.1.7 — RFC 5639, Section 4.1
static const uint8_t kOID[] = {0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01,
0x01, 0x07};
OPENSSL_memcpy(out->oid, kOID, sizeof(kOID));
out->oid_len = sizeof(kOID);

ec_group_init_static_mont(
&out->field, OPENSSL_ARRAY_SIZE(kbrainpoolP256r1Field),
kbrainpoolP256r1Field, kbrainpoolP256r1FieldRR, kbrainpoolP256r1FieldN0);
ec_group_init_static_mont(
&out->order, OPENSSL_ARRAY_SIZE(kbrainpoolP256r1Order),
kbrainpoolP256r1Order, kbrainpoolP256r1OrderRR, kbrainpoolP256r1OrderN0);

out->meth = EC_GFp_mont_method();
out->generator.group = out;
OPENSSL_memcpy(out->generator.raw.X.words, kbrainpoolP256r1MontGX,
sizeof(kbrainpoolP256r1MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kbrainpoolP256r1MontGY,
sizeof(kbrainpoolP256r1MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kbrainpoolP256r1FieldR,
sizeof(kbrainpoolP256r1FieldR));
OPENSSL_memcpy(out->b.words, kbrainpoolP256r1MontB,
sizeof(kbrainpoolP256r1MontB));

ec_group_set_a_mont(out, kbrainpoolP256r1MontA,
sizeof(kbrainpoolP256r1MontA));
out->has_order = 1;
out->field_greater_than_order = 1;
out->conv_form = POINT_CONVERSION_UNCOMPRESSED;
out->mutable_ec_group = 0;
}

DEFINE_CURVE_DATA(EC_GROUP, EC_group_brainpoolP320r1) {
out->curve_name = NID_brainpoolP320r1;
out->comment = "brainpoolP320r1";
// OID 1.3.36.3.3.2.8.1.1.9 — RFC 5639, Section 4.1
static const uint8_t kOID[] = {0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01,
0x01, 0x09};
OPENSSL_memcpy(out->oid, kOID, sizeof(kOID));
out->oid_len = sizeof(kOID);

ec_group_init_static_mont(
&out->field, OPENSSL_ARRAY_SIZE(kbrainpoolP320r1Field),
kbrainpoolP320r1Field, kbrainpoolP320r1FieldRR, kbrainpoolP320r1FieldN0);
ec_group_init_static_mont(
&out->order, OPENSSL_ARRAY_SIZE(kbrainpoolP320r1Order),
kbrainpoolP320r1Order, kbrainpoolP320r1OrderRR, kbrainpoolP320r1OrderN0);

out->meth = EC_GFp_mont_method();
out->generator.group = out;
OPENSSL_memcpy(out->generator.raw.X.words, kbrainpoolP320r1MontGX,
sizeof(kbrainpoolP320r1MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kbrainpoolP320r1MontGY,
sizeof(kbrainpoolP320r1MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kbrainpoolP320r1FieldR,
sizeof(kbrainpoolP320r1FieldR));
OPENSSL_memcpy(out->b.words, kbrainpoolP320r1MontB,
sizeof(kbrainpoolP320r1MontB));

ec_group_set_a_mont(out, kbrainpoolP320r1MontA,
sizeof(kbrainpoolP320r1MontA));
out->has_order = 1;
out->field_greater_than_order = 1;
out->conv_form = POINT_CONVERSION_UNCOMPRESSED;
out->mutable_ec_group = 0;
}

DEFINE_CURVE_DATA(EC_GROUP, EC_group_brainpoolP384r1) {
out->curve_name = NID_brainpoolP384r1;
out->comment = "brainpoolP384r1";
// OID 1.3.36.3.3.2.8.1.1.11 — RFC 5639, Section 4.1
static const uint8_t kOID[] = {0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01,
0x01, 0x0b};
OPENSSL_memcpy(out->oid, kOID, sizeof(kOID));
out->oid_len = sizeof(kOID);

ec_group_init_static_mont(
&out->field, OPENSSL_ARRAY_SIZE(kbrainpoolP384r1Field),
kbrainpoolP384r1Field, kbrainpoolP384r1FieldRR, kbrainpoolP384r1FieldN0);
ec_group_init_static_mont(
&out->order, OPENSSL_ARRAY_SIZE(kbrainpoolP384r1Order),
kbrainpoolP384r1Order, kbrainpoolP384r1OrderRR, kbrainpoolP384r1OrderN0);

out->meth = EC_GFp_mont_method();
out->generator.group = out;
OPENSSL_memcpy(out->generator.raw.X.words, kbrainpoolP384r1MontGX,
sizeof(kbrainpoolP384r1MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kbrainpoolP384r1MontGY,
sizeof(kbrainpoolP384r1MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kbrainpoolP384r1FieldR,
sizeof(kbrainpoolP384r1FieldR));
OPENSSL_memcpy(out->b.words, kbrainpoolP384r1MontB,
sizeof(kbrainpoolP384r1MontB));

ec_group_set_a_mont(out, kbrainpoolP384r1MontA,
sizeof(kbrainpoolP384r1MontA));
out->has_order = 1;
out->field_greater_than_order = 1;
out->conv_form = POINT_CONVERSION_UNCOMPRESSED;
out->mutable_ec_group = 0;
}

DEFINE_CURVE_DATA(EC_GROUP, EC_group_brainpoolP512r1) {
out->curve_name = NID_brainpoolP512r1;
out->comment = "brainpoolP512r1";
// OID 1.3.36.3.3.2.8.1.1.13 — RFC 5639, Section 4.1
static const uint8_t kOID[] = {0x2b, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01,
0x01, 0x0d};
OPENSSL_memcpy(out->oid, kOID, sizeof(kOID));
out->oid_len = sizeof(kOID);

ec_group_init_static_mont(
&out->field, OPENSSL_ARRAY_SIZE(kbrainpoolP512r1Field),
kbrainpoolP512r1Field, kbrainpoolP512r1FieldRR, kbrainpoolP512r1FieldN0);
ec_group_init_static_mont(
&out->order, OPENSSL_ARRAY_SIZE(kbrainpoolP512r1Order),
kbrainpoolP512r1Order, kbrainpoolP512r1OrderRR, kbrainpoolP512r1OrderN0);

out->meth = EC_GFp_mont_method();
out->generator.group = out;
OPENSSL_memcpy(out->generator.raw.X.words, kbrainpoolP512r1MontGX,
sizeof(kbrainpoolP512r1MontGX));
OPENSSL_memcpy(out->generator.raw.Y.words, kbrainpoolP512r1MontGY,
sizeof(kbrainpoolP512r1MontGY));
OPENSSL_memcpy(out->generator.raw.Z.words, kbrainpoolP512r1FieldR,
sizeof(kbrainpoolP512r1FieldR));
OPENSSL_memcpy(out->b.words, kbrainpoolP512r1MontB,
sizeof(kbrainpoolP512r1MontB));

ec_group_set_a_mont(out, kbrainpoolP512r1MontA,
sizeof(kbrainpoolP512r1MontA));
out->has_order = 1;
out->field_greater_than_order = 1;
out->conv_form = POINT_CONVERSION_UNCOMPRESSED;
out->mutable_ec_group = 0;
}

const EC_GROUP *ec_group_new_by_curve_name_nonfips(int nid) {
switch (nid) {
case NID_brainpoolP224r1:
return EC_group_brainpoolP224r1();
case NID_brainpoolP256r1:
return EC_group_brainpoolP256r1();
case NID_brainpoolP320r1:
return EC_group_brainpoolP320r1();
case NID_brainpoolP384r1:
return EC_group_brainpoolP384r1();
case NID_brainpoolP512r1:
return EC_group_brainpoolP512r1();
default:
return NULL;
}
}
6 changes: 6 additions & 0 deletions crypto/ec_extra/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ OPENSSL_EXPORT int ec_hash_to_scalar_p384_xmd_sha512_draft07(
const EC_GROUP *group, EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
const uint8_t *msg, size_t msg_len);

// ec_group_new_by_curve_name_nonfips returns the EC_GROUP for non-FIPS curves,
// or NULL if |nid| is not a supported non-FIPS curve. Called from the default
// fallthrough in EC_GROUP_new_by_curve_name to keep per-curve dispatch logic
// outside the FIPS module boundary (bcm.o).
const EC_GROUP *ec_group_new_by_curve_name_nonfips(int nid);

enum ECParametersType {
UNKNOWN_EC_PARAMETERS = 0,
NAMED_CURVE_EC_PARAMETERS = 1,
Expand Down
Loading
Loading