1 // Copyright 2019 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 #ifndef TINK_CORE_KEY_MANAGER_IMPL_H_
17 #define TINK_CORE_KEY_MANAGER_IMPL_H_
18
19 #include <functional>
20 #include <memory>
21 #include <string>
22 #include <utility>
23
24 #include "absl/base/casts.h"
25 #include "absl/memory/memory.h"
26 #include "absl/status/status.h"
27 #include "absl/strings/str_cat.h"
28 #include "tink/core/key_type_manager.h"
29 #include "tink/key_manager.h"
30 #include "tink/util/constants.h"
31 #include "tink/util/status.h"
32 #include "proto/tink.pb.h"
33
34 namespace crypto {
35 namespace tink {
36 namespace internal {
37
38 // Template declaration of the class "KeyFactoryImpl" with a single template
39 // argument. We first declare it, then later give two "partial template
40 // specializations". This will imply that the KeyFactoryImpl can only be
41 // instantiated with arguments of the form KeyTypeManager<...>.
42 template <class KeyTypeManager>
43 class KeyFactoryImpl;
44
45 // First partial template specialization for KeyFactoryImpl: the given
46 // KeyTypeManager is of the form KeyTypeManager<KeyProto,
47 // KeyFormatProto, List<Primitives...>>.
48 template <class KeyProto, class KeyFormatProto, class... Primitives>
49 class KeyFactoryImpl<
50 KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>>
51 : public KeyFactory {
52 public:
KeyFactoryImpl(KeyTypeManager<KeyProto,KeyFormatProto,List<Primitives...>> * key_type_manager)53 explicit KeyFactoryImpl(KeyTypeManager<KeyProto, KeyFormatProto,
54 List<Primitives...>>* key_type_manager)
55 : key_type_manager_(key_type_manager) {}
56
57 crypto::tink::util::StatusOr<std::unique_ptr<portable_proto::MessageLite>>
NewKey(const portable_proto::MessageLite & key_format)58 NewKey(const portable_proto::MessageLite& key_format) const override {
59 if (key_format.GetTypeName() != KeyFormatProto().GetTypeName()) {
60 return crypto::tink::util::Status(
61 absl::StatusCode::kInvalidArgument,
62 absl::StrCat("Key format proto '", key_format.GetTypeName(),
63 "' is not supported by this manager."));
64 }
65 auto validation = key_type_manager_->ValidateKeyFormat(
66 static_cast<const KeyFormatProto&>(key_format));
67 if (!validation.ok()) {
68 return validation;
69 }
70 crypto::tink::util::StatusOr<KeyProto> new_key_result =
71 key_type_manager_->CreateKey(
72 static_cast<const KeyFormatProto&>(key_format));
73 if (!new_key_result.ok()) return new_key_result.status();
74 return absl::implicit_cast<std::unique_ptr<portable_proto::MessageLite>>(
75 absl::make_unique<KeyProto>(std::move(new_key_result.value())));
76 }
77
78 crypto::tink::util::StatusOr<std::unique_ptr<portable_proto::MessageLite>>
NewKey(absl::string_view serialized_key_format)79 NewKey(absl::string_view serialized_key_format) const override {
80 KeyFormatProto key_format;
81 if (!key_format.ParseFromString(std::string(serialized_key_format))) {
82 return crypto::tink::util::Status(
83 absl::StatusCode::kInvalidArgument,
84 absl::StrCat("Could not parse the passed string as proto '",
85 KeyFormatProto().GetTypeName(), "'."));
86 }
87 auto validation = key_type_manager_->ValidateKeyFormat(key_format);
88 if (!validation.ok()) {
89 return validation;
90 }
91 return NewKey(static_cast<const portable_proto::MessageLite&>(key_format));
92 }
93
94 crypto::tink::util::StatusOr<std::unique_ptr<google::crypto::tink::KeyData>>
NewKeyData(absl::string_view serialized_key_format)95 NewKeyData(absl::string_view serialized_key_format) const override {
96 auto new_key_result = NewKey(serialized_key_format);
97 if (!new_key_result.ok()) return new_key_result.status();
98 auto new_key = static_cast<const KeyProto&>(*(new_key_result.value()));
99 auto key_data = absl::make_unique<google::crypto::tink::KeyData>();
100 key_data->set_type_url(
101 absl::StrCat(kTypeGoogleapisCom, KeyProto().GetTypeName()));
102 key_data->set_value(new_key.SerializeAsString());
103 key_data->set_key_material_type(key_type_manager_->key_material_type());
104 return std::move(key_data);
105 }
106
107 private:
108 KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>*
109 key_type_manager_;
110 };
111
112 // Second partial template specialization for KeyFactoryImpl: the given
113 // KeyTypeManager is of the form KeyTypeManager<KeyProto, void,
114 // List<Primitives...>>.
115 template <class KeyProto, class... Primitives>
116 class KeyFactoryImpl<KeyTypeManager<KeyProto, void, List<Primitives...>>>
117 : public KeyFactory {
118 public:
119 // We don't need the KeyTypeManager, but this is called from a template,
120 // so the easiest way to ignore the argument is to provide a constructor which
121 // ignores the argument.
KeyFactoryImpl(KeyTypeManager<KeyProto,void,List<Primitives...>> * key_type_manager)122 explicit KeyFactoryImpl(
123 KeyTypeManager<KeyProto, void, List<Primitives...>>* key_type_manager) {}
124
125 crypto::tink::util::StatusOr<std::unique_ptr<portable_proto::MessageLite>>
NewKey(const portable_proto::MessageLite & key_format)126 NewKey(const portable_proto::MessageLite& key_format) const override {
127 return util::Status(
128 absl::StatusCode::kUnimplemented,
129 "Creating new keys is not supported for this key manager.");
130 }
131
132 crypto::tink::util::StatusOr<std::unique_ptr<portable_proto::MessageLite>>
NewKey(absl::string_view serialized_key_format)133 NewKey(absl::string_view serialized_key_format) const override {
134 return util::Status(
135 absl::StatusCode::kUnimplemented,
136 "Creating new keys is not supported for this key manager.");
137 }
138
139 crypto::tink::util::StatusOr<std::unique_ptr<google::crypto::tink::KeyData>>
NewKeyData(absl::string_view serialized_key_format)140 NewKeyData(absl::string_view serialized_key_format) const override {
141 return util::Status(
142 absl::StatusCode::kUnimplemented,
143 "Creating new keys is not supported for this key manager.");
144 }
145 };
146
147 // Template declaration of the class "KeyManagerImpl" with two template
148 // arguments. There is only one specialization which is defined, namely when
149 // the KeyTypeManager argument is of the form KeyTypeManager<KeyProto,
150 // KeyFormatProto, List<Primitives...>>. We don't provide a
151 // specialization for the case KeyFormatProto = void, so the compiler will pick
152 // this instantiation in this case.
153 template <class Primitive, class KeyTypeManager>
154 class KeyManagerImpl;
155
156 // The first template argument to the KeyManagerImpl is the primitive for which
157 // we should generate a KeyManager. The second is the KeyTypeManager, which
158 // takes itself template arguments. The list of the Primitives there must
159 // contain the first Primitive argument (otherwise there will be failures at
160 // runtime).
161 template <class Primitive, class KeyProto, class KeyFormatProto,
162 class... Primitives>
163 class KeyManagerImpl<
164 Primitive, KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>>
165 : public KeyManager<Primitive> {
166 public:
KeyManagerImpl(KeyTypeManager<KeyProto,KeyFormatProto,List<Primitives...>> * key_type_manager)167 explicit KeyManagerImpl(KeyTypeManager<KeyProto, KeyFormatProto,
168 List<Primitives...>>* key_type_manager)
169 : key_type_manager_(key_type_manager),
170 key_factory_(
171 absl::make_unique<KeyFactoryImpl<
172 KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>>>(
173 key_type_manager_)) {}
174
175 // Constructs an instance of Primitive for the given 'key_data'.
GetPrimitive(const google::crypto::tink::KeyData & key_data)176 crypto::tink::util::StatusOr<std::unique_ptr<Primitive>> GetPrimitive(
177 const google::crypto::tink::KeyData& key_data) const override {
178 if (!this->DoesSupport(key_data.type_url())) {
179 return ToStatusF(absl::StatusCode::kInvalidArgument,
180 "Key type '%s' is not supported by this manager.",
181 key_data.type_url());
182 }
183 KeyProto key_proto;
184 if (!key_proto.ParseFromString(key_data.value())) {
185 return ToStatusF(absl::StatusCode::kInvalidArgument,
186 "Could not parse key_data.value as key type '%s'.",
187 key_data.type_url());
188 }
189 auto validation = key_type_manager_->ValidateKey(key_proto);
190 if (!validation.ok()) {
191 return validation;
192 }
193 return key_type_manager_->template GetPrimitive<Primitive>(key_proto);
194 }
195
GetPrimitive(const portable_proto::MessageLite & key)196 crypto::tink::util::StatusOr<std::unique_ptr<Primitive>> GetPrimitive(
197 const portable_proto::MessageLite& key) const override {
198 std::string key_type = absl::StrCat(kTypeGoogleapisCom, key.GetTypeName());
199 if (!this->DoesSupport(key_type)) {
200 return ToStatusF(absl::StatusCode::kInvalidArgument,
201 "Key type '%s' is not supported by this manager.",
202 key_type);
203 }
204 const KeyProto& key_proto = static_cast<const KeyProto&>(key);
205 auto validation = key_type_manager_->ValidateKey(key_proto);
206 if (!validation.ok()) {
207 return validation;
208 }
209 return key_type_manager_->template GetPrimitive<Primitive>(key_proto);
210 }
211
get_version()212 uint32_t get_version() const override {
213 return key_type_manager_->get_version();
214 }
215
get_key_type()216 const std::string& get_key_type() const override {
217 return key_type_manager_->get_key_type();
218 }
219
get_key_factory()220 const KeyFactory& get_key_factory() const override {
221 return *key_factory_;
222 }
223
224 private:
225 KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>*
226 key_type_manager_;
227 std::unique_ptr<KeyFactory> key_factory_;
228 };
229
230 // Helper function to create a KeyManager<Primitive> from a KeyTypeManager.
231 // Using this, all template arguments except the first one can be infered.
232 // Example:
233 // std::unique_ptr<KeyManager<Aead>> km =
234 // MakeKeyManager<Aead>(my_key_type_manager.get());
235 template <class Primitive, class KeyProto, class KeyFormatProto,
236 class... Primitives>
MakeKeyManager(KeyTypeManager<KeyProto,KeyFormatProto,List<Primitives...>> * key_type_manager)237 std::unique_ptr<KeyManager<Primitive>> MakeKeyManager(
238 KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>*
239 key_type_manager) {
240 return absl::make_unique<
241 KeyManagerImpl<Primitive, KeyTypeManager<KeyProto, KeyFormatProto,
242 List<Primitives...>>>>(
243 key_type_manager);
244 }
245
246 // Creates a function which can derive a key, using the given KeyTypeManager.
247 // Note that the returned function stores a pointer to the given KeyTypeManager,
248 // which must remain valid for the lifetime of the function.
249 template <class KeyProto, class KeyFormatProto, class... Primitives>
250 std::function<crypto::tink::util::StatusOr<google::crypto::tink::KeyData>(
251 absl::string_view, InputStream*)>
CreateDeriverFunctionFor(KeyTypeManager<KeyProto,KeyFormatProto,List<Primitives...>> * key_type_manager)252 CreateDeriverFunctionFor(
253 KeyTypeManager<KeyProto, KeyFormatProto, List<Primitives...>>*
254 key_type_manager) {
255 return [key_type_manager](absl::string_view serialized_key_format,
256 InputStream* randomness)
257 -> crypto::tink::util::StatusOr<google::crypto::tink::KeyData> {
258 KeyFormatProto key_format;
259 if (!key_format.ParseFromString(std::string(serialized_key_format))) {
260 return crypto::tink::util::Status(
261 absl::StatusCode::kInvalidArgument,
262 absl::StrCat("Could not parse the passed string as proto '",
263 KeyFormatProto().GetTypeName(), "'."));
264 }
265 auto status = key_type_manager->ValidateKeyFormat(key_format);
266 if (!status.ok()) {
267 return status;
268 }
269 auto key_proto_or = key_type_manager->DeriveKey(key_format, randomness);
270 if (!key_proto_or.ok()) {
271 return key_proto_or.status();
272 }
273 status = key_type_manager->ValidateKey(key_proto_or.value());
274 if (!status.ok()) {
275 return status;
276 }
277 google::crypto::tink::KeyData result;
278 result.set_type_url(key_type_manager->get_key_type());
279 result.set_value(key_proto_or.value().SerializeAsString());
280 result.set_key_material_type(key_type_manager->key_material_type());
281 return std::move(result);
282 };
283 }
284
285 // Template specialization of CreateDeriverFor in case the KeyTypeManager has
286 // KeyFormatProto = void, and hence there is no key derivation.
287 template <class KeyProto, class... Primitives>
288 std::function<crypto::tink::util::StatusOr<google::crypto::tink::KeyData>(
289 absl::string_view, InputStream*)>
CreateDeriverFunctionFor(KeyTypeManager<KeyProto,void,List<Primitives...>> * key_type_manager)290 CreateDeriverFunctionFor(
291 KeyTypeManager<KeyProto, void, List<Primitives...>>*
292 key_type_manager) {
293 return [key_type_manager](absl::string_view serialized_key_format,
294 InputStream* randomness)
295 -> crypto::tink::util::StatusOr<google::crypto::tink::KeyData> {
296 return crypto::tink::util::Status(
297 absl::StatusCode::kUnimplemented,
298 absl::StrCat("Registered KeyManager for type '",
299 key_type_manager->get_key_type(),
300 "' does not support key generation."));
301 };
302 }
303
304 } // namespace internal
305 } // namespace tink
306 } // namespace crypto
307
308 #endif // TINK_CORE_KEY_MANAGER_IMPL_H_
309