blob: a2a8c6fb858c4453ea77a188e22c1cfe6c9ed317 [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
//
// 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.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef TINK_CORE_KEY_TYPE_MANAGER_H_
#define TINK_CORE_KEY_TYPE_MANAGER_H_
#include <string>
#include <tuple>
#include <typeinfo>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "tink/core/template_util.h"
#include "tink/input_stream.h"
#include "tink/internal/fips_utils.h"
#include "tink/util/status.h"
#include "tink/util/statusor.h"
#include "proto/tink.pb.h"
namespace crypto {
namespace tink {
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 {
public:
virtual ~InternalKeyFactory() {}
// Validates a key format proto. KeyFormatProtos
// on which this function returns a non-ok status will not be passed to
// CreateKey or DeriveKey.
virtual crypto::tink::util::Status ValidateKeyFormat(
const KeyFormatProto& key_format) const = 0;
// Creates a new key. This is expected to be randomized.
virtual crypto::tink::util::StatusOr<KeyProto> CreateKey(
const KeyFormatProto& key_format) const = 0;
// Creates a new key. Only needs to be overridden if it should be possible to
// derive keys of this type. This must be deterministic. Furthermore, in order
// to support long term usability of old keys, the KeyFormatProto should be
// versioned.
virtual crypto::tink::util::StatusOr<KeyProto> DeriveKey(
const KeyFormatProto& key_format, InputStream* input_stream) const {
return crypto::tink::util::Status(
absl::StatusCode::kUnimplemented,
"Deriving key not implemented for this key type.");
}
};
// Template specialization for when KeyFormatProto = void. The compiler will
// pick the most specialized template when compiling.
template <typename KeyProto>
class InternalKeyFactory<KeyProto, void> {
public:
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> {
public:
static_assert(
!crypto::tink::internal::HasDuplicates<Primitives...>::value,
"List or primitives contains a duplicate, which is not allowed.");
// 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 {
public:
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)
: primitive_factories_{std::move(primitives)...} {}
// 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>
util::StatusOr<std::unique_ptr<Primitive>> GetPrimitive(
const KeyProto& key) const {
return GetPrimitiveImpl<Primitive>(key);
}
// Returns the FIPS compatibility of this KeyTypeManager.
virtual internal::FipsCompatibility FipsStatus() const {
return internal::FipsCompatibility::kNotFips;
}
private:
// TODO(C++17) replace with `constexpr if` after migration
template <typename Primitive>
typename std::enable_if<
!internal::OccursInTuple<Primitive, std::tuple<Primitives...>>::value,
util::StatusOr<std::unique_ptr<Primitive>>>::type
GetPrimitiveImpl(const KeyProto& key) const {
return util::Status(
absl::StatusCode::kInvalidArgument,
absl::StrCat("No PrimitiveFactory was registered for type ",
typeid(Primitive).name()));
}
template <typename Primitive>
typename std::enable_if<
internal::OccursInTuple<Primitive, std::tuple<Primitives...>>::value,
util::StatusOr<std::unique_ptr<Primitive>>>::type
GetPrimitiveImpl(const KeyProto& key) const {
// TODO(C++14) replace with std::get<T> after migration
constexpr size_t index =
internal::IndexOf<Primitive, List<Primitives...>>::value;
return std::get<index>(primitive_factories_)->Create(key);
}
std::tuple<std::unique_ptr<PrimitiveFactory<Primitives>>...>
primitive_factories_;
};
} // namespace tink
} // namespace crypto
#endif // TINK_CORE_KEY_TYPE_MANAGER_H_