xref: /aosp_15_r20/external/tink/cc/core/keyset_handle.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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