blob: e9607819bbfa86f34fa5bd41aaa38ae03e0e6ed9 [file] [log] [blame]
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
#include "tink/keyset_manager.h"
#include <inttypes.h>
#include <random>
#include "absl/memory/memory.h"
#include "tink/keyset_handle.h"
#include "tink/keyset_reader.h"
#include "tink/registry.h"
#include "tink/util/enums.h"
#include "tink/util/errors.h"
#include "proto/tink.pb.h"
namespace crypto {
namespace tink {
using google::crypto::tink::Keyset;
using google::crypto::tink::KeyStatusType;
using google::crypto::tink::KeyTemplate;
using crypto::tink::util::Enums;
using crypto::tink::util::Status;
using crypto::tink::util::StatusOr;
namespace {
uint32_t NewKeyId() {
std::random_device rd;
std::minstd_rand0 gen(rd());
std::uniform_int_distribution<uint32_t> dist;
return dist(gen);
}
} // namespace
// static
StatusOr<std::unique_ptr<KeysetManager>> KeysetManager::New(
const KeyTemplate& key_template) {
auto manager = absl::make_unique<KeysetManager>();
auto rotate_result = manager->Rotate(key_template);
if (!rotate_result.ok()) return rotate_result.status();
return std::move(manager);
}
// static
StatusOr<std::unique_ptr<KeysetManager>> KeysetManager::New(
const KeysetHandle& keyset_handle) {
auto manager = absl::make_unique<KeysetManager>();
manager->keyset_ = keyset_handle.get_keyset();
return std::move(manager);
}
uint32_t KeysetManager::GenerateNewKeyId() {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
while (true) {
uint32_t key_id = NewKeyId();
bool already_exists = false;
for (auto& key : keyset_.key()) {
if (key.key_id() == key_id) {
already_exists = true;
break;
}
}
if (!already_exists) return key_id;
}
}
std::unique_ptr<KeysetHandle> KeysetManager::GetKeysetHandle() {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
std::unique_ptr<Keyset> keyset_copy(new Keyset(keyset_));
std::unique_ptr<KeysetHandle> handle(
new KeysetHandle(std::move(keyset_copy)));
return handle;
}
StatusOr<uint32_t> KeysetManager::Add(const KeyTemplate& key_template) {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
auto key_data_result = Registry::NewKeyData(key_template);
if (!key_data_result.ok()) return key_data_result.status();
auto key_data = std::move(key_data_result.ValueOrDie());
Keyset::Key* key = keyset_.add_key();
uint32_t key_id = GenerateNewKeyId();
*(key->mutable_key_data()) = *key_data;
key->set_status(KeyStatusType::ENABLED);
key->set_key_id(key_id);
key->set_output_prefix_type(key_template.output_prefix_type());
return key_id;
}
StatusOr<uint32_t> KeysetManager::Rotate(const KeyTemplate& key_template) {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
auto add_result = Add(key_template);
if (!add_result.ok()) return add_result.status();
auto key_id = add_result.ValueOrDie();
auto status = SetPrimary(key_id);
if (!status.ok()) return status;
return key_id;
}
Status KeysetManager::Enable(uint32_t key_id) {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
for (auto& key : *(keyset_.mutable_key())) {
if (key.key_id() == key_id) {
if (key.status() != KeyStatusType::DISABLED &&
key.status() != KeyStatusType::ENABLED) {
return ToStatusF(util::error::INVALID_ARGUMENT,
"Cannot enable key with key_id %" PRIu32
" and status %s.",
key_id, Enums::KeyStatusName(key.status()));
}
key.set_status(KeyStatusType::ENABLED);
return Status::OK;
}
}
return ToStatusF(util::error::NOT_FOUND,
"No key with key_id %" PRIu32 " found in the keyset.",
key_id);
}
Status KeysetManager::Disable(uint32_t key_id) {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
if (keyset_.primary_key_id() == key_id) {
return ToStatusF(util::error::INVALID_ARGUMENT,
"Cannot disable primary key (key_id %" PRIu32 ").",
key_id);
}
for (auto& key : *(keyset_.mutable_key())) {
if (key.key_id() == key_id) {
if (key.status() != KeyStatusType::DISABLED &&
key.status() != KeyStatusType::ENABLED) {
return ToStatusF(util::error::INVALID_ARGUMENT,
"Cannot disable key with key_id %" PRIu32
" and status %s.",
key_id, Enums::KeyStatusName(key.status()));
}
key.set_status(KeyStatusType::DISABLED);
return Status::OK;
}
}
return ToStatusF(util::error::NOT_FOUND,
"No key with key_id %" PRIu32 " found in the keyset.",
key_id);
}
Status KeysetManager::Delete(uint32_t key_id) {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
if (keyset_.primary_key_id() == key_id) {
return ToStatusF(util::error::INVALID_ARGUMENT,
"Cannot delete primary key (key_id %" PRIu32 ").",
key_id);
}
auto key_field = keyset_.mutable_key();
for (auto key_iter = key_field->begin();
key_iter != key_field->end();
key_iter++) {
auto key = *key_iter;
if (key.key_id() == key_id) {
keyset_.mutable_key()->erase(key_iter);
return Status::OK;
}
}
return ToStatusF(util::error::NOT_FOUND,
"No key with key_id %" PRIu32 " found in the keyset.",
key_id);
}
Status KeysetManager::Destroy(uint32_t key_id) {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
if (keyset_.primary_key_id() == key_id) {
return ToStatusF(util::error::INVALID_ARGUMENT,
"Cannot destroy primary key (key_id %" PRIu32 ").",
key_id);
}
for (auto& key : *(keyset_.mutable_key())) {
if (key.key_id() == key_id) {
if (key.status() != KeyStatusType::DISABLED &&
key.status() != KeyStatusType::DESTROYED &&
key.status() != KeyStatusType::ENABLED) {
return ToStatusF(util::error::INVALID_ARGUMENT,
"Cannot destroy key with key_id %" PRIu32
" and status %s.",
key_id, Enums::KeyStatusName(key.status()));
}
key.clear_key_data();
key.set_status(KeyStatusType::DESTROYED);
return Status::OK;
}
}
return ToStatusF(util::error::NOT_FOUND,
"No key with key_id %" PRIu32 " found in the keyset.",
key_id);
}
Status KeysetManager::SetPrimary(uint32_t key_id) {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
for (auto& key : keyset_.key()) {
if (key.key_id() == key_id) {
if (key.status() != KeyStatusType::ENABLED) {
return ToStatusF(util::error::INVALID_ARGUMENT,
"The candidate for the primary key must be ENABLED"
" (key_id %" PRIu32 ").", key_id);
}
keyset_.set_primary_key_id(key_id);
return Status::OK;
}
}
return ToStatusF(util::error::NOT_FOUND,
"No key with key_id %" PRIu32 " found in the keyset.",
key_id);
}
int KeysetManager::KeyCount() const {
std::lock_guard<std::recursive_mutex> lock(keyset_mutex_);
return keyset_.key_size();
}
} // namespace tink
} // namespace crypto