diff options
Diffstat (limited to 'src/crypto/ec/ec_test.cc')
-rw-r--r-- | src/crypto/ec/ec_test.cc | 450 |
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> ¶ms) { + // 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); |