//////////////////////////////////////////////////////////////////////////////// // Copyright 2019 Google LLC. // // This software is licensed under the terms defined in the Widevine Master // License Agreement. For a copy of this agreement, please contact // widevine-licensing@google.com. //////////////////////////////////////////////////////////////////////////////// // // Description: // Unit tests for the ECPrivateKey and ECPublicKey classes. #include "common/ec_key.h" #include #include #include "testing/gmock.h" #include "testing/gunit.h" #include "openssl/sha.h" #include "common/ec_test_keys.h" #include "common/ec_util.h" #include "common/random_util.h" using ::testing::IsNull; namespace widevine { class ECKeyTest : public ::testing::Test { public: static std::vector > GetTestKeyList() { std::vector > test_key_list; ECTestKeys test_keys; test_key_list.push_back( std::make_tuple(test_keys.private_test_key_1_secp521r1(), test_keys.public_test_key_1_secp521r1())); test_key_list.push_back( std::make_tuple(test_keys.private_test_key_1_secp384r1(), test_keys.public_test_key_1_secp384r1())); test_key_list.push_back( std::make_tuple(test_keys.private_test_key_1_secp256r1(), test_keys.public_test_key_1_secp256r1())); return test_key_list; } protected: ECKeyTest() { plaintext_message_ = "This is a plaintext message."; } void GenerateEphemeralKeyPair(ECPrivateKey::EllipticCurve curve) { ASSERT_NE(curve, ECPrivateKey::UNDEFINED_CURVE); bssl::UniquePtr ephemeral_key_pair( EC_KEY_new_by_curve_name(ec_util::CurveToNid(curve))); ASSERT_TRUE(ephemeral_key_pair != nullptr); ASSERT_TRUE(EC_KEY_generate_key(ephemeral_key_pair.get())); // Separate them out into their private and public parts. std::string private_key; std::string public_key; ASSERT_TRUE( ec_util::SerializeECPrivateKey(ephemeral_key_pair.get(), &private_key)); ASSERT_TRUE( ec_util::SerializeECPublicKey(ephemeral_key_pair.get(), &public_key)); ephemeral_private_key_ = ECPrivateKey::Create(private_key); ephemeral_public_key_ = ECPublicKey::Create(public_key); } std::unique_ptr ephemeral_private_key_; std::unique_ptr ephemeral_public_key_; std::string plaintext_message_; }; TEST_F(ECKeyTest, KeyCurve) { ECTestKeys test_keys; EXPECT_EQ( ECPrivateKey::Create(test_keys.private_test_key_1_secp521r1())->Curve(), ECPrivateKey::SECP521R1); EXPECT_EQ( ECPrivateKey::Create(test_keys.private_test_key_1_secp384r1())->Curve(), ECPrivateKey::SECP384R1); EXPECT_EQ( ECPrivateKey::Create(test_keys.private_test_key_1_secp256r1())->Curve(), ECPrivateKey::SECP256R1); EXPECT_EQ( ECPublicKey::Create(test_keys.public_test_key_1_secp521r1())->Curve(), ECPrivateKey::SECP521R1); EXPECT_EQ( ECPublicKey::Create(test_keys.public_test_key_1_secp384r1())->Curve(), ECPrivateKey::SECP384R1); EXPECT_EQ( ECPublicKey::Create(test_keys.public_test_key_1_secp256r1())->Curve(), ECPrivateKey::SECP256R1); } TEST_F(ECKeyTest, KeyPointEncodingNullDeath) { EXPECT_DEATH(ephemeral_public_key_->GetPointEncodedKey(nullptr), ""); } class ECKeyTestKeyPairs : public ECKeyTest, public ::testing::WithParamInterface< std::tuple > { protected: ECKeyTestKeyPairs() { test_private_key_ = std::get<0>(GetParam()); test_public_key_ = std::get<1>(GetParam()); private_key_ = ECPrivateKey::Create(test_private_key_); public_key_ = ECPublicKey::Create(test_public_key_); } std::string test_private_key_; std::string test_public_key_; std::unique_ptr private_key_; std::unique_ptr public_key_; }; TEST_P(ECKeyTestKeyPairs, CreateWrongKey) { EXPECT_EQ(ECPrivateKey::Create(test_public_key_), nullptr); EXPECT_EQ(ECPublicKey::Create(test_private_key_), nullptr); } TEST_P(ECKeyTestKeyPairs, InvalidKeyConstructorParameters) { EXPECT_DEATH(ECPrivateKey(nullptr), ""); EXPECT_DEATH(ECPublicKey(nullptr), ""); EC_KEY* key; ASSERT_TRUE(ec_util::DeserializeECPrivateKey(test_private_key_, &key)); // Brace initialization to avoid most vexing parse. EXPECT_DEATH(ECPublicKey{key}, ""); EC_KEY_free(key); ASSERT_TRUE(ec_util::DeserializeECPublicKey(test_public_key_, &key)); EXPECT_DEATH(ECPrivateKey{key}, ""); EC_KEY_free(key); } TEST_P(ECKeyTestKeyPairs, KeyMatch) { EXPECT_TRUE(private_key_->MatchesPrivateKey(*private_key_)); EXPECT_TRUE(private_key_->MatchesPublicKey(*public_key_)); EXPECT_TRUE(public_key_->MatchesPrivateKey(*private_key_)); EXPECT_TRUE(public_key_->MatchesPublicKey(*public_key_)); } TEST_P(ECKeyTestKeyPairs, DeriveSharedSessionKey) { std::string derived_shared_session_key_1; // Generate a temporary key pair as part of ECDH. GenerateEphemeralKeyPair(private_key_->Curve()); EXPECT_TRUE(private_key_->DeriveSharedSessionKey( *ephemeral_public_key_, &derived_shared_session_key_1)); EXPECT_EQ(derived_shared_session_key_1.size(), SHA256_DIGEST_LENGTH); std::string derived_shared_session_key_2; EXPECT_TRUE(ephemeral_private_key_->DeriveSharedSessionKey( *public_key_, &derived_shared_session_key_2)); EXPECT_EQ(derived_shared_session_key_1, derived_shared_session_key_2); } TEST_P(ECKeyTestKeyPairs, InvalidDeriveSharedSessionKeyParameters) { GenerateEphemeralKeyPair(private_key_->Curve()); EXPECT_FALSE( private_key_->DeriveSharedSessionKey(*ephemeral_public_key_, nullptr)); EXPECT_FALSE( ephemeral_private_key_->DeriveSharedSessionKey(*public_key_, nullptr)); } TEST_P(ECKeyTestKeyPairs, SignVerify) { std::string signature; EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature)); EXPECT_TRUE(public_key_->VerifySignature(plaintext_message_, signature)); } TEST_P(ECKeyTestKeyPairs, InvalidSignVerifyParameters) { std::string signature; EXPECT_FALSE(private_key_->GenerateSignature("", &signature)); EXPECT_FALSE(public_key_->VerifySignature("", "signature")); EXPECT_FALSE(private_key_->GenerateSignature(plaintext_message_, nullptr)); EXPECT_FALSE(public_key_->VerifySignature(plaintext_message_, "")); } TEST_P(ECKeyTestKeyPairs, KeyMismatch) { GenerateEphemeralKeyPair(private_key_->Curve()); EXPECT_FALSE(private_key_->MatchesPrivateKey(*ephemeral_private_key_)); EXPECT_FALSE(private_key_->MatchesPublicKey(*ephemeral_public_key_)); EXPECT_FALSE(public_key_->MatchesPrivateKey(*ephemeral_private_key_)); EXPECT_FALSE(public_key_->MatchesPublicKey(*ephemeral_public_key_)); } TEST_P(ECKeyTestKeyPairs, SignVerifyKeyMismatch) { std::string signature; GenerateEphemeralKeyPair(private_key_->Curve()); EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature)); EXPECT_FALSE( ephemeral_public_key_->VerifySignature(plaintext_message_, signature)); } TEST_P(ECKeyTestKeyPairs, KeyPointEncodingCreateBadKeyPoint) { ASSERT_THAT(ECPublicKey::CreateFromKeyPoint(public_key_->Curve(), ""), IsNull()); } TEST_P(ECKeyTestKeyPairs, KeyPointEncodingCreateBadCurve) { std::string serialized_key_point; ASSERT_TRUE(public_key_->GetPointEncodedKey(&serialized_key_point)); ASSERT_THAT(ECPublicKey::CreateFromKeyPoint(ECPrivateKey::UNDEFINED_CURVE, serialized_key_point), IsNull()); } TEST_P(ECKeyTestKeyPairs, KeyPointEncodingSuccess) { std::string serialized_key_point; ASSERT_TRUE(public_key_->GetPointEncodedKey(&serialized_key_point)); ASSERT_EQ(ec_util::GetPublicKeyPointSize(public_key_->Curve()), serialized_key_point.size()); // Check that the leading byte indicates uncompressed. ASSERT_EQ(4, serialized_key_point[0]); std::unique_ptr new_public_key = ECPublicKey::CreateFromKeyPoint( public_key_->Curve(), serialized_key_point); ASSERT_THAT(new_public_key, testing::NotNull()); EXPECT_TRUE(new_public_key->MatchesPublicKey(*public_key_)); EXPECT_TRUE(new_public_key->MatchesPrivateKey(*private_key_)); }; INSTANTIATE_TEST_SUITE_P(ECKeyTestKeyPairs, ECKeyTestKeyPairs, ::testing::ValuesIn(ECKeyTest::GetTestKeyList())); class ECKeyTestCurveMismatch : public ECKeyTest, public ::testing::WithParamInterface< std::tuple, std::tuple > > { protected: ECKeyTestCurveMismatch() { private_key_ = ECPrivateKey::Create(std::get<0>(std::get<0>(GetParam()))); public_key_ = ECPublicKey::Create(std::get<1>(std::get<0>(GetParam()))); wrong_curve_private_key_ = ECPrivateKey::Create(std::get<0>(std::get<1>(GetParam()))); wrong_curve_public_key_ = ECPublicKey::Create(std::get<1>(std::get<1>(GetParam()))); } void SetUp() override { // Only run combinations where the two curves differ. if (std::get<0>(GetParam()) == std::get<1>(GetParam())) GTEST_SKIP(); } std::unique_ptr private_key_; std::unique_ptr public_key_; std::unique_ptr wrong_curve_private_key_; std::unique_ptr wrong_curve_public_key_; }; TEST_P(ECKeyTestCurveMismatch, CurveMismatch) { EXPECT_FALSE(private_key_->MatchesPrivateKey(*wrong_curve_private_key_)); EXPECT_FALSE(private_key_->MatchesPublicKey(*wrong_curve_public_key_)); EXPECT_FALSE(public_key_->MatchesPrivateKey(*wrong_curve_private_key_)); EXPECT_FALSE(public_key_->MatchesPublicKey(*wrong_curve_public_key_)); } TEST_P(ECKeyTestCurveMismatch, DeriveSharedSessionKeyCurveMismatch) { std::string derived_shared_session_key; EXPECT_FALSE(private_key_->DeriveSharedSessionKey( *wrong_curve_public_key_, &derived_shared_session_key)); } TEST_P(ECKeyTestCurveMismatch, SignVerifyCurveMismatch) { std::string signature; EXPECT_TRUE(private_key_->GenerateSignature(plaintext_message_, &signature)); EXPECT_FALSE( wrong_curve_public_key_->VerifySignature(plaintext_message_, signature)); } INSTANTIATE_TEST_SUITE_P( ECKeyTestCurveMismatch, ECKeyTestCurveMismatch, ::testing::Combine(::testing::ValuesIn(ECKeyTest::GetTestKeyList()), ::testing::ValuesIn(ECKeyTest::GetTestKeyList()))); } // namespace widevine