// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// #include "tink/signature/ecdsa_sign_key_manager.h" #include #include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/status/status.h" #include "absl/strings/string_view.h" #include "tink/internal/ec_util.h" #include "tink/internal/ssl_util.h" #include "tink/public_key_sign.h" #include "tink/public_key_verify.h" #include "tink/signature/ecdsa_verify_key_manager.h" #include "tink/subtle/ecdsa_verify_boringssl.h" #include "tink/util/enums.h" #include "tink/util/istream_input_stream.h" #include "tink/util/status.h" #include "tink/util/statusor.h" #include "tink/util/test_matchers.h" #include "tink/util/test_util.h" #include "proto/ecdsa.pb.h" namespace crypto { namespace tink { using ::crypto::tink::test::IsOk; using ::crypto::tink::test::StatusIs; using ::crypto::tink::util::Enums; using ::crypto::tink::util::StatusOr; using ::google::crypto::tink::EcdsaKeyFormat; using ::google::crypto::tink::EcdsaParams; using ::google::crypto::tink::EcdsaPrivateKey; using ::google::crypto::tink::EcdsaPublicKey; using ::google::crypto::tink::EcdsaSignatureEncoding; using ::google::crypto::tink::EllipticCurveType; using ::google::crypto::tink::HashType; using ::google::crypto::tink::KeyData; using ::testing::Eq; using ::testing::Gt; using ::testing::Not; using ::testing::SizeIs; namespace { TEST(EcdsaSignKeyManagerTest, Basic) { EXPECT_THAT(EcdsaSignKeyManager().get_version(), Eq(0)); EXPECT_THAT(EcdsaSignKeyManager().key_material_type(), Eq(KeyData::ASYMMETRIC_PRIVATE)); EXPECT_THAT(EcdsaSignKeyManager().get_key_type(), Eq("type.googleapis.com/google.crypto.tink.EcdsaPrivateKey")); } TEST(EcdsaSignKeyManagerTest, ValidateEmptyKeyFormat) { EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(EcdsaKeyFormat()), Not(IsOk())); } EcdsaKeyFormat CreateValidKeyFormat() { EcdsaKeyFormat key_format; EcdsaParams* params = key_format.mutable_params(); params->set_hash_type(HashType::SHA256); params->set_curve(EllipticCurveType::NIST_P256); params->set_encoding(EcdsaSignatureEncoding::DER); return key_format; } TEST(EcdsaSignKeyManagerTest, ValidateKeyFormat) { EcdsaKeyFormat format = CreateValidKeyFormat(); EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(format), IsOk()); } TEST(EcdsaSignKeyManagerTest, ValidateKeyFormatUnknownCurve) { EcdsaKeyFormat format = CreateValidKeyFormat(); EcdsaParams* params = format.mutable_params(); params->set_curve(EllipticCurveType::UNKNOWN_CURVE); EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(format), Not(IsOk())); } TEST(EcdsaSignKeyManagerTest, ValidateKeyFormatBadHashP256) { EcdsaKeyFormat format = CreateValidKeyFormat(); EcdsaParams* params = format.mutable_params(); params->set_curve(EllipticCurveType::NIST_P256); params->set_hash_type(HashType::SHA512); EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(format), Not(IsOk())); EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(format), StatusIs(absl::StatusCode::kInvalidArgument)); } TEST(EcdsaSignKeyManagerTest, ValidateKeyFormatBadHashP384) { EcdsaKeyFormat format = CreateValidKeyFormat(); EcdsaParams* params = format.mutable_params(); params->set_curve(EllipticCurveType::NIST_P384); params->set_hash_type(HashType::SHA256); EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(format), Not(IsOk())); EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(format), StatusIs(absl::StatusCode::kInvalidArgument)); } TEST(EcdsaSignKeyManagerTest, ValidateKeyFormatBadHashP521) { EcdsaKeyFormat format = CreateValidKeyFormat(); EcdsaParams* params = format.mutable_params(); params->set_curve(EllipticCurveType::NIST_P521); params->set_hash_type(HashType::SHA256); EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(format), Not(IsOk())); EXPECT_THAT(EcdsaSignKeyManager().ValidateKeyFormat(format), StatusIs(absl::StatusCode::kInvalidArgument)); } TEST(EcdsaSignKeyManagerTest, CreateKey) { EcdsaKeyFormat format = CreateValidKeyFormat(); StatusOr key_or = EcdsaSignKeyManager().CreateKey(format); ASSERT_THAT(key_or, IsOk()); EcdsaPrivateKey key = key_or.value(); EXPECT_THAT(key.version(), Eq(0)); EXPECT_THAT(key.public_key().version(), Eq(key.version())); EXPECT_THAT(key.public_key().params().hash_type(), Eq(format.params().hash_type())); EXPECT_THAT(key.public_key().params().curve(), Eq(format.params().curve())); EXPECT_THAT(key.public_key().params().encoding(), Eq(format.params().encoding())); EXPECT_THAT(key.public_key().x(), SizeIs(Gt(0))); EXPECT_THAT(key.public_key().y(), SizeIs(Gt(0))); EXPECT_THAT(key.key_value(), SizeIs(Gt(0))); } TEST(EcdsaSignKeyManagerTest, CreateKeyValid) { EcdsaKeyFormat format = CreateValidKeyFormat(); StatusOr key_or = EcdsaSignKeyManager().CreateKey(format); ASSERT_THAT(key_or, IsOk()); EXPECT_THAT(EcdsaSignKeyManager().ValidateKey(key_or.value()), IsOk()); } EcdsaPrivateKey CreateValidKey() { EcdsaKeyFormat format = CreateValidKeyFormat(); return EcdsaSignKeyManager().CreateKey(format).value(); } TEST(EcdsaSignKeyManagerTest, ValidateKey) { EcdsaPrivateKey key = CreateValidKey(); EXPECT_THAT(EcdsaSignKeyManager().ValidateKey(key), IsOk()); } TEST(EcdsaSignKeyManagerTest, ValidateKeyBadHashP256) { EcdsaPrivateKey key = CreateValidKey(); EcdsaParams* params = key.mutable_public_key()->mutable_params(); params->set_curve(EllipticCurveType::NIST_P256); params->set_hash_type(HashType::SHA512); EXPECT_THAT(EcdsaSignKeyManager().ValidateKey(key), Not(IsOk())); EXPECT_THAT(EcdsaSignKeyManager().ValidateKey(key), StatusIs(absl::StatusCode::kInvalidArgument)); } TEST(EcdsaSignKeyManagerTest, ValidateKeyBadHashP384) { EcdsaPrivateKey key = CreateValidKey(); EcdsaParams* params = key.mutable_public_key()->mutable_params(); params->set_curve(EllipticCurveType::NIST_P384); params->set_hash_type(HashType::SHA256); EXPECT_THAT(EcdsaSignKeyManager().ValidateKey(key), Not(IsOk())); EXPECT_THAT(EcdsaSignKeyManager().ValidateKey(key), StatusIs(absl::StatusCode::kInvalidArgument)); } TEST(EcdsaSignKeyManagerTest, ValidateKeyBadHashP521) { EcdsaPrivateKey key = CreateValidKey(); EcdsaParams* params = key.mutable_public_key()->mutable_params(); params->set_curve(EllipticCurveType::NIST_P521); params->set_hash_type(HashType::SHA256); EXPECT_THAT(EcdsaSignKeyManager().ValidateKey(key), Not(IsOk())); EXPECT_THAT(EcdsaSignKeyManager().ValidateKey(key), StatusIs(absl::StatusCode::kInvalidArgument)); } TEST(EcdsaSignKeyManagerTest, GetPublicKey) { EcdsaPrivateKey key = CreateValidKey(); StatusOr public_key_or = EcdsaSignKeyManager().GetPublicKey(key); ASSERT_THAT(public_key_or, IsOk()); EcdsaPublicKey public_key = public_key_or.value(); EXPECT_THAT(public_key.version(), Eq(key.public_key().version())); EXPECT_THAT(public_key.params().hash_type(), Eq(key.public_key().params().hash_type())); EXPECT_THAT(public_key.params().curve(), Eq(key.public_key().params().curve())); EXPECT_THAT(public_key.params().encoding(), Eq(key.public_key().params().encoding())); EXPECT_THAT(public_key.x(), Eq(key.public_key().x())); EXPECT_THAT(public_key.y(), Eq(key.public_key().y())); } TEST(EcdsaSignKeyManagerTest, Create) { EcdsaPrivateKey private_key = CreateValidKey(); EcdsaPublicKey public_key = EcdsaSignKeyManager().GetPublicKey(private_key).value(); auto signer_or = EcdsaSignKeyManager().GetPrimitive(private_key); ASSERT_THAT(signer_or, IsOk()); internal::EcKey ec_key; ec_key.curve = Enums::ProtoToSubtle(public_key.params().curve()); ec_key.pub_x = public_key.x(); ec_key.pub_y = public_key.y(); auto direct_verifier_or = subtle::EcdsaVerifyBoringSsl::New( ec_key, Enums::ProtoToSubtle(public_key.params().hash_type()), Enums::ProtoToSubtle(public_key.params().encoding())); ASSERT_THAT(direct_verifier_or, IsOk()); std::string message = "Some message"; EXPECT_THAT(direct_verifier_or.value()->Verify( signer_or.value()->Sign(message).value(), message), IsOk()); } TEST(EcdsaSignKeyManagerTest, CreateDifferentKey) { EcdsaPrivateKey private_key = CreateValidKey(); // Note: we create a new key in the next line. EcdsaPublicKey public_key = EcdsaSignKeyManager().GetPublicKey(CreateValidKey()).value(); auto signer_or = EcdsaSignKeyManager().GetPrimitive(private_key); ASSERT_THAT(signer_or, IsOk()); internal::EcKey ec_key; ec_key.curve = Enums::ProtoToSubtle(public_key.params().curve()); ec_key.pub_x = public_key.x(); ec_key.pub_y = public_key.y(); auto direct_verifier_or = subtle::EcdsaVerifyBoringSsl::New( ec_key, Enums::ProtoToSubtle(public_key.params().hash_type()), Enums::ProtoToSubtle(public_key.params().encoding())); ASSERT_THAT(direct_verifier_or, IsOk()); std::string message = "Some message"; EXPECT_THAT(direct_verifier_or.value()->Verify( signer_or.value()->Sign(message).value(), message), Not(IsOk())); } TEST(EcdsaSignKeyManagerTest, DeriveKeyFailsWithOpenSsl) { if (internal::IsBoringSsl()) { GTEST_SKIP() << "OpenSSL-only test, skipping because Tink is using BoringSSL"; } EcdsaKeyFormat format = CreateValidKeyFormat(); util::IstreamInputStream input_stream{ absl::make_unique("0123456789abcdef0123456789abcdef")}; EXPECT_THAT(EcdsaSignKeyManager().DeriveKey(format, &input_stream).status(), Not(IsOk())); } TEST(EcdsaSignKeyManagerTest, DeriveKeySignVerifySucceedsWithBoringSsl) { if (!internal::IsBoringSsl()) { GTEST_SKIP() << "Key derivation from an input stream is not supported with OpenSSL"; } EcdsaKeyFormat format = CreateValidKeyFormat(); util::IstreamInputStream input_stream{ absl::make_unique("0123456789abcdef0123456789abcdef")}; util::StatusOr key = EcdsaSignKeyManager().DeriveKey(format, &input_stream); ASSERT_THAT(key, IsOk()); util::StatusOr> signer = EcdsaSignKeyManager().GetPrimitive(*key); ASSERT_THAT(signer, IsOk()); constexpr absl::string_view kMessage = "Some message"; util::StatusOr signature = (*signer)->Sign(kMessage); ASSERT_THAT(signature, IsOk()); util::StatusOr> verifier = EcdsaVerifyKeyManager().GetPrimitive(key->public_key()); ASSERT_THAT(verifier, IsOk()); EXPECT_THAT((*verifier)->Verify(*signature, kMessage), IsOk()); } TEST(EcdsaSignKeyManagerTest, DeriveKeyNotEnoughRandomness) { if (!internal::IsBoringSsl()) { GTEST_SKIP() << "Key derivation from an input stream is not supported with OpenSSL"; } EcdsaKeyFormat format = CreateValidKeyFormat(); util::IstreamInputStream input_stream{ absl::make_unique("tooshort")}; ASSERT_THAT(EcdsaSignKeyManager().DeriveKey(format, &input_stream).status(), test::StatusIs(absl::StatusCode::kInvalidArgument)); } TEST(EcdsaSignKeyManagerTest, DeriveKeyWithInvalidKeyTemplateVersionFails) { if (!internal::IsBoringSsl()) { GTEST_SKIP() << "Key derivation from an input stream is not supported with OpenSSL"; } EcdsaKeyFormat format; format.set_version(1); EcdsaParams* params = format.mutable_params(); params->set_hash_type(HashType::SHA256); params->set_curve(EllipticCurveType::NIST_P256); params->set_encoding(EcdsaSignatureEncoding::DER); util::IstreamInputStream input_stream{ absl::make_unique("tooshort")}; ASSERT_THAT(EcdsaSignKeyManager().DeriveKey(format, &input_stream).status(), test::StatusIs(absl::StatusCode::kInvalidArgument)); } TEST(EcdsaSignKeyManagerTest, DeriveKeyInvalidCurve) { if (!internal::IsBoringSsl()) { GTEST_SKIP() << "Key derivation from an input stream is not supported with OpenSSL"; } EcdsaKeyFormat format = CreateValidKeyFormat(); EcdsaParams* params = format.mutable_params(); params->set_curve(EllipticCurveType::CURVE25519); util::IstreamInputStream input_stream{ absl::make_unique("0123456789abcdef0123456789abcdef")}; ASSERT_THAT(EcdsaSignKeyManager().DeriveKey(format, &input_stream).status(), test::StatusIs(absl::StatusCode::kInvalidArgument)); } // Test vectors have been manually generated based on BoringSSL // Date: 2021/06/03 commit: 88df13d73d5a74505f046f0bf37fb2fb3e1f1a58 using NistCurveParamsDeriveTest = ::testing::TestWithParam< std::tuple>; INSTANTIATE_TEST_SUITE_P( NistCurvesParams, NistCurveParamsDeriveTest, ::testing::Values( std::make_tuple( EllipticCurveType::NIST_P256, "0123456789abcdef0123456789abcdef", "ed615ab1a0a8bc0412a02f097e747f33c61c5d1f0c720f3e232213ce4a4b7c38"), std::make_tuple( EllipticCurveType::NIST_P256, "0000000000000000", "19d85dacc6634391175a26a692af2230a1de00860bda799d90e2df6ed8e1e5c6"), std::make_tuple( EllipticCurveType::NIST_P256, "4242424242424242", "055d555a117782553a01a93544ffeced88bc08a50a22138b54c422c4a8cfb3ec"), std::make_tuple(EllipticCurveType::NIST_P384, "0123456789abcdef0123456789abcdef", "4c2204d997b64a288ce7c8dbcb9d9543f45c7de458410cd996f28a" "d123e45a146367c2d2100a4336bad949535d1d9e89"), std::make_tuple(EllipticCurveType::NIST_P384, "000000000000000000000000", "88d0af7371ae92b3aa2daea3d68d514a5c335ac6c6e5af2a7cf60a" "f71364241d318c022f7846b261c6345bc0c810d816"), std::make_tuple(EllipticCurveType::NIST_P384, "424242424242424242424242", "53cfa0a8205c69cd56173a76a99caf19b15bd56ce9a08c6d26067e" "b6b48925bd445cdf213e35b69330e47535ff8f27ad"), std::make_tuple(EllipticCurveType::NIST_P521, "0123456789abcdef0123456789abcdef", "014ef526b2a9e965227e83396387a34a441d471f5ab3fe62607e78" "e56619a698ad73bba12e42459e457c08dfa8492daaf8188f72f707" "6b8bc902d4c68729a3330b8f"), std::make_tuple(EllipticCurveType::NIST_P521, "00000000000000000000000000000000", "01effa21f65dda9fe6eacd5d4a1865a4117db0ac5617cdaaaae1cf" "f17b261a5fd1804e75e49d8cca288bd3f0a7b77d39bb230c9c5192" "c70e1af9f93403e3705a49d6"), std::make_tuple(EllipticCurveType::NIST_P521, "42424242424242424242424242424242", "013fa619e3ea1f71f923b6716619d0044d168637d36e44b828901e" "cef00f6fabcffbd6b5c2c24468a35fed8611aaeeb36b2af7be1eff" "d393151c6b5135a07789f8a4"))); TEST_P(NistCurveParamsDeriveTest, TestVectors) { if (!internal::IsBoringSsl()) { GTEST_SKIP() << "Key derivation from an input stream is not supported with OpenSSL"; } EcdsaKeyFormat key_format; key_format.mutable_params()->set_curve(std::get<0>(GetParam())); util::IstreamInputStream input_stream{ absl::make_unique(std::get<1>(GetParam()))}; util::StatusOr private_key = EcdsaSignKeyManager().DeriveKey(key_format, &input_stream); ASSERT_THAT(private_key, IsOk()); EXPECT_THAT(private_key->key_value(), Eq(test::HexDecodeOrDie(std::get<2>(GetParam())))); } } // namespace } // namespace tink } // namespace crypto