blob: 25f62a4df6f28d3d809afa0cb0e39ca50c711cfa [file] [log] [blame]
// Copyright 2019 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
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <typeindex>
#include "absl/container/flat_hash_map.h"
#include "tink/core/template_util.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "proto/tink.pb.h"
namespace crypto {
namespace tink {
template <typename... P>
class List {};
namespace internal {
// InternalKeyFactory should not be used directly: it is an implementation
// detail. The internal key factory provides the functions which are required
// if a KeyTypeManager can create new keys: ValidateKeyFormat and
// CreateKey. The special case where KeyFormatProto = void implies that the
// functions do not exist.
template <typename KeyProto, typename KeyFormatProto>
class InternalKeyFactory {
virtual ~InternalKeyFactory() {}
virtual crypto::tink::util::Status ValidateKeyFormat(
const KeyFormatProto& key_format) const = 0;
virtual crypto::tink::util::StatusOr<KeyProto> CreateKey(
const KeyFormatProto& key_format) const = 0;
// Template specialization for when KeyFormatProto = void. The compiler will
// pick the most specialized template when compiling.
template <typename KeyProto>
class InternalKeyFactory<KeyProto, void> {
virtual ~InternalKeyFactory() {}
} // namespace internal
// We declare a KeyTypeManager without giving an implementation. We then
// provide a specialization only for the case where PrimitivesList is a
// List with multiple interfaces primitives. This allows to ensure
// that such is always the case.
template <typename KeyProto, typename KeyFormatProto, typename PrimitivesList>
class KeyTypeManager;
// A KeyTypeManager manages a single key proto. This includes
// * parsing and validating keys
// * parsing and validating key formats (in case generating keys is allowed).
// * creating primitives.
// To implement, one should subclass KeyTypeManager with the corresponding
// KeyProto as a template parameter; KeyFormatProto should be void in case
// the key manager cannot produce keys and a protobuf otherwise.
// The constructor should take unique pointers to primitive factories.
// KeyTypeManager uses templates for KeyProto, KeyFormatProto and a list of
// Primitives which have to be provided as a List.
template <typename KeyProtoParam, typename KeyFormatProtoParam,
typename... Primitives>
class KeyTypeManager<KeyProtoParam, KeyFormatProtoParam, List<Primitives...>>
: public internal::InternalKeyFactory<KeyProtoParam, KeyFormatProtoParam> {
// The types used in this key type manager; these can be useful when writing
// templated code.
using KeyProto = KeyProtoParam;
using KeyFormatProto = KeyFormatProtoParam;
using PrimitiveList = List<Primitives...>;
// A PrimitiveFactory<Primitive> knows how to create instances of the
// Primitive.
template <typename Primitive>
class PrimitiveFactory {
virtual ~PrimitiveFactory() {}
virtual crypto::tink::util::StatusOr<std::unique_ptr<Primitive>> Create(
const KeyProto& key) const = 0;
// Creates a new KeyTypeManager. The parameter(s) primitives must be some
// number of unique_ptr<PrimitiveFactory<P>> types.
explicit KeyTypeManager(
std::unique_ptr<PrimitiveFactory<Primitives>>... primitives) {
"List or primitives contains a duplicate, which is not allowed.");
int unused[] = {(AddPrimitive(std::move(primitives)), 0)...};
// Returns the type_url identifying the key type handled by this manager.
virtual const std::string& get_key_type() const = 0;
// Returns the version of this key manager.
virtual uint32_t get_version() const = 0;
// Returns the key material type for this key type.
virtual google::crypto::tink::KeyData::KeyMaterialType key_material_type()
const = 0;
// Validates the key. Returns util::OkStatus() if the key is valid,
// and an invalid argument error otherwise.
virtual util::Status ValidateKey(const KeyProto& key) const = 0;
// Creates a new primitive using one of the primitive factories passed in at
// construction time.
template <typename Primitive>
crypto::tink::util::StatusOr<std::unique_ptr<Primitive>> GetPrimitive(
const KeyProto& key) const {
auto iter = primitive_factories_.find(std::type_index(typeid(Primitive)));
if (iter == primitive_factories_.end()) {
return crypto::tink::util::Status(
absl::StrCat("No PrimitiveFactory was registered for type ",
return static_cast<PrimitiveFactory<Primitive>*>(iter->second.get())
// Helper function which adds a single primivie.
template <typename Primitive>
void AddPrimitive(std::unique_ptr<PrimitiveFactory<Primitive>> primitive) {
// We use a shared_ptr here because shared_ptr<void> is valid (as opposed to
// unique_ptr<void>, where we would have to add a custom deleter with extra
// work).
absl::flat_hash_map<std::type_index, std::shared_ptr<void>>
} // namespace tink
} // namespace crypto