Tighten EC_KEY's association with its group.
This is to simplify https://boringssl-review.googlesource.com/c/boringssl/+/24445/. Setting or changing an EC_KEY's group after the public or private keys have been configured is quite awkward w.r.t. consistency checks. It becomes additionally messy if we mean to store private keys as EC_SCALARs (and avoid the BIGNUM timing leak), whose size is curve-dependent. Instead, require that callers configure the group before setting either half of the keypair. Additionally, reject EC_KEY_set_group calls that change the group. This will simplify clearing one more BIGNUM timing leak. Update-Note: This will break code which sets the group and key in a weird order. I checked calls of EC_KEY_new and confirmed they all set the group first. If I missed any, let me know. Change-Id: Ie89f90a318b31b6b98f71138e5ff3de5323bc9a6 Reviewed-on: https://boringssl-review.googlesource.com/24425 Commit-Queue: Adam Langley <agl@google.com> Reviewed-by: Adam Langley <agl@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
This commit is contained in:
parent
e15019572b
commit
5bcaa113e2
@ -233,20 +233,21 @@ int EC_KEY_is_opaque(const EC_KEY *key) {
|
||||
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; }
|
||||
|
||||
int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) {
|
||||
// If |key| already has a group, it is an error to switch to another one.
|
||||
if (key->group != NULL) {
|
||||
if (EC_GROUP_cmp(key->group, group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
assert(key->priv_key == NULL);
|
||||
assert(key->pub_key == NULL);
|
||||
|
||||
EC_GROUP_free(key->group);
|
||||
// TODO(fork): duplicating the group seems wasteful but see
|
||||
// |EC_KEY_set_conv_form|.
|
||||
key->group = EC_GROUP_dup(group);
|
||||
if (key->group == NULL) {
|
||||
return 0;
|
||||
}
|
||||
// XXX: |BN_cmp| is not constant time.
|
||||
if (key->priv_key != NULL &&
|
||||
(BN_is_negative(key->priv_key) ||
|
||||
BN_cmp(key->priv_key, EC_GROUP_get0_order(group)) >= 0)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
return key->group != NULL;
|
||||
}
|
||||
|
||||
const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
|
||||
@ -254,10 +255,14 @@ const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
|
||||
}
|
||||
|
||||
int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) {
|
||||
if (key->group == NULL) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// XXX: |BN_cmp| is not constant time.
|
||||
if (key->group != NULL &&
|
||||
(BN_is_negative(priv_key) ||
|
||||
BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0)) {
|
||||
if (BN_is_negative(priv_key) ||
|
||||
BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
|
||||
return 0;
|
||||
}
|
||||
@ -271,6 +276,16 @@ const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key) {
|
||||
}
|
||||
|
||||
int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) {
|
||||
if (key->group == NULL) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (EC_GROUP_cmp(key->group, pub_key->group, NULL) != 0) {
|
||||
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EC_POINT_free(key->pub_key);
|
||||
key->pub_key = EC_POINT_dup(pub_key, key->group);
|
||||
return (key->pub_key == NULL) ? 0 : 1;
|
||||
|
@ -305,6 +305,36 @@ TEST(ECTest, ArbitraryCurve) {
|
||||
EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
|
||||
}
|
||||
|
||||
TEST(ECTest, SetKeyWithoutGroup) {
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
|
||||
ASSERT_TRUE(key);
|
||||
|
||||
// Private keys may not be configured without a group.
|
||||
EXPECT_FALSE(EC_KEY_set_private_key(key.get(), BN_value_one()));
|
||||
|
||||
// Public keys may not be configured without a group.
|
||||
bssl::UniquePtr<EC_GROUP> group(
|
||||
EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
ASSERT_TRUE(group);
|
||||
EXPECT_FALSE(
|
||||
EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(group.get())));
|
||||
}
|
||||
|
||||
TEST(ECTest, GroupMismatch) {
|
||||
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_secp384r1));
|
||||
ASSERT_TRUE(key);
|
||||
bssl::UniquePtr<EC_GROUP> p256(
|
||||
EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
|
||||
ASSERT_TRUE(p256);
|
||||
|
||||
// Changing a key's group is invalid.
|
||||
EXPECT_FALSE(EC_KEY_set_group(key.get(), p256.get()));
|
||||
|
||||
// Configuring a public key with the wrong group is invalid.
|
||||
EXPECT_FALSE(
|
||||
EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
|
||||
}
|
||||
|
||||
class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
|
||||
|
||||
TEST_P(ECCurveTest, SetAffine) {
|
||||
|
@ -116,14 +116,16 @@ OPENSSL_EXPORT int EC_KEY_is_opaque(const EC_KEY *key);
|
||||
OPENSSL_EXPORT const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
|
||||
|
||||
// EC_KEY_set_group sets the |EC_GROUP| object that |key| will use to |group|.
|
||||
// It returns one on success and zero otherwise.
|
||||
// It returns one on success and zero otherwise. If |key| already has a group,
|
||||
// it is an error to change to a different one.
|
||||
OPENSSL_EXPORT int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group);
|
||||
|
||||
// EC_KEY_get0_private_key returns a pointer to the private key inside |key|.
|
||||
OPENSSL_EXPORT const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key);
|
||||
|
||||
// EC_KEY_set_private_key sets the private key of |key| to |priv|. It returns
|
||||
// one on success and zero otherwise.
|
||||
// one on success and zero otherwise. |key| must already have had a group
|
||||
// configured (see |EC_KEY_set_group| and |EC_KEY_new_by_curve_name|).
|
||||
OPENSSL_EXPORT int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv);
|
||||
|
||||
// EC_KEY_get0_public_key returns a pointer to the public key point inside
|
||||
@ -131,7 +133,9 @@ OPENSSL_EXPORT int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv);
|
||||
OPENSSL_EXPORT const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key);
|
||||
|
||||
// EC_KEY_set_public_key sets the public key of |key| to |pub|, by copying it.
|
||||
// It returns one on success and zero otherwise.
|
||||
// It returns one on success and zero otherwise. |key| must already have had a
|
||||
// group configured (see |EC_KEY_set_group| and |EC_KEY_new_by_curve_name|), and
|
||||
// |pub| must also belong to that group.
|
||||
OPENSSL_EXPORT int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);
|
||||
|
||||
#define EC_PKEY_NO_PARAMETERS 0x001
|
||||
|
Loading…
Reference in New Issue
Block a user