xref: /aosp_15_r20/external/tink/cc/internal/registry_impl.h (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2018 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 
17 #ifndef TINK_INTERNAL_REGISTRY_IMPL_H_
18 #define TINK_INTERNAL_REGISTRY_IMPL_H_
19 
20 #include <algorithm>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 
25 #include "absl/base/thread_annotations.h"
26 #include "absl/container/flat_hash_map.h"
27 #include "absl/functional/any_invocable.h"
28 #include "absl/memory/memory.h"
29 #include "absl/status/status.h"
30 #include "absl/strings/string_view.h"
31 #include "absl/synchronization/mutex.h"
32 #include "tink/core/key_type_manager.h"
33 #include "tink/core/private_key_type_manager.h"
34 #include "tink/input_stream.h"
35 #include "tink/internal/fips_utils.h"
36 #include "tink/internal/key_type_info_store.h"
37 #include "tink/internal/keyset_wrapper.h"
38 #include "tink/internal/keyset_wrapper_store.h"
39 #include "tink/key_manager.h"
40 #include "tink/monitoring/monitoring.h"
41 #include "tink/primitive_set.h"
42 #include "tink/primitive_wrapper.h"
43 #include "tink/util/status.h"
44 #include "tink/util/statusor.h"
45 #include "proto/tink.pb.h"
46 
47 namespace crypto {
48 namespace tink {
49 namespace internal {
50 
51 class RegistryImpl {
52  public:
GlobalInstance()53   static RegistryImpl& GlobalInstance() {
54     static RegistryImpl* instance = new RegistryImpl();
55     return *instance;
56   }
57 
58   RegistryImpl() = default;
59   RegistryImpl(const RegistryImpl&) = delete;
60   RegistryImpl& operator=(const RegistryImpl&) = delete;
61 
62   // Registers the given 'manager' for the key type 'manager->get_key_type()'.
63   // Takes ownership of 'manager', which must be non-nullptr. KeyManager is the
64   // legacy/internal version of KeyTypeManager.
65   template <class P>
66   crypto::tink::util::Status RegisterKeyManager(KeyManager<P>* manager,
67                                                 bool new_key_allowed = true)
68       ABSL_LOCKS_EXCLUDED(maps_mutex_);
69 
70   // Takes ownership of 'manager', which must be non-nullptr.
71   template <class KeyProto, class KeyFormatProto, class PrimitiveList>
72   crypto::tink::util::Status RegisterKeyTypeManager(
73       std::unique_ptr<KeyTypeManager<KeyProto, KeyFormatProto, PrimitiveList>>
74           manager,
75       bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_);
76 
77   // Takes ownership of 'private_manager' and 'public_manager'. Both must be
78   // non-nullptr.
79   template <class PrivateKeyProto, class KeyFormatProto, class PublicKeyProto,
80             class PrivatePrimitivesList, class PublicPrimitivesList>
81   crypto::tink::util::Status RegisterAsymmetricKeyManagers(
82       PrivateKeyTypeManager<PrivateKeyProto, KeyFormatProto, PublicKeyProto,
83                             PrivatePrimitivesList>* private_manager,
84       KeyTypeManager<PublicKeyProto, void, PublicPrimitivesList>*
85           public_manager,
86       bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_);
87 
88   template <class P>
89   crypto::tink::util::StatusOr<const KeyManager<P>*> get_key_manager(
90       absl::string_view type_url) const ABSL_LOCKS_EXCLUDED(maps_mutex_);
91 
92   // Takes ownership of 'wrapper', which must be non-nullptr.
93   template <class P, class Q>
94   crypto::tink::util::Status RegisterPrimitiveWrapper(
95       PrimitiveWrapper<P, Q>* wrapper) ABSL_LOCKS_EXCLUDED(maps_mutex_);
96 
97   template <class P>
98   crypto::tink::util::StatusOr<std::unique_ptr<P>> GetPrimitive(
99       const google::crypto::tink::KeyData& key_data) const
100       ABSL_LOCKS_EXCLUDED(maps_mutex_);
101 
102   crypto::tink::util::StatusOr<std::unique_ptr<google::crypto::tink::KeyData>>
103   NewKeyData(const google::crypto::tink::KeyTemplate& key_template) const
104       ABSL_LOCKS_EXCLUDED(maps_mutex_);
105 
106   crypto::tink::util::StatusOr<std::unique_ptr<google::crypto::tink::KeyData>>
107   GetPublicKeyData(absl::string_view type_url,
108                    absl::string_view serialized_private_key) const
109       ABSL_LOCKS_EXCLUDED(maps_mutex_);
110 
111   template <class P>
112   crypto::tink::util::StatusOr<std::unique_ptr<P>> Wrap(
113       std::unique_ptr<PrimitiveSet<P>> primitive_set) const
114       ABSL_LOCKS_EXCLUDED(maps_mutex_);
115 
116   // Wraps a `keyset` and annotates it with `annotations`.
117   template <class P>
118   crypto::tink::util::StatusOr<std::unique_ptr<P>> WrapKeyset(
119       const google::crypto::tink::Keyset& keyset,
120       const absl::flat_hash_map<std::string, std::string>& annotations) const
121       ABSL_LOCKS_EXCLUDED(maps_mutex_);
122 
123   crypto::tink::util::StatusOr<google::crypto::tink::KeyData> DeriveKey(
124       const google::crypto::tink::KeyTemplate& key_template,
125       InputStream* randomness) const ABSL_LOCKS_EXCLUDED(maps_mutex_);
126 
127   void Reset() ABSL_LOCKS_EXCLUDED(maps_mutex_, monitoring_factory_mutex_);
128 
129   crypto::tink::util::Status RestrictToFipsIfEmpty() const
130       ABSL_LOCKS_EXCLUDED(maps_mutex_);
131 
132   // Registers a `monitoring_factory`. Only one factory can be registered,
133   // subsequent calls to this method will return a kAlreadyExists error.
134   crypto::tink::util::Status RegisterMonitoringClientFactory(
135       std::unique_ptr<crypto::tink::MonitoringClientFactory> monitoring_factory)
136       ABSL_LOCKS_EXCLUDED(monitoring_factory_mutex_);
137 
138   // Returns a pointer to the registered monitoring factory if any, and nullptr
139   // otherwise.
GetMonitoringClientFactory()140   crypto::tink::MonitoringClientFactory* GetMonitoringClientFactory() const
141       ABSL_LOCKS_EXCLUDED(monitoring_factory_mutex_) {
142     absl::MutexLock lock(&monitoring_factory_mutex_);
143     return monitoring_factory_.get();
144   }
145 
146  private:
147   // Returns the key type info for a given type URL. Since we never replace
148   // key type infos, the pointers will stay valid for the lifetime of the
149   // binary.
150   crypto::tink::util::StatusOr<const KeyTypeInfoStore::Info*> get_key_type_info(
151       absl::string_view type_url) const ABSL_LOCKS_EXCLUDED(maps_mutex_);
152 
153   mutable absl::Mutex maps_mutex_;
154   // Stores information about key types constructed from their KeyTypeManager or
155   // KeyManager.
156   // Once inserted, KeyTypeInfoStore::Info objects must remain valid for the
157   // lifetime of the binary, and the Info object's pointer stability is
158   // required. Elements in Info, which include the KeyTypeManager or KeyManager,
159   // must not be replaced.
160   KeyTypeInfoStore key_type_info_store_ ABSL_GUARDED_BY(maps_mutex_);
161   // Stores information about keyset wrappers constructed from their
162   // PrimitiveWrapper.
163   KeysetWrapperStore keyset_wrapper_store_ ABSL_GUARDED_BY(maps_mutex_);
164 
165   mutable absl::Mutex monitoring_factory_mutex_;
166   std::unique_ptr<crypto::tink::MonitoringClientFactory> monitoring_factory_
167       ABSL_GUARDED_BY(monitoring_factory_mutex_);
168 };
169 
170 template <class P>
RegisterKeyManager(KeyManager<P> * manager,bool new_key_allowed)171 crypto::tink::util::Status RegistryImpl::RegisterKeyManager(
172     KeyManager<P>* manager, bool new_key_allowed) {
173   auto owned_manager = absl::WrapUnique(manager);
174   if (manager == nullptr) {
175     return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument,
176                                       "Parameter 'manager' must be non-null.");
177   }
178   absl::MutexLock lock(&maps_mutex_);
179   return key_type_info_store_.AddKeyManager(std::move(owned_manager),
180                                             new_key_allowed);
181 }
182 
183 template <class KeyProto, class KeyFormatProto, class PrimitiveList>
RegisterKeyTypeManager(std::unique_ptr<KeyTypeManager<KeyProto,KeyFormatProto,PrimitiveList>> manager,bool new_key_allowed)184 crypto::tink::util::Status RegistryImpl::RegisterKeyTypeManager(
185     std::unique_ptr<KeyTypeManager<KeyProto, KeyFormatProto, PrimitiveList>>
186         manager,
187     bool new_key_allowed) {
188   if (manager == nullptr) {
189     return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument,
190                                       "Parameter 'manager' must be non-null.");
191   }
192   absl::MutexLock lock(&maps_mutex_);
193   return key_type_info_store_.AddKeyTypeManager(std::move(manager),
194                                                 new_key_allowed);
195 }
196 
197 template <class PrivateKeyProto, class KeyFormatProto, class PublicKeyProto,
198           class PrivatePrimitivesList, class PublicPrimitivesList>
RegisterAsymmetricKeyManagers(PrivateKeyTypeManager<PrivateKeyProto,KeyFormatProto,PublicKeyProto,PrivatePrimitivesList> * private_manager,KeyTypeManager<PublicKeyProto,void,PublicPrimitivesList> * public_manager,bool new_key_allowed)199 crypto::tink::util::Status RegistryImpl::RegisterAsymmetricKeyManagers(
200     PrivateKeyTypeManager<PrivateKeyProto, KeyFormatProto, PublicKeyProto,
201                           PrivatePrimitivesList>* private_manager,
202     KeyTypeManager<PublicKeyProto, void, PublicPrimitivesList>* public_manager,
203     bool new_key_allowed) ABSL_LOCKS_EXCLUDED(maps_mutex_) {
204   auto owned_private_manager = absl::WrapUnique(private_manager);
205   auto owned_public_manager = absl::WrapUnique(public_manager);
206 
207   if (private_manager == nullptr) {
208     return crypto::tink::util::Status(
209         absl::StatusCode::kInvalidArgument,
210         "Parameter 'private_manager' must be non-null.");
211   }
212   if (public_manager == nullptr) {
213     return crypto::tink::util::Status(
214         absl::StatusCode::kInvalidArgument,
215         "Parameter 'public_manager' must be non-null.");
216   }
217 
218   absl::MutexLock lock(&maps_mutex_);
219   return key_type_info_store_.AddAsymmetricKeyTypeManagers(
220       std::move(owned_private_manager), std::move(owned_public_manager),
221       new_key_allowed);
222 }
223 
224 template <class P, class Q>
RegisterPrimitiveWrapper(PrimitiveWrapper<P,Q> * wrapper)225 crypto::tink::util::Status RegistryImpl::RegisterPrimitiveWrapper(
226     PrimitiveWrapper<P, Q>* wrapper) {
227   if (wrapper == nullptr) {
228     return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument,
229                                       "Parameter 'wrapper' must be non-null.");
230   }
231   std::unique_ptr<PrimitiveWrapper<P, Q>> owned_wrapper(wrapper);
232 
233   absl::MutexLock lock(&maps_mutex_);
234   absl::AnyInvocable<crypto::tink::util::StatusOr<std::unique_ptr<P>>(
235       const google::crypto::tink::KeyData& key_data) const>
236       primitive_getter = [this](const google::crypto::tink::KeyData& key_data) {
237         return this->GetPrimitive<P>(key_data);
238       };
239   return keyset_wrapper_store_.Add(std::move(owned_wrapper),
240                                    std::move(primitive_getter));
241 }
242 
243 template <class P>
244 crypto::tink::util::StatusOr<const KeyManager<P>*>
get_key_manager(absl::string_view type_url)245 RegistryImpl::get_key_manager(absl::string_view type_url) const {
246   crypto::tink::util::StatusOr<
247       const crypto::tink::internal::KeyTypeInfoStore::Info*>
248       info = get_key_type_info(type_url);
249   if (!info.ok()) {
250     return info.status();
251   }
252   return (*info)->get_key_manager<P>(type_url);
253 }
254 
255 template <class P>
GetPrimitive(const google::crypto::tink::KeyData & key_data)256 crypto::tink::util::StatusOr<std::unique_ptr<P>> RegistryImpl::GetPrimitive(
257     const google::crypto::tink::KeyData& key_data) const {
258   auto key_manager_result = get_key_manager<P>(key_data.type_url());
259   if (key_manager_result.ok()) {
260     return key_manager_result.value()->GetPrimitive(key_data);
261   }
262   return key_manager_result.status();
263 }
264 
265 template <class P>
Wrap(std::unique_ptr<PrimitiveSet<P>> primitive_set)266 crypto::tink::util::StatusOr<std::unique_ptr<P>> RegistryImpl::Wrap(
267     std::unique_ptr<PrimitiveSet<P>> primitive_set) const {
268   if (primitive_set == nullptr) {
269     return crypto::tink::util::Status(
270         absl::StatusCode::kInvalidArgument,
271         "Parameter 'primitive_set' must be non-null.");
272   }
273   const PrimitiveWrapper<P, P>* wrapper = nullptr;
274   {
275     absl::MutexLock lock(&maps_mutex_);
276     crypto::tink::util::StatusOr<const PrimitiveWrapper<P, P>*> wrapper_status =
277         keyset_wrapper_store_.GetPrimitiveWrapper<P>();
278     if (!wrapper_status.ok()) {
279       return wrapper_status.status();
280     }
281     wrapper = *wrapper_status;
282   }
283   return wrapper->Wrap(std::move(primitive_set));
284 }
285 
286 template <class P>
WrapKeyset(const google::crypto::tink::Keyset & keyset,const absl::flat_hash_map<std::string,std::string> & annotations)287 crypto::tink::util::StatusOr<std::unique_ptr<P>> RegistryImpl::WrapKeyset(
288     const google::crypto::tink::Keyset& keyset,
289     const absl::flat_hash_map<std::string, std::string>& annotations) const {
290   const KeysetWrapper<P>* keyset_wrapper = nullptr;
291   {
292     absl::MutexLock lock(&maps_mutex_);
293     crypto::tink::util::StatusOr<const KeysetWrapper<P>*>
294         keyset_wrapper_status = keyset_wrapper_store_.Get<P>();
295     if (!keyset_wrapper_status.ok()) {
296       return keyset_wrapper_status.status();
297     }
298     keyset_wrapper = *keyset_wrapper_status;
299   }
300   // `maps_mutex_` must be released before calling Wrap or this will deadlock,
301   // as Wrap calls get_key_manager.
302   return keyset_wrapper->Wrap(keyset, annotations);
303 }
304 
RestrictToFipsIfEmpty()305 inline crypto::tink::util::Status RegistryImpl::RestrictToFipsIfEmpty() const {
306   absl::MutexLock lock(&maps_mutex_);
307   // If we are already in FIPS mode, then do nothing..
308   if (IsFipsModeEnabled()) {
309     return util::OkStatus();
310   }
311   if (key_type_info_store_.IsEmpty()) {
312     SetFipsRestricted();
313     return util::OkStatus();
314   }
315   return util::Status(absl::StatusCode::kInternal,
316                       "Could not set FIPS only mode. Registry is not empty.");
317 }
318 
319 }  // namespace internal
320 }  // namespace tink
321 }  // namespace crypto
322 
323 #endif  // TINK_INTERNAL_REGISTRY_IMPL_H_
324