1 // Copyright 2017 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 #include "tink/keyset_handle.h"
18
19 #include <cstdint>
20 #include <memory>
21 #include <string>
22 #include <utility>
23 #include <vector>
24
25 #include "absl/container/flat_hash_map.h"
26 #include "absl/log/check.h"
27 #include "absl/memory/memory.h"
28 #include "absl/status/status.h"
29 #include "absl/strings/string_view.h"
30 #include "absl/types/optional.h"
31 #include "tink/aead.h"
32 #include "tink/config/global_registry.h"
33 #include "tink/insecure_secret_key_access.h"
34 #include "tink/internal/key_gen_configuration_impl.h"
35 #include "tink/internal/key_info.h"
36 #include "tink/internal/key_status_util.h"
37 #include "tink/internal/key_type_info_store.h"
38 #include "tink/internal/mutable_serialization_registry.h"
39 #include "tink/internal/proto_key_serialization.h"
40 #include "tink/internal/util.h"
41 #include "tink/key_gen_configuration.h"
42 #include "tink/key_manager.h"
43 #include "tink/key_status.h"
44 #include "tink/keyset_reader.h"
45 #include "tink/keyset_writer.h"
46 #include "tink/registry.h"
47 #include "tink/util/errors.h"
48 #include "tink/util/keyset_util.h"
49 #include "tink/util/status.h"
50 #include "tink/util/statusor.h"
51 #include "proto/tink.pb.h"
52
53 using google::crypto::tink::EncryptedKeyset;
54 using google::crypto::tink::KeyData;
55 using google::crypto::tink::Keyset;
56 using google::crypto::tink::KeysetInfo;
57 using google::crypto::tink::KeyStatusType;
58 using google::crypto::tink::KeyTemplate;
59 using google::crypto::tink::OutputPrefixType;
60
61 namespace crypto {
62 namespace tink {
63
64 namespace {
65
Encrypt(const Keyset & keyset,const Aead & master_key_aead,absl::string_view associated_data)66 util::StatusOr<std::unique_ptr<EncryptedKeyset>> Encrypt(
67 const Keyset& keyset, const Aead& master_key_aead,
68 absl::string_view associated_data) {
69 auto encrypt_result =
70 master_key_aead.Encrypt(keyset.SerializeAsString(), associated_data);
71 if (!encrypt_result.ok()) return encrypt_result.status();
72 auto enc_keyset = absl::make_unique<EncryptedKeyset>();
73 enc_keyset->set_encrypted_keyset(encrypt_result.value());
74 return std::move(enc_keyset);
75 }
76
Decrypt(const EncryptedKeyset & enc_keyset,const Aead & master_key_aead,absl::string_view associated_data)77 util::StatusOr<std::unique_ptr<Keyset>> Decrypt(
78 const EncryptedKeyset& enc_keyset, const Aead& master_key_aead,
79 absl::string_view associated_data) {
80 auto decrypt_result =
81 master_key_aead.Decrypt(enc_keyset.encrypted_keyset(), associated_data);
82 if (!decrypt_result.ok()) return decrypt_result.status();
83 auto keyset = absl::make_unique<Keyset>();
84 if (!keyset->ParseFromString(decrypt_result.value())) {
85 return util::Status(
86 absl::StatusCode::kInvalidArgument,
87 "Could not parse the decrypted data as a Keyset-proto.");
88 }
89 return std::move(keyset);
90 }
91
ValidateNoSecret(const Keyset & keyset)92 util::Status ValidateNoSecret(const Keyset& keyset) {
93 for (const Keyset::Key& key : keyset.key()) {
94 if (key.key_data().key_material_type() == KeyData::UNKNOWN_KEYMATERIAL ||
95 key.key_data().key_material_type() == KeyData::SYMMETRIC ||
96 key.key_data().key_material_type() == KeyData::ASYMMETRIC_PRIVATE) {
97 return util::Status(
98 absl::StatusCode::kFailedPrecondition,
99 "Cannot create KeysetHandle with secret key material from "
100 "potentially unencrypted source.");
101 }
102 }
103 return util::OkStatus();
104 }
105
ToProtoKeySerialization(Keyset::Key key)106 util::StatusOr<internal::ProtoKeySerialization> ToProtoKeySerialization(
107 Keyset::Key key) {
108 absl::optional<int> id_requirement = absl::nullopt;
109 if (key.output_prefix_type() != OutputPrefixType::RAW) {
110 id_requirement = key.key_id();
111 }
112
113 return internal::ProtoKeySerialization::Create(
114 key.key_data().type_url(),
115 RestrictedData(key.key_data().value(), InsecureSecretKeyAccess::Get()),
116 key.key_data().key_material_type(), key.output_prefix_type(),
117 id_requirement);
118 }
119
120 } // anonymous namespace
121
ValidateAt(int index) const122 util::Status KeysetHandle::ValidateAt(int index) const {
123 const Keyset::Key& proto_key = get_keyset().key(index);
124 OutputPrefixType output_prefix_type = proto_key.output_prefix_type();
125 absl::optional<int> id_requirement = absl::nullopt;
126 if (output_prefix_type != OutputPrefixType::RAW) {
127 id_requirement = proto_key.key_id();
128 }
129
130 if (!internal::IsPrintableAscii(proto_key.key_data().type_url())) {
131 return util::Status(absl::StatusCode::kFailedPrecondition,
132 "Non-printable ASCII character in type URL.");
133 }
134
135 util::StatusOr<KeyStatus> key_status =
136 internal::FromKeyStatusType(proto_key.status());
137 if (!key_status.ok()) return key_status.status();
138
139 return util::OkStatus();
140 }
141
Validate() const142 util::Status KeysetHandle::Validate() const {
143 int num_primary = 0;
144 const Keyset& keyset = get_keyset();
145
146 for (int i = 0; i < size(); ++i) {
147 util::Status status = ValidateAt(i);
148 if (!status.ok()) return status;
149
150 Keyset::Key proto_key = keyset.key(i);
151 if (proto_key.key_id() == keyset.primary_key_id()) {
152 ++num_primary;
153 if (proto_key.status() != KeyStatusType::ENABLED) {
154 return util::Status(absl::StatusCode::kFailedPrecondition,
155 "Keyset has primary that is not enabled");
156 }
157 }
158 }
159
160 if (num_primary < 1) {
161 return util::Status(absl::StatusCode::kFailedPrecondition,
162 "Keyset has no primary");
163 }
164 if (num_primary > 1) {
165 return util::Status(absl::StatusCode::kFailedPrecondition,
166 "Keyset has more than one primary");
167 }
168
169 return util::OkStatus();
170 }
171
GetPrimary() const172 KeysetHandle::Entry KeysetHandle::GetPrimary() const {
173 util::Status validation = Validate();
174 CHECK_OK(validation);
175
176 const Keyset& keyset = get_keyset();
177 for (int i = 0; i < keyset.key_size(); ++i) {
178 if (keyset.key(i).key_id() == keyset.primary_key_id()) {
179 return (*this)[i];
180 }
181 }
182
183 // Since keyset handle was validated, it should have a valid primary key.
184 internal::LogFatal("Keyset handle should have a valid primary key.");
185 }
186
operator [](int index) const187 KeysetHandle::Entry KeysetHandle::operator[](int index) const {
188 CHECK(index >= 0 && index < size())
189 << "Invalid index " << index << " for keyset of size " << size();
190
191 if (!entries_.empty() && entries_.size() > index) {
192 return *entries_[index];
193 }
194 // Since `entries_` has not been populated, the entry must be created on
195 // demand from the key proto entry at `index` in `keyset_`. This special
196 // case will no longer be necessary after `keyset_` has been removed from the
197 // `KeysetHandle` class.
198 //
199 // TODO(b/277792846): Remove after transition to rely solely on
200 // `KeysetHandle::Entry`.
201 return CreateEntryAt(index);
202 }
203
CreateEntryAt(int index) const204 KeysetHandle::Entry KeysetHandle::CreateEntryAt(int index) const {
205 CHECK(index >= 0 && index < size())
206 << "Invalid index " << index << " for keyset of size " << size();
207
208 util::Status validation = ValidateAt(index);
209 CHECK_OK(validation);
210
211 Keyset keyset = get_keyset();
212 util::StatusOr<Entry> entry =
213 CreateEntry(keyset.key(index), keyset.primary_key_id());
214 // Status should be OK since this keyset handle has been validated.
215 CHECK_OK(entry.status());
216 return *entry;
217 }
218
CreateEntry(const Keyset::Key & proto_key,uint32_t primary_key_id)219 util::StatusOr<KeysetHandle::Entry> KeysetHandle::CreateEntry(
220 const Keyset::Key& proto_key, uint32_t primary_key_id) {
221 util::StatusOr<internal::ProtoKeySerialization> serialization =
222 ToProtoKeySerialization(proto_key);
223 if (!serialization.ok()) {
224 return serialization.status();
225 }
226
227 util::StatusOr<std::shared_ptr<const Key>> key =
228 internal::MutableSerializationRegistry::GlobalInstance()
229 .ParseKeyWithLegacyFallback(*serialization,
230 InsecureSecretKeyAccess::Get());
231 if (!key.ok()) {
232 return key.status();
233 }
234
235 util::StatusOr<KeyStatus> key_status =
236 internal::FromKeyStatusType(proto_key.status());
237 if (!key_status.ok()) {
238 return key_status.status();
239 }
240
241 return Entry(*std::move(key), *key_status, proto_key.key_id(),
242 proto_key.key_id() == primary_key_id);
243 }
244
Read(std::unique_ptr<KeysetReader> reader,const Aead & master_key_aead,const absl::flat_hash_map<std::string,std::string> & monitoring_annotations)245 util::StatusOr<std::unique_ptr<KeysetHandle>> KeysetHandle::Read(
246 std::unique_ptr<KeysetReader> reader, const Aead& master_key_aead,
247 const absl::flat_hash_map<std::string, std::string>&
248 monitoring_annotations) {
249 return ReadWithAssociatedData(std::move(reader), master_key_aead,
250 /*associated_data=*/"", monitoring_annotations);
251 }
252
253 util::StatusOr<std::unique_ptr<KeysetHandle>>
ReadWithAssociatedData(std::unique_ptr<KeysetReader> reader,const Aead & master_key_aead,absl::string_view associated_data,const absl::flat_hash_map<std::string,std::string> & monitoring_annotations)254 KeysetHandle::ReadWithAssociatedData(
255 std::unique_ptr<KeysetReader> reader, const Aead& master_key_aead,
256 absl::string_view associated_data,
257 const absl::flat_hash_map<std::string, std::string>&
258 monitoring_annotations) {
259 util::StatusOr<std::unique_ptr<EncryptedKeyset>> enc_keyset_result =
260 reader->ReadEncrypted();
261 if (!enc_keyset_result.ok()) {
262 return ToStatusF(absl::StatusCode::kInvalidArgument,
263 "Error reading encrypted keyset data: %s",
264 enc_keyset_result.status().message());
265 }
266
267 auto keyset_result =
268 Decrypt(*enc_keyset_result.value(), master_key_aead, associated_data);
269 if (!keyset_result.ok()) {
270 return ToStatusF(absl::StatusCode::kInvalidArgument,
271 "Error decrypting encrypted keyset: %s",
272 keyset_result.status().message());
273 }
274 util::StatusOr<std::vector<std::shared_ptr<const Entry>>> entries =
275 GetEntriesFromKeyset(**keyset_result);
276 if (!entries.ok()) {
277 return entries.status();
278 }
279 if (entries->size() != (*keyset_result)->key_size()) {
280 return util::Status(absl::StatusCode::kInternal,
281 "Error converting keyset proto into key entries.");
282 }
283 return absl::WrapUnique(new KeysetHandle(*std::move(keyset_result), *entries,
284 monitoring_annotations));
285 }
286
ReadNoSecret(const std::string & serialized_keyset,const absl::flat_hash_map<std::string,std::string> & monitoring_annotations)287 util::StatusOr<std::unique_ptr<KeysetHandle>> KeysetHandle::ReadNoSecret(
288 const std::string& serialized_keyset,
289 const absl::flat_hash_map<std::string, std::string>&
290 monitoring_annotations) {
291 Keyset keyset;
292 if (!keyset.ParseFromString(serialized_keyset)) {
293 return util::Status(absl::StatusCode::kInvalidArgument,
294 "Could not parse the input string as a Keyset-proto.");
295 }
296 util::Status validation = ValidateNoSecret(keyset);
297 if (!validation.ok()) {
298 return validation;
299 }
300 util::StatusOr<std::vector<std::shared_ptr<const Entry>>> entries =
301 GetEntriesFromKeyset(keyset);
302 if (!entries.ok()) {
303 return entries.status();
304 }
305 if (entries->size() != keyset.key_size()) {
306 return util::Status(absl::StatusCode::kInternal,
307 "Error converting keyset proto into key entries.");
308 }
309 return absl::WrapUnique(
310 new KeysetHandle(std::move(keyset), *entries, monitoring_annotations));
311 }
312
Write(KeysetWriter * writer,const Aead & master_key_aead) const313 util::Status KeysetHandle::Write(KeysetWriter* writer,
314 const Aead& master_key_aead) const {
315 return WriteWithAssociatedData(writer, master_key_aead, "");
316 }
317
WriteWithAssociatedData(KeysetWriter * writer,const Aead & master_key_aead,absl::string_view associated_data) const318 util::Status KeysetHandle::WriteWithAssociatedData(
319 KeysetWriter* writer, const Aead& master_key_aead,
320 absl::string_view associated_data) const {
321 if (writer == nullptr) {
322 return util::Status(absl::StatusCode::kInvalidArgument,
323 "Writer must be non-null");
324 }
325 auto encrypt_result = Encrypt(get_keyset(), master_key_aead, associated_data);
326 if (!encrypt_result.ok()) {
327 return ToStatusF(absl::StatusCode::kInvalidArgument,
328 "Encryption of the keyset failed: %s",
329 encrypt_result.status().message());
330 }
331 return writer->Write(*(encrypt_result.value()));
332 }
333
WriteNoSecret(KeysetWriter * writer) const334 util::Status KeysetHandle::WriteNoSecret(KeysetWriter* writer) const {
335 if (writer == nullptr) {
336 return util::Status(absl::StatusCode::kInvalidArgument,
337 "Writer must be non-null");
338 }
339
340 util::Status validation = ValidateNoSecret(get_keyset());
341 if (!validation.ok()) return validation;
342
343 return writer->Write(get_keyset());
344 }
345
GenerateNew(const KeyTemplate & key_template,const KeyGenConfiguration & config,const absl::flat_hash_map<std::string,std::string> & monitoring_annotations)346 util::StatusOr<std::unique_ptr<KeysetHandle>> KeysetHandle::GenerateNew(
347 const KeyTemplate& key_template, const KeyGenConfiguration& config,
348 const absl::flat_hash_map<std::string, std::string>&
349 monitoring_annotations) {
350 auto handle =
351 absl::WrapUnique(new KeysetHandle(Keyset(), monitoring_annotations));
352 util::StatusOr<uint32_t> const result =
353 handle->AddKey(key_template, /*as_primary=*/true, config);
354 if (!result.ok()) {
355 return result.status();
356 }
357 return std::move(handle);
358 }
359
GenerateNew(const KeyTemplate & key_template,const absl::flat_hash_map<std::string,std::string> & monitoring_annotations)360 util::StatusOr<std::unique_ptr<KeysetHandle>> KeysetHandle::GenerateNew(
361 const KeyTemplate& key_template,
362 const absl::flat_hash_map<std::string, std::string>&
363 monitoring_annotations) {
364 KeyGenConfiguration config;
365 util::Status status =
366 internal::KeyGenConfigurationImpl::SetGlobalRegistryMode(config);
367 if (!status.ok()) {
368 return status;
369 }
370 return GenerateNew(key_template, config, monitoring_annotations);
371 }
372
ExtractPublicKey(const Keyset::Key & key,const KeyGenConfiguration & config)373 util::StatusOr<std::unique_ptr<Keyset::Key>> ExtractPublicKey(
374 const Keyset::Key& key, const KeyGenConfiguration& config) {
375 if (key.key_data().key_material_type() != KeyData::ASYMMETRIC_PRIVATE) {
376 return util::Status(
377 absl::StatusCode::kInvalidArgument,
378 "Key material is not of type KeyData::ASYMMETRIC_PRIVATE");
379 }
380
381 util::StatusOr<std::unique_ptr<KeyData>> key_data;
382 if (internal::KeyGenConfigurationImpl::IsInGlobalRegistryMode(config)) {
383 key_data = Registry::GetPublicKeyData(key.key_data().type_url(),
384 key.key_data().value());
385 } else {
386 util::StatusOr<const internal::KeyTypeInfoStore*> key_type_info_store =
387 internal::KeyGenConfigurationImpl::GetKeyTypeInfoStore(config);
388 if (!key_type_info_store.ok()) {
389 return key_type_info_store.status();
390 }
391 util::StatusOr<const internal::KeyTypeInfoStore::Info*> key_type_info =
392 (*key_type_info_store)->Get(key.key_data().type_url());
393 if (!key_type_info.ok()) {
394 return key_type_info.status();
395 }
396 auto factory = dynamic_cast<const PrivateKeyFactory*>(
397 &(*key_type_info)->key_factory());
398 if (factory == nullptr) {
399 return ToStatusF(
400 absl::StatusCode::kInvalidArgument,
401 "KeyManager for type '%s' does not have a PrivateKeyFactory.",
402 key.key_data().type_url());
403 }
404 key_data = factory->GetPublicKeyData(key.key_data().value());
405 }
406 if (!key_data.ok()) {
407 return key_data.status();
408 }
409
410 auto public_key = absl::make_unique<Keyset::Key>(key);
411 public_key->mutable_key_data()->Swap(key_data->get());
412 return std::move(public_key);
413 }
414
415 util::StatusOr<std::unique_ptr<KeysetHandle>>
GetPublicKeysetHandle(const KeyGenConfiguration & config) const416 KeysetHandle::GetPublicKeysetHandle(const KeyGenConfiguration& config) const {
417 std::unique_ptr<Keyset> public_keyset(new Keyset());
418 for (const Keyset::Key& key : get_keyset().key()) {
419 auto public_key_result = ExtractPublicKey(key, config);
420 if (!public_key_result.ok()) return public_key_result.status();
421 public_keyset->add_key()->Swap(public_key_result.value().get());
422 }
423 public_keyset->set_primary_key_id(get_keyset().primary_key_id());
424 util::StatusOr<std::vector<std::shared_ptr<const Entry>>> entries =
425 GetEntriesFromKeyset(*public_keyset);
426 if (!entries.ok()) {
427 return entries.status();
428 }
429 if (entries->size() != public_keyset->key_size()) {
430 return util::Status(absl::StatusCode::kInternal,
431 "Error converting keyset proto into key entries.");
432 }
433 std::unique_ptr<KeysetHandle> handle(
434 new KeysetHandle(std::move(public_keyset), *entries));
435 return std::move(handle);
436 }
437
438 util::StatusOr<std::unique_ptr<KeysetHandle>>
GetPublicKeysetHandle() const439 KeysetHandle::GetPublicKeysetHandle() const {
440 return GetPublicKeysetHandle(KeyGenConfigGlobalRegistry());
441 }
442
AddToKeyset(const google::crypto::tink::KeyTemplate & key_template,bool as_primary,const KeyGenConfiguration & config,Keyset * keyset)443 crypto::tink::util::StatusOr<uint32_t> KeysetHandle::AddToKeyset(
444 const google::crypto::tink::KeyTemplate& key_template, bool as_primary,
445 const KeyGenConfiguration& config, Keyset* keyset) {
446 if (key_template.output_prefix_type() ==
447 google::crypto::tink::OutputPrefixType::UNKNOWN_PREFIX) {
448 return util::Status(absl::StatusCode::kInvalidArgument,
449 "key template has unknown prefix");
450 }
451
452 // Generate new key data.
453 util::StatusOr<std::unique_ptr<KeyData>> key_data;
454 if (internal::KeyGenConfigurationImpl::IsInGlobalRegistryMode(config)) {
455 key_data = Registry::NewKeyData(key_template);
456 } else {
457 util::StatusOr<const internal::KeyTypeInfoStore*> key_type_info_store =
458 internal::KeyGenConfigurationImpl::GetKeyTypeInfoStore(config);
459 if (!key_type_info_store.ok()) {
460 return key_type_info_store.status();
461 }
462 util::StatusOr<const internal::KeyTypeInfoStore::Info*> key_type_info =
463 (*key_type_info_store)->Get(key_template.type_url());
464 if (!key_type_info.ok()) {
465 return key_type_info.status();
466 }
467 key_data = (*key_type_info)->key_factory().NewKeyData(key_template.value());
468 }
469 if (!key_data.ok()) {
470 return key_data.status();
471 }
472
473 // Add and fill in new key in `keyset`.
474 Keyset::Key* key = keyset->add_key();
475 *(key->mutable_key_data()) = *std::move(key_data).value();
476 key->set_status(KeyStatusType::ENABLED);
477 key->set_output_prefix_type(key_template.output_prefix_type());
478
479 uint32_t key_id = GenerateUnusedKeyId(*keyset);
480 key->set_key_id(key_id);
481 if (as_primary) {
482 keyset->set_primary_key_id(key_id);
483 }
484 return key_id;
485 }
486
AddKey(const google::crypto::tink::KeyTemplate & key_template,bool as_primary,const KeyGenConfiguration & config)487 crypto::tink::util::StatusOr<uint32_t> KeysetHandle::AddKey(
488 const google::crypto::tink::KeyTemplate& key_template, bool as_primary,
489 const KeyGenConfiguration& config) {
490 util::StatusOr<uint32_t> id =
491 AddToKeyset(key_template, as_primary, config, &keyset_);
492 if (!id.ok()) {
493 return id.status();
494 }
495 util::StatusOr<const Entry> entry = CreateEntry(
496 keyset_.key(keyset_.key_size() - 1), keyset_.primary_key_id());
497 if (!entry.ok()) {
498 return entry.status();
499 }
500 entries_.push_back(std::make_shared<const Entry>(*entry));
501 return *id;
502 }
503
GetKeysetInfo() const504 KeysetInfo KeysetHandle::GetKeysetInfo() const {
505 return KeysetInfoFromKeyset(get_keyset());
506 }
507
508 util::StatusOr<std::vector<std::shared_ptr<const KeysetHandle::Entry>>>
GetEntriesFromKeyset(const Keyset & keyset)509 KeysetHandle::GetEntriesFromKeyset(const Keyset& keyset) {
510 std::vector<std::shared_ptr<const Entry>> entries;
511 for (const Keyset::Key& key : keyset.key()) {
512 util::StatusOr<const Entry> entry =
513 CreateEntry(key, keyset.primary_key_id());
514 if (!entry.ok()) {
515 return entry.status();
516 }
517 entries.push_back(std::make_shared<const Entry>(*entry));
518 }
519 return entries;
520 }
521
522 } // namespace tink
523 } // namespace crypto
524