summaryrefslogtreecommitdiff
path: root/src/crypto/ec/ec_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/ec/ec_test.cc')
-rw-r--r--src/crypto/ec/ec_test.cc450
1 files changed, 152 insertions, 298 deletions
diff --git a/src/crypto/ec/ec_test.cc b/src/crypto/ec/ec_test.cc
index 31619b1e..02b9ef20 100644
--- a/src/crypto/ec/ec_test.cc
+++ b/src/crypto/ec/ec_test.cc
@@ -17,6 +17,8 @@
#include <vector>
+#include <gtest/gtest.h>
+
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
@@ -24,6 +26,9 @@
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/nid.h>
+#include <openssl/obj.h>
+
+#include "../test/test_util.h"
// kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
@@ -123,201 +128,75 @@ static bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
return true;
}
-static bool Testd2i_ECPrivateKey() {
- bssl::UniquePtr<EC_KEY> key = DecodeECPrivateKey(kECKeyWithoutPublic,
- sizeof(kECKeyWithoutPublic));
- if (!key) {
- fprintf(stderr, "Failed to parse private key.\n");
- ERR_print_errors_fp(stderr);
- return false;
- }
+TEST(ECTest, Encoding) {
+ bssl::UniquePtr<EC_KEY> key =
+ DecodeECPrivateKey(kECKeyWithoutPublic, sizeof(kECKeyWithoutPublic));
+ ASSERT_TRUE(key);
+ // Test that the encoding round-trips.
std::vector<uint8_t> out;
- if (!EncodeECPrivateKey(&out, key.get())) {
- fprintf(stderr, "Failed to serialize private key.\n");
- ERR_print_errors_fp(stderr);
- return false;
- }
-
- if (std::vector<uint8_t>(kECKeyWithoutPublic,
- kECKeyWithoutPublic + sizeof(kECKeyWithoutPublic)) !=
- out) {
- fprintf(stderr, "Serialisation of key doesn't match original.\n");
- return false;
- }
+ ASSERT_TRUE(EncodeECPrivateKey(&out, key.get()));
+ EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
const EC_POINT *pub_key = EC_KEY_get0_public_key(key.get());
- if (pub_key == NULL) {
- fprintf(stderr, "Public key missing.\n");
- return false;
- }
+ ASSERT_TRUE(pub_key) << "Public key missing";
bssl::UniquePtr<BIGNUM> x(BN_new());
bssl::UniquePtr<BIGNUM> y(BN_new());
- if (!x || !y) {
- return false;
- }
- if (!EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
- pub_key, x.get(), y.get(), NULL)) {
- fprintf(stderr, "Failed to get public key in affine coordinates.\n");
- return false;
- }
+ ASSERT_TRUE(x);
+ ASSERT_TRUE(y);
+ ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
+ EC_KEY_get0_group(key.get()), pub_key, x.get(), y.get(), NULL));
bssl::UniquePtr<char> x_hex(BN_bn2hex(x.get()));
bssl::UniquePtr<char> y_hex(BN_bn2hex(y.get()));
- if (!x_hex || !y_hex) {
- return false;
- }
- if (0 != strcmp(
- x_hex.get(),
- "c81561ecf2e54edefe6617db1c7a34a70744ddb261f269b83dacfcd2ade5a681") ||
- 0 != strcmp(
- y_hex.get(),
- "e0e2afa3f9b6abe4c698ef6495f1be49a3196c5056acb3763fe4507eec596e88")) {
- fprintf(stderr, "Incorrect public key: %s %s\n", x_hex.get(), y_hex.get());
- return false;
- }
-
- return true;
+ ASSERT_TRUE(x_hex);
+ ASSERT_TRUE(y_hex);
+
+ EXPECT_STREQ(
+ "c81561ecf2e54edefe6617db1c7a34a70744ddb261f269b83dacfcd2ade5a681",
+ x_hex.get());
+ EXPECT_STREQ(
+ "e0e2afa3f9b6abe4c698ef6495f1be49a3196c5056acb3763fe4507eec596e88",
+ y_hex.get());
}
-static bool TestZeroPadding() {
+TEST(ECTest, ZeroPadding) {
// Check that the correct encoding round-trips.
- bssl::UniquePtr<EC_KEY> key = DecodeECPrivateKey(kECKeyWithZeros,
- sizeof(kECKeyWithZeros));
+ bssl::UniquePtr<EC_KEY> key =
+ DecodeECPrivateKey(kECKeyWithZeros, sizeof(kECKeyWithZeros));
+ ASSERT_TRUE(key);
std::vector<uint8_t> out;
- if (!key || !EncodeECPrivateKey(&out, key.get())) {
- ERR_print_errors_fp(stderr);
- return false;
- }
-
- if (std::vector<uint8_t>(kECKeyWithZeros,
- kECKeyWithZeros + sizeof(kECKeyWithZeros)) != out) {
- fprintf(stderr, "Serialisation of key was incorrect.\n");
- return false;
- }
+ EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
+ EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
// Keys without leading zeros also parse, but they encode correctly.
key = DecodeECPrivateKey(kECKeyMissingZeros, sizeof(kECKeyMissingZeros));
- if (!key || !EncodeECPrivateKey(&out, key.get())) {
- ERR_print_errors_fp(stderr);
- return false;
- }
-
- if (std::vector<uint8_t>(kECKeyWithZeros,
- kECKeyWithZeros + sizeof(kECKeyWithZeros)) != out) {
- fprintf(stderr, "Serialisation of key was incorrect.\n");
- return false;
- }
-
- return true;
+ ASSERT_TRUE(key);
+ EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
+ EXPECT_EQ(Bytes(kECKeyWithZeros), Bytes(out.data(), out.size()));
}
-static bool TestSpecifiedCurve() {
+TEST(ECTest, SpecifiedCurve) {
// Test keys with specified curves may be decoded.
bssl::UniquePtr<EC_KEY> key =
DecodeECPrivateKey(kECKeySpecifiedCurve, sizeof(kECKeySpecifiedCurve));
- if (!key) {
- ERR_print_errors_fp(stderr);
- return false;
- }
+ ASSERT_TRUE(key);
// The group should have been interpreted as P-256.
- if (EC_GROUP_get_curve_name(EC_KEY_get0_group(key.get())) !=
- NID_X9_62_prime256v1) {
- fprintf(stderr, "Curve name incorrect.\n");
- return false;
- }
+ EXPECT_EQ(NID_X9_62_prime256v1,
+ EC_GROUP_get_curve_name(EC_KEY_get0_group(key.get())));
// Encoding the key should still use named form.
std::vector<uint8_t> out;
- if (!EncodeECPrivateKey(&out, key.get())) {
- ERR_print_errors_fp(stderr);
- return false;
- }
- if (std::vector<uint8_t>(kECKeyWithoutPublic,
- kECKeyWithoutPublic + sizeof(kECKeyWithoutPublic)) !=
- out) {
- fprintf(stderr, "Serialisation of key was incorrect.\n");
- return false;
- }
-
- return true;
-}
-
-static bool TestSetAffine(const int nid) {
- bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
- if (!key) {
- return false;
- }
-
- const EC_GROUP *const group = EC_KEY_get0_group(key.get());
-
- if (!EC_KEY_generate_key(key.get())) {
- fprintf(stderr, "EC_KEY_generate_key failed with nid %d\n", nid);
- ERR_print_errors_fp(stderr);
- return false;
- }
-
- if (!EC_POINT_is_on_curve(group, EC_KEY_get0_public_key(key.get()),
- nullptr)) {
- fprintf(stderr, "generated point is not on curve with nid %d", nid);
- ERR_print_errors_fp(stderr);
- return false;
- }
-
- bssl::UniquePtr<BIGNUM> x(BN_new());
- bssl::UniquePtr<BIGNUM> y(BN_new());
- if (!EC_POINT_get_affine_coordinates_GFp(group,
- EC_KEY_get0_public_key(key.get()),
- x.get(), y.get(), nullptr)) {
- fprintf(stderr, "EC_POINT_get_affine_coordinates_GFp failed with nid %d\n",
- nid);
- ERR_print_errors_fp(stderr);
- return false;
- }
-
- auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group));
- if (!point) {
- return false;
- }
-
- if (!EC_POINT_set_affine_coordinates_GFp(group, point.get(), x.get(), y.get(),
- nullptr)) {
- fprintf(stderr, "EC_POINT_set_affine_coordinates_GFp failed with nid %d\n",
- nid);
- ERR_print_errors_fp(stderr);
- return false;
- }
-
- // Subtract one from |y| to make the point no longer on the curve.
- if (!BN_sub(y.get(), y.get(), BN_value_one())) {
- return false;
- }
-
- bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group));
- if (!invalid_point) {
- return false;
- }
-
- if (EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(), x.get(),
- y.get(), nullptr)) {
- fprintf(stderr,
- "EC_POINT_set_affine_coordinates_GFp succeeded with invalid "
- "coordinates with nid %d\n",
- nid);
- ERR_print_errors_fp(stderr);
- return false;
- }
-
- return true;
+ EXPECT_TRUE(EncodeECPrivateKey(&out, key.get()));
+ EXPECT_EQ(Bytes(kECKeyWithoutPublic), Bytes(out.data(), out.size()));
}
-static bool TestArbitraryCurve() {
+TEST(ECTest, ArbitraryCurve) {
// Make a P-256 key and extract the affine coordinates.
bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
- if (!key || !EC_KEY_generate_key(key.get())) {
- return false;
- }
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(EC_KEY_generate_key(key.get()));
// Make an arbitrary curve which is identical to P-256.
static const uint8_t kP[] = {
@@ -351,186 +230,161 @@ static bool TestArbitraryCurve() {
0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51,
};
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
+ ASSERT_TRUE(ctx);
bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
+ ASSERT_TRUE(p);
bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr));
+ ASSERT_TRUE(a);
bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr));
+ ASSERT_TRUE(b);
bssl::UniquePtr<BIGNUM> gx(BN_bin2bn(kX, sizeof(kX), nullptr));
+ ASSERT_TRUE(gx);
bssl::UniquePtr<BIGNUM> gy(BN_bin2bn(kY, sizeof(kY), nullptr));
+ ASSERT_TRUE(gy);
bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr));
- bssl::UniquePtr<BIGNUM> cofactor(BN_new());
- if (!ctx || !p || !a || !b || !gx || !gy || !order || !cofactor ||
- !BN_set_word(cofactor.get(), 1)) {
- return false;
- }
+ ASSERT_TRUE(order);
bssl::UniquePtr<EC_GROUP> group(
EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get()));
- if (!group) {
- return false;
- }
+ ASSERT_TRUE(group);
bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
- if (!generator ||
- !EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(),
- gx.get(), gy.get(), ctx.get()) ||
- !EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
- cofactor.get())) {
- return false;
- }
+ ASSERT_TRUE(generator);
+ ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(
+ group.get(), generator.get(), gx.get(), gy.get(), ctx.get()));
+ ASSERT_TRUE(EC_GROUP_set_generator(group.get(), generator.get(), order.get(),
+ BN_value_one()));
// |group| should not have a curve name.
- if (EC_GROUP_get_curve_name(group.get()) != NID_undef) {
- return false;
- }
+ EXPECT_EQ(NID_undef, EC_GROUP_get_curve_name(group.get()));
// Copy |key| to |key2| using |group|.
bssl::UniquePtr<EC_KEY> key2(EC_KEY_new());
+ ASSERT_TRUE(key2);
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
+ ASSERT_TRUE(point);
bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new());
- if (!key2 || !point || !x || !y ||
- !EC_KEY_set_group(key2.get(), group.get()) ||
- !EC_KEY_set_private_key(key2.get(), EC_KEY_get0_private_key(key.get())) ||
- !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(key.get()),
- EC_KEY_get0_public_key(key.get()),
- x.get(), y.get(), nullptr) ||
- !EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(), x.get(),
- y.get(), nullptr) ||
- !EC_KEY_set_public_key(key2.get(), point.get())) {
- fprintf(stderr, "Could not copy key.\n");
- return false;
- }
+ ASSERT_TRUE(x);
+ ASSERT_TRUE(EC_KEY_set_group(key2.get(), group.get()));
+ ASSERT_TRUE(
+ EC_KEY_set_private_key(key2.get(), EC_KEY_get0_private_key(key.get())));
+ ASSERT_TRUE(EC_POINT_get_affine_coordinates_GFp(
+ EC_KEY_get0_group(key.get()), EC_KEY_get0_public_key(key.get()), x.get(),
+ y.get(), nullptr));
+ ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp(group.get(), point.get(),
+ x.get(), y.get(), nullptr));
+ ASSERT_TRUE(EC_KEY_set_public_key(key2.get(), point.get()));
// The key must be valid according to the new group too.
- if (!EC_KEY_check_key(key2.get())) {
- fprintf(stderr, "Copied key is not valid.\n");
- return false;
- }
-
- return true;
+ EXPECT_TRUE(EC_KEY_check_key(key2.get()));
}
-static bool TestAddingEqualPoints(int nid) {
- bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(nid));
- if (!key) {
- return false;
- }
+class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
+
+TEST_P(ECCurveTest, SetAffine) {
+ // Generate an EC_KEY.
+ bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(EC_KEY_generate_key(key.get()));
const EC_GROUP *const group = EC_KEY_get0_group(key.get());
+ EXPECT_TRUE(
+ EC_POINT_is_on_curve(group, EC_KEY_get0_public_key(key.get()), nullptr));
- if (!EC_KEY_generate_key(key.get())) {
- fprintf(stderr, "EC_KEY_generate_key failed with nid %d\n", nid);
- ERR_print_errors_fp(stderr);
- return false;
- }
+ // Get the public key's coordinates.
+ bssl::UniquePtr<BIGNUM> x(BN_new());
+ ASSERT_TRUE(x);
+ bssl::UniquePtr<BIGNUM> y(BN_new());
+ ASSERT_TRUE(y);
+ EXPECT_TRUE(EC_POINT_get_affine_coordinates_GFp(
+ group, EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr));
+
+ // Points on the curve should be accepted.
+ auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group));
+ ASSERT_TRUE(point);
+ EXPECT_TRUE(EC_POINT_set_affine_coordinates_GFp(group, point.get(), x.get(),
+ y.get(), nullptr));
+
+ // Subtract one from |y| to make the point no longer on the curve.
+ EXPECT_TRUE(BN_sub(y.get(), y.get(), BN_value_one()));
+
+ // Points not on the curve should be rejected.
+ bssl::UniquePtr<EC_POINT> invalid_point(EC_POINT_new(group));
+ ASSERT_TRUE(invalid_point);
+ EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(),
+ x.get(), y.get(), nullptr));
+}
+
+TEST_P(ECCurveTest, AddingEqualPoints) {
+ bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(GetParam().nid));
+ ASSERT_TRUE(key);
+ ASSERT_TRUE(EC_KEY_generate_key(key.get()));
+
+ const EC_GROUP *const group = EC_KEY_get0_group(key.get());
bssl::UniquePtr<EC_POINT> p1(EC_POINT_new(group));
- bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group));
- bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group));
- bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group));
- if (!p1 || !p2 || !double_p1 || !p1_plus_p2) {
- return false;
- }
+ ASSERT_TRUE(p1);
+ ASSERT_TRUE(EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())));
- if (!EC_POINT_copy(p1.get(), EC_KEY_get0_public_key(key.get())) ||
- !EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get()))) {
- fprintf(stderr, "EC_POINT_COPY failed with nid %d\n", nid);
- ERR_print_errors_fp(stderr);
- return false;
- }
+ bssl::UniquePtr<EC_POINT> p2(EC_POINT_new(group));
+ ASSERT_TRUE(p2);
+ ASSERT_TRUE(EC_POINT_copy(p2.get(), EC_KEY_get0_public_key(key.get())));
+ bssl::UniquePtr<EC_POINT> double_p1(EC_POINT_new(group));
+ ASSERT_TRUE(double_p1);
bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
- if (!ctx) {
- return false;
- }
-
- if (!EC_POINT_dbl(group, double_p1.get(), p1.get(), ctx.get()) ||
- !EC_POINT_add(group, p1_plus_p2.get(), p1.get(), p2.get(), ctx.get())) {
- fprintf(stderr, "Point operation failed with nid %d\n", nid);
- ERR_print_errors_fp(stderr);
- return false;
- }
+ ASSERT_TRUE(ctx);
+ ASSERT_TRUE(EC_POINT_dbl(group, double_p1.get(), p1.get(), ctx.get()));
- if (EC_POINT_cmp(group, double_p1.get(), p1_plus_p2.get(), ctx.get()) != 0) {
- fprintf(stderr, "A+A != 2A for nid %d", nid);
- return false;
- }
+ bssl::UniquePtr<EC_POINT> p1_plus_p2(EC_POINT_new(group));
+ ASSERT_TRUE(p1_plus_p2);
+ ASSERT_TRUE(
+ EC_POINT_add(group, p1_plus_p2.get(), p1.get(), p2.get(), ctx.get()));
- return true;
+ EXPECT_EQ(0,
+ EC_POINT_cmp(group, double_p1.get(), p1_plus_p2.get(), ctx.get()))
+ << "A+A != 2A";
}
-static bool TestMulZero(int nid) {
- bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid));
- if (!group) {
- return false;
- }
+TEST_P(ECCurveTest, MulZero) {
+ bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid));
+ ASSERT_TRUE(group);
bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
+ ASSERT_TRUE(point);
bssl::UniquePtr<BIGNUM> zero(BN_new());
- if (!point || !zero) {
- return false;
- }
-
+ ASSERT_TRUE(zero);
BN_zero(zero.get());
- if (!EC_POINT_mul(group.get(), point.get(), zero.get(), nullptr, nullptr,
- nullptr)) {
- return false;
- }
+ ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), zero.get(), nullptr,
+ nullptr, nullptr));
- if (!EC_POINT_is_at_infinity(group.get(), point.get())) {
- fprintf(stderr, "g * 0 did not return point at infinity.\n");
- return false;
- }
+ EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
+ << "g * 0 did not return point at infinity.";
// Test that zero times an arbitrary point is also infinity. The generator is
// used as the arbitrary point.
bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
- bssl::UniquePtr<BIGNUM> one(BN_new());
- if (!generator ||
- !one ||
- !BN_one(one.get()) ||
- !EC_POINT_mul(group.get(), generator.get(), one.get(), nullptr, nullptr,
- nullptr) ||
- !EC_POINT_mul(group.get(), point.get(), nullptr, generator.get(),
- zero.get(), nullptr)) {
- return false;
- }
-
- if (!EC_POINT_is_at_infinity(group.get(), point.get())) {
- fprintf(stderr, "p * 0 did not return point at infinity.\n");
- return false;
- }
-
- return true;
+ ASSERT_TRUE(generator);
+ ASSERT_TRUE(EC_POINT_mul(group.get(), generator.get(), BN_value_one(),
+ nullptr, nullptr, nullptr));
+ ASSERT_TRUE(EC_POINT_mul(group.get(), point.get(), nullptr, generator.get(),
+ zero.get(), nullptr));
+
+ EXPECT_TRUE(EC_POINT_is_at_infinity(group.get(), point.get()))
+ << "p * 0 did not return point at infinity.";
}
-static bool ForEachCurve(bool (*test_func)(int nid)) {
+static std::vector<EC_builtin_curve> AllCurves() {
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
std::vector<EC_builtin_curve> curves(num_curves);
EC_get_builtin_curves(curves.data(), num_curves);
-
- for (const auto& curve : curves) {
- if (!test_func(curve.nid)) {
- fprintf(stderr, "Test failed for %s\n", curve.comment);
- return false;
- }
- }
-
- return true;
+ return curves;
}
-int main() {
- CRYPTO_library_init();
-
- if (!Testd2i_ECPrivateKey() ||
- !TestZeroPadding() ||
- !TestSpecifiedCurve() ||
- !ForEachCurve(TestSetAffine) ||
- !ForEachCurve(TestAddingEqualPoints) ||
- !ForEachCurve(TestMulZero) ||
- !TestArbitraryCurve()) {
- fprintf(stderr, "failed\n");
- return 1;
- }
-
- printf("PASS\n");
- return 0;
+static std::string CurveToString(
+ const testing::TestParamInfo<EC_builtin_curve> &params) {
+ // The comment field contains characters GTest rejects, so use the OBJ name.
+ return OBJ_nid2sn(params.param.nid);
}
+
+INSTANTIATE_TEST_CASE_P(, ECCurveTest, testing::ValuesIn(AllCurves()),
+ CurveToString);