| // Copyright 2018 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. |
| // |
| /////////////////////////////////////////////////////////////////////////////// |
| #ifndef TINK_INTERNAL_REGISTRY_IMPL_H_ |
| #define TINK_INTERNAL_REGISTRY_IMPL_H_ |
| |
| #include <algorithm> |
| #include <functional> |
| #include <initializer_list> |
| #include <memory> |
| #include <string> |
| #include <tuple> |
| #include <typeindex> |
| #include <typeinfo> |
| #include <utility> |
| |
| #include "absl/base/thread_annotations.h" |
| #include "absl/container/flat_hash_map.h" |
| #include "absl/memory/memory.h" |
| #include "absl/status/status.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_join.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/synchronization/mutex.h" |
| #include "absl/types/optional.h" |
| #include "tink/catalogue.h" |
| #include "tink/core/key_manager_impl.h" |
| #include "tink/core/key_type_manager.h" |
| #include "tink/core/private_key_manager_impl.h" |
| #include "tink/core/private_key_type_manager.h" |
| #include "tink/internal/fips_utils.h" |
| #include "tink/internal/keyset_wrapper.h" |
| #include "tink/internal/keyset_wrapper_impl.h" |
| #include "tink/key_manager.h" |
| #include "tink/monitoring/monitoring.h" |
| #include "tink/primitive_set.h" |
| #include "tink/primitive_wrapper.h" |
| #include "tink/util/errors.h" |
| #include "tink/util/protobuf_helper.h" |
| #include "tink/util/status.h" |
| #include "tink/util/validation.h" |
| #include "proto/tink.pb.h" |
| |
| namespace crypto { |
| namespace tink { |
| namespace internal { |
| |
| class RegistryImpl { |
| public: |
| static RegistryImpl& GlobalInstance() { |
| static RegistryImpl* instance = new RegistryImpl(); |
| return *instance; |
| } |
| |
| RegistryImpl() = default; |
| RegistryImpl(const RegistryImpl&) = delete; |
| RegistryImpl& operator=(const RegistryImpl&) = delete; |
| |
| template <class P> |
| crypto::tink::util::StatusOr<const Catalogue<P>*> get_catalogue( |
| absl::string_view catalogue_name) const ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| template <class P> |
| crypto::tink::util::Status AddCatalogue(absl::string_view catalogue_name, |
| Catalogue<P>* catalogue) |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| // Registers the given 'manager' for the key type 'manager->get_key_type()'. |
| // Takes ownership of 'manager', which must be non-nullptr. |
| template <class P> |
| crypto::tink::util::Status RegisterKeyManager(KeyManager<P>* manager, |
| bool new_key_allowed = true) |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| // Takes ownership of 'manager', which must be non-nullptr. |
| template <class KeyProto, class KeyFormatProto, class PrimitiveList> |
| crypto::tink::util::Status RegisterKeyTypeManager( |
| std::unique_ptr<KeyTypeManager<KeyProto, KeyFormatProto, PrimitiveList>> |
| manager, |
| bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| // Takes ownership of 'private_key_manager' and 'public_key_manager'. Both |
| // must be non-nullptr. |
| template <class PrivateKeyProto, class KeyFormatProto, class PublicKeyProto, |
| class PrivatePrimitivesList, class PublicPrimitivesList> |
| crypto::tink::util::Status RegisterAsymmetricKeyManagers( |
| PrivateKeyTypeManager<PrivateKeyProto, KeyFormatProto, PublicKeyProto, |
| PrivatePrimitivesList>* private_key_manager, |
| KeyTypeManager<PublicKeyProto, void, PublicPrimitivesList>* |
| public_key_manager, |
| bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| template <class P> |
| crypto::tink::util::StatusOr<const KeyManager<P>*> get_key_manager( |
| absl::string_view type_url) const ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| // Takes ownership of 'wrapper', which must be non-nullptr. |
| template <class P, class Q> |
| crypto::tink::util::Status RegisterPrimitiveWrapper( |
| PrimitiveWrapper<P, Q>* wrapper) ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| template <class P> |
| crypto::tink::util::StatusOr<std::unique_ptr<P>> GetPrimitive( |
| const google::crypto::tink::KeyData& key_data) const |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| template <class P> |
| crypto::tink::util::StatusOr<std::unique_ptr<P>> GetPrimitive( |
| absl::string_view type_url, const portable_proto::MessageLite& key) const |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| crypto::tink::util::StatusOr<std::unique_ptr<google::crypto::tink::KeyData>> |
| NewKeyData(const google::crypto::tink::KeyTemplate& key_template) const |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| crypto::tink::util::StatusOr<std::unique_ptr<google::crypto::tink::KeyData>> |
| GetPublicKeyData(absl::string_view type_url, |
| absl::string_view serialized_private_key) const |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| template <class P> |
| crypto::tink::util::StatusOr<std::unique_ptr<P>> Wrap( |
| std::unique_ptr<PrimitiveSet<P>> primitive_set) const |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| // Wraps a `keyset` and annotates it with `annotations`. |
| template <class P> |
| crypto::tink::util::StatusOr<std::unique_ptr<P>> WrapKeyset( |
| const google::crypto::tink::Keyset& keyset, |
| const absl::flat_hash_map<std::string, std::string>& annotations) const |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| crypto::tink::util::StatusOr<google::crypto::tink::KeyData> DeriveKey( |
| const google::crypto::tink::KeyTemplate& key_template, |
| InputStream* randomness) const ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| void Reset() ABSL_LOCKS_EXCLUDED(maps_mutex_, monitoring_factory_mutex_); |
| |
| crypto::tink::util::Status RestrictToFipsIfEmpty() const |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| // Registers a `monitoring_factory`. Only one factory can be registered, |
| // subsequent calls to this method will return a kAlreadyExists error. |
| crypto::tink::util::Status RegisterMonitoringClientFactory( |
| std::unique_ptr<crypto::tink::MonitoringClientFactory> monitoring_factory) |
| ABSL_LOCKS_EXCLUDED(monitoring_factory_mutex_); |
| |
| // Returns a pointer to the registered monitoring factory if any, and nullptr |
| // otherwise. |
| crypto::tink::MonitoringClientFactory* GetMonitoringClientFactory() const |
| ABSL_LOCKS_EXCLUDED(monitoring_factory_mutex_) { |
| absl::MutexLock lock(&monitoring_factory_mutex_); |
| return monitoring_factory_.get(); |
| } |
| |
| private: |
| // All information for a given type url. |
| class KeyTypeInfo { |
| public: |
| // Takes ownership of the 'key_manager'. |
| template <typename P> |
| KeyTypeInfo(KeyManager<P>* key_manager, bool new_key_allowed) |
| : key_manager_type_index_(std::type_index(typeid(*key_manager))), |
| public_key_manager_type_index_(absl::nullopt), |
| new_key_allowed_(new_key_allowed), |
| internal_key_factory_(nullptr), |
| key_factory_(&key_manager->get_key_factory()), |
| key_type_manager_(nullptr) { |
| primitive_to_manager_.emplace(std::type_index(typeid(P)), |
| absl::WrapUnique(key_manager)); |
| } |
| |
| // Takes ownership of the 'key_manager'. |
| template <typename KeyProto, typename KeyFormatProto, |
| typename... Primitives> |
| KeyTypeInfo(KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>* |
| key_manager, |
| bool new_key_allowed) |
| : key_manager_type_index_(std::type_index(typeid(*key_manager))), |
| public_key_manager_type_index_(absl::nullopt), |
| new_key_allowed_(new_key_allowed), |
| internal_key_factory_( |
| absl::make_unique<internal::KeyFactoryImpl<KeyTypeManager< |
| KeyProto, KeyFormatProto, List<Primitives...>>>>( |
| key_manager)), |
| key_factory_(internal_key_factory_.get()), |
| key_deriver_(CreateDeriverFunctionFor(key_manager)), |
| key_type_manager_(absl::WrapUnique(key_manager)) { |
| // TODO(C++17) replace with a fold expression |
| (void)std::initializer_list<int>{ |
| 0, (primitive_to_manager_.emplace( |
| std::type_index(typeid(Primitives)), |
| internal::MakeKeyManager<Primitives>(key_manager)), |
| 0)...}; |
| } |
| |
| // Takes ownership of the 'private_key_manager', but *not* of the |
| // 'public_key_manager'. The public_key_manager must only be alive for the |
| // duration of the constructor. |
| template <typename PrivateKeyProto, typename KeyFormatProto, |
| typename PublicKeyProto, typename PublicPrimitivesList, |
| typename... PrivatePrimitives> |
| KeyTypeInfo( |
| PrivateKeyTypeManager<PrivateKeyProto, KeyFormatProto, PublicKeyProto, |
| List<PrivatePrimitives...>>* private_key_manager, |
| KeyTypeManager<PublicKeyProto, void, PublicPrimitivesList>* |
| public_key_manager, |
| bool new_key_allowed) |
| : key_manager_type_index_( |
| std::type_index(typeid(*private_key_manager))), |
| public_key_manager_type_index_( |
| std::type_index(typeid(*public_key_manager))), |
| new_key_allowed_(new_key_allowed), |
| internal_key_factory_( |
| absl::make_unique<internal::PrivateKeyFactoryImpl< |
| PrivateKeyProto, KeyFormatProto, PublicKeyProto, |
| List<PrivatePrimitives...>, PublicPrimitivesList>>( |
| private_key_manager, public_key_manager)), |
| key_factory_(internal_key_factory_.get()), |
| key_deriver_(CreateDeriverFunctionFor(private_key_manager)), |
| key_type_manager_(absl::WrapUnique(private_key_manager)) { |
| // TODO(C++17) replace with a fold expression |
| (void)std::initializer_list<int>{ |
| 0, (primitive_to_manager_.emplace( |
| std::type_index(typeid(PrivatePrimitives)), |
| internal::MakePrivateKeyManager<PrivatePrimitives>( |
| private_key_manager, public_key_manager)), |
| 0)...}; |
| } |
| |
| template <typename P> |
| crypto::tink::util::StatusOr<const KeyManager<P>*> get_key_manager( |
| absl::string_view requested_type_url) const { |
| auto it = primitive_to_manager_.find(std::type_index(typeid(P))); |
| if (it == primitive_to_manager_.end()) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| absl::StrCat( |
| "Primitive type ", typeid(P).name(), |
| " not among supported primitives ", |
| absl::StrJoin( |
| primitive_to_manager_.begin(), primitive_to_manager_.end(), |
| ", ", |
| [](std::string* out, |
| const std::pair<const std::type_index, |
| std::unique_ptr<KeyManagerBase>>& kv) { |
| absl::StrAppend(out, kv.first.name()); |
| }), |
| " for type URL ", requested_type_url)); |
| } |
| return static_cast<const KeyManager<P>*>(it->second.get()); |
| } |
| |
| const std::type_index& key_manager_type_index() const { |
| return key_manager_type_index_; |
| } |
| |
| const absl::optional<std::type_index>& public_key_manager_type_index() |
| const { |
| return public_key_manager_type_index_; |
| } |
| |
| bool new_key_allowed() const { return new_key_allowed_; } |
| void set_new_key_allowed(bool b) { new_key_allowed_ = b; } |
| |
| const KeyFactory& key_factory() const { return *key_factory_; } |
| |
| const std::function<crypto::tink::util::StatusOr< |
| google::crypto::tink::KeyData>(absl::string_view, InputStream*)>& |
| key_deriver() const { |
| return key_deriver_; |
| } |
| |
| private: |
| // dynamic std::type_index of the actual key manager class for which this |
| // key was inserted. |
| std::type_index key_manager_type_index_; |
| // dynamic std::type_index of the public key manager corresponding to this |
| // class, in case it was inserted using RegisterAsymmetricKeyManagers, |
| // nullopt otherwise. |
| absl::optional<std::type_index> public_key_manager_type_index_; |
| |
| // For each primitive, the corresponding names and key_manager. |
| absl::flat_hash_map<std::type_index, std::unique_ptr<KeyManagerBase>> |
| primitive_to_manager_; |
| // Whether the key manager allows creating new keys. |
| bool new_key_allowed_; |
| // A factory constructed from an internal key manager. Owned version of |
| // key_factory if constructed with a KeyTypeManager. This is nullptr if |
| // constructed with a KeyManager. |
| std::unique_ptr<const KeyFactory> internal_key_factory_; |
| // Unowned copy of internal_key_factory, always different from |
| // nullptr. |
| const KeyFactory* key_factory_; |
| // A function to call to derive a key. If the container was constructed with |
| // a KeyTypeManager which has non-void keyformat type, this will forward to |
| // the function DeriveKey of this container. Otherwise, the function is |
| // 'empty', i.e., "key_deriver_" will cast to false when cast to a bool. |
| std::function<crypto::tink::util::StatusOr<google::crypto::tink::KeyData>( |
| absl::string_view, InputStream*)> |
| key_deriver_; |
| // The owned pointer in case we use a KeyTypeManager, nullptr if |
| // constructed with a KeyManager. |
| const std::shared_ptr<void> key_type_manager_; |
| }; |
| |
| class WrapperInfo { |
| public: |
| template <typename P, typename Q> |
| explicit WrapperInfo(std::unique_ptr<PrimitiveWrapper<P, Q>> wrapper) |
| : is_same_primitive_wrapping_(std::is_same<P, Q>::value), |
| wrapper_type_index_(std::type_index(typeid(*wrapper))), |
| q_type_index_(std::type_index(typeid(Q))) { |
| auto keyset_wrapper_unique_ptr = |
| absl::make_unique<KeysetWrapperImpl<P, Q>>( |
| wrapper.get(), [](const google::crypto::tink::KeyData& key_data) { |
| return RegistryImpl::GlobalInstance().GetPrimitive<P>(key_data); |
| }); |
| keyset_wrapper_ = std::move(keyset_wrapper_unique_ptr); |
| original_wrapper_ = std::move(wrapper); |
| } |
| |
| template <typename Q> |
| crypto::tink::util::StatusOr<const KeysetWrapper<Q>*> GetKeysetWrapper() |
| const { |
| if (q_type_index_ != std::type_index(typeid(Q))) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInternal, |
| "RegistryImpl::KeysetWrapper() called with wrong type"); |
| } |
| return static_cast<KeysetWrapper<Q>*>(keyset_wrapper_.get()); |
| } |
| |
| template <typename P> |
| crypto::tink::util::StatusOr<const PrimitiveWrapper<P, P>*> |
| GetLegacyWrapper() const { |
| if (!is_same_primitive_wrapping_) { |
| // This happens if a user uses a legacy method (like Registry::Wrap) |
| // directly or has a custom key manager for a primitive which has a |
| // PrimitiveWrapper<P,Q> with P != Q. |
| return crypto::tink::util::Status( |
| absl::StatusCode::kFailedPrecondition, |
| absl::StrCat("Cannot use primitive type ", typeid(P).name(), |
| " with a custom key manager.")); |
| } |
| if (q_type_index_ != std::type_index(typeid(P))) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInternal, |
| "RegistryImpl::LegacyWrapper() called with wrong type"); |
| } |
| return static_cast<const PrimitiveWrapper<P, P>*>( |
| original_wrapper_.get()); |
| } |
| |
| // Returns true if the PrimitiveWrapper is the same class as the one used |
| // to construct this WrapperInfo |
| template <typename P, typename Q> |
| bool HasSameType(const PrimitiveWrapper<P, Q>& wrapper) { |
| return wrapper_type_index_ == std::type_index(typeid(wrapper)); |
| } |
| |
| private: |
| bool is_same_primitive_wrapping_; |
| // dynamic std::type_index of the actual PrimitiveWrapper<P,Q> class for |
| // which this key was inserted. |
| std::type_index wrapper_type_index_; |
| // dynamic std::type_index of Q, when PrimitiveWrapper<P,Q> was inserted. |
| std::type_index q_type_index_; |
| // The primitive_wrapper passed in. We use a shared_ptr because |
| // unique_ptr<void> is invalid. |
| std::shared_ptr<void> original_wrapper_; |
| // The keyset_wrapper_. We use a shared_ptr because unique_ptr<void> is |
| // invalid. |
| std::shared_ptr<void> keyset_wrapper_; |
| }; |
| |
| // All information for a given primitive label. |
| struct LabelInfo { |
| LabelInfo(std::shared_ptr<void> catalogue, std::type_index type_index, |
| const char* type_id_name) |
| : catalogue(std::move(catalogue)), |
| type_index(type_index), |
| type_id_name(type_id_name) {} |
| // A pointer to the underlying Catalogue<P>. We use a shared_ptr because |
| // shared_ptr<void> is valid (as opposed to unique_ptr<void>). |
| const std::shared_ptr<void> catalogue; |
| // std::type_index of the primitive for which this key was inserted. |
| std::type_index type_index; |
| // TypeId name of the primitive for which this key was inserted. |
| const std::string type_id_name; |
| }; |
| |
| template <class P> |
| crypto::tink::util::StatusOr<const PrimitiveWrapper<P, P>*> GetLegacyWrapper() |
| const ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| template <class P> |
| crypto::tink::util::StatusOr<const KeysetWrapper<P>*> GetKeysetWrapper() const |
| ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| // Returns the key type info for a given type URL. Since we never replace |
| // key type infos, the pointers will stay valid for the lifetime of the |
| // binary. |
| crypto::tink::util::StatusOr<const KeyTypeInfo*> get_key_type_info( |
| absl::string_view type_url) const ABSL_LOCKS_EXCLUDED(maps_mutex_); |
| |
| // Returns OK if the key manager with the given type index can be inserted |
| // for type url type_url and parameter new_key_allowed. Otherwise returns |
| // an error to be returned to the user. |
| crypto::tink::util::Status CheckInsertable( |
| absl::string_view type_url, const std::type_index& key_manager_type_index, |
| bool new_key_allowed) const ABSL_SHARED_LOCKS_REQUIRED(maps_mutex_); |
| |
| mutable absl::Mutex maps_mutex_; |
| // A map from the type_url to the given KeyTypeInfo. Once emplaced KeyTypeInfo |
| // objects must remain valid throughout the life time of the binary. Hence, |
| // one should /never/ replace any element of the KeyTypeInfo. This is because |
| // get_key_type_manager() needs to guarantee that the returned |
| // key_type_manager remains valid. |
| // NOTE: We require pointer stability of the value, as get_key_type_info |
| // returns a pointer which needs to stay alive. |
| absl::flat_hash_map<std::string, KeyTypeInfo> type_url_to_info_ |
| ABSL_GUARDED_BY(maps_mutex_); |
| // A map from the type_id to the corresponding wrapper. |
| absl::flat_hash_map<std::type_index, WrapperInfo> primitive_to_wrapper_ |
| ABSL_GUARDED_BY(maps_mutex_); |
| |
| absl::flat_hash_map<std::string, LabelInfo> name_to_catalogue_map_ |
| ABSL_GUARDED_BY(maps_mutex_); |
| |
| mutable absl::Mutex monitoring_factory_mutex_; |
| std::unique_ptr<crypto::tink::MonitoringClientFactory> monitoring_factory_ |
| ABSL_GUARDED_BY(monitoring_factory_mutex_); |
| }; |
| |
| template <class P> |
| crypto::tink::util::Status RegistryImpl::AddCatalogue( |
| absl::string_view catalogue_name, Catalogue<P>* catalogue) { |
| if (catalogue == nullptr) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| "Parameter 'catalogue' must be non-null."); |
| } |
| std::shared_ptr<void> entry(catalogue); |
| absl::MutexLock lock(&maps_mutex_); |
| auto curr_catalogue = name_to_catalogue_map_.find(catalogue_name); |
| if (curr_catalogue != name_to_catalogue_map_.end()) { |
| auto existing = |
| static_cast<Catalogue<P>*>(curr_catalogue->second.catalogue.get()); |
| if (std::type_index(typeid(*existing)) != |
| std::type_index(typeid(*catalogue))) { |
| return ToStatusF(absl::StatusCode::kAlreadyExists, |
| "A catalogue named '%s' has been already added.", |
| catalogue_name); |
| } |
| } else { |
| name_to_catalogue_map_.emplace( |
| std::piecewise_construct, std::forward_as_tuple(catalogue_name), |
| std::forward_as_tuple(std::move(entry), std::type_index(typeid(P)), |
| typeid(P).name())); |
| } |
| return crypto::tink::util::OkStatus(); |
| } |
| |
| template <class P> |
| crypto::tink::util::StatusOr<const Catalogue<P>*> RegistryImpl::get_catalogue( |
| absl::string_view catalogue_name) const { |
| absl::MutexLock lock(&maps_mutex_); |
| auto catalogue_entry = name_to_catalogue_map_.find(catalogue_name); |
| if (catalogue_entry == name_to_catalogue_map_.end()) { |
| return ToStatusF(absl::StatusCode::kNotFound, |
| "No catalogue named '%s' has been added.", catalogue_name); |
| } |
| if (catalogue_entry->second.type_id_name != typeid(P).name()) { |
| return ToStatusF(absl::StatusCode::kInvalidArgument, |
| "Wrong Primitive type for catalogue named '%s': " |
| "got '%s', expected '%s'", |
| catalogue_name, typeid(P).name(), |
| catalogue_entry->second.type_id_name); |
| } |
| return static_cast<Catalogue<P>*>(catalogue_entry->second.catalogue.get()); |
| } |
| |
| template <class P> |
| crypto::tink::util::Status RegistryImpl::RegisterKeyManager( |
| KeyManager<P>* manager, bool new_key_allowed) { |
| auto owned_manager = absl::WrapUnique(manager); |
| if (owned_manager == nullptr) { |
| return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument, |
| "Parameter 'manager' must be non-null."); |
| } |
| std::string type_url = owned_manager->get_key_type(); |
| if (!manager->DoesSupport(type_url)) { |
| return ToStatusF(absl::StatusCode::kInvalidArgument, |
| "The manager does not support type '%s'.", type_url); |
| } |
| absl::MutexLock lock(&maps_mutex_); |
| crypto::tink::util::Status status = CheckInsertable( |
| type_url, std::type_index(typeid(*owned_manager)), new_key_allowed); |
| if (!status.ok()) return status; |
| |
| auto it = type_url_to_info_.find(type_url); |
| if (it != type_url_to_info_.end()) { |
| it->second.set_new_key_allowed(new_key_allowed); |
| } else { |
| type_url_to_info_.emplace( |
| std::piecewise_construct, std::forward_as_tuple(type_url), |
| std::forward_as_tuple(owned_manager.release(), new_key_allowed)); |
| } |
| return crypto::tink::util::OkStatus(); |
| } |
| |
| template <class KeyProto, class KeyFormatProto, class PrimitiveList> |
| crypto::tink::util::Status RegistryImpl::RegisterKeyTypeManager( |
| std::unique_ptr<KeyTypeManager<KeyProto, KeyFormatProto, PrimitiveList>> |
| owned_manager, |
| bool new_key_allowed) { |
| if (owned_manager == nullptr) { |
| return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument, |
| "Parameter 'manager' must be non-null."); |
| } |
| std::string type_url = owned_manager->get_key_type(); |
| absl::MutexLock lock(&maps_mutex_); |
| |
| // Check FIPS status |
| internal::FipsCompatibility fips_compatible = owned_manager->FipsStatus(); |
| auto fips_status = internal::ChecksFipsCompatibility(fips_compatible); |
| if (!fips_status.ok()) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInternal, |
| absl::StrCat("Failed registering the key manager for ", |
| typeid(*owned_manager).name(), |
| " as it is not FIPS compatible.")); |
| } |
| |
| crypto::tink::util::Status status = CheckInsertable( |
| type_url, std::type_index(typeid(*owned_manager)), new_key_allowed); |
| if (!status.ok()) return status; |
| |
| auto it = type_url_to_info_.find(type_url); |
| if (it != type_url_to_info_.end()) { |
| it->second.set_new_key_allowed(new_key_allowed); |
| } else { |
| type_url_to_info_.emplace( |
| std::piecewise_construct, std::forward_as_tuple(type_url), |
| std::forward_as_tuple(owned_manager.release(), new_key_allowed)); |
| } |
| return crypto::tink::util::OkStatus(); |
| } |
| |
| template <class PrivateKeyProto, class KeyFormatProto, class PublicKeyProto, |
| class PrivatePrimitivesList, class PublicPrimitivesList> |
| crypto::tink::util::Status RegistryImpl::RegisterAsymmetricKeyManagers( |
| PrivateKeyTypeManager<PrivateKeyProto, KeyFormatProto, PublicKeyProto, |
| PrivatePrimitivesList>* private_key_manager, |
| KeyTypeManager<PublicKeyProto, void, PublicPrimitivesList>* |
| public_key_manager, |
| bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_) { |
| auto owned_private_key_manager = absl::WrapUnique(private_key_manager); |
| auto owned_public_key_manager = absl::WrapUnique(public_key_manager); |
| if (private_key_manager == nullptr) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| "Parameter 'private_key_manager' must be non-null."); |
| } |
| if (owned_public_key_manager == nullptr) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| "Parameter 'public_key_manager' must be non-null."); |
| } |
| std::string private_type_url = private_key_manager->get_key_type(); |
| std::string public_type_url = public_key_manager->get_key_type(); |
| |
| absl::MutexLock lock(&maps_mutex_); |
| |
| // Check FIPS status |
| auto private_fips_status = |
| internal::ChecksFipsCompatibility(private_key_manager->FipsStatus()); |
| |
| if (!private_fips_status.ok()) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInternal, |
| absl::StrCat("Failed registering the key manager for ", |
| typeid(*private_key_manager).name(), |
| " as it is not FIPS compatible.")); |
| } |
| |
| auto public_fips_status = |
| internal::ChecksFipsCompatibility(public_key_manager->FipsStatus()); |
| |
| if (!public_fips_status.ok()) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInternal, |
| absl::StrCat("Failed registering the key manager for ", |
| typeid(*public_key_manager).name(), |
| " as it is not FIPS compatible.")); |
| } |
| |
| crypto::tink::util::Status status = CheckInsertable( |
| private_type_url, std::type_index(typeid(*private_key_manager)), |
| new_key_allowed); |
| if (!status.ok()) return status; |
| status = CheckInsertable(public_type_url, |
| std::type_index(typeid(*public_key_manager)), |
| new_key_allowed); |
| if (!status.ok()) return status; |
| |
| if (private_type_url == public_type_url) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| "Passed in key managers must have different get_key_type() results."); |
| } |
| |
| auto private_it = type_url_to_info_.find(private_type_url); |
| auto public_it = type_url_to_info_.find(public_type_url); |
| bool private_found = private_it != type_url_to_info_.end(); |
| bool public_found = public_it != type_url_to_info_.end(); |
| |
| if (private_found && !public_found) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| absl::StrCat( |
| "Private key manager corresponding to ", |
| typeid(*private_key_manager).name(), |
| " was previously registered, but key manager corresponding to ", |
| typeid(*public_key_manager).name(), |
| " was not, so it's impossible to register them jointly")); |
| } |
| if (!private_found && public_found) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| absl::StrCat("Key manager corresponding to ", |
| typeid(*public_key_manager).name(), |
| " was previously registered, but private key manager " |
| "corresponding to ", |
| typeid(*private_key_manager).name(), |
| " was not, so it's impossible to register them jointly")); |
| } |
| |
| if (private_found) { |
| // implies public_found. |
| if (!private_it->second.public_key_manager_type_index().has_value()) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| absl::StrCat("private key manager corresponding to ", |
| typeid(*private_key_manager).name(), |
| " is already registered without public key manager, " |
| "cannot be re-registered with public key manager. ")); |
| } |
| if (*private_it->second.public_key_manager_type_index() != |
| std::type_index(typeid(*public_key_manager))) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| absl::StrCat( |
| "private key manager corresponding to ", |
| typeid(*private_key_manager).name(), |
| " is already registered with ", |
| private_it->second.public_key_manager_type_index()->name(), |
| ", cannot be re-registered with ", |
| typeid(*public_key_manager).name())); |
| } |
| } |
| |
| if (!private_found) { |
| // !public_found must hold. |
| type_url_to_info_.emplace( |
| std::piecewise_construct, std::forward_as_tuple(private_type_url), |
| std::forward_as_tuple(owned_private_key_manager.release(), |
| owned_public_key_manager.get(), new_key_allowed)); |
| type_url_to_info_.emplace( |
| std::piecewise_construct, std::forward_as_tuple(public_type_url), |
| std::forward_as_tuple(owned_public_key_manager.release(), |
| new_key_allowed)); |
| } else { |
| private_it->second.set_new_key_allowed(new_key_allowed); |
| } |
| |
| return util::OkStatus(); |
| } |
| |
| template <class P, class Q> |
| crypto::tink::util::Status RegistryImpl::RegisterPrimitiveWrapper( |
| PrimitiveWrapper<P, Q>* wrapper) { |
| if (wrapper == nullptr) { |
| return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument, |
| "Parameter 'wrapper' must be non-null."); |
| } |
| std::unique_ptr<PrimitiveWrapper<P, Q>> entry(wrapper); |
| |
| absl::MutexLock lock(&maps_mutex_); |
| auto it = primitive_to_wrapper_.find(std::type_index(typeid(Q))); |
| if (it != primitive_to_wrapper_.end()) { |
| if (!it->second.HasSameType(*wrapper)) { |
| return util::Status( |
| absl::StatusCode::kAlreadyExists, |
| "A wrapper named for this primitive has already been added."); |
| } |
| return crypto::tink::util::OkStatus(); |
| } |
| primitive_to_wrapper_.emplace( |
| std::piecewise_construct, |
| std::forward_as_tuple(std::type_index(typeid(Q))), |
| std::forward_as_tuple(std::move(entry))); |
| return crypto::tink::util::OkStatus(); |
| } |
| |
| template <class P> |
| crypto::tink::util::StatusOr<const KeyManager<P>*> |
| RegistryImpl::get_key_manager(absl::string_view type_url) const { |
| absl::MutexLock lock(&maps_mutex_); |
| auto it = type_url_to_info_.find(type_url); |
| if (it == type_url_to_info_.end()) { |
| return ToStatusF(absl::StatusCode::kNotFound, |
| "No manager for type '%s' has been registered.", type_url); |
| } |
| return it->second.get_key_manager<P>(type_url); |
| } |
| |
| template <class P> |
| crypto::tink::util::StatusOr<std::unique_ptr<P>> RegistryImpl::GetPrimitive( |
| const google::crypto::tink::KeyData& key_data) const { |
| auto key_manager_result = get_key_manager<P>(key_data.type_url()); |
| if (key_manager_result.ok()) { |
| return key_manager_result.value()->GetPrimitive(key_data); |
| } |
| return key_manager_result.status(); |
| } |
| |
| template <class P> |
| crypto::tink::util::StatusOr<std::unique_ptr<P>> RegistryImpl::GetPrimitive( |
| absl::string_view type_url, const portable_proto::MessageLite& key) const { |
| auto key_manager_result = get_key_manager<P>(type_url); |
| if (key_manager_result.ok()) { |
| return key_manager_result.value()->GetPrimitive(key); |
| } |
| return key_manager_result.status(); |
| } |
| |
| template <class P> |
| crypto::tink::util::StatusOr<const PrimitiveWrapper<P, P>*> |
| RegistryImpl::GetLegacyWrapper() const { |
| absl::MutexLock lock(&maps_mutex_); |
| auto it = primitive_to_wrapper_.find(std::type_index(typeid(P))); |
| if (it == primitive_to_wrapper_.end()) { |
| return util::Status( |
| absl::StatusCode::kNotFound, |
| absl::StrCat("No wrapper registered for type ", typeid(P).name())); |
| } |
| return it->second.GetLegacyWrapper<P>(); |
| } |
| |
| template <class P> |
| crypto::tink::util::StatusOr<const KeysetWrapper<P>*> |
| RegistryImpl::GetKeysetWrapper() const { |
| absl::MutexLock lock(&maps_mutex_); |
| auto it = primitive_to_wrapper_.find(std::type_index(typeid(P))); |
| if (it == primitive_to_wrapper_.end()) { |
| return util::Status( |
| absl::StatusCode::kNotFound, |
| absl::StrCat("No wrapper registered for type ", typeid(P).name())); |
| } |
| return it->second.GetKeysetWrapper<P>(); |
| } |
| |
| template <class P> |
| crypto::tink::util::StatusOr<std::unique_ptr<P>> RegistryImpl::Wrap( |
| std::unique_ptr<PrimitiveSet<P>> primitive_set) const { |
| if (primitive_set == nullptr) { |
| return crypto::tink::util::Status( |
| absl::StatusCode::kInvalidArgument, |
| "Parameter 'primitive_set' must be non-null."); |
| } |
| util::StatusOr<const PrimitiveWrapper<P, P>*> wrapper_result = |
| GetLegacyWrapper<P>(); |
| if (!wrapper_result.ok()) { |
| return wrapper_result.status(); |
| } |
| return wrapper_result.value()->Wrap(std::move(primitive_set)); |
| } |
| |
| template <class P> |
| crypto::tink::util::StatusOr<std::unique_ptr<P>> RegistryImpl::WrapKeyset( |
| const google::crypto::tink::Keyset& keyset, |
| const absl::flat_hash_map<std::string, std::string>& annotations) const { |
| crypto::tink::util::StatusOr<const KeysetWrapper<P>*> keyset_wrapper = |
| GetKeysetWrapper<P>(); |
| if (!keyset_wrapper.ok()) { |
| return keyset_wrapper.status(); |
| } |
| return (*keyset_wrapper)->Wrap(keyset, annotations); |
| } |
| |
| inline crypto::tink::util::Status RegistryImpl::RestrictToFipsIfEmpty() const { |
| absl::MutexLock lock(&maps_mutex_); |
| if (type_url_to_info_.empty()) { |
| SetFipsRestricted(); |
| return util::OkStatus(); |
| } |
| return util::Status(absl::StatusCode::kInternal, |
| "Could not set FIPS only mode. Registry is not empty."); |
| } |
| |
| } // namespace internal |
| } // namespace tink |
| } // namespace crypto |
| |
| #endif // TINK_INTERNAL_REGISTRY_IMPL_H_ |