blob: 570ad3d3a13fd7c8754a761974eb10f160c26c7d [file] [log] [blame]
// 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