xref: /aosp_15_r20/external/tink/cc/internal/key_type_info_store.h (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2018 Google LLC
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_KEY_TYPE_INFO_STORE_H_
18 #define TINK_INTERNAL_KEY_TYPE_INFO_STORE_H_
19 
20 #include <atomic>
21 #include <functional>
22 #include <initializer_list>
23 #include <memory>
24 #include <string>
25 #include <typeindex>
26 #include <utility>
27 
28 #include "absl/container/flat_hash_map.h"
29 #include "absl/strings/str_join.h"
30 #include "tink/core/key_manager_impl.h"
31 #include "tink/core/key_type_manager.h"
32 #include "tink/core/private_key_manager_impl.h"
33 #include "tink/core/private_key_type_manager.h"
34 #include "tink/internal/fips_utils.h"
35 #include "tink/key_manager.h"
36 
37 namespace crypto {
38 namespace tink {
39 namespace internal {
40 
41 // Stores information about key types constructed from their KeyTypeManager or
42 // KeyManager. This is used by the Configuration and Registry classes.
43 //
44 // Once inserted, Info objects must remain valid for the lifetime of the
45 // KeyTypeInfoStore object, and the Info object's pointer stability is required.
46 // Elements in Info, which include the KeyTypeManager or KeyManager, must not
47 // be replaced.
48 //
49 // Example:
50 //  KeyTypeInfoStore store;
51 //  crypto::tink::util::Status status =
52 //      store.AddKeyTypeManager(absl::make_unique<AesGcmKeyManager>(), true);
53 //  crypto::tink::util::StatusOr<KeyTypeInfoStore::Info*> info =
54 //      store.Get(AesGcmKeyManager().get_key_type());
55 class KeyTypeInfoStore {
56  public:
57   KeyTypeInfoStore() = default;
58 
59   // Movable, but not copyable.
60   KeyTypeInfoStore(KeyTypeInfoStore&& other) = default;
61   KeyTypeInfoStore& operator=(KeyTypeInfoStore&& other) = default;
62 
63   // Information about a key type constructed from its KeyTypeManager or
64   // KeyManager.
65   class Info {
66    public:
67     // Takes ownership of `manager`.
68     template <typename KeyProto, typename KeyFormatProto,
69               typename... Primitives>
Info(KeyTypeManager<KeyProto,KeyFormatProto,List<Primitives...>> * manager,bool new_key_allowed)70     Info(KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>* manager,
71          bool new_key_allowed)
72         : key_manager_type_index_(std::type_index(typeid(*manager))),
73           public_key_type_manager_type_index_(absl::nullopt),
74           new_key_allowed_(new_key_allowed),
75           key_type_manager_(absl::WrapUnique(manager)),
76           internal_key_factory_(
77               absl::make_unique<internal::KeyFactoryImpl<KeyTypeManager<
78                   KeyProto, KeyFormatProto, List<Primitives...>>>>(manager)),
79           key_factory_(internal_key_factory_.get()),
80           key_deriver_(CreateDeriverFunctionFor(manager)) {
81       // TODO(C++17): Replace with a fold expression.
82       (void)std::initializer_list<int>{
83           0, (primitive_to_manager_.emplace(
84                   std::type_index(typeid(Primitives)),
85                   internal::MakeKeyManager<Primitives>(manager)),
86               0)...};
87     }
88 
89     // Takes ownership of `private_manager`, but not of `public_manager`, which
90     // must only be alive for the duration of the constructor.
91     template <typename PrivateKeyProto, typename KeyFormatProto,
92               typename PublicKeyProto, typename PublicPrimitivesList,
93               typename... PrivatePrimitives>
Info(PrivateKeyTypeManager<PrivateKeyProto,KeyFormatProto,PublicKeyProto,List<PrivatePrimitives...>> * private_manager,KeyTypeManager<PublicKeyProto,void,PublicPrimitivesList> * public_manager,bool new_key_allowed)94     Info(PrivateKeyTypeManager<PrivateKeyProto, KeyFormatProto, PublicKeyProto,
95                                List<PrivatePrimitives...>>* private_manager,
96          KeyTypeManager<PublicKeyProto, void, PublicPrimitivesList>*
97              public_manager,
98          bool new_key_allowed)
99         : key_manager_type_index_(std::type_index(typeid(*private_manager))),
100           public_key_type_manager_type_index_(
101               std::type_index(typeid(*public_manager))),
102           new_key_allowed_(new_key_allowed),
103           key_type_manager_(absl::WrapUnique(private_manager)),
104           internal_key_factory_(
105               absl::make_unique<internal::PrivateKeyFactoryImpl<
106                   PrivateKeyProto, KeyFormatProto, PublicKeyProto,
107                   List<PrivatePrimitives...>, PublicPrimitivesList>>(
108                   private_manager, public_manager)),
109           key_factory_(internal_key_factory_.get()),
110           key_deriver_(CreateDeriverFunctionFor(private_manager)) {
111       // TODO(C++17): Replace with a fold expression.
112       (void)std::initializer_list<int>{
113           0, (primitive_to_manager_.emplace(
114                   std::type_index(typeid(PrivatePrimitives)),
115                   internal::MakePrivateKeyManager<PrivatePrimitives>(
116                       private_manager, public_manager)),
117               0)...};
118     }
119 
120     // Takes ownership of `manager`. KeyManager is the legacy/internal version
121     // of KeyTypeManager.
122     template <typename P>
Info(KeyManager<P> * manager,bool new_key_allowed)123     Info(KeyManager<P>* manager, bool new_key_allowed)
124         : key_manager_type_index_(std::type_index(typeid(*manager))),
125           public_key_type_manager_type_index_(absl::nullopt),
126           new_key_allowed_(new_key_allowed),
127           key_type_manager_(nullptr),
128           internal_key_factory_(nullptr),
129           key_factory_(&manager->get_key_factory()) {
130       primitive_to_manager_.emplace(std::type_index(typeid(P)),
131                                     absl::WrapUnique(manager));
132     }
133 
134     template <typename P>
get_key_manager(absl::string_view requested_type_url)135     crypto::tink::util::StatusOr<const KeyManager<P>*> get_key_manager(
136         absl::string_view requested_type_url) const {
137       auto it = primitive_to_manager_.find(std::type_index(typeid(P)));
138       if (it == primitive_to_manager_.end()) {
139         return crypto::tink::util::Status(
140             absl::StatusCode::kInvalidArgument,
141             absl::StrCat(
142                 "Primitive type ", typeid(P).name(),
143                 " not among supported primitives ",
144                 absl::StrJoin(
145                     primitive_to_manager_.begin(), primitive_to_manager_.end(),
146                     ", ",
147                     [](std::string* out,
148                        const std::pair<const std::type_index,
149                                        std::unique_ptr<KeyManagerBase>>& kv) {
150                       absl::StrAppend(out, kv.first.name());
151                     }),
152                 " for type URL ", requested_type_url));
153       }
154       return static_cast<const KeyManager<P>*>(it->second.get());
155     }
156 
key_manager_type_index()157     const std::type_index& key_manager_type_index() const {
158       return key_manager_type_index_;
159     }
160 
public_key_type_manager_type_index()161     const absl::optional<std::type_index>& public_key_type_manager_type_index()
162         const {
163       return public_key_type_manager_type_index_;
164     }
165 
new_key_allowed()166     bool new_key_allowed() const { return new_key_allowed_.load(); }
167 
set_new_key_allowed(bool b)168     void set_new_key_allowed(bool b) { new_key_allowed_.store(b); }
169 
key_factory()170     const KeyFactory& key_factory() const { return *key_factory_; }
171 
172     const std::function<crypto::tink::util::StatusOr<
173         google::crypto::tink::KeyData>(absl::string_view, InputStream*)>&
key_deriver()174     key_deriver() const {
175       return key_deriver_;
176     }
177 
178    private:
179     // Dynamic type_index of the KeyManager or KeyTypeManager for this key type.
180     std::type_index key_manager_type_index_;
181     // Dynamic type_index of the public KeyTypeManager for this key type when
182     // inserted into the registry via RegisterAsymmetricKeyManagers. Otherwise,
183     // nullopt.
184     absl::optional<std::type_index> public_key_type_manager_type_index_;
185     // Whether the key manager allows the creation of new keys.
186     std::atomic<bool> new_key_allowed_;
187 
188     // Map from primitive type_index to KeyManager.
189     absl::flat_hash_map<std::type_index, std::unique_ptr<KeyManagerBase>>
190         primitive_to_manager_;
191     // Key type manager. Equals nullptr if Info was constructed from a
192     // KeyManager.
193     const std::shared_ptr<void> key_type_manager_;
194 
195     // Key factory. Equals nullptr if Info was constructed from a KeyManager.
196     std::unique_ptr<const KeyFactory> internal_key_factory_;
197     // Unowned version of `internal_key_factory_` if Info was constructed from a
198     // KeyTypeManager. Key factory belonging to the KeyManager if Info was
199     // constructed from a KeyManager.
200     const KeyFactory* key_factory_;
201 
202     // Derives a key if Info was constructed from a KeyTypeManager with a
203     // non-void KeyFormat type. Else, this function is empty and casting to a
204     // bool returns false.
205     std::function<crypto::tink::util::StatusOr<google::crypto::tink::KeyData>(
206         absl::string_view, InputStream*)>
207         key_deriver_;
208   };
209 
210   // Adds a crypto::tink::KeyTypeManager to KeyTypeInfoStore. `new_key_allowed`
211   // indicates whether `manager` may create new keys.
212   template <class KeyTypeManager>
213   crypto::tink::util::Status AddKeyTypeManager(
214       std::unique_ptr<KeyTypeManager> manager, bool new_key_allowed);
215 
216   // Adds a pair of crypto::tink::PrivateKeyTypeManager and
217   // crypto::tink::KeyTypeManager to KeyTypeInfoStore. `new_key_allowed`
218   // indicates whether `private_manager` may create new keys.
219   template <class PrivateKeyTypeManager, class PublicKeyTypeManager>
220   crypto::tink::util::Status AddAsymmetricKeyTypeManagers(
221       std::unique_ptr<PrivateKeyTypeManager> private_manager,
222       std::unique_ptr<PublicKeyTypeManager> public_manager,
223       bool new_key_allowed);
224 
225   // Adds a crypto::tink::KeyManager to KeyTypeInfoStore. `new_key_allowed`
226   // indicates whether `manager` may create new keys. KeyManager is the
227   // legacy/internal version of KeyTypeManager.
228   template <class P>
229   crypto::tink::util::Status AddKeyManager(
230       std::unique_ptr<KeyManager<P>> manager, bool new_key_allowed);
231 
232   // Gets Info associated with `type_url`, returning either a valid, non-null
233   // Info or an error.
234   crypto::tink::util::StatusOr<Info*> Get(absl::string_view type_url) const;
235 
IsEmpty()236   bool IsEmpty() const { return type_url_to_info_.empty(); }
237 
238  private:
239   // Whether a key manager with `type_url` and `key_manager_type_index` can be
240   // inserted.
241   crypto::tink::util::Status IsInsertable(
242       absl::string_view type_url, const std::type_index& key_manager_type_index,
243       bool new_key_allowed) const;
244 
Add(std::string type_url,std::unique_ptr<Info> info,bool new_key_allowed)245   void Add(std::string type_url, std::unique_ptr<Info> info,
246            bool new_key_allowed) {
247     auto it = type_url_to_info_.find(type_url);
248     if (it != type_url_to_info_.end()) {
249       it->second->set_new_key_allowed(new_key_allowed);
250     } else {
251       type_url_to_info_.insert({type_url, std::move(info)});
252     }
253   }
254 
255   // Map from the type_url to Info.
256   // Elements in Info must not be replaced, and pointer stability is required
257   // for `Get()`.
258   absl::flat_hash_map<std::string, std::unique_ptr<Info>> type_url_to_info_;
259 };
260 
261 template <class P>
AddKeyManager(std::unique_ptr<KeyManager<P>> manager,bool new_key_allowed)262 crypto::tink::util::Status KeyTypeInfoStore::AddKeyManager(
263     std::unique_ptr<KeyManager<P>> manager, bool new_key_allowed) {
264   std::string type_url = manager->get_key_type();
265   if (!manager->DoesSupport(type_url)) {
266     return ToStatusF(absl::StatusCode::kInvalidArgument,
267                      "The manager does not support type '%s'.", type_url);
268   }
269 
270   crypto::tink::util::Status status = IsInsertable(
271       type_url, std::type_index(typeid(*manager)), new_key_allowed);
272   if (!status.ok()) {
273     return status;
274   }
275 
276   auto info = absl::make_unique<Info>(manager.release(), new_key_allowed);
277   Add(type_url, std::move(info), new_key_allowed);
278   return crypto::tink::util::OkStatus();
279 }
280 
281 template <class KeyTypeManager>
AddKeyTypeManager(std::unique_ptr<KeyTypeManager> manager,bool new_key_allowed)282 crypto::tink::util::Status KeyTypeInfoStore::AddKeyTypeManager(
283     std::unique_ptr<KeyTypeManager> manager, bool new_key_allowed) {
284   // Check FIPS status.
285   internal::FipsCompatibility fips_compatible = manager->FipsStatus();
286   auto fips_status = internal::ChecksFipsCompatibility(fips_compatible);
287   if (!fips_status.ok()) {
288     return crypto::tink::util::Status(
289         absl::StatusCode::kInternal,
290         absl::StrCat("Failed registering the key manager for ",
291                      typeid(*manager).name(),
292                      " as it is not FIPS compatible: ", fips_status.message()));
293   }
294 
295   std::string type_url = manager->get_key_type();
296   crypto::tink::util::Status status = IsInsertable(
297       type_url, std::type_index(typeid(*manager)), new_key_allowed);
298   if (!status.ok()) {
299     return status;
300   }
301 
302   auto info = absl::make_unique<Info>(manager.release(), new_key_allowed);
303   Add(type_url, std::move(info), new_key_allowed);
304   return crypto::tink::util::OkStatus();
305 }
306 
307 template <class PrivateKeyTypeManager, class PublicKeyTypeManager>
AddAsymmetricKeyTypeManagers(std::unique_ptr<PrivateKeyTypeManager> private_manager,std::unique_ptr<PublicKeyTypeManager> public_manager,bool new_key_allowed)308 crypto::tink::util::Status KeyTypeInfoStore::AddAsymmetricKeyTypeManagers(
309     std::unique_ptr<PrivateKeyTypeManager> private_manager,
310     std::unique_ptr<PublicKeyTypeManager> public_manager,
311     bool new_key_allowed) {
312   std::string private_type_url = private_manager->get_key_type();
313   std::string public_type_url = public_manager->get_key_type();
314   if (private_type_url == public_type_url) {
315     return crypto::tink::util::Status(
316         absl::StatusCode::kInvalidArgument,
317         "Passed in key managers must have different get_key_type() results.");
318   }
319 
320   // Check FIPS status.
321   auto private_fips_status =
322       internal::ChecksFipsCompatibility(private_manager->FipsStatus());
323   if (!private_fips_status.ok()) {
324     return crypto::tink::util::Status(
325         absl::StatusCode::kInternal,
326         absl::StrCat(
327             "Failed registering the key manager for ",
328             typeid(*private_manager).name(),
329             " as it is not FIPS compatible: ", private_fips_status.message()));
330   }
331   auto public_fips_status =
332       internal::ChecksFipsCompatibility(public_manager->FipsStatus());
333   if (!public_fips_status.ok()) {
334     return crypto::tink::util::Status(
335         absl::StatusCode::kInternal,
336         absl::StrCat(
337             "Failed registering the key manager for ",
338             typeid(*public_manager).name(),
339             " as it is not FIPS compatible: ", public_fips_status.message()));
340   }
341 
342   crypto::tink::util::Status private_status =
343       IsInsertable(private_type_url, std::type_index(typeid(*private_manager)),
344                    new_key_allowed);
345   if (!private_status.ok()) {
346     return private_status;
347   }
348   crypto::tink::util::Status public_status =
349       IsInsertable(public_type_url, std::type_index(typeid(*public_manager)),
350                    new_key_allowed);
351   if (!public_status.ok()) {
352     return public_status;
353   }
354 
355   util::StatusOr<KeyTypeInfoStore::Info*> private_found = Get(private_type_url);
356   util::StatusOr<const KeyTypeInfoStore::Info*> public_found =
357       Get(public_type_url);
358 
359   // Only one of the private and public key type managers is found.
360   if (private_found.ok() && !public_found.ok()) {
361     return crypto::tink::util::Status(
362         absl::StatusCode::kInvalidArgument,
363         absl::StrCat(
364             "Private key manager corresponding to ",
365             typeid(*private_manager).name(),
366             " was previously registered, but key manager corresponding to ",
367             typeid(*public_manager).name(),
368             " was not, so it's impossible to register them jointly"));
369   }
370   if (!private_found.ok() && public_found.ok()) {
371     return crypto::tink::util::Status(
372         absl::StatusCode::kInvalidArgument,
373         absl::StrCat("Key manager corresponding to ",
374                      typeid(*public_manager).name(),
375                      " was previously registered, but private key manager "
376                      "corresponding to ",
377                      typeid(*private_manager).name(),
378                      " was not, so it's impossible to register them jointly"));
379   }
380 
381   // Both private and public key type managers are found.
382   if (private_found.ok() && public_found.ok()) {
383     if (!(*private_found)->public_key_type_manager_type_index().has_value()) {
384       return crypto::tink::util::Status(
385           absl::StatusCode::kInvalidArgument,
386           absl::StrCat("private key manager corresponding to ",
387                        typeid(*private_manager).name(),
388                        " is already registered without public key manager, "
389                        "cannot be re-registered with public key manager. "));
390     }
391     if ((*private_found)->public_key_type_manager_type_index() !=
392         std::type_index(typeid(*public_manager))) {
393       return crypto::tink::util::Status(
394           absl::StatusCode::kInvalidArgument,
395           absl::StrCat(
396               "private key manager corresponding to ",
397               typeid(*private_manager).name(), " is already registered with ",
398               (*private_found)->public_key_type_manager_type_index()->name(),
399               ", cannot be re-registered with ",
400               typeid(*public_manager).name()));
401     }
402     // Since `private_manager` passed the `IsInsertable` check above, the
403     // `set_new_key_allowed` operation is permissible.
404     (*private_found)->set_new_key_allowed(new_key_allowed);
405     return crypto::tink::util::OkStatus();
406   }
407 
408   // Both private and public key type managers were not found.
409   auto private_info = absl::make_unique<Info>(
410       private_manager.release(), public_manager.get(), new_key_allowed);
411   Add(private_type_url, std::move(private_info), new_key_allowed);
412   // TODO(b/265705174): Store public key type managers in an asymmetric pair
413   // with new_key_allowed = false.
414   auto public_info =
415       absl::make_unique<Info>(public_manager.release(), new_key_allowed);
416   Add(public_type_url, std::move(public_info), new_key_allowed);
417 
418   return crypto::tink::util::OkStatus();
419 }
420 
421 }  // namespace internal
422 }  // namespace tink
423 }  // namespace crypto
424 
425 #endif  // TINK_INTERNAL_KEY_TYPE_INFO_STORE_H_
426