// 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 #include #include #include #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/functional/any_invocable.h" #include "absl/memory/memory.h" #include "absl/status/status.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "tink/core/key_type_manager.h" #include "tink/core/private_key_type_manager.h" #include "tink/input_stream.h" #include "tink/internal/fips_utils.h" #include "tink/internal/key_type_info_store.h" #include "tink/internal/keyset_wrapper.h" #include "tink/internal/keyset_wrapper_store.h" #include "tink/key_manager.h" #include "tink/monitoring/monitoring.h" #include "tink/primitive_set.h" #include "tink/primitive_wrapper.h" #include "tink/util/status.h" #include "tink/util/statusor.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; // Registers the given 'manager' for the key type 'manager->get_key_type()'. // Takes ownership of 'manager', which must be non-nullptr. KeyManager is the // legacy/internal version of KeyTypeManager. template crypto::tink::util::Status RegisterKeyManager(KeyManager

* manager, bool new_key_allowed = true) ABSL_LOCKS_EXCLUDED(maps_mutex_); // Takes ownership of 'manager', which must be non-nullptr. template crypto::tink::util::Status RegisterKeyTypeManager( std::unique_ptr> manager, bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_); // Takes ownership of 'private_manager' and 'public_manager'. Both must be // non-nullptr. template crypto::tink::util::Status RegisterAsymmetricKeyManagers( PrivateKeyTypeManager* private_manager, KeyTypeManager* public_manager, bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_); template crypto::tink::util::StatusOr*> get_key_manager( absl::string_view type_url) const ABSL_LOCKS_EXCLUDED(maps_mutex_); // Takes ownership of 'wrapper', which must be non-nullptr. template crypto::tink::util::Status RegisterPrimitiveWrapper( PrimitiveWrapper* wrapper) ABSL_LOCKS_EXCLUDED(maps_mutex_); template crypto::tink::util::StatusOr> GetPrimitive( const google::crypto::tink::KeyData& key_data) const ABSL_LOCKS_EXCLUDED(maps_mutex_); crypto::tink::util::StatusOr> NewKeyData(const google::crypto::tink::KeyTemplate& key_template) const ABSL_LOCKS_EXCLUDED(maps_mutex_); crypto::tink::util::StatusOr> GetPublicKeyData(absl::string_view type_url, absl::string_view serialized_private_key) const ABSL_LOCKS_EXCLUDED(maps_mutex_); template crypto::tink::util::StatusOr> Wrap( std::unique_ptr> primitive_set) const ABSL_LOCKS_EXCLUDED(maps_mutex_); // Wraps a `keyset` and annotates it with `annotations`. template crypto::tink::util::StatusOr> WrapKeyset( const google::crypto::tink::Keyset& keyset, const absl::flat_hash_map& annotations) const ABSL_LOCKS_EXCLUDED(maps_mutex_); crypto::tink::util::StatusOr 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 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: // 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 get_key_type_info( absl::string_view type_url) const ABSL_LOCKS_EXCLUDED(maps_mutex_); mutable absl::Mutex maps_mutex_; // Stores information about key types constructed from their KeyTypeManager or // KeyManager. // Once inserted, KeyTypeInfoStore::Info objects must remain valid for the // lifetime of the binary, and the Info object's pointer stability is // required. Elements in Info, which include the KeyTypeManager or KeyManager, // must not be replaced. KeyTypeInfoStore key_type_info_store_ ABSL_GUARDED_BY(maps_mutex_); // Stores information about keyset wrappers constructed from their // PrimitiveWrapper. KeysetWrapperStore keyset_wrapper_store_ ABSL_GUARDED_BY(maps_mutex_); mutable absl::Mutex monitoring_factory_mutex_; std::unique_ptr monitoring_factory_ ABSL_GUARDED_BY(monitoring_factory_mutex_); }; template crypto::tink::util::Status RegistryImpl::RegisterKeyManager( KeyManager

* manager, bool new_key_allowed) { auto owned_manager = absl::WrapUnique(manager); if (manager == nullptr) { return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument, "Parameter 'manager' must be non-null."); } absl::MutexLock lock(&maps_mutex_); return key_type_info_store_.AddKeyManager(std::move(owned_manager), new_key_allowed); } template crypto::tink::util::Status RegistryImpl::RegisterKeyTypeManager( std::unique_ptr> manager, bool new_key_allowed) { if (manager == nullptr) { return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument, "Parameter 'manager' must be non-null."); } absl::MutexLock lock(&maps_mutex_); return key_type_info_store_.AddKeyTypeManager(std::move(manager), new_key_allowed); } template crypto::tink::util::Status RegistryImpl::RegisterAsymmetricKeyManagers( PrivateKeyTypeManager* private_manager, KeyTypeManager* public_manager, bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_) { auto owned_private_manager = absl::WrapUnique(private_manager); auto owned_public_manager = absl::WrapUnique(public_manager); if (private_manager == nullptr) { return crypto::tink::util::Status( absl::StatusCode::kInvalidArgument, "Parameter 'private_manager' must be non-null."); } if (public_manager == nullptr) { return crypto::tink::util::Status( absl::StatusCode::kInvalidArgument, "Parameter 'public_manager' must be non-null."); } absl::MutexLock lock(&maps_mutex_); return key_type_info_store_.AddAsymmetricKeyTypeManagers( std::move(owned_private_manager), std::move(owned_public_manager), new_key_allowed); } template crypto::tink::util::Status RegistryImpl::RegisterPrimitiveWrapper( PrimitiveWrapper* wrapper) { if (wrapper == nullptr) { return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument, "Parameter 'wrapper' must be non-null."); } std::unique_ptr> owned_wrapper(wrapper); absl::MutexLock lock(&maps_mutex_); absl::AnyInvocable>( const google::crypto::tink::KeyData& key_data) const> primitive_getter = [this](const google::crypto::tink::KeyData& key_data) { return this->GetPrimitive

(key_data); }; return keyset_wrapper_store_.Add(std::move(owned_wrapper), std::move(primitive_getter)); } template crypto::tink::util::StatusOr*> RegistryImpl::get_key_manager(absl::string_view type_url) const { crypto::tink::util::StatusOr< const crypto::tink::internal::KeyTypeInfoStore::Info*> info = get_key_type_info(type_url); if (!info.ok()) { return info.status(); } return (*info)->get_key_manager

(type_url); } template crypto::tink::util::StatusOr> RegistryImpl::GetPrimitive( const google::crypto::tink::KeyData& key_data) const { auto key_manager_result = get_key_manager

(key_data.type_url()); if (key_manager_result.ok()) { return key_manager_result.value()->GetPrimitive(key_data); } return key_manager_result.status(); } template crypto::tink::util::StatusOr> RegistryImpl::Wrap( std::unique_ptr> primitive_set) const { if (primitive_set == nullptr) { return crypto::tink::util::Status( absl::StatusCode::kInvalidArgument, "Parameter 'primitive_set' must be non-null."); } const PrimitiveWrapper* wrapper = nullptr; { absl::MutexLock lock(&maps_mutex_); crypto::tink::util::StatusOr*> wrapper_status = keyset_wrapper_store_.GetPrimitiveWrapper

(); if (!wrapper_status.ok()) { return wrapper_status.status(); } wrapper = *wrapper_status; } return wrapper->Wrap(std::move(primitive_set)); } template crypto::tink::util::StatusOr> RegistryImpl::WrapKeyset( const google::crypto::tink::Keyset& keyset, const absl::flat_hash_map& annotations) const { const KeysetWrapper

* keyset_wrapper = nullptr; { absl::MutexLock lock(&maps_mutex_); crypto::tink::util::StatusOr*> keyset_wrapper_status = keyset_wrapper_store_.Get

(); if (!keyset_wrapper_status.ok()) { return keyset_wrapper_status.status(); } keyset_wrapper = *keyset_wrapper_status; } // `maps_mutex_` must be released before calling Wrap or this will deadlock, // as Wrap calls get_key_manager. return keyset_wrapper->Wrap(keyset, annotations); } inline crypto::tink::util::Status RegistryImpl::RestrictToFipsIfEmpty() const { absl::MutexLock lock(&maps_mutex_); // If we are already in FIPS mode, then do nothing.. if (IsFipsModeEnabled()) { return util::OkStatus(); } if (key_type_info_store_.IsEmpty()) { 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_