| // Copyright 2021 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cryptohome/user_secret_stash.h" |
| |
| #include <base/logging.h> |
| #include <brillo/secure_blob.h> |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <string> |
| |
| #include "cryptohome/aes_gcm_encrypted_uss_generated.h" |
| #include "cryptohome/crypto/aes.h" |
| #include "cryptohome/crypto/secure_blob_util.h" |
| #include "cryptohome/cryptohome_common.h" |
| #include "cryptohome/flatbuffer_secure_allocator_bridge.h" |
| #include "cryptohome/user_secret_stash_generated.h" |
| |
| namespace cryptohome { |
| |
| namespace { |
| |
| brillo::SecureBlob GenerateAesGcmEncryptedUSS( |
| const brillo::SecureBlob& ciphertext, |
| const brillo::SecureBlob& tag, |
| const brillo::SecureBlob& iv) { |
| std::unique_ptr<flatbuffers::Allocator> allocator = |
| std::make_unique<FlatbufferSecureAllocatorBridge>(); |
| flatbuffers::FlatBufferBuilder builder(4096, allocator.get(), |
| /*own_allocator=*/false); |
| |
| auto ciphertext_vector = |
| builder.CreateVector(ciphertext.data(), ciphertext.size()); |
| auto tag_vector = builder.CreateVector(tag.data(), tag.size()); |
| auto iv_vector = builder.CreateVector(iv.data(), iv.size()); |
| |
| AesGcmEncryptedUSSBuilder encrypted_uss_builder(builder); |
| encrypted_uss_builder.add_ciphertext(ciphertext_vector); |
| encrypted_uss_builder.add_tag(tag_vector); |
| encrypted_uss_builder.add_iv(iv_vector); |
| auto encrypted_uss = encrypted_uss_builder.Finish(); |
| |
| builder.Finish(encrypted_uss); |
| |
| auto ret_val = |
| brillo::SecureBlob(builder.GetBufferPointer(), |
| builder.GetBufferPointer() + builder.GetSize()); |
| |
| builder.Clear(); |
| |
| return ret_val; |
| } |
| |
| } // namespace |
| |
| const brillo::SecureBlob& UserSecretStash::GetFileSystemKey() const { |
| return file_system_key_.value(); |
| } |
| |
| void UserSecretStash::SetFileSystemKey(const brillo::SecureBlob& key) { |
| file_system_key_ = key; |
| } |
| |
| const brillo::SecureBlob& UserSecretStash::GetResetSecret() const { |
| return reset_secret_.value(); |
| } |
| |
| void UserSecretStash::SetResetSecret(const brillo::SecureBlob& secret) { |
| reset_secret_ = secret; |
| } |
| |
| void UserSecretStash::InitializeRandom() { |
| file_system_key_ = |
| CreateSecureRandomBlob(CRYPTOHOME_DEFAULT_512_BIT_KEY_SIZE); |
| reset_secret_ = CreateSecureRandomBlob(CRYPTOHOME_RESET_SECRET_LENGTH); |
| } |
| |
| base::Optional<brillo::SecureBlob> UserSecretStash::GetAesGcmEncrypted( |
| const brillo::SecureBlob& main_key) { |
| std::unique_ptr<flatbuffers::Allocator> allocator = |
| std::make_unique<FlatbufferSecureAllocatorBridge>(); |
| flatbuffers::FlatBufferBuilder builder(4096, allocator.get(), |
| /*own_allocator=*/false); |
| |
| auto fs_key_vector = |
| builder.CreateVector(file_system_key_->data(), file_system_key_->size()); |
| auto reset_secret_vector = |
| builder.CreateVector(reset_secret_->data(), reset_secret_->size()); |
| |
| UserSecretStashBufBuilder uss_builder(builder); |
| uss_builder.add_file_system_key(fs_key_vector); |
| uss_builder.add_reset_secret(reset_secret_vector); |
| auto uss = uss_builder.Finish(); |
| |
| builder.Finish(uss); |
| |
| brillo::SecureBlob serialized_uss( |
| builder.GetBufferPointer(), |
| builder.GetBufferPointer() + builder.GetSize()); |
| |
| brillo::SecureBlob tag, iv, ciphertext; |
| if (!AesGcmEncrypt(serialized_uss, /*ad=*/base::nullopt, main_key, &iv, &tag, |
| &ciphertext)) { |
| LOG(ERROR) << "Failed to encrypt UserSecretStash"; |
| return base::nullopt; |
| } |
| |
| builder.Clear(); |
| |
| return base::Optional<brillo::SecureBlob>( |
| GenerateAesGcmEncryptedUSS(ciphertext, tag, iv)); |
| } |
| |
| bool UserSecretStash::FromAesGcmEncrypted(const brillo::SecureBlob& flatbuffer, |
| const brillo::SecureBlob& main_key) { |
| flatbuffers::Verifier aes_verifier(flatbuffer.data(), flatbuffer.size()); |
| if (!VerifyAesGcmEncryptedUSSBuffer(aes_verifier)) { |
| LOG(ERROR) << "The AesGcmEncryptedUSS flatbuffer is invalid"; |
| return false; |
| } |
| |
| auto encrypted_uss = GetAesGcmEncryptedUSS(flatbuffer.data()); |
| if (!flatbuffers::IsFieldPresent(encrypted_uss, |
| AesGcmEncryptedUSS::VT_CIPHERTEXT) || |
| !flatbuffers::IsFieldPresent(encrypted_uss, AesGcmEncryptedUSS::VT_IV) || |
| !flatbuffers::IsFieldPresent(encrypted_uss, AesGcmEncryptedUSS::VT_TAG)) { |
| LOG(ERROR) << "AesGcmEncryptedUSS is missing fields"; |
| return false; |
| } |
| |
| brillo::SecureBlob ciphertext(encrypted_uss->ciphertext()->begin(), |
| encrypted_uss->ciphertext()->end()); |
| brillo::SecureBlob iv(encrypted_uss->iv()->begin(), |
| encrypted_uss->iv()->end()); |
| brillo::SecureBlob tag(encrypted_uss->tag()->begin(), |
| encrypted_uss->tag()->end()); |
| |
| if (ciphertext.empty() || iv.empty() || tag.empty()) { |
| LOG(ERROR) << "AesGcmEncryptedUSS has empty fields"; |
| return false; |
| } |
| |
| brillo::SecureBlob serialized_uss; |
| if (!AesGcmDecrypt(ciphertext, /*ad=*/base::nullopt, tag, main_key, iv, |
| &serialized_uss)) { |
| LOG(ERROR) << "Failed to decrypt UserSecretStash"; |
| return false; |
| } |
| |
| flatbuffers::Verifier uss_verifier(serialized_uss.data(), |
| serialized_uss.size()); |
| if (!VerifyUserSecretStashBufBuffer(uss_verifier)) { |
| LOG(ERROR) << "The UserSecretStashBuf flatbuffer is invalid"; |
| return false; |
| } |
| |
| auto uss = GetUserSecretStashBuf(serialized_uss.data()); |
| |
| brillo::SecureBlob file_system_key; |
| if (flatbuffers::IsFieldPresent(uss, |
| UserSecretStashBuf::VT_FILE_SYSTEM_KEY)) { |
| file_system_key = brillo::SecureBlob(uss->file_system_key()->begin(), |
| uss->file_system_key()->end()); |
| } |
| if (!file_system_key.empty()) { |
| file_system_key_ = file_system_key; |
| } |
| |
| brillo::SecureBlob reset_secret; |
| if (flatbuffers::IsFieldPresent(uss, UserSecretStashBuf::VT_RESET_SECRET)) { |
| reset_secret = brillo::SecureBlob(uss->reset_secret()->begin(), |
| uss->reset_secret()->end()); |
| } |
| if (!reset_secret.empty()) { |
| reset_secret_ = reset_secret; |
| } |
| |
| return true; |
| } |
| |
| } // namespace cryptohome |