xref: /aosp_15_r20/external/tink/cc/internal/keyset_wrapper_store.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_KEYSET_WRAPPER_STORE_H_
18 #define TINK_INTERNAL_KEYSET_WRAPPER_STORE_H_
19 
20 #include <memory>
21 #include <typeindex>
22 
23 #include "absl/functional/any_invocable.h"
24 #include "tink/internal/keyset_wrapper.h"
25 #include "tink/internal/keyset_wrapper_impl.h"
26 #include "tink/primitive_wrapper.h"
27 #include "tink/util/status.h"
28 #include "tink/util/statusor.h"
29 
30 namespace crypto {
31 namespace tink {
32 namespace internal {
33 
34 // Stores KeysetWrappers constructed from their PrimitiveWrapper. This is used
35 // by the Configuration and Registry classes.
36 //
37 // Once inserted, elements in Info, which include the PrimitiveWrapper, must not
38 // be replaced.
39 //
40 // Example:
41 //  KeysetWrapperStore store;
42 //  crypto::tink::util::Status status = store.Add<Aead, Aead>(
43 //      absl::make_unique<AeadWrapper>(), std::move(primitive_getter));
44 //  crypto::tink::util::StatusOr<const KeysetWrapper<Aead>*> wrapper =
45 //      store.Get<Aead>();
46 class KeysetWrapperStore {
47  public:
48   KeysetWrapperStore() = default;
49 
50   // Movable, but not copyable.
51   KeysetWrapperStore(KeysetWrapperStore&& other) = default;
52   KeysetWrapperStore& operator=(KeysetWrapperStore&& other) = default;
53 
54   // Adds a crypto::tink::PrimitiveWrapper and `primitive_getter` function to
55   // KeysetWrapperStore.
56   template <class P, class Q>
57   crypto::tink::util::Status Add(
58       std::unique_ptr<PrimitiveWrapper<P, Q>> wrapper,
59       absl::AnyInvocable<crypto::tink::util::StatusOr<std::unique_ptr<P>>(
60           const google::crypto::tink::KeyData& key_data) const>
61           primitive_getter);
62 
63   // Gets the PrimitiveWrapper that produces primitive P. This is a legacy
64   // function.
65   template <class P>
66   crypto::tink::util::StatusOr<const PrimitiveWrapper<P, P>*>
67   GetPrimitiveWrapper() const;
68 
69   // Gets the KeysetWrapper that produces primitive Q.
70   template <class Q>
71   crypto::tink::util::StatusOr<const KeysetWrapper<Q>*> Get() const;
72 
IsEmpty()73   bool IsEmpty() const { return primitive_to_info_.empty(); }
74 
75  private:
76   class Info {
77    public:
78     template <typename P, typename Q>
Info(std::unique_ptr<PrimitiveWrapper<P,Q>> wrapper,absl::AnyInvocable<crypto::tink::util::StatusOr<std::unique_ptr<P>> (const google::crypto::tink::KeyData & key_data)const> primitive_getter)79     explicit Info(
80         std::unique_ptr<PrimitiveWrapper<P, Q>> wrapper,
81         absl::AnyInvocable<crypto::tink::util::StatusOr<std::unique_ptr<P>>(
82             const google::crypto::tink::KeyData& key_data) const>
83             primitive_getter)
84         : is_same_primitive_wrapping_(std::is_same<P, Q>::value),
85           wrapper_type_index_(std::type_index(typeid(*wrapper))),
86           q_type_index_(std::type_index(typeid(Q))) {
87       keyset_wrapper_ = absl::make_unique<KeysetWrapperImpl<P, Q>>(
88           wrapper.get(), std::move(primitive_getter));
89       original_wrapper_ = std::move(wrapper);
90     }
91 
92     template <typename Q>
Get()93     crypto::tink::util::StatusOr<const KeysetWrapper<Q>*> Get() const {
94       if (q_type_index_ != std::type_index(typeid(Q))) {
95         return crypto::tink::util::Status(
96             absl::StatusCode::kInternal,
97             "RegistryImpl::KeysetWrapper() called with wrong type");
98       }
99       return static_cast<KeysetWrapper<Q>*>(keyset_wrapper_.get());
100     }
101 
102     // TODO(b/171021679): Deprecate this and upstream functions.
103     template <typename P>
104     crypto::tink::util::StatusOr<const PrimitiveWrapper<P, P>*>
GetPrimitiveWrapper()105     GetPrimitiveWrapper() const {
106       if (!is_same_primitive_wrapping_) {
107         // This happens if a user uses a legacy method (like Registry::Wrap)
108         // directly or has a custom key manager for a primitive which has a
109         // PrimitiveWrapper<P,Q> with P != Q.
110         return crypto::tink::util::Status(
111             absl::StatusCode::kFailedPrecondition,
112             absl::StrCat("Cannot use primitive type ", typeid(P).name(),
113                          " with a custom key manager."));
114       }
115       if (q_type_index_ != std::type_index(typeid(P))) {
116         return crypto::tink::util::Status(
117             absl::StatusCode::kInternal,
118             "RegistryImpl::LegacyWrapper() called with wrong type");
119       }
120       return static_cast<const PrimitiveWrapper<P, P>*>(
121           original_wrapper_.get());
122     }
123 
124     // Returns true if the PrimitiveWrapper is the same class as the one used
125     // to construct this Info.
126     template <typename P, typename Q>
HasSameType(const PrimitiveWrapper<P,Q> & wrapper)127     bool HasSameType(const PrimitiveWrapper<P, Q>& wrapper) {
128       return wrapper_type_index_ == std::type_index(typeid(wrapper));
129     }
130 
131    private:
132     bool is_same_primitive_wrapping_;
133     // dynamic std::type_index of the actual PrimitiveWrapper<P,Q> class for
134     // which this key was inserted.
135     std::type_index wrapper_type_index_;
136     // dynamic std::type_index of Q, when PrimitiveWrapper<P,Q> was inserted.
137     std::type_index q_type_index_;
138     // The primitive_wrapper passed in. We use a shared_ptr because
139     // unique_ptr<void> is invalid.
140     std::shared_ptr<void> original_wrapper_;
141     // The keyset_wrapper_. We use a shared_ptr because unique_ptr<void> is
142     // invalid.
143     std::shared_ptr<void> keyset_wrapper_;
144   };
145 
146   // Map from primitive type_index to Info.
147   absl::flat_hash_map<std::type_index, Info> primitive_to_info_;
148 };
149 
150 template <class P, class Q>
Add(std::unique_ptr<PrimitiveWrapper<P,Q>> wrapper,absl::AnyInvocable<crypto::tink::util::StatusOr<std::unique_ptr<P>> (const google::crypto::tink::KeyData & key_data)const> primitive_getter)151 crypto::tink::util::Status KeysetWrapperStore::Add(
152     std::unique_ptr<PrimitiveWrapper<P, Q>> wrapper,
153     absl::AnyInvocable<crypto::tink::util::StatusOr<std::unique_ptr<P>>(
154         const google::crypto::tink::KeyData& key_data) const>
155         primitive_getter) {
156   if (wrapper == nullptr) {
157     return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument,
158                                       "Parameter 'wrapper' must be non-null.");
159   }
160   auto it = primitive_to_info_.find(std::type_index(typeid(Q)));
161   if (it != primitive_to_info_.end()) {
162     if (!it->second.HasSameType(*wrapper)) {
163       return util::Status(absl::StatusCode::kAlreadyExists,
164                           "A wrapper named for this primitive already exists.");
165     }
166     return crypto::tink::util::OkStatus();
167   }
168 
169   primitive_to_info_.insert(
170       {std::type_index(typeid(Q)),
171        Info(std::move(wrapper), std::move(primitive_getter))});
172 
173   return crypto::tink::util::OkStatus();
174 }
175 
176 template <class P>
177 crypto::tink::util::StatusOr<const PrimitiveWrapper<P, P>*>
GetPrimitiveWrapper()178 KeysetWrapperStore::GetPrimitiveWrapper() const {
179   auto it = primitive_to_info_.find(std::type_index(typeid(P)));
180   if (it == primitive_to_info_.end()) {
181     return util::Status(
182         absl::StatusCode::kNotFound,
183         absl::StrCat("No wrapper registered for type ", typeid(P).name()));
184   }
185   return it->second.GetPrimitiveWrapper<P>();
186 }
187 
188 template <class P>
Get()189 crypto::tink::util::StatusOr<const KeysetWrapper<P>*> KeysetWrapperStore::Get()
190     const {
191   auto it = primitive_to_info_.find(std::type_index(typeid(P)));
192   if (it == primitive_to_info_.end()) {
193     return util::Status(
194         absl::StatusCode::kNotFound,
195         absl::StrCat("No wrapper registered for type ", typeid(P).name()));
196   }
197   return it->second.Get<P>();
198 }
199 
200 }  // namespace internal
201 }  // namespace tink
202 }  // namespace crypto
203 
204 #endif  // TINK_INTERNAL_KEYSET_WRAPPER_STORE_H_
205