// Copyright 2017 Google Inc. // // 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/internal/registry_impl.h" #include #include #include #include #include // NOLINT(build/c++11) #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/memory/memory.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "openssl/crypto.h" #include "tink/aead.h" #include "tink/aead/aead_wrapper.h" #include "tink/aead/aes_gcm_key_manager.h" #include "tink/core/key_manager_impl.h" #include "tink/core/key_type_manager.h" #include "tink/core/private_key_manager_impl.h" #include "tink/core/private_key_type_manager.h" #include "tink/core/template_util.h" #include "tink/hybrid/ecies_aead_hkdf_private_key_manager.h" #include "tink/hybrid/ecies_aead_hkdf_public_key_manager.h" #include "tink/hybrid_decrypt.h" #include "tink/input_stream.h" #include "tink/internal/fips_utils.h" #include "tink/key_manager.h" #include "tink/mac.h" #include "tink/monitoring/monitoring_client_mocks.h" #include "tink/primitive_set.h" #include "tink/primitive_wrapper.h" #include "tink/registry.h" #include "tink/subtle/aes_gcm_boringssl.h" #include "tink/subtle/random.h" #include "tink/util/input_stream_util.h" #include "tink/util/istream_input_stream.h" #include "tink/util/protobuf_helper.h" #include "tink/util/secret_data.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/aes_ctr_hmac_aead.pb.h" #include "proto/aes_gcm.pb.h" #include "proto/common.pb.h" #include "proto/ecdsa.pb.h" #include "proto/ecies_aead_hkdf.pb.h" #include "proto/tink.pb.h" namespace crypto { namespace tink { namespace internal { namespace { using ::crypto::tink::test::AddLegacyKey; using ::crypto::tink::test::AddRawKey; using ::crypto::tink::test::AddTinkKey; using ::crypto::tink::test::DummyAead; using ::crypto::tink::test::IsOk; using ::crypto::tink::test::StatusIs; using ::crypto::tink::util::Status; using ::google::crypto::tink::AesCtrHmacAeadKey; using ::google::crypto::tink::AesGcmKey; using ::google::crypto::tink::AesGcmKeyFormat; using ::google::crypto::tink::EcdsaKeyFormat; using ::google::crypto::tink::EcdsaPrivateKey; using ::google::crypto::tink::EcdsaPublicKey; using ::google::crypto::tink::EcdsaSignatureEncoding; using ::google::crypto::tink::EcPointFormat; using ::google::crypto::tink::EllipticCurveType; using ::google::crypto::tink::HashType; using ::google::crypto::tink::KeyData; using ::google::crypto::tink::Keyset; using ::google::crypto::tink::KeysetInfo; using ::google::crypto::tink::KeyStatusType; using ::google::crypto::tink::KeyTemplate; using ::google::crypto::tink::OutputPrefixType; using ::portable_proto::MessageLite; using ::testing::Eq; using ::testing::HasSubstr; using ::testing::IsNull; using ::testing::Not; using ::testing::SizeIs; class RegistryTest : public ::testing::Test { protected: void SetUp() override { Registry::Reset(); } void TearDown() override { // Reset is needed here to ensure Mock objects get deleted and do not leak. Registry::Reset(); } }; class TestKeyFactory : public KeyFactory { public: explicit TestKeyFactory(const std::string& key_type) : key_type_(key_type) {} util::StatusOr> NewKey( const MessageLite& key_format) const override { return util::Status(absl::StatusCode::kUnknown, "TestKeyFactory cannot produce a key"); } util::StatusOr> NewKey( absl::string_view serialized_key_format) const override { return util::Status(absl::StatusCode::kUnknown, "TestKeyFactory cannot produce a key"); } util::StatusOr> NewKeyData( absl::string_view serialized_key_format) const override { auto key_data = absl::make_unique(); key_data->set_type_url(key_type_); key_data->set_value(std::string(serialized_key_format)); return std::move(key_data); } private: std::string key_type_; }; class TestAeadKeyManager : public KeyManager { public: explicit TestAeadKeyManager(const std::string& key_type) : key_type_(key_type), key_factory_(key_type) {} util::StatusOr> GetPrimitive( const KeyData& key) const override { std::unique_ptr aead(new DummyAead(key_type_)); return std::move(aead); } util::StatusOr> GetPrimitive( const MessageLite& key) const override { return util::Status(absl::StatusCode::kUnknown, "TestKeyFactory cannot construct an aead"); } uint32_t get_version() const override { return 0; } const std::string& get_key_type() const override { return key_type_; } const KeyFactory& get_key_factory() const override { return key_factory_; } private: std::string key_type_; TestKeyFactory key_factory_; }; // A class for testing. We will construct objects from an aead key, so that we // can check that a keymanager can handle multiple primitives. It is really // insecure, as it does nothing except provide access to the key. class AeadVariant { public: explicit AeadVariant(std::string s) : s_(s) {} std::string get() { return s_; } private: std::string s_; }; class ExampleKeyTypeManager : public KeyTypeManager> { public: class AeadFactory : public PrimitiveFactory { public: crypto::tink::util::StatusOr> Create( const AesGcmKey& key) const override { // Ignore the key and returned one with a fixed size for this test. return {subtle::AesGcmBoringSsl::New( util::SecretDataFromStringView(key.key_value()))}; } }; class AeadVariantFactory : public PrimitiveFactory { public: crypto::tink::util::StatusOr> Create( const AesGcmKey& key) const override { return absl::make_unique(key.key_value()); } }; ExampleKeyTypeManager() : KeyTypeManager(absl::make_unique(), absl::make_unique()) {} google::crypto::tink::KeyData::KeyMaterialType key_material_type() const override { return google::crypto::tink::KeyData::SYMMETRIC; } uint32_t get_version() const override { return kVersion; } const std::string& get_key_type() const override { return kKeyType; } crypto::tink::util::Status ValidateKey(const AesGcmKey& key) const override { return util::OkStatus(); } crypto::tink::util::Status ValidateKeyFormat( const AesGcmKeyFormat& key_format) const override { return util::OkStatus(); } crypto::tink::util::StatusOr CreateKey( const AesGcmKeyFormat& key_format) const override { AesGcmKey result; result.set_key_value(subtle::Random::GetRandomBytes(key_format.key_size())); return result; } crypto::tink::util::StatusOr DeriveKey( const AesGcmKeyFormat& key_format, InputStream* input_stream) const override { // Note: in an actual key type manager we need to do more work, e.g., test // that the generated key is long enough. crypto::tink::util::StatusOr randomness = ReadBytesFromStream(key_format.key_size(), input_stream); if (!randomness.status().ok()) { return randomness.status(); } AesGcmKey key; key.set_key_value(randomness.value()); return key; } MOCK_METHOD(FipsCompatibility, FipsStatus, (), (const, override)); private: static constexpr int kVersion = 0; const std::string kKeyType = "type.googleapis.com/google.crypto.tink.AesGcmKey"; }; template class TestWrapper : public PrimitiveWrapper { public: TestWrapper() = default; crypto::tink::util::StatusOr> Wrap( std::unique_ptr> primitive_set) const override { return util::Status(absl::StatusCode::kUnimplemented, "This is a test wrapper."); } }; class AeadVariantWrapper : public PrimitiveWrapper { public: crypto::tink::util::StatusOr> Wrap( std::unique_ptr> primitive_set) const override { return absl::make_unique( primitive_set->get_primary()->get_primitive().get()); } }; class AeadVariantToStringWrapper : public PrimitiveWrapper { public: crypto::tink::util::StatusOr> Wrap( std::unique_ptr> primitive_set) const override { return absl::make_unique( primitive_set->get_primary()->get_primitive().get()); } }; void register_test_managers(const std::string& key_type_prefix, int manager_count) { for (int i = 0; i < manager_count; i++) { std::string key_type = key_type_prefix + std::to_string(i); util::Status status = Registry::RegisterKeyManager( absl::make_unique(key_type), /* new_key_allowed= */ true); EXPECT_TRUE(status.ok()) << status; } } void verify_test_managers(const std::string& key_type_prefix, int manager_count) { for (int i = 0; i < manager_count; i++) { std::string key_type = key_type_prefix + std::to_string(i); auto manager_result = Registry::get_key_manager(key_type); EXPECT_TRUE(manager_result.ok()) << manager_result.status(); auto manager = manager_result.value(); EXPECT_EQ(key_type, manager->get_key_type()); } } TEST_F(RegistryTest, testRegisterKeyManagerMoreRestrictiveNewKeyAllowed) { std::string key_type = "some_key_type"; KeyTemplate key_template; key_template.set_type_url(key_type); // Register the key manager with new_key_allowed == true and verify that // new key data can be created. util::Status status = Registry::RegisterKeyManager( absl::make_unique(key_type), /* new_key_allowed= */ true); EXPECT_TRUE(status.ok()) << status; auto result_before = Registry::NewKeyData(key_template); EXPECT_TRUE(result_before.ok()) << result_before.status(); // Re-register the key manager with new_key_allowed == false and check the // restriction (i.e. new key data cannot be created). status = Registry::RegisterKeyManager( absl::make_unique(key_type), /* new_key_allowed= */ false); EXPECT_TRUE(status.ok()) << status; auto result_after = Registry::NewKeyData(key_template); EXPECT_FALSE(result_after.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, result_after.status().code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, key_type, std::string(result_after.status().message())); EXPECT_PRED_FORMAT2(testing::IsSubstring, "does not allow", std::string(result_after.status().message())); } TEST_F(RegistryTest, testRegisterKeyManagerLessRestrictiveNewKeyAllowed) { std::string key_type = "some_key_type"; KeyTemplate key_template; key_template.set_type_url(key_type); // Register the key manager with new_key_allowed == false. util::Status status = Registry::RegisterKeyManager( absl::make_unique(key_type), /* new_key_allowed= */ false); EXPECT_TRUE(status.ok()) << status; // Verify that re-registering the key manager with new_key_allowed == true is // not possible and that the restriction still holds after that operation // (i.e. new key data cannot be created). status = Registry::RegisterKeyManager( absl::make_unique(key_type), /* new_key_allowed= */ true); EXPECT_FALSE(status.ok()); EXPECT_EQ(absl::StatusCode::kAlreadyExists, status.code()) << status; EXPECT_PRED_FORMAT2(testing::IsSubstring, key_type, std::string(status.message())) << status; EXPECT_PRED_FORMAT2(testing::IsSubstring, "forbidden new key operation", std::string(status.message())) << status; auto result_after = Registry::NewKeyData(key_template); EXPECT_FALSE(result_after.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, result_after.status().code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, key_type, std::string(result_after.status().message())); EXPECT_PRED_FORMAT2(testing::IsSubstring, "does not allow", std::string(result_after.status().message())); } TEST_F(RegistryTest, testConcurrentRegistration) { std::string key_type_prefix_a = "key_type_a_"; std::string key_type_prefix_b = "key_type_b_"; int count_a = 42; int count_b = 72; // Register some managers. std::thread register_a(register_test_managers, key_type_prefix_a, count_a); std::thread register_b(register_test_managers, key_type_prefix_b, count_b); register_a.join(); register_b.join(); // Check that the managers were registered. Also, keep registering new // versions while we check. std::thread register_more_a(register_test_managers, key_type_prefix_a, count_a); std::thread register_more_b(register_test_managers, key_type_prefix_b, count_b); std::thread verify_a(verify_test_managers, key_type_prefix_a, count_a); std::thread verify_b(verify_test_managers, key_type_prefix_b, count_b); verify_a.join(); verify_b.join(); register_more_a.join(); register_more_b.join(); // Check that there are no extra managers. std::string key_type = key_type_prefix_a + std::to_string(count_a - 1); auto manager_result = Registry::get_key_manager(key_type); EXPECT_TRUE(manager_result.ok()) << manager_result.status(); EXPECT_EQ(key_type, manager_result.value()->get_key_type()); key_type = key_type_prefix_a + std::to_string(count_a); manager_result = Registry::get_key_manager(key_type); EXPECT_FALSE(manager_result.ok()); EXPECT_EQ(absl::StatusCode::kNotFound, manager_result.status().code()); } TEST_F(RegistryTest, testBasic) { std::string key_type_1 = "google.crypto.tink.AesCtrHmacAeadKey"; std::string key_type_2 = "google.crypto.tink.AesGcmKey"; auto manager_result = Registry::get_key_manager(key_type_1); EXPECT_FALSE(manager_result.ok()); EXPECT_EQ(absl::StatusCode::kNotFound, manager_result.status().code()); auto status = Registry::RegisterKeyManager( absl::make_unique(key_type_1), true); EXPECT_TRUE(status.ok()) << status; status = Registry::RegisterKeyManager( absl::make_unique(key_type_2), true); EXPECT_TRUE(status.ok()) << status; manager_result = Registry::get_key_manager(key_type_1); EXPECT_TRUE(manager_result.ok()) << manager_result.status(); auto manager = manager_result.value(); EXPECT_TRUE(manager->DoesSupport(key_type_1)); EXPECT_FALSE(manager->DoesSupport(key_type_2)); manager_result = Registry::get_key_manager(key_type_2); EXPECT_TRUE(manager_result.ok()) << manager_result.status(); manager = manager_result.value(); EXPECT_TRUE(manager->DoesSupport(key_type_2)); EXPECT_FALSE(manager->DoesSupport(key_type_1)); } TEST_F(RegistryTest, testRegisterKeyManager) { std::string key_type_1 = AesGcmKeyManager().get_key_type(); std::unique_ptr null_key_manager = nullptr; auto status = Registry::RegisterKeyManager(std::move(null_key_manager), true); EXPECT_FALSE(status.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code()) << status; // Register a key manager. status = Registry::RegisterKeyManager( absl::make_unique(key_type_1), true); EXPECT_TRUE(status.ok()) << status; // Register the same key manager again, it should work (idempotence). status = Registry::RegisterKeyManager( absl::make_unique(key_type_1), true); EXPECT_TRUE(status.ok()) << status; // Try overriding a key manager. AesGcmKeyManager key_type_manager; status = Registry::RegisterKeyManager( crypto::tink::internal::MakeKeyManager(&key_type_manager), true); EXPECT_FALSE(status.ok()); EXPECT_EQ(absl::StatusCode::kAlreadyExists, status.code()) << status; // Check the key manager is still registered. auto manager_result = Registry::get_key_manager(key_type_1); EXPECT_TRUE(manager_result.ok()) << manager_result.status(); auto manager = manager_result.value(); EXPECT_TRUE(manager->DoesSupport(key_type_1)); } // Tests that if we register a key manager once more after a call to // get_key_manager, the key manager previously obtained with "get_key_manager()" // remains valid. TEST_F(RegistryTest, GetKeyManagerRemainsValid) { std::string key_type = AesGcmKeyManager().get_key_type(); EXPECT_THAT(Registry::RegisterKeyManager( absl::make_unique(key_type), true), IsOk()); crypto::tink::util::StatusOr*> key_manager = Registry::get_key_manager(key_type); ASSERT_THAT(key_manager, IsOk()); EXPECT_THAT(Registry::RegisterKeyManager( absl::make_unique(key_type), true), IsOk()); EXPECT_THAT(key_manager.value()->get_key_type(), Eq(key_type)); } TEST_F(RegistryTest, testGettingPrimitives) { std::string key_type_1 = "google.crypto.tink.AesCtrHmacAeadKey"; std::string key_type_2 = "google.crypto.tink.AesGcmKey"; AesCtrHmacAeadKey dummy_key_1; AesGcmKey dummy_key_2; // Prepare keyset. Keyset keyset; uint32_t key_id_1 = 1234543; AddTinkKey(key_type_1, key_id_1, dummy_key_1, KeyStatusType::ENABLED, KeyData::SYMMETRIC, &keyset); uint32_t key_id_2 = 726329; AddTinkKey(key_type_2, key_id_2, dummy_key_2, KeyStatusType::DISABLED, KeyData::SYMMETRIC, &keyset); uint32_t key_id_3 = 7213743; AddLegacyKey(key_type_2, key_id_3, dummy_key_2, KeyStatusType::ENABLED, KeyData::SYMMETRIC, &keyset); uint32_t key_id_4 = 6268492; AddRawKey(key_type_1, key_id_4, dummy_key_1, KeyStatusType::ENABLED, KeyData::SYMMETRIC, &keyset); uint32_t key_id_5 = 42; AddRawKey(key_type_2, key_id_5, dummy_key_2, KeyStatusType::ENABLED, KeyData::SYMMETRIC, &keyset); keyset.set_primary_key_id(key_id_3); // Register key managers. util::Status status; status = Registry::RegisterKeyManager( absl::make_unique(key_type_1), true); EXPECT_TRUE(status.ok()) << status; status = Registry::RegisterKeyManager( absl::make_unique(key_type_2), true); EXPECT_TRUE(status.ok()) << status; // Get and use primitives. std::string plaintext = "some data"; std::string aad = "aad"; // Key #1. { auto result = Registry::GetPrimitive(keyset.key(0).key_data()); EXPECT_TRUE(result.ok()) << result.status(); auto aead = std::move(result.value()); EXPECT_EQ(DummyAead(key_type_1).Encrypt(plaintext, aad).value(), aead->Encrypt(plaintext, aad).value()); } // Key #3. { auto result = Registry::GetPrimitive(keyset.key(2).key_data()); EXPECT_TRUE(result.ok()) << result.status(); auto aead = std::move(result.value()); EXPECT_EQ(DummyAead(key_type_2).Encrypt(plaintext, aad).value(), aead->Encrypt(plaintext, aad).value()); } } TEST_F(RegistryTest, testNewKeyData) { std::string key_type_1 = "google.crypto.tink.AesCtrHmacAeadKey"; std::string key_type_2 = "google.crypto.tink.AesGcmKey"; std::string key_type_3 = "yet/another/keytype"; // Register key managers. util::Status status; status = Registry::RegisterKeyManager( absl::make_unique(key_type_1), /*new_key_allowed=*/true); EXPECT_TRUE(status.ok()) << status; status = Registry::RegisterKeyManager( absl::make_unique(key_type_2), /*new_key_allowed=*/true); EXPECT_TRUE(status.ok()) << status; status = Registry::RegisterKeyManager( absl::make_unique(key_type_3), /*new_key_allowed=*/false); EXPECT_TRUE(status.ok()) << status; { // A supported key type. KeyTemplate key_template; key_template.set_type_url(key_type_1); key_template.set_value("test value 42"); auto new_key_data_result = Registry::NewKeyData(key_template); EXPECT_TRUE(new_key_data_result.ok()) << new_key_data_result.status(); EXPECT_EQ(key_type_1, new_key_data_result.value()->type_url()); EXPECT_EQ(key_template.value(), new_key_data_result.value()->value()); } { // Another supported key type. KeyTemplate key_template; key_template.set_type_url(key_type_2); key_template.set_value("yet another test value 42"); auto new_key_data_result = Registry::NewKeyData(key_template); EXPECT_TRUE(new_key_data_result.ok()) << new_key_data_result.status(); EXPECT_EQ(key_type_2, new_key_data_result.value()->type_url()); EXPECT_EQ(key_template.value(), new_key_data_result.value()->value()); } { // A key type that does not allow NewKey-operations. KeyTemplate key_template; key_template.set_type_url(key_type_3); key_template.set_value("some other value 72"); auto new_key_data_result = Registry::NewKeyData(key_template); EXPECT_FALSE(new_key_data_result.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, new_key_data_result.status().code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, key_type_3, std::string(new_key_data_result.status().message())); EXPECT_PRED_FORMAT2(testing::IsSubstring, "does not allow", std::string(new_key_data_result.status().message())); } { // A key type that is not supported. KeyTemplate key_template; std::string bad_type_url = "some key type that is not supported"; key_template.set_type_url(bad_type_url); key_template.set_value("some totally other value 42"); auto new_key_data_result = Registry::NewKeyData(key_template); EXPECT_FALSE(new_key_data_result.ok()); EXPECT_EQ(absl::StatusCode::kNotFound, new_key_data_result.status().code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, bad_type_url, std::string(new_key_data_result.status().message())); } } TEST_F(RegistryTest, testGetPublicKeyData) { // Setup the registry. Registry::Reset(); auto private_key_type_manager = absl::make_unique(); auto public_key_type_manager = absl::make_unique(); auto status = Registry::RegisterKeyManager( internal::MakePrivateKeyManager( private_key_type_manager.get(), public_key_type_manager.get()), true); ASSERT_TRUE(status.ok()) << status; AesGcmKeyManager key_type_manager; status = Registry::RegisterKeyManager( crypto::tink::internal::MakeKeyManager(&key_type_manager), true); ASSERT_TRUE(status.ok()) << status; // Get a test private key. auto ecies_key = test::GetEciesAesGcmHkdfTestKey( EllipticCurveType::NIST_P256, EcPointFormat::UNCOMPRESSED, HashType::SHA256, /* aes_gcm_key_size= */ 24); // Extract public key data and check. auto public_key_data_result = Registry::GetPublicKeyData( EciesAeadHkdfPrivateKeyManager().get_key_type(), ecies_key.SerializeAsString()); EXPECT_TRUE(public_key_data_result.ok()) << public_key_data_result.status(); auto public_key_data = std::move(public_key_data_result.value()); EXPECT_EQ(EciesAeadHkdfPublicKeyManager().get_key_type(), public_key_data->type_url()); EXPECT_EQ(KeyData::ASYMMETRIC_PUBLIC, public_key_data->key_material_type()); EXPECT_EQ(ecies_key.public_key().SerializeAsString(), public_key_data->value()); // Try with a wrong key type. auto wrong_key_type_result = Registry::GetPublicKeyData( AesGcmKeyManager().get_key_type(), ecies_key.SerializeAsString()); EXPECT_FALSE(wrong_key_type_result.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, wrong_key_type_result.status().code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "PrivateKeyFactory", std::string(wrong_key_type_result.status().message())); // Try with a bad serialized key. auto bad_key_result = Registry::GetPublicKeyData( EciesAeadHkdfPrivateKeyManager().get_key_type(), "some bad serialized key"); EXPECT_FALSE(bad_key_result.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, bad_key_result.status().code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "Could not parse", std::string(bad_key_result.status().message())); } // Tests that if we register the same type of wrapper twice, the second call // succeeds. TEST_F(RegistryTest, RegisterWrapperTwice) { EXPECT_TRUE( Registry::RegisterPrimitiveWrapper(absl::make_unique()) .ok()); EXPECT_TRUE( Registry::RegisterPrimitiveWrapper(absl::make_unique()) .ok()); } // Tests that if we register the same type of wrapper twice, the second call // succeeds. TEST_F(RegistryTest, RegisterTransformingWrapperTwice) { EXPECT_TRUE(Registry::RegisterPrimitiveWrapper( absl::make_unique()) .ok()); EXPECT_TRUE(Registry::RegisterPrimitiveWrapper( absl::make_unique()) .ok()); } // Test that if we register a second wrapper, wrapping to the same type as a // previous wrapper it will fail. TEST_F(RegistryTest, RegisterTransformingWrapperTwiceMixing) { EXPECT_TRUE(Registry::RegisterPrimitiveWrapper( absl::make_unique()) .ok()); // We cannot register a different wrapper creating a std::string. EXPECT_THAT(Registry::RegisterPrimitiveWrapper( absl::make_unique>()), Not(IsOk())); // But one creating an Aead. EXPECT_THAT(Registry::RegisterPrimitiveWrapper( absl::make_unique>()), IsOk()); } // Test that if we register a second wrapper, wrapping to the same type as a // previous wrapper it will fail (order swapped). TEST_F(RegistryTest, RegisterTransformingWrapperTwiceMixingBackwards) { EXPECT_THAT(Registry::RegisterPrimitiveWrapper( absl::make_unique>()), IsOk()); // We cannot register another wrapper producing strings. EXPECT_THAT(Registry::RegisterPrimitiveWrapper( absl::make_unique()), Not(IsOk())); } // Tests that if we register different wrappers for the same primitive twice, // the second call fails. TEST_F(RegistryTest, RegisterDifferentWrappers) { EXPECT_TRUE( Registry::RegisterPrimitiveWrapper(absl::make_unique()) .ok()); util::Status result = Registry::RegisterPrimitiveWrapper( absl::make_unique>()); EXPECT_FALSE(result.ok()); EXPECT_EQ(absl::StatusCode::kAlreadyExists, result.code()); } // Tests that if we register different wrappers for different primitives, this // returns ok. TEST_F(RegistryTest, RegisterDifferentWrappersDifferentPrimitives) { EXPECT_TRUE( Registry::RegisterPrimitiveWrapper(absl::make_unique>()) .ok()); EXPECT_TRUE( Registry::RegisterPrimitiveWrapper(absl::make_unique>()) .ok()); } // Tests that if we do not register a wrapper, then calls to Wrap // fail with "No wrapper registered" -- even if there is a wrapper for a // different primitive registered. TEST_F(RegistryTest, NoWrapperRegistered) { EXPECT_TRUE( Registry::RegisterPrimitiveWrapper(absl::make_unique>()) .ok()); crypto::tink::util::StatusOr> result = Registry::Wrap(absl::make_unique>()); EXPECT_FALSE(result.ok()); EXPECT_EQ(absl::StatusCode::kNotFound, result.status().code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "No wrapper registered", std::string(result.status().message())); } // Tests that if the wrapper fails, the error of the wrapped is forwarded // in GetWrappedPrimitive. TEST_F(RegistryTest, WrapperFails) { EXPECT_TRUE( Registry::RegisterPrimitiveWrapper(absl::make_unique>()) .ok()); crypto::tink::util::StatusOr> result = Registry::Wrap(absl::make_unique>()); EXPECT_FALSE(result.ok()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "This is a test wrapper", std::string(result.status().message())); } // Tests that wrapping works as expected in the usual case. TEST_F(RegistryTest, UsualWrappingTest) { KeysetInfo keyset_info; keyset_info.add_key_info(); keyset_info.mutable_key_info(0)->set_output_prefix_type( OutputPrefixType::TINK); keyset_info.mutable_key_info(0)->set_key_id(1234543); keyset_info.mutable_key_info(0)->set_status(KeyStatusType::ENABLED); keyset_info.add_key_info(); keyset_info.mutable_key_info(1)->set_output_prefix_type( OutputPrefixType::LEGACY); keyset_info.mutable_key_info(1)->set_key_id(726329); keyset_info.mutable_key_info(1)->set_status(KeyStatusType::ENABLED); keyset_info.add_key_info(); keyset_info.mutable_key_info(2)->set_output_prefix_type( OutputPrefixType::TINK); keyset_info.mutable_key_info(2)->set_key_id(7213743); keyset_info.mutable_key_info(2)->set_status(KeyStatusType::ENABLED); auto primitive_set = absl::make_unique>(); ASSERT_TRUE(primitive_set ->AddPrimitive(absl::make_unique("aead0"), keyset_info.key_info(0)) .ok()); ASSERT_TRUE(primitive_set ->AddPrimitive(absl::make_unique("aead1"), keyset_info.key_info(1)) .ok()); auto entry_result = primitive_set->AddPrimitive( absl::make_unique("primary_aead"), keyset_info.key_info(2)); ASSERT_THAT(primitive_set->set_primary(entry_result.value()), IsOk()); EXPECT_TRUE( Registry::RegisterPrimitiveWrapper(absl::make_unique()) .ok()); auto aead_result = Registry::Wrap(std::move(primitive_set)); EXPECT_TRUE(aead_result.ok()) << aead_result.status(); std::unique_ptr aead = std::move(aead_result.value()); std::string plaintext = "some_plaintext"; std::string aad = "some_aad"; auto encrypt_result = aead->Encrypt(plaintext, aad); EXPECT_TRUE(encrypt_result.ok()) << encrypt_result.status(); std::string ciphertext = encrypt_result.value(); EXPECT_PRED_FORMAT2(testing::IsSubstring, "primary_aead", ciphertext); auto decrypt_result = aead->Decrypt(ciphertext, aad); EXPECT_TRUE(decrypt_result.ok()) << decrypt_result.status(); EXPECT_EQ(plaintext, decrypt_result.value()); decrypt_result = aead->Decrypt("some bad ciphertext", aad); EXPECT_FALSE(decrypt_result.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, decrypt_result.status().code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "decryption failed", std::string(decrypt_result.status().message())); } std::string AddAesGcmKey(uint32_t key_id, OutputPrefixType output_prefix_type, KeyStatusType key_status_type, Keyset& modified_keyset) { AesGcmKey key; key.set_version(0); key.set_key_value(subtle::Random::GetRandomBytes(16)); KeyData key_data; key_data.set_value(key.SerializeAsString()); key_data.set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey"); test::AddKeyData(key_data, key_id, output_prefix_type, key_status_type, &modified_keyset); return key.key_value(); } // Tests that wrapping of a keyset works in the usual case. TEST_F(RegistryTest, KeysetWrappingTest) { if (!IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported when BoringSSL is not built in FIPS-mode."; } Keyset keyset; std::string raw_key = AddAesGcmKey(13, OutputPrefixType::TINK, KeyStatusType::ENABLED, keyset); keyset.set_primary_key_id(13); auto fips_key_manager = absl::make_unique(); ON_CALL(*fips_key_manager, FipsStatus()) .WillByDefault(testing::Return(FipsCompatibility::kRequiresBoringCrypto)); ASSERT_THAT( Registry::RegisterKeyTypeManager(std::move(fips_key_manager), true), IsOk()); ASSERT_THAT(Registry::RegisterPrimitiveWrapper( absl::make_unique()), IsOk()); crypto::tink::util::StatusOr> aead_variant = RegistryImpl::GlobalInstance().WrapKeyset( keyset, /*annotations=*/{}); EXPECT_THAT(aead_variant, IsOk()); EXPECT_THAT(aead_variant.value()->get(), Eq(raw_key)); } // Tests that wrapping of a keyset works. TEST_F(RegistryTest, TransformingKeysetWrappingTest) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } Keyset keyset; std::string raw_key = AddAesGcmKey(13, OutputPrefixType::TINK, KeyStatusType::ENABLED, keyset); keyset.set_primary_key_id(13); ASSERT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); ASSERT_THAT(Registry::RegisterPrimitiveWrapper( absl::make_unique()), IsOk()); crypto::tink::util::StatusOr> string_primitive = RegistryImpl::GlobalInstance().WrapKeyset( keyset, /*annotations=*/{}); EXPECT_THAT(string_primitive, IsOk()); EXPECT_THAT(*string_primitive.value(), Eq(raw_key)); } // Tests that when we ask the registry to wrap a PrimitiveSet into an // Aead, but the wrapper is in fact from something else into Aead, we give a // correct error message. TEST_F(RegistryTest, TransformingPrimitiveWrapperCustomKeyManager) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } ASSERT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); // Register a transforming wrapper taking strings and making Aeads. ASSERT_THAT(Registry::RegisterPrimitiveWrapper( absl::make_unique>()), IsOk()); KeysetInfo keyset_info; keyset_info.add_key_info(); keyset_info.mutable_key_info(0)->set_output_prefix_type( OutputPrefixType::TINK); keyset_info.mutable_key_info(0)->set_key_id(1234543); keyset_info.mutable_key_info(0)->set_status(KeyStatusType::ENABLED); keyset_info.set_primary_key_id(1234543); auto primitive_set = absl::make_unique>(); ASSERT_TRUE(primitive_set ->AddPrimitive(absl::make_unique("aead0"), keyset_info.key_info(0)) .ok()); EXPECT_THAT(Registry::Wrap(std::move(primitive_set)).status(), StatusIs(absl::StatusCode::kFailedPrecondition, HasSubstr("custom key manager"))); } // Tests that the error message in GetKeyManager contains the type_id.name() of // the primitive for which the key manager was actually registered. TEST_F(RegistryTest, GetKeyManagerErrorMessage) { AesGcmKeyManager key_type_manager; EXPECT_TRUE( Registry::RegisterKeyManager( crypto::tink::internal::MakeKeyManager(&key_type_manager), true) .ok()); auto result = Registry::get_key_manager(AesGcmKeyManager().get_key_type()); EXPECT_FALSE(result.ok()); EXPECT_THAT(std::string(result.status().message()), HasSubstr(AesGcmKeyManager().get_key_type())); // Note: The C++ standard does not guarantee the next line. If some toolchain // update fails it, one can delete it. EXPECT_THAT(std::string(result.status().message()), HasSubstr(typeid(Aead).name())); } TEST_F(RegistryTest, RegisterKeyTypeManager) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); } TEST_F(RegistryTest, RegisterFipsKeyTypeManager) { if (!kUseOnlyFips || !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Only supported in FIPS-mode with BoringCrypto available."; } auto fips_key_manager = absl::make_unique(); ON_CALL(*fips_key_manager, FipsStatus()) .WillByDefault(testing::Return(FipsCompatibility::kRequiresBoringCrypto)); EXPECT_THAT( Registry::RegisterKeyTypeManager(std::move(fips_key_manager), true), IsOk()); } TEST_F(RegistryTest, RegisterFipsKeyTypeManagerNoBoringCrypto) { if (!kUseOnlyFips || IsFipsEnabledInSsl()) { GTEST_SKIP() << "Only supported in FIPS-mode with BoringCrypto not available."; } auto fips_key_manager = absl::make_unique(); ON_CALL(*fips_key_manager, FipsStatus()) .WillByDefault(testing::Return(FipsCompatibility::kNotFips)); EXPECT_THAT( Registry::RegisterKeyTypeManager(std::move(fips_key_manager), true), StatusIs(absl::StatusCode::kInternal)); } TEST_F(RegistryTest, KeyTypeManagerGetFirstKeyManager) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); AesGcmKeyFormat format; format.set_key_size(16); AesGcmKey key = ExampleKeyTypeManager().CreateKey(format).value(); auto aead = Registry::get_key_manager( "type.googleapis.com/google.crypto.tink.AesGcmKey") .value() ->GetPrimitive(key) .value(); std::string encryption = aead->Encrypt("TESTMESSAGE", "").value(); std::string decryption = aead->Decrypt(encryption, "").value(); EXPECT_THAT(decryption, Eq("TESTMESSAGE")); } TEST_F(RegistryTest, KeyTypeManagerGetSecondKeyManager) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); AesGcmKeyFormat format; format.set_key_size(16); AesGcmKey key = ExampleKeyTypeManager().CreateKey(format).value(); auto aead_variant = Registry::get_key_manager( "type.googleapis.com/google.crypto.tink.AesGcmKey") .value() ->GetPrimitive(key) .value(); EXPECT_THAT(aead_variant->get(), Eq(key.key_value())); } TEST_F(RegistryTest, KeyTypeManagerNotSupportedPrimitive) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); EXPECT_THAT(Registry::get_key_manager( "type.googleapis.com/google.crypto.tink.AesGcmKey") .status(), StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("not among supported primitives"))); } // Tests that if we register a key manager once more after a call to // get_key_manager, the key manager previously obtained with "get_key_manager()" // remains valid. TEST_F(RegistryTest, GetKeyManagerRemainsValidForKeyTypeManagers) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); crypto::tink::util::StatusOr*> key_manager = Registry::get_key_manager(ExampleKeyTypeManager().get_key_type()); ASSERT_THAT(key_manager, IsOk()); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); EXPECT_THAT(key_manager.value()->get_key_type(), Eq(ExampleKeyTypeManager().get_key_type())); } TEST_F(RegistryTest, KeyTypeManagerNewKey) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); AesGcmKeyFormat format; format.set_key_size(32); KeyTemplate key_template; key_template.set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey"); key_template.set_value(format.SerializeAsString()); KeyData key_data = *Registry::NewKeyData(key_template).value(); EXPECT_THAT(key_data.type_url(), Eq("type.googleapis.com/google.crypto.tink.AesGcmKey")); EXPECT_THAT(key_data.key_material_type(), Eq(google::crypto::tink::KeyData::SYMMETRIC)); AesGcmKey key; key.ParseFromString(key_data.value()); EXPECT_THAT(key.key_value(), SizeIs(32)); } TEST_F(RegistryTest, KeyTypeManagerNewKeyInvalidSize) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); AesGcmKeyFormat format; format.set_key_size(33); KeyTemplate key_template; key_template.set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey"); key_template.set_value(format.SerializeAsString()); EXPECT_THAT(Registry::NewKeyData(key_template), IsOk()); } TEST_F(RegistryTest, KeyTypeManagerDeriveKey) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); AesGcmKeyFormat format; format.set_key_size(32); KeyTemplate key_template; key_template.set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey"); key_template.set_value(format.SerializeAsString()); crypto::tink::util::IstreamInputStream input_stream{ absl::make_unique( "0123456789012345678901234567890123456789")}; auto key_data_or = RegistryImpl::GlobalInstance().DeriveKey(key_template, &input_stream); ASSERT_THAT(key_data_or, IsOk()); EXPECT_THAT(key_data_or.value().type_url(), Eq(key_template.type_url())); AesGcmKey key; EXPECT_TRUE(key.ParseFromString(key_data_or.value().value())); // 32 byte prefix of above string. EXPECT_THAT(key.key_value(), Eq("01234567890123456789012345678901")); } // The same, but we register the key manager twice. This should catch some of // the possible lifetime issues. TEST_F(RegistryTest, KeyTypeManagerDeriveKeyRegisterTwice) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); AesGcmKeyFormat format; format.set_key_size(32); KeyTemplate key_template; key_template.set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey"); key_template.set_value(format.SerializeAsString()); crypto::tink::util::IstreamInputStream input_stream{ absl::make_unique( "0123456789012345678901234567890123456789")}; auto key_data_or = RegistryImpl::GlobalInstance().DeriveKey(key_template, &input_stream); ASSERT_THAT(key_data_or, IsOk()); EXPECT_THAT(key_data_or.value().type_url(), Eq(key_template.type_url())); AesGcmKey key; EXPECT_TRUE(key.ParseFromString(key_data_or.value().value())); // 32 byte prefix of above string. EXPECT_THAT(key.key_value(), Eq("01234567890123456789012345678901")); } // Tests that if we register a KeyManager instead of a KeyTypeManager, DeriveKey // fails properly. TEST_F(RegistryTest, KeyManagerDeriveKeyFail) { std::string key_type = "type.googleapis.com/google.crypto.tink.AesGcmKey"; ASSERT_THAT(Registry::RegisterKeyManager( absl::make_unique(key_type), /* new_key_allowed= */ true), IsOk()); KeyTemplate key_template; key_template.set_type_url("type.googleapis.com/google.crypto.tink.AesGcmKey"); EXPECT_THAT( RegistryImpl::GlobalInstance().DeriveKey(key_template, nullptr).status(), StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("cannot derive"))); } TEST_F(RegistryTest, KeyManagerDeriveNotRegistered) { KeyTemplate key_template; key_template.set_type_url("some_inexistent_keytype"); EXPECT_THAT( RegistryImpl::GlobalInstance().DeriveKey(key_template, nullptr).status(), StatusIs(absl::StatusCode::kNotFound, HasSubstr("No manager"))); } TEST_F(RegistryTest, RegisterKeyTypeManagerTwiceMoreRestrictive) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), false), IsOk()); } TEST_F(RegistryTest, RegisterKeyTypeManagerTwice) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), false), IsOk()); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), false), IsOk()); } TEST_F(RegistryTest, RegisterKeyTypeManagerLessRestrictive) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), false), IsOk()); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), StatusIs(absl::StatusCode::kAlreadyExists)); } TEST_F(RegistryTest, RegisterKeyTypeManagerBeforeKeyManager) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), IsOk()); EXPECT_THAT(Registry::RegisterKeyManager( absl::make_unique( "type.googleapis.com/google.crypto.tink.AesGcmKey"), true), StatusIs(absl::StatusCode::kAlreadyExists)); } TEST_F(RegistryTest, RegisterKeyTypeManagerAfterKeyManager) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } EXPECT_THAT(Registry::RegisterKeyManager( absl::make_unique( "type.googleapis.com/google.crypto.tink.AesGcmKey"), true), IsOk()); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), StatusIs(absl::StatusCode::kAlreadyExists)); } } // namespace // NOTE: These are outside of the anonymous namespace to allow compiling with // MSVC. class PrivatePrimitiveA {}; class PrivatePrimitiveB {}; namespace { class TestPrivateKeyTypeManager : public PrivateKeyTypeManager> { public: class PrivatePrimitiveAFactory : public PrimitiveFactory { public: crypto::tink::util::StatusOr> Create( const EcdsaPrivateKey& key) const override { return util::Status(absl::StatusCode::kUnimplemented, "Not implemented"); } }; class PrivatePrimitiveBFactory : public PrimitiveFactory { public: crypto::tink::util::StatusOr> Create( const EcdsaPrivateKey& key) const override { return util::Status(absl::StatusCode::kUnimplemented, "Not implemented"); } }; TestPrivateKeyTypeManager() : PrivateKeyTypeManager(absl::make_unique(), absl::make_unique()) {} google::crypto::tink::KeyData::KeyMaterialType key_material_type() const override { return google::crypto::tink::KeyData::ASYMMETRIC_PRIVATE; } uint32_t get_version() const override { return 0; } crypto::tink::util::Status ValidateKey( const EcdsaPrivateKey& key) const override { return crypto::tink::util::OkStatus(); } crypto::tink::util::Status ValidateKeyFormat( const EcdsaKeyFormat& key) const override { return crypto::tink::util::OkStatus(); } const std::string& get_key_type() const override { return kKeyType; } crypto::tink::util::StatusOr CreateKey( const EcdsaKeyFormat& key_format) const override { EcdsaPublicKey public_key; *public_key.mutable_params() = key_format.params(); EcdsaPrivateKey result; *result.mutable_public_key() = public_key; return result; } crypto::tink::util::StatusOr GetPublicKey( const EcdsaPrivateKey& private_key) const override { return private_key.public_key(); } MOCK_METHOD(FipsCompatibility, FipsStatus, (), (const, override)); private: const std::string kKeyType = "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"; }; } // namespace // NOTE: These are outside of the anonymous namespace to allow compiling with // MSVC. class PublicPrimitiveA {}; class PublicPrimitiveB {}; namespace { class TestPublicKeyTypeManager : public KeyTypeManager> { public: class PublicPrimitiveAFactory : public PrimitiveFactory { public: crypto::tink::util::StatusOr> Create( const EcdsaPublicKey& key) const override { return util::Status(absl::StatusCode::kUnimplemented, "Not implemented"); } }; class PublicPrimitiveBFactory : public PrimitiveFactory { public: crypto::tink::util::StatusOr> Create( const EcdsaPublicKey& key) const override { return util::Status(absl::StatusCode::kUnimplemented, "Not implemented"); } }; TestPublicKeyTypeManager() : KeyTypeManager(absl::make_unique(), absl::make_unique()) {} google::crypto::tink::KeyData::KeyMaterialType key_material_type() const override { return google::crypto::tink::KeyData::ASYMMETRIC_PRIVATE; } uint32_t get_version() const override { return 0; } crypto::tink::util::Status ValidateKey( const EcdsaPublicKey& key) const override { return crypto::tink::util::OkStatus(); } const std::string& get_key_type() const override { return kKeyType; } MOCK_METHOD(FipsCompatibility, FipsStatus, (), (const, override)); private: const std::string kKeyType = "type.googleapis.com/google.crypto.tink.EcdsaPublicKey"; }; std::unique_ptr CreateTestPrivateKeyManagerFipsCompatible() { auto private_key_manager = absl::make_unique(); ON_CALL(*private_key_manager, FipsStatus()) .WillByDefault(testing::Return(FipsCompatibility::kRequiresBoringCrypto)); return private_key_manager; } std::unique_ptr CreateTestPublicKeyManagerFipsCompatible() { auto public_key_manager = absl::make_unique(); ON_CALL(*public_key_manager, FipsStatus()) .WillByDefault(testing::Return(FipsCompatibility::kRequiresBoringCrypto)); return public_key_manager; } TEST_F(RegistryTest, RegisterAsymmetricKeyManagers) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } crypto::tink::util::Status status = Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true); ASSERT_TRUE(status.ok()) << status; } TEST_F(RegistryTest, AsymmetricMoreRestrictiveNewKey) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); crypto::tink::util::Status status = Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), false); ASSERT_TRUE(status.ok()) << status; } TEST_F(RegistryTest, AsymmetricSameNewKey) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); crypto::tink::util::Status status = Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true); ASSERT_TRUE(status.ok()) << status; ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), false) .ok()); status = Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), false); ASSERT_TRUE(status.ok()) << status; } TEST_F(RegistryTest, AsymmetricLessRestrictiveGivesError) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } crypto::tink::util::Status status = Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), false); ASSERT_TRUE(status.ok()) << status; EXPECT_THAT(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true), StatusIs(absl::StatusCode::kAlreadyExists, HasSubstr("forbidden new key operation"))); } // Tests that if we register asymmetric key managers once more after a call to // get_key_manager, the key manager previously obtained with "get_key_manager()" // remains valid. TEST_F(RegistryTest, RegisterAsymmetricKeyManagersGetKeyManagerStaysValid) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_THAT(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true), IsOk()); crypto::tink::util::StatusOr*> private_key_manager = Registry::get_key_manager( TestPrivateKeyTypeManager().get_key_type()); crypto::tink::util::StatusOr*> public_key_manager = Registry::get_key_manager( TestPublicKeyTypeManager().get_key_type()); ASSERT_THAT(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true), IsOk()); EXPECT_THAT(private_key_manager.value()->get_key_type(), Eq(TestPrivateKeyTypeManager().get_key_type())); EXPECT_THAT(public_key_manager.value()->get_key_type(), Eq(TestPublicKeyTypeManager().get_key_type())); } TEST_F(RegistryTest, AsymmetricPrivateRegisterAlone) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterKeyTypeManager( CreateTestPrivateKeyManagerFipsCompatible(), true) .ok()); ASSERT_TRUE(Registry::RegisterKeyTypeManager( CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); // Registering the same as asymmetric key managers must fail, because doing so // would mean we invalidate key managers previously obtained with // get_key_manager(). ASSERT_FALSE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); ASSERT_TRUE(Registry::RegisterKeyTypeManager( CreateTestPrivateKeyManagerFipsCompatible(), true) .ok()); ASSERT_TRUE(Registry::RegisterKeyTypeManager( CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); } TEST_F(RegistryTest, AsymmetricGetPrimitiveA) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); crypto::tink::util::StatusOr*> km = Registry::get_key_manager( TestPrivateKeyTypeManager().get_key_type()); ASSERT_TRUE(km.ok()) << km.status(); EXPECT_THAT(km.value()->get_key_type(), Eq(TestPrivateKeyTypeManager().get_key_type())); } TEST_F(RegistryTest, AsymmetricGetPrimitiveB) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); crypto::tink::util::StatusOr*> km = Registry::get_key_manager( TestPrivateKeyTypeManager().get_key_type()); ASSERT_TRUE(km.ok()) << km.status(); EXPECT_THAT(km.value()->get_key_type(), Eq(TestPrivateKeyTypeManager().get_key_type())); } TEST_F(RegistryTest, AsymmetricGetPublicPrimitiveA) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); crypto::tink::util::StatusOr*> km = Registry::get_key_manager( TestPublicKeyTypeManager().get_key_type()); ASSERT_TRUE(km.ok()) << km.status(); EXPECT_THAT(km.value()->get_key_type(), Eq(TestPublicKeyTypeManager().get_key_type())); } TEST_F(RegistryTest, AsymmetricGetPublicPrimitiveB) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); crypto::tink::util::StatusOr*> km = Registry::get_key_manager( TestPublicKeyTypeManager().get_key_type()); ASSERT_TRUE(km.ok()) << km.status(); EXPECT_THAT(km.value()->get_key_type(), Eq(TestPublicKeyTypeManager().get_key_type())); } TEST_F(RegistryTest, AsymmetricGetWrongPrimitiveError) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); crypto::tink::util::StatusOr*> km = Registry::get_key_manager( TestPrivateKeyTypeManager().get_key_type()); EXPECT_THAT(km.status(), StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("not among supported primitives"))); } class PrivateKeyManagerImplTest : public testing::Test { void SetUp() override { Registry::Reset(); } void TearDown() override { // Reset is needed here to ensure Mock objects get deleted and do not leak. Registry::Reset(); } }; TEST_F(PrivateKeyManagerImplTest, AsymmetricFactoryNewKeyFromMessage) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); EcdsaKeyFormat key_format; key_format.mutable_params()->set_encoding(EcdsaSignatureEncoding::DER); KeyTemplate key_template; key_template.set_type_url(TestPrivateKeyTypeManager().get_key_type()); key_template.set_value(key_format.SerializeAsString()); key_template.set_output_prefix_type(OutputPrefixType::TINK); std::unique_ptr key_data = Registry::NewKeyData(key_template).value(); EXPECT_THAT(key_data->type_url(), Eq(TestPrivateKeyTypeManager().get_key_type())); EcdsaPrivateKey private_key; private_key.ParseFromString(key_data->value()); EXPECT_THAT(private_key.public_key().params().encoding(), Eq(EcdsaSignatureEncoding::DER)); } TEST_F(PrivateKeyManagerImplTest, AsymmetricNewKeyDisallowed) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true) .ok()); ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), false) .ok()); KeyTemplate key_template; key_template.set_type_url(TestPrivateKeyTypeManager().get_key_type()); EXPECT_THAT( Registry::NewKeyData(key_template).status(), StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("not allow"))); } TEST_F(RegistryTest, AsymmetricGetPublicKeyData) { if (kUseOnlyFips && !IsFipsEnabledInSsl()) { GTEST_SKIP() << "Not supported if FIPS-mode is used and BoringCrypto is " "not available"; } crypto::tink::util::Status status = Registry::RegisterAsymmetricKeyManagers( CreateTestPrivateKeyManagerFipsCompatible(), CreateTestPublicKeyManagerFipsCompatible(), true); EcdsaPrivateKey private_key; private_key.mutable_public_key()->mutable_params()->set_encoding( EcdsaSignatureEncoding::DER); std::unique_ptr key_data = Registry::GetPublicKeyData(TestPrivateKeyTypeManager().get_key_type(), private_key.SerializeAsString()) .value(); ASSERT_THAT(key_data->type_url(), Eq(TestPublicKeyTypeManager().get_key_type())); EcdsaPublicKey public_key; public_key.ParseFromString(key_data->value()); EXPECT_THAT(public_key.params().encoding(), Eq(EcdsaSignatureEncoding::DER)); } class TestPrivateKeyTypeManager2 : public TestPrivateKeyTypeManager {}; class TestPublicKeyTypeManager2 : public TestPublicKeyTypeManager {}; TEST_F(RegistryTest, RegisterAssymmetricReregistrationWithWrongClasses) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( absl::make_unique(), absl::make_unique(), true) .ok()); EXPECT_THAT(Registry::RegisterAsymmetricKeyManagers( absl::make_unique(), absl::make_unique(), true), StatusIs(absl::StatusCode::kAlreadyExists, HasSubstr("already registered"))); EXPECT_THAT(Registry::RegisterAsymmetricKeyManagers( absl::make_unique(), absl::make_unique(), true), StatusIs(absl::StatusCode::kAlreadyExists, HasSubstr("already registered"))); EXPECT_THAT(Registry::RegisterAsymmetricKeyManagers( absl::make_unique(), absl::make_unique(), true), StatusIs(absl::StatusCode::kAlreadyExists, HasSubstr("already registered"))); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), StatusIs(absl::StatusCode::kAlreadyExists, HasSubstr("already registered"))); EXPECT_THAT(Registry::RegisterKeyTypeManager( absl::make_unique(), true), StatusIs(absl::StatusCode::kAlreadyExists, HasSubstr("already registered"))); } class TestPublicKeyTypeManagerWithDifferentKeyType : public TestPublicKeyTypeManager { const std::string& get_key_type() const override { return kKeyType; } private: const std::string kKeyType = "bla"; }; TEST_F(RegistryTest, RegisterAssymmetricReregistrationWithNewKeyType) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } ASSERT_TRUE(Registry::RegisterAsymmetricKeyManagers( absl::make_unique(), absl::make_unique(), true) .ok()); EXPECT_THAT( Registry::RegisterAsymmetricKeyManagers( absl::make_unique(), absl::make_unique(), true), StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("impossible to register"))); } // The DelegatingKeyTypeManager calls the registry class DelegatingKeyTypeManager : public PrivateKeyTypeManager> { public: DelegatingKeyTypeManager() : PrivateKeyTypeManager() {} void set_registry(RegistryImpl* registry) { registry_ = registry; } google::crypto::tink::KeyData::KeyMaterialType key_material_type() const override { return google::crypto::tink::KeyData::SYMMETRIC; } uint32_t get_version() const override { return kVersion; } const std::string& get_key_type() const override { return kKeyType; } crypto::tink::util::Status ValidateKey( const EcdsaPrivateKey& key) const override { return util::OkStatus(); } crypto::tink::util::Status ValidateKeyFormat( const EcdsaKeyFormat& key_format) const override { return util::OkStatus(); } crypto::tink::util::StatusOr CreateKey( const EcdsaKeyFormat& key_format) const override { AesGcmKeyFormat format; KeyTemplate key_template; key_template.set_type_url( "type.googleapis.com/google.crypto.tink.AesGcmKey"); key_template.set_value(format.SerializeAsString()); auto result = registry_->NewKeyData(key_template); if (!result.ok()) return result.status(); // Return a string we can check for. return util::Status(absl::StatusCode::kDeadlineExceeded, "CreateKey worked"); } crypto::tink::util::StatusOr DeriveKey( const EcdsaKeyFormat& key_format, InputStream* input_stream) const override { AesGcmKeyFormat format; KeyTemplate key_template; key_template.set_type_url( "type.googleapis.com/google.crypto.tink.AesGcmKey"); key_template.set_value(format.SerializeAsString()); auto result = registry_->DeriveKey(key_template, input_stream); if (!result.ok()) return result.status(); // Return a string we can check for. return util::Status(absl::StatusCode::kDeadlineExceeded, "DeriveKey worked"); } crypto::tink::util::StatusOr GetPublicKey( const EcdsaPrivateKey& private_key) const override { AesGcmKeyFormat format; KeyTemplate key_template; key_template.set_type_url( "type.googleapis.com/google.crypto.tink.AesGcmKey"); key_template.set_value(format.SerializeAsString()); auto result = registry_->NewKeyData(key_template); if (!result.ok()) return result.status(); // Return a string we can check for. return util::Status(absl::StatusCode::kDeadlineExceeded, "GetPublicKey worked"); } private: RegistryImpl* registry_; static constexpr int kVersion = 0; const std::string kKeyType = "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"; }; class RegistryImplTest : public ::testing::Test { protected: void TearDown() override { // Calling RestrictToFipsIfEmpty() may call SetFipsRestricted(), which // set a global variable to true. We have to reset that after the test. UnSetFipsRestricted(); } }; // Check that we can call the registry again from within NewKeyData TEST_F(RegistryImplTest, CanDelegateCreateKey) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } RegistryImpl registry_impl; auto delegating_key_manager = absl::make_unique(); delegating_key_manager->set_registry(®istry_impl); auto status = registry_impl .RegisterKeyTypeManager>( std::move(delegating_key_manager), true); EXPECT_THAT(status, IsOk()); status = registry_impl.RegisterKeyTypeManager>( absl::make_unique(), true); EXPECT_THAT(status, IsOk()); EcdsaKeyFormat format; KeyTemplate key_template; key_template.set_type_url( "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"); key_template.set_value(format.SerializeAsString()); EXPECT_THAT(registry_impl.NewKeyData(key_template).status(), StatusIs(absl::StatusCode::kDeadlineExceeded, HasSubstr("CreateKey worked"))); } // Check that we can call the registry again from within NewKeyData TEST_F(RegistryImplTest, CanDelegateDeriveKey) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } RegistryImpl registry_impl; auto delegating_key_manager = absl::make_unique(); delegating_key_manager->set_registry(®istry_impl); auto status = registry_impl .RegisterKeyTypeManager>( std::move(delegating_key_manager), true); EXPECT_THAT(status, IsOk()); status = registry_impl.RegisterKeyTypeManager>( absl::make_unique(), true); EXPECT_THAT(status, IsOk()); EcdsaKeyFormat format; KeyTemplate key_template; key_template.set_type_url( "type.googleapis.com/google.crypto.tink.EcdsaPrivateKey"); key_template.set_value(format.SerializeAsString()); EXPECT_THAT(registry_impl.DeriveKey(key_template, nullptr).status(), StatusIs(absl::StatusCode::kDeadlineExceeded, HasSubstr("DeriveKey worked"))); } TEST_F(RegistryImplTest, CanDelegateGetPublicKey) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } RegistryImpl registry_impl; auto delegating_key_manager = absl::make_unique(); delegating_key_manager->set_registry(®istry_impl); auto status = registry_impl.RegisterAsymmetricKeyManagers( delegating_key_manager.release(), absl::make_unique().release(), true); EXPECT_THAT(status, IsOk()); status = registry_impl.RegisterKeyTypeManager>( absl::make_unique(), true); EXPECT_THAT(status, IsOk()); EcdsaPrivateKey private_key; private_key.mutable_public_key()->mutable_params()->set_encoding( EcdsaSignatureEncoding::DER); EXPECT_THAT(registry_impl .GetPublicKeyData(DelegatingKeyTypeManager().get_key_type(), private_key.SerializeAsString()) .status(), StatusIs(absl::StatusCode::kDeadlineExceeded, HasSubstr("GetPublicKey worked"))); } TEST_F(RegistryImplTest, FipsRestrictionSucceedsOnEmptyRegistry) { RegistryImpl registry_impl; EXPECT_THAT(registry_impl.RestrictToFipsIfEmpty(), IsOk()); } TEST_F(RegistryImplTest, FipsRestrictionSucceedsWhenSettingMultipleTimes) { RegistryImpl registry_impl; EXPECT_THAT(registry_impl.RestrictToFipsIfEmpty(), IsOk()); EXPECT_THAT(registry_impl.RestrictToFipsIfEmpty(), IsOk()); EXPECT_THAT(registry_impl.RestrictToFipsIfEmpty(), IsOk()); } TEST_F(RegistryImplTest, FipsRestrictionSucceedsIfBuildInFipsMode) { if (!kUseOnlyFips) { GTEST_SKIP() << "Not supported when Tink is not built in FIPS mode."; } RegistryImpl registry_impl; EXPECT_THAT(registry_impl.RestrictToFipsIfEmpty(), IsOk()); } TEST_F(RegistryImplTest, FipsFailsIfNotEmpty) { if (kUseOnlyFips) { GTEST_SKIP() << "Not supported in FIPS-only mode"; } auto fips_key_manager = absl::make_unique(); ON_CALL(*fips_key_manager, FipsStatus()) .WillByDefault(testing::Return(FipsCompatibility::kRequiresBoringCrypto)); RegistryImpl registry_impl; auto status = registry_impl.RegisterKeyTypeManager>( std::move(fips_key_manager), true); EXPECT_THAT(status, IsOk()); EXPECT_THAT(registry_impl.RestrictToFipsIfEmpty(), StatusIs(absl::StatusCode::kInternal)); } TEST_F(RegistryImplTest, CanRegisterOnlyOneMonitoringFactory) { auto monitoring_client_factory = absl::make_unique(); RegistryImpl registry_impl; EXPECT_THAT(registry_impl.RegisterMonitoringClientFactory( std::move(monitoring_client_factory)), IsOk()); ASSERT_THAT(registry_impl.GetMonitoringClientFactory(), Not(IsNull())); EXPECT_THAT(registry_impl.RegisterMonitoringClientFactory( std::move(monitoring_client_factory)), StatusIs(absl::StatusCode::kAlreadyExists)); } } // namespace } // namespace internal } // namespace tink } // namespace crypto