Skip to content

Commit

Permalink
Expose EcKeyFromSslEcKey in ec_util.h
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 567719742
Change-Id: I9115ce38922760eb518c41221e2dc41b70ab5826
  • Loading branch information
ise-crypto authored and copybara-github committed Sep 22, 2023
1 parent 35f1b6b commit f5a4938
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 45 deletions.
91 changes: 47 additions & 44 deletions tink/internal/ec_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "openssl/bn.h"
#ifdef OPENSSL_IS_BORINGSSL
#include "openssl/base.h"
#include "openssl/ec_key.h"
#else
#include "openssl/ec.h"
#endif
#include "openssl/crypto.h"
#include "openssl/ecdsa.h"
#include "openssl/evp.h"
Expand Down Expand Up @@ -92,7 +97,7 @@ util::StatusOr<SslUniquePtr<EC_POINT>> SslGetEcPointFromCoordinates(
}
SslUniquePtr<EC_POINT> pub_key(EC_POINT_new(group));
// In BoringSSL and OpenSSL > 1.1.0 EC_POINT_set_affine_coordinates_GFp
// already checkes if the point is on the curve.
// already checks if the point is on the curve.
if (EC_POINT_set_affine_coordinates_GFp(group, pub_key.get(), bn_x->get(),
bn_y->get(), nullptr) != 1) {
return util::Status(absl::StatusCode::kInternal,
Expand Down Expand Up @@ -191,49 +196,6 @@ size_t SslEcFieldSizeInBytes(const EC_GROUP *group) {
return (degree_bits + 7) / 8;
}

// Given an OpenSSL/BoringSSL key EC_KEY `key` and curve type `curve` return an
// EcKey.
util::StatusOr<EcKey> EcKeyFromSslEcKey(EllipticCurveType curve,
const EC_KEY &key) {
util::StatusOr<SslUniquePtr<EC_GROUP>> group = EcGroupFromCurveType(curve);
if (!group.ok()) {
return group.status();
}
const BIGNUM *priv_key = EC_KEY_get0_private_key(&key);
const EC_POINT *pub_key = EC_KEY_get0_public_key(&key);

util::StatusOr<EcPointCoordinates> pub_key_bns =
SslGetEcPointCoordinates(group->get(), pub_key);
if (!pub_key_bns.ok()) {
return pub_key_bns.status();
}

const int kFieldElementSizeInBytes = SslEcFieldSizeInBytes(group->get());

util::StatusOr<std::string> pub_x_str =
BignumToString(pub_key_bns->x.get(), kFieldElementSizeInBytes);
if (!pub_x_str.ok()) {
return pub_x_str.status();
}
util::StatusOr<std::string> pub_y_str =
BignumToString(pub_key_bns->y.get(), kFieldElementSizeInBytes);
if (!pub_y_str.ok()) {
return pub_y_str.status();
}
util::StatusOr<util::SecretData> priv_key_data =
BignumToSecretData(priv_key, ScalarSizeInBytes(group->get()));
if (!priv_key_data.ok()) {
return priv_key_data.status();
}
EcKey ec_key = {
/*curve=*/curve,
/*pub_x=*/*std::move(pub_x_str),
/*pub_y=*/*std::move(pub_y_str),
/*priv=*/*std::move(priv_key_data),
};
return ec_key;
}

enum SslEvpPkeyType {
kX25519Key = EVP_PKEY_X25519,
kEd25519Key = EVP_PKEY_ED25519
Expand Down Expand Up @@ -308,6 +270,47 @@ util::StatusOr<std::string> SslEcdsaSignatureToBytes(

} // namespace

util::StatusOr<EcKey> EcKeyFromSslEcKey(EllipticCurveType curve,
const EC_KEY &key) {
util::StatusOr<SslUniquePtr<EC_GROUP>> group = EcGroupFromCurveType(curve);
if (!group.ok()) {
return group.status();
}
const BIGNUM *priv_key = EC_KEY_get0_private_key(&key);
const EC_POINT *pub_key = EC_KEY_get0_public_key(&key);

util::StatusOr<EcPointCoordinates> pub_key_bns =
SslGetEcPointCoordinates(group->get(), pub_key);
if (!pub_key_bns.ok()) {
return pub_key_bns.status();
}

const int kFieldElementSizeInBytes = SslEcFieldSizeInBytes(group->get());

util::StatusOr<std::string> pub_x_str =
BignumToString(pub_key_bns->x.get(), kFieldElementSizeInBytes);
if (!pub_x_str.ok()) {
return pub_x_str.status();
}
util::StatusOr<std::string> pub_y_str =
BignumToString(pub_key_bns->y.get(), kFieldElementSizeInBytes);
if (!pub_y_str.ok()) {
return pub_y_str.status();
}
util::StatusOr<util::SecretData> priv_key_data =
BignumToSecretData(priv_key, ScalarSizeInBytes(group->get()));
if (!priv_key_data.ok()) {
return priv_key_data.status();
}
EcKey ec_key = {
/*curve=*/curve,
/*pub_x=*/*std::move(pub_x_str),
/*pub_y=*/*std::move(pub_y_str),
/*priv=*/*std::move(priv_key_data),
};
return ec_key;
}

util::StatusOr<int32_t> EcFieldSizeInBytes(EllipticCurveType curve_type) {
if (curve_type == EllipticCurveType::CURVE25519) {
return 32;
Expand Down
5 changes: 5 additions & 0 deletions tink/internal/ec_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ crypto::tink::util::StatusOr<std::unique_ptr<X25519Key>> X25519KeyFromEcKey(
// Returns an EcKey matching the specified X25519Key.
EcKey EcKeyFromX25519Key(const X25519Key *x25519_key);

// Given an OpenSSL/BoringSSL key EC_KEY `key` and curve type `curve` return an
// EcKey.
util::StatusOr<EcKey> EcKeyFromSslEcKey(
crypto::tink::subtle::EllipticCurveType curve, const EC_KEY &key);

// Generates a shared secret using `private_key` and `peer_public_key`; keys
// must be X25519 keys otherwise an error is returned.
crypto::tink::util::StatusOr<util::SecretData> ComputeX25519SharedSecret(
Expand Down
44 changes: 43 additions & 1 deletion tink/internal/ec_util_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
#include "absl/strings/str_split.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#ifdef OPENSSL_IS_BORINGSSL
#include "openssl/base.h"
#include "openssl/ec_key.h"
#endif
#include "openssl/bn.h"
#include "openssl/ec.h"
#include "openssl/ecdsa.h"
Expand All @@ -42,7 +46,6 @@
#include "tink/subtle/subtle_util.h"
#include "tink/subtle/wycheproof_util.h"
#include "tink/util/secret_data.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "tink/util/test_matchers.h"

Expand Down Expand Up @@ -707,6 +710,45 @@ TEST(EcUtilTest, EcSignatureIeeeToDer) {
}
}

using EcKeyFromSslEcKeyTestWithParam =
testing::TestWithParam<EllipticCurveType>;

TEST_P(EcKeyFromSslEcKeyTestWithParam, EcKeyFromSslEcKeySucceeds) {
EllipticCurveType curve_type = GetParam();
util::StatusOr<SslUniquePtr<EC_GROUP>> group =
EcGroupFromCurveType(curve_type);
SslUniquePtr<EC_KEY> key(EC_KEY_new());
EC_KEY_set_group(key.get(), group->get());
EC_KEY_generate_key(key.get());

util::StatusOr<EcKey> ec_key = EcKeyFromSslEcKey(curve_type, *key);

EXPECT_THAT(ec_key, IsOk());
EXPECT_THAT(ec_key->curve, Eq(curve_type));
EXPECT_THAT(ec_key->priv, Not(IsEmpty()));
EXPECT_THAT(ec_key->pub_x, Not(IsEmpty()));
EXPECT_THAT(ec_key->pub_y, Not(IsEmpty()));
}

TEST(EcKeyFromSSLEcKeyTest, EcKeyFromSslKeyFailsWrongCurveType) {
util::StatusOr<SslUniquePtr<EC_GROUP>> group =
EcGroupFromCurveType(EllipticCurveType::NIST_P256);
SslUniquePtr<EC_KEY> key(EC_KEY_new());
EC_KEY_set_group(key.get(), group->get());
EC_KEY_generate_key(key.get());

util::StatusOr<EcKey> ec_key =
EcKeyFromSslEcKey(EllipticCurveType::NIST_P384, *key);

EXPECT_THAT(ec_key.status(), StatusIs(absl::StatusCode::kInternal));
}

INSTANTIATE_TEST_SUITE_P(EcKeyFromSslEcKeyTestWithParams,
EcKeyFromSslEcKeyTestWithParam,
testing::ValuesIn({EllipticCurveType::NIST_P256,
EllipticCurveType::NIST_P384,
EllipticCurveType::NIST_P521}));

// ECDH test vector.
struct EcdhWycheproofTestVector {
std::string testcase_name;
Expand Down

0 comments on commit f5a4938

Please sign in to comment.