blob: 6ca880a2e6e58b5ab65d3dd452980edf3b3d0e2b [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 <memory>
#include <random>
#include <utility>
#include "absl/memory/memory.h"
#include "absl/status/status.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 "tink/util/status.h"
#include "tink/util/statusor.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;
// 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>();
absl::MutexLock lock(&manager->keyset_mutex_);
manager->keyset_ = keyset_handle.get_keyset();
return std::move(manager);
}
std::unique_ptr<KeysetHandle> KeysetManager::GetKeysetHandle() {
absl::MutexLock 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) {
return Add(key_template, false);
}
crypto::tink::util::StatusOr<uint32_t> KeysetManager::Add(
const google::crypto::tink::KeyTemplate& key_template, bool as_primary) {
absl::MutexLock lock(&keyset_mutex_);
return KeysetHandle::AddToKeyset(key_template, as_primary, &keyset_);
}
StatusOr<uint32_t> KeysetManager::Rotate(const KeyTemplate& key_template) {
return Add(key_template, true);
}
Status KeysetManager::Enable(uint32_t key_id) {
absl::MutexLock 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(absl::StatusCode::kInvalidArgument,
"Cannot enable key with key_id %u and status %s.",
key_id, Enums::KeyStatusName(key.status()));
}
key.set_status(KeyStatusType::ENABLED);
return util::OkStatus();
}
}
return ToStatusF(absl::StatusCode::kNotFound,
"No key with key_id %u found in the keyset.", key_id);
}
Status KeysetManager::Disable(uint32_t key_id) {
absl::MutexLock lock(&keyset_mutex_);
if (keyset_.primary_key_id() == key_id) {
return ToStatusF(absl::StatusCode::kInvalidArgument,
"Cannot disable primary key (key_id %u).", 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(absl::StatusCode::kInvalidArgument,
"Cannot disable key with key_id %u and status %s.",
key_id, Enums::KeyStatusName(key.status()));
}
key.set_status(KeyStatusType::DISABLED);
return util::OkStatus();
}
}
return ToStatusF(absl::StatusCode::kNotFound,
"No key with key_id %u found in the keyset.", key_id);
}
Status KeysetManager::Delete(uint32_t key_id) {
absl::MutexLock lock(&keyset_mutex_);
if (keyset_.primary_key_id() == key_id) {
return ToStatusF(absl::StatusCode::kInvalidArgument,
"Cannot delete primary key (key_id %u).", 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 util::OkStatus();
}
}
return ToStatusF(absl::StatusCode::kNotFound,
"No key with key_id %u found in the keyset.", key_id);
}
Status KeysetManager::Destroy(uint32_t key_id) {
absl::MutexLock lock(&keyset_mutex_);
if (keyset_.primary_key_id() == key_id) {
return ToStatusF(absl::StatusCode::kInvalidArgument,
"Cannot destroy primary key (key_id %u).", 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(absl::StatusCode::kInvalidArgument,
"Cannot destroy key with key_id %u and status %s.",
key_id, Enums::KeyStatusName(key.status()));
}
key.clear_key_data();
key.set_status(KeyStatusType::DESTROYED);
return util::OkStatus();
}
}
return ToStatusF(absl::StatusCode::kNotFound,
"No key with key_id %u found in the keyset.", key_id);
}
Status KeysetManager::SetPrimary(uint32_t key_id) {
absl::MutexLock lock(&keyset_mutex_);
for (auto& key : keyset_.key()) {
if (key.key_id() == key_id) {
if (key.status() != KeyStatusType::ENABLED) {
return ToStatusF(absl::StatusCode::kInvalidArgument,
"The candidate for the primary key must be ENABLED"
" (key_id %u).",
key_id);
}
keyset_.set_primary_key_id(key_id);
return util::OkStatus();
}
}
return ToStatusF(absl::StatusCode::kNotFound,
"No key with key_id %u found in the keyset.", key_id);
}
int KeysetManager::KeyCount() const {
absl::MutexLock lock(&keyset_mutex_);
return keyset_.key_size();
}
} // namespace tink
} // namespace crypto