// Copyright 2017 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// #include "tink/keyset_manager.h" #include #include "gtest/gtest.h" #include "tink/aead/aead_config.h" #include "tink/aead/aes_gcm_key_manager.h" #include "tink/keyset_handle.h" #include "tink/util/test_keyset_handle.h" #include "proto/aes_gcm.pb.h" #include "proto/tink.pb.h" using google::crypto::tink::AesGcmKeyFormat; using google::crypto::tink::KeyData; using google::crypto::tink::KeyStatusType; using google::crypto::tink::KeyTemplate; using google::crypto::tink::OutputPrefixType; namespace crypto { namespace tink { class KeysetManagerTest : public ::testing::Test { protected: void SetUp() override { auto status = AeadConfig::Register(); ASSERT_TRUE(status.ok()) << status; } void TearDown() override {} }; TEST_F(KeysetManagerTest, testBasicOperations) { AesGcmKeyFormat key_format; key_format.set_key_size(16); KeyTemplate key_template; key_template.set_type_url(AesGcmKeyManager().get_key_type()); key_template.set_output_prefix_type(OutputPrefixType::TINK); key_template.set_value(key_format.SerializeAsString()); // Create a keyset manager with a single key. auto new_result = KeysetManager::New(key_template); EXPECT_TRUE(new_result.ok()) << new_result.status(); auto keyset_manager = std::move(new_result.value()); EXPECT_EQ(1, keyset_manager->KeyCount()); // Verify the keyset. auto keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(1, keyset.key().size()); auto key_id_0 = keyset.key(0).key_id(); EXPECT_EQ(key_id_0, keyset.primary_key_id()); EXPECT_EQ(KeyStatusType::ENABLED, keyset.key(0).status()); EXPECT_EQ(OutputPrefixType::TINK, keyset.key(0).output_prefix_type()); EXPECT_EQ(AesGcmKeyManager().get_key_type(), keyset.key(0).key_data().type_url()); EXPECT_EQ(KeyData::SYMMETRIC, keyset.key(0).key_data().key_material_type()); // Add another key. key_template.set_output_prefix_type(OutputPrefixType::RAW); auto add_result = keyset_manager->Add(key_template); EXPECT_TRUE(add_result.ok()) << add_result.status(); EXPECT_EQ(2, keyset_manager->KeyCount()); auto key_id_1 = add_result.value(); keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(2, keyset.key().size()); EXPECT_EQ(key_id_0, keyset.primary_key_id()); EXPECT_FALSE(keyset.key(0).key_data().value() == keyset.key(1).key_data().value()); EXPECT_EQ(KeyStatusType::ENABLED, keyset.key(1).status()); EXPECT_EQ(OutputPrefixType::RAW, keyset.key(1).output_prefix_type()); EXPECT_EQ(AesGcmKeyManager().get_key_type(), keyset.key(1).key_data().type_url()); EXPECT_EQ(KeyData::SYMMETRIC, keyset.key(1).key_data().key_material_type()); // And another one, via rotation. key_template.set_output_prefix_type(OutputPrefixType::LEGACY); auto rotate_result = keyset_manager->Rotate(key_template); EXPECT_TRUE(rotate_result.ok()) << add_result.status(); EXPECT_EQ(3, keyset_manager->KeyCount()); auto key_id_2 = rotate_result.value(); keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(3, keyset.key().size()); EXPECT_EQ(key_id_2, keyset.primary_key_id()); EXPECT_FALSE(keyset.key(0).key_data().value() == keyset.key(2).key_data().value()); EXPECT_FALSE(keyset.key(1).key_data().value() == keyset.key(2).key_data().value()); EXPECT_EQ(KeyStatusType::ENABLED, keyset.key(2).status()); EXPECT_EQ(OutputPrefixType::LEGACY, keyset.key(2).output_prefix_type()); EXPECT_EQ(AesGcmKeyManager().get_key_type(), keyset.key(2).key_data().type_url()); EXPECT_EQ(KeyData::SYMMETRIC, keyset.key(2).key_data().key_material_type()); // Change the primary. auto status = keyset_manager->SetPrimary(key_id_1); EXPECT_TRUE(status.ok()) << status; keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(3, keyset.key().size()); EXPECT_EQ(3, keyset_manager->KeyCount()); EXPECT_EQ(key_id_1, keyset.primary_key_id()); // Clone a keyset via the manager, and check equality. auto keyset_manager_2 = std::move(KeysetManager::New(*keyset_manager->GetKeysetHandle()).value()); auto keyset_2 = TestKeysetHandle::GetKeyset(*(keyset_manager_2->GetKeysetHandle())); EXPECT_EQ(keyset.SerializeAsString(), keyset_2.SerializeAsString()); // Disable a key, and try to set it as primary. EXPECT_EQ(KeyStatusType::ENABLED, keyset.key(2).status()); status = keyset_manager->Disable(key_id_2); EXPECT_TRUE(status.ok()) << status; EXPECT_EQ(3, keyset_manager->KeyCount()); keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(KeyStatusType::DISABLED, keyset.key(2).status()); status = keyset_manager->SetPrimary(key_id_2); EXPECT_FALSE(status.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "must be ENABLED", std::string(status.message())); keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(key_id_1, keyset.primary_key_id()); // Enable ENABLED key, disable a DISABLED one. EXPECT_EQ(KeyStatusType::ENABLED, keyset.key(1).status()); status = keyset_manager->Enable(key_id_1); EXPECT_TRUE(status.ok()) << status; keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(KeyStatusType::ENABLED, keyset.key(1).status()); EXPECT_EQ(KeyStatusType::DISABLED, keyset.key(2).status()); status = keyset_manager->Disable(key_id_2); EXPECT_TRUE(status.ok()) << status; keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(KeyStatusType::DISABLED, keyset.key(2).status()); // Enable the disabled key, then destroy it, and try to re-enable. EXPECT_EQ(KeyStatusType::DISABLED, keyset.key(2).status()); status = keyset_manager->Enable(key_id_2); EXPECT_TRUE(status.ok()) << status; keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(KeyStatusType::ENABLED, keyset.key(2).status()); EXPECT_TRUE(keyset.key(2).has_key_data()); status = keyset_manager->Destroy(key_id_2); EXPECT_TRUE(status.ok()) << status; EXPECT_EQ(3, keyset_manager->KeyCount()); keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(KeyStatusType::DESTROYED, keyset.key(2).status()); EXPECT_FALSE(keyset.key(2).has_key_data()); status = keyset_manager->Enable(key_id_2); EXPECT_FALSE(status.ok()); EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "Cannot enable", std::string(status.message())); keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(KeyStatusType::DESTROYED, keyset.key(2).status()); EXPECT_EQ(key_id_1, keyset.primary_key_id()); // Delete the destroyed key, then try to destroy and delete it again. status = keyset_manager->Delete(key_id_2); EXPECT_TRUE(status.ok()) << status; EXPECT_EQ(2, keyset_manager->KeyCount()); keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(2, keyset.key().size()); status = keyset_manager->Destroy(key_id_2); EXPECT_EQ(absl::StatusCode::kNotFound, status.code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "No key with key_id", std::string(status.message())); status = keyset_manager->Delete(key_id_2); EXPECT_EQ(absl::StatusCode::kNotFound, status.code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "No key with key_id", std::string(status.message())); // Try disabling/destroying/deleting the primary key. keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(key_id_1, keyset.primary_key_id()); status = keyset_manager->Disable(key_id_1); EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "Cannot disable primary", std::string(status.message())); status = keyset_manager->Destroy(key_id_1); EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "Cannot destroy primary", std::string(status.message())); status = keyset_manager->Delete(key_id_1); EXPECT_EQ(absl::StatusCode::kInvalidArgument, status.code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "Cannot delete primary", std::string(status.message())); keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(key_id_1, keyset.primary_key_id()); // Delete the first key, then try to set it as primary. status = keyset_manager->Delete(key_id_0); EXPECT_TRUE(status.ok()) << status; keyset = TestKeysetHandle::GetKeyset(*(keyset_manager->GetKeysetHandle())); EXPECT_EQ(1, keyset.key().size()); EXPECT_EQ(key_id_1, keyset.key(0).key_id()); status = keyset_manager->SetPrimary(key_id_0); EXPECT_FALSE(status.ok()); EXPECT_EQ(absl::StatusCode::kNotFound, status.code()); EXPECT_PRED_FORMAT2(testing::IsSubstring, "No key with key_id", std::string(status.message())); EXPECT_EQ(1, keyset_manager->KeyCount()); } } // namespace tink } // namespace crypto