| // 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 <memory> |
| #include <string> |
| #include <thread> // NOLINT(build/c++11) |
| #include <utility> |
| #include <vector> |
| |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "absl/memory/memory.h" |
| #include "absl/status/status.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/catalogue.h" |
| #include "tink/config/tink_fips.h" |
| #include "tink/core/key_manager_impl.h" |
| #include "tink/core/key_type_manager.h" |
| #include "tink/crypto_format.h" |
| #include "tink/hybrid/ecies_aead_hkdf_private_key_manager.h" |
| #include "tink/hybrid/ecies_aead_hkdf_public_key_manager.h" |
| #include "tink/keyset_manager.h" |
| #include "tink/monitoring/monitoring.h" |
| #include "tink/monitoring/monitoring_client_mocks.h" |
| #include "tink/registry.h" |
| #include "tink/subtle/aes_gcm_boringssl.h" |
| #include "tink/subtle/random.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_keyset_handle.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/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<std::unique_ptr<portable_proto::MessageLite>> NewKey( |
| const MessageLite& key_format) const override { |
| return util::Status(absl::StatusCode::kUnknown, |
| "TestKeyFactory cannot produce a key"); |
| } |
| |
| util::StatusOr<std::unique_ptr<portable_proto::MessageLite>> NewKey( |
| absl::string_view serialized_key_format) const override { |
| return util::Status(absl::StatusCode::kUnknown, |
| "TestKeyFactory cannot produce a key"); |
| } |
| |
| util::StatusOr<std::unique_ptr<KeyData>> NewKeyData( |
| absl::string_view serialized_key_format) const override { |
| auto key_data = absl::make_unique<KeyData>(); |
| 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<Aead> { |
| public: |
| explicit TestAeadKeyManager(const std::string& key_type) |
| : key_type_(key_type), key_factory_(key_type) {} |
| |
| util::StatusOr<std::unique_ptr<Aead>> |
| GetPrimitive(const KeyData& key) const override { |
| std::unique_ptr<Aead> aead(new DummyAead(key_type_)); |
| return std::move(aead); |
| } |
| |
| util::StatusOr<std::unique_ptr<Aead>> |
| 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<AesGcmKey, AesGcmKeyFormat, |
| List<Aead, AeadVariant>> { |
| public: |
| class AeadFactory : public PrimitiveFactory<Aead> { |
| public: |
| crypto::tink::util::StatusOr<std::unique_ptr<Aead>> 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<AeadVariant> { |
| public: |
| crypto::tink::util::StatusOr<std::unique_ptr<AeadVariant>> Create( |
| const AesGcmKey& key) const override { |
| return absl::make_unique<AeadVariant>(key.key_value()); |
| } |
| }; |
| |
| ExampleKeyTypeManager() |
| : KeyTypeManager(absl::make_unique<AeadFactory>(), |
| absl::make_unique<AeadVariantFactory>()) {} |
| |
| 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<AesGcmKey> 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<AesGcmKey> 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<std::string> 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 <typename P, typename Q = P> |
| class TestWrapper : public PrimitiveWrapper<P, Q> { |
| public: |
| TestWrapper() {} |
| crypto::tink::util::StatusOr<std::unique_ptr<Q>> Wrap( |
| std::unique_ptr<PrimitiveSet<P>> primitive_set) const override { |
| return util::Status(absl::StatusCode::kUnimplemented, |
| "This is a test wrapper."); |
| } |
| }; |
| |
| class AeadVariantWrapper : public PrimitiveWrapper<AeadVariant, AeadVariant> { |
| public: |
| crypto::tink::util::StatusOr<std::unique_ptr<AeadVariant>> Wrap( |
| std::unique_ptr<PrimitiveSet<AeadVariant>> primitive_set) const override { |
| return absl::make_unique<AeadVariant>( |
| primitive_set->get_primary()->get_primitive().get()); |
| } |
| }; |
| |
| class AeadVariantToStringWrapper |
| : public PrimitiveWrapper<AeadVariant, std::string> { |
| public: |
| crypto::tink::util::StatusOr<std::unique_ptr<std::string>> Wrap( |
| std::unique_ptr<PrimitiveSet<AeadVariant>> primitive_set) const override { |
| return absl::make_unique<std::string>( |
| 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( |
| new TestAeadKeyManager(key_type)); |
| 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<Aead>(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<TestAeadKeyManager>(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<TestAeadKeyManager>(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<TestAeadKeyManager>(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<TestAeadKeyManager>(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<Aead>(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<Aead>(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<Aead>(key_type_1); |
| EXPECT_FALSE(manager_result.ok()); |
| EXPECT_EQ(absl::StatusCode::kNotFound, manager_result.status().code()); |
| |
| auto status = Registry::RegisterKeyManager( |
| absl::make_unique<TestAeadKeyManager>(key_type_1), true); |
| |
| |
| EXPECT_TRUE(status.ok()) << status; |
| |
| status = Registry::RegisterKeyManager( |
| absl::make_unique<TestAeadKeyManager>(key_type_2), true); |
| EXPECT_TRUE(status.ok()) << status; |
| |
| manager_result = Registry::get_key_manager<Aead>(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<Aead>(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<TestAeadKeyManager> 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<TestAeadKeyManager>(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<TestAeadKeyManager>(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<Aead>(&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<Aead>(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<TestAeadKeyManager>(key_type), true), IsOk()); |
| |
| crypto::tink::util::StatusOr<const KeyManager<Aead>*> key_manager = |
| Registry::get_key_manager<Aead>(key_type); |
| ASSERT_THAT(key_manager, IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyManager( |
| absl::make_unique<TestAeadKeyManager>(key_type), true), |
| IsOk()); |
| EXPECT_THAT(key_manager.value()->get_key_type(), Eq(key_type)); |
| } |
| |
| class TestAeadCatalogue : public Catalogue<Aead> { |
| public: |
| TestAeadCatalogue() {} |
| |
| util::StatusOr<std::unique_ptr<KeyManager<Aead>>> GetKeyManager( |
| const std::string& type_url, const std::string& primitive_name, |
| uint32_t min_version) const override { |
| return util::Status(absl::StatusCode::kUnimplemented, |
| "This is a test catalogue."); |
| } |
| }; |
| |
| class TestAeadCatalogue2 : public TestAeadCatalogue {}; |
| |
| TEST_F(RegistryTest, testAddCatalogue) { |
| std::string catalogue_name = "SomeCatalogue"; |
| |
| std::unique_ptr<TestAeadCatalogue> null_catalogue = nullptr; |
| auto status = |
| Registry::AddCatalogue(catalogue_name, std::move(null_catalogue)); |
| EXPECT_FALSE(status.ok()); |
| EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code()) << status; |
| |
| // Add a catalogue. |
| status = Registry::AddCatalogue(catalogue_name, |
| absl::make_unique<TestAeadCatalogue>()); |
| EXPECT_TRUE(status.ok()) << status; |
| |
| // Add the same catalogue again, it should work (idempotence). |
| status = Registry::AddCatalogue(catalogue_name, |
| absl::make_unique<TestAeadCatalogue>()); |
| EXPECT_TRUE(status.ok()) << status; |
| |
| // Try overriding a catalogue. |
| status = Registry::AddCatalogue(catalogue_name, |
| absl::make_unique<TestAeadCatalogue2>()); |
| EXPECT_FALSE(status.ok()); |
| EXPECT_EQ(absl::StatusCode::kAlreadyExists, status.code()) << status; |
| |
| // Check the catalogue is still present. |
| EXPECT_THAT(Registry::get_catalogue<Aead>(catalogue_name), IsOk()); |
| } |
| |
| 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<TestAeadKeyManager>(key_type_1), true); |
| EXPECT_TRUE(status.ok()) << status; |
| status = Registry::RegisterKeyManager( |
| absl::make_unique<TestAeadKeyManager>(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<Aead>(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<Aead>(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<TestAeadKeyManager>(key_type_1), |
| /*new_key_allowed=*/true); |
| EXPECT_TRUE(status.ok()) << status; |
| status = Registry::RegisterKeyManager( |
| absl::make_unique<TestAeadKeyManager>(key_type_2), |
| /*new_key_allowed=*/true); |
| EXPECT_TRUE(status.ok()) << status; |
| status = Registry::RegisterKeyManager( |
| absl::make_unique<TestAeadKeyManager>(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<EciesAeadHkdfPrivateKeyManager>(); |
| auto public_key_type_manager = |
| absl::make_unique<EciesAeadHkdfPublicKeyManager>(); |
| |
| auto status = Registry::RegisterKeyManager( |
| internal::MakePrivateKeyManager<HybridDecrypt>( |
| 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<Aead>(&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<AeadWrapper>()) |
| .ok()); |
| EXPECT_TRUE( |
| Registry::RegisterPrimitiveWrapper(absl::make_unique<AeadWrapper>()) |
| .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<AeadVariantToStringWrapper>()) |
| .ok()); |
| EXPECT_TRUE(Registry::RegisterPrimitiveWrapper( |
| absl::make_unique<AeadVariantToStringWrapper>()) |
| .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<AeadVariantToStringWrapper>()) |
| .ok()); |
| // We cannot register a different wrapper creating a std::string. |
| EXPECT_THAT(Registry::RegisterPrimitiveWrapper( |
| absl::make_unique<TestWrapper<std::string>>()), |
| Not(IsOk())); |
| // But one creating an Aead. |
| EXPECT_THAT(Registry::RegisterPrimitiveWrapper( |
| absl::make_unique<TestWrapper<AeadVariant>>()), |
| 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<TestWrapper<std::string>>()), |
| IsOk()); |
| // We cannot register another wrapper producing strings. |
| EXPECT_THAT(Registry::RegisterPrimitiveWrapper( |
| absl::make_unique<AeadVariantToStringWrapper>()), |
| 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<AeadWrapper>()) |
| .ok()); |
| util::Status result = Registry::RegisterPrimitiveWrapper( |
| absl::make_unique<TestWrapper<Aead>>()); |
| 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<TestWrapper<Aead>>()) |
| .ok()); |
| EXPECT_TRUE( |
| Registry::RegisterPrimitiveWrapper(absl::make_unique<TestWrapper<Mac>>()) |
| .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<TestWrapper<Mac>>()) |
| .ok()); |
| |
| crypto::tink::util::StatusOr<std::unique_ptr<Aead>> result = |
| Registry::Wrap<Aead>(absl::make_unique<PrimitiveSet<Aead>>()); |
| 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<TestWrapper<Aead>>()) |
| .ok()); |
| |
| crypto::tink::util::StatusOr<std::unique_ptr<Aead>> result = |
| Registry::Wrap<Aead>(absl::make_unique<PrimitiveSet<Aead>>()); |
| 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<PrimitiveSet<Aead>>(); |
| ASSERT_TRUE(primitive_set |
| ->AddPrimitive(absl::make_unique<DummyAead>("aead0"), |
| keyset_info.key_info(0)) |
| .ok()); |
| ASSERT_TRUE(primitive_set |
| ->AddPrimitive(absl::make_unique<DummyAead>("aead1"), |
| keyset_info.key_info(1)) |
| .ok()); |
| auto entry_result = primitive_set->AddPrimitive( |
| absl::make_unique<DummyAead>("primary_aead"), keyset_info.key_info(2)); |
| ASSERT_THAT(primitive_set->set_primary(entry_result.value()), IsOk()); |
| |
| EXPECT_TRUE( |
| Registry::RegisterPrimitiveWrapper(absl::make_unique<AeadWrapper>()) |
| .ok()); |
| |
| auto aead_result = Registry::Wrap<Aead>(std::move(primitive_set)); |
| EXPECT_TRUE(aead_result.ok()) << aead_result.status(); |
| std::unique_ptr<Aead> 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 (!FIPS_mode()) { |
| 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<ExampleKeyTypeManager>(); |
| |
| 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<AeadVariantWrapper>()), |
| IsOk()); |
| |
| crypto::tink::util::StatusOr<std::unique_ptr<AeadVariant>> aead_variant = |
| RegistryImpl::GlobalInstance().WrapKeyset<AeadVariant>( |
| 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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| ASSERT_THAT(Registry::RegisterPrimitiveWrapper( |
| absl::make_unique<AeadVariantToStringWrapper>()), |
| IsOk()); |
| |
| crypto::tink::util::StatusOr<std::unique_ptr<std::string>> string_primitive = |
| RegistryImpl::GlobalInstance().WrapKeyset<std::string>( |
| 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<Aead> 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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| // Register a transforming wrapper taking strings and making Aeads. |
| ASSERT_THAT(Registry::RegisterPrimitiveWrapper( |
| absl::make_unique<TestWrapper<std::string, Aead>>()), |
| 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<PrimitiveSet<Aead>>(); |
| ASSERT_TRUE(primitive_set |
| ->AddPrimitive(absl::make_unique<DummyAead>("aead0"), |
| keyset_info.key_info(0)) |
| .ok()); |
| |
| EXPECT_THAT(Registry::Wrap<Aead>(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<Aead>(&key_type_manager), true) |
| .ok()); |
| auto result = |
| Registry::get_key_manager<int>(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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| } |
| |
| TEST_F(RegistryTest, RegisterFipsKeyTypeManager) { |
| if (!kUseOnlyFips || !FIPS_mode()) { |
| GTEST_SKIP() << "Only supported in FIPS-mode with BoringCrypto available."; |
| } |
| |
| auto fips_key_manager = absl::make_unique<ExampleKeyTypeManager>(); |
| |
| 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 || FIPS_mode()) { |
| GTEST_SKIP() |
| << "Only supported in FIPS-mode with BoringCrypto not available."; |
| } |
| |
| auto fips_key_manager = absl::make_unique<ExampleKeyTypeManager>(); |
| |
| 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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| AesGcmKeyFormat format; |
| format.set_key_size(16); |
| AesGcmKey key = ExampleKeyTypeManager().CreateKey(format).value(); |
| auto aead = Registry::get_key_manager<Aead>( |
| "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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| AesGcmKeyFormat format; |
| format.set_key_size(16); |
| AesGcmKey key = ExampleKeyTypeManager().CreateKey(format).value(); |
| auto aead_variant = Registry::get_key_manager<AeadVariant>( |
| "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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| EXPECT_THAT(Registry::get_key_manager<Mac>( |
| "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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| |
| crypto::tink::util::StatusOr<const KeyManager<Aead>*> key_manager = |
| Registry::get_key_manager<Aead>(ExampleKeyTypeManager().get_key_type()); |
| ASSERT_THAT(key_manager, IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), 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<ExampleKeyTypeManager>(), 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<ExampleKeyTypeManager>(), 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<ExampleKeyTypeManager>(), 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<std::stringstream>( |
| "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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), 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<std::stringstream>( |
| "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<TestAeadKeyManager>(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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), false), |
| IsOk()); |
| } |
| |
| TEST_F(RegistryTest, RegisterKeyTypeManagerTwice) { |
| if (kUseOnlyFips) { |
| GTEST_SKIP() << "Not supported in FIPS-only mode"; |
| } |
| |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), false), |
| IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), false), |
| IsOk()); |
| } |
| |
| TEST_F(RegistryTest, RegisterKeyTypeManagerLessRestrictive) { |
| if (kUseOnlyFips) { |
| GTEST_SKIP() << "Not supported in FIPS-only mode"; |
| } |
| |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), false), |
| IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), 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<ExampleKeyTypeManager>(), true), |
| IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyManager( |
| absl::make_unique<TestAeadKeyManager>( |
| "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<TestAeadKeyManager>( |
| "type.googleapis.com/google.crypto.tink.AesGcmKey"), |
| true), |
| IsOk()); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<ExampleKeyTypeManager>(), true), |
| StatusIs(absl::StatusCode::kAlreadyExists)); |
| } |
| |
| class PrivatePrimitiveA {}; |
| class PrivatePrimitiveB {}; |
| |
| class TestPrivateKeyTypeManager |
| : public PrivateKeyTypeManager<EcdsaPrivateKey, EcdsaKeyFormat, |
| EcdsaPublicKey, |
| List<PrivatePrimitiveA, PrivatePrimitiveB>> { |
| public: |
| class PrivatePrimitiveAFactory : public PrimitiveFactory<PrivatePrimitiveA> { |
| public: |
| crypto::tink::util::StatusOr<std::unique_ptr<PrivatePrimitiveA>> Create( |
| const EcdsaPrivateKey& key) const override { |
| return util::Status(absl::StatusCode::kUnimplemented, "Not implemented"); |
| } |
| }; |
| class PrivatePrimitiveBFactory : public PrimitiveFactory<PrivatePrimitiveB> { |
| public: |
| crypto::tink::util::StatusOr<std::unique_ptr<PrivatePrimitiveB>> Create( |
| const EcdsaPrivateKey& key) const override { |
| return util::Status(absl::StatusCode::kUnimplemented, "Not implemented"); |
| } |
| }; |
| |
| TestPrivateKeyTypeManager() |
| : PrivateKeyTypeManager(absl::make_unique<PrivatePrimitiveAFactory>(), |
| absl::make_unique<PrivatePrimitiveBFactory>()) {} |
| |
| 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<EcdsaPrivateKey> 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<EcdsaPublicKey> 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"; |
| }; |
| |
| class PublicPrimitiveA {}; |
| class PublicPrimitiveB {}; |
| |
| class TestPublicKeyTypeManager |
| : public KeyTypeManager<EcdsaPublicKey, void, |
| List<PublicPrimitiveA, PublicPrimitiveB>> { |
| public: |
| class PublicPrimitiveAFactory : public PrimitiveFactory<PublicPrimitiveA> { |
| public: |
| crypto::tink::util::StatusOr<std::unique_ptr<PublicPrimitiveA>> Create( |
| const EcdsaPublicKey& key) const override { |
| return util::Status(absl::StatusCode::kUnimplemented, "Not implemented"); |
| } |
| }; |
| class PublicPrimitiveBFactory : public PrimitiveFactory<PublicPrimitiveB> { |
| public: |
| crypto::tink::util::StatusOr<std::unique_ptr<PublicPrimitiveB>> Create( |
| const EcdsaPublicKey& key) const override { |
| return util::Status(absl::StatusCode::kUnimplemented, "Not implemented"); |
| } |
| }; |
| |
| TestPublicKeyTypeManager() |
| : KeyTypeManager(absl::make_unique<PublicPrimitiveAFactory>(), |
| absl::make_unique<PublicPrimitiveBFactory>()) {} |
| |
| 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<TestPrivateKeyTypeManager> |
| CreateTestPrivateKeyManagerFipsCompatible() { |
| auto private_key_manager = absl::make_unique<TestPrivateKeyTypeManager>(); |
| ON_CALL(*private_key_manager, FipsStatus()) |
| .WillByDefault(testing::Return(FipsCompatibility::kRequiresBoringCrypto)); |
| return private_key_manager; |
| } |
| |
| std::unique_ptr<TestPublicKeyTypeManager> |
| CreateTestPublicKeyManagerFipsCompatible() { |
| auto public_key_manager = absl::make_unique<TestPublicKeyTypeManager>(); |
| ON_CALL(*public_key_manager, FipsStatus()) |
| .WillByDefault(testing::Return(FipsCompatibility::kRequiresBoringCrypto)); |
| return public_key_manager; |
| } |
| |
| TEST_F(RegistryTest, RegisterAsymmetricKeyManagers) { |
| if (kUseOnlyFips && !FIPS_mode()) { |
| 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 && !FIPS_mode()) { |
| 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 && !FIPS_mode()) { |
| 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 && !FIPS_mode()) { |
| 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 && !FIPS_mode()) { |
| 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<const KeyManager<PrivatePrimitiveA>*> |
| private_key_manager = Registry::get_key_manager<PrivatePrimitiveA>( |
| TestPrivateKeyTypeManager().get_key_type()); |
| crypto::tink::util::StatusOr<const KeyManager<PublicPrimitiveA>*> |
| public_key_manager = Registry::get_key_manager<PublicPrimitiveA>( |
| 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 && !FIPS_mode()) { |
| 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 && !FIPS_mode()) { |
| 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<const KeyManager<PrivatePrimitiveA>*> km = |
| Registry::get_key_manager<PrivatePrimitiveA>( |
| 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 && !FIPS_mode()) { |
| 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<const KeyManager<PrivatePrimitiveB>*> km = |
| Registry::get_key_manager<PrivatePrimitiveB>( |
| 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 && !FIPS_mode()) { |
| 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<const KeyManager<PublicPrimitiveA>*> km = |
| Registry::get_key_manager<PublicPrimitiveA>( |
| 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 && !FIPS_mode()) { |
| 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<const KeyManager<PublicPrimitiveB>*> km = |
| Registry::get_key_manager<PublicPrimitiveB>( |
| 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 && !FIPS_mode()) { |
| 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<const KeyManager<PublicPrimitiveA>*> km = |
| Registry::get_key_manager<PublicPrimitiveA>( |
| 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 && !FIPS_mode()) { |
| 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<KeyData> 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 && !FIPS_mode()) { |
| 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 && !FIPS_mode()) { |
| 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<KeyData> 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<TestPrivateKeyTypeManager>(), |
| absl::make_unique<TestPublicKeyTypeManager>(), true) |
| .ok()); |
| EXPECT_THAT(Registry::RegisterAsymmetricKeyManagers( |
| absl::make_unique<TestPrivateKeyTypeManager2>(), |
| absl::make_unique<TestPublicKeyTypeManager>(), true), |
| StatusIs(absl::StatusCode::kAlreadyExists, |
| HasSubstr("already registered"))); |
| EXPECT_THAT(Registry::RegisterAsymmetricKeyManagers( |
| absl::make_unique<TestPrivateKeyTypeManager>(), |
| absl::make_unique<TestPublicKeyTypeManager2>(), true), |
| StatusIs(absl::StatusCode::kAlreadyExists, |
| HasSubstr("already registered"))); |
| EXPECT_THAT(Registry::RegisterAsymmetricKeyManagers( |
| absl::make_unique<TestPrivateKeyTypeManager2>(), |
| absl::make_unique<TestPublicKeyTypeManager2>(), true), |
| StatusIs(absl::StatusCode::kAlreadyExists, |
| HasSubstr("already registered"))); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<TestPrivateKeyTypeManager2>(), true), |
| StatusIs(absl::StatusCode::kAlreadyExists, |
| HasSubstr("already registered"))); |
| EXPECT_THAT(Registry::RegisterKeyTypeManager( |
| absl::make_unique<TestPublicKeyTypeManager2>(), 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<TestPrivateKeyTypeManager>(), |
| absl::make_unique<TestPublicKeyTypeManager>(), true) |
| .ok()); |
| EXPECT_THAT( |
| Registry::RegisterAsymmetricKeyManagers( |
| absl::make_unique<TestPrivateKeyTypeManager>(), |
| absl::make_unique<TestPublicKeyTypeManagerWithDifferentKeyType>(), |
| true), |
| StatusIs(absl::StatusCode::kInvalidArgument, |
| HasSubstr("impossible to register"))); |
| } |
| |
| // The DelegatingKeyTypeManager calls the registry |
| class DelegatingKeyTypeManager |
| : public PrivateKeyTypeManager<EcdsaPrivateKey, EcdsaKeyFormat, |
| EcdsaPublicKey, List<>> { |
| 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<EcdsaPrivateKey> 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<EcdsaPrivateKey> 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<EcdsaPublicKey> 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<DelegatingKeyTypeManager>(); |
| delegating_key_manager->set_registry(®istry_impl); |
| auto status = |
| registry_impl |
| .RegisterKeyTypeManager<EcdsaPrivateKey, EcdsaKeyFormat, List<>>( |
| std::move(delegating_key_manager), true); |
| EXPECT_THAT(status, IsOk()); |
| status = registry_impl.RegisterKeyTypeManager<AesGcmKey, AesGcmKeyFormat, |
| List<Aead, AeadVariant>>( |
| absl::make_unique<ExampleKeyTypeManager>(), 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<DelegatingKeyTypeManager>(); |
| delegating_key_manager->set_registry(®istry_impl); |
| auto status = |
| registry_impl |
| .RegisterKeyTypeManager<EcdsaPrivateKey, EcdsaKeyFormat, List<>>( |
| std::move(delegating_key_manager), true); |
| EXPECT_THAT(status, IsOk()); |
| status = registry_impl.RegisterKeyTypeManager<AesGcmKey, AesGcmKeyFormat, |
| List<Aead, AeadVariant>>( |
| absl::make_unique<ExampleKeyTypeManager>(), 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<DelegatingKeyTypeManager>(); |
| delegating_key_manager->set_registry(®istry_impl); |
| auto status = registry_impl.RegisterAsymmetricKeyManagers( |
| delegating_key_manager.release(), |
| absl::make_unique<TestPublicKeyTypeManager>().release(), true); |
| EXPECT_THAT(status, IsOk()); |
| status = registry_impl.RegisterKeyTypeManager<AesGcmKey, AesGcmKeyFormat, |
| List<Aead, AeadVariant>>( |
| absl::make_unique<ExampleKeyTypeManager>(), 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, FipsSucceedsOnEmptyRegistry) { |
| RegistryImpl registry_impl; |
| EXPECT_THAT(registry_impl.RestrictToFipsIfEmpty(), IsOk()); |
| } |
| |
| TEST_F(RegistryImplTest, FipsFailsIfNotEmpty) { |
| if (!FIPS_mode()) { |
| GTEST_SKIP() << "Not supported when BoringSSL is not built in FIPS-mode."; |
| } |
| |
| auto fips_key_manager = absl::make_unique<ExampleKeyTypeManager>(); |
| ON_CALL(*fips_key_manager, FipsStatus()) |
| .WillByDefault(testing::Return(FipsCompatibility::kRequiresBoringCrypto)); |
| |
| RegistryImpl registry_impl; |
| auto status = registry_impl.RegisterKeyTypeManager<AesGcmKey, AesGcmKeyFormat, |
| List<Aead, AeadVariant>>( |
| 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<MockMonitoringClientFactory>(); |
| |
| 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 |