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