blob: 6752ac33fc2515d590bab08714e6744ac0a81ca2 [file] [log] [blame]
// 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 <string>
#include <utility>
#include "gtest/gtest.h"
#include "absl/status/status.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