blob: 42b7d1b662380188a9b3206d7057441604b660be [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cryptohome/uss_migrator.h"
#include <memory>
#include <string>
#include <utility>
#include <base/functional/bind.h>
#include <brillo/cryptohome.h>
#include <brillo/secure_blob.h>
#include <libhwsec-foundation/crypto/hmac.h>
#include <libhwsec-foundation/crypto/sha.h>
#include "cryptohome/cryptohome_metrics.h"
#include "cryptohome/error/cryptohome_error.h"
#include "cryptohome/storage/file_system_keyset.h"
#include "cryptohome/user_secret_stash.h"
#include "cryptohome/user_secret_stash_storage.h"
#include "cryptohome/vault_keyset.h"
namespace cryptohome {
namespace {
using brillo::cryptohome::home::SanitizeUserName;
using cryptohome::error::CryptohomeError;
using hwsec::StatusOr;
using hwsec_foundation::HmacSha256;
using hwsec_foundation::status::OkStatus;
constexpr char kMigrationSecretDerivationPublicInfo[] =
"CHROMEOS_USS_MIGRATION_SECRET";
constexpr char kMigrationSecretLabel[] = "vk_to_uss_migration_secret_label";
} // namespace
UssMigrator::UssMigrator(Username username) : username_(std::move(username)) {}
void UssMigrator::MigrateVaultKeysetToUss(
const UserSecretStashStorage& user_secret_stash_storage,
const VaultKeyset& vault_keyset,
CompletionCallback completion_callback) {
// Create migration secret.
GenerateMigrationSecret(vault_keyset);
// Get the existing UserSecretStash and the main key if it exists, generate a
// new UserSecretStash otherwise. This UserSecretStash will contain only one
// key_block, with migration secret. The other key_blocks are added as the
// credentials are migrated to AuthFactors and USS.
// Load the USS container with the encrypted payload.
std::unique_ptr<UserSecretStash> user_secret_stash;
brillo::SecureBlob uss_main_key;
CryptohomeStatusOr<brillo::Blob> encrypted_uss =
user_secret_stash_storage.LoadPersisted(SanitizeUserName(username_));
if (!encrypted_uss.ok()) {
// If no UserSecretStash file found for the user create a new
// UserSecretStash from the passed VaultKeyset and add the migration_secret
// block.
auto uss_status =
UserSecretStash::CreateRandom(FileSystemKeyset(vault_keyset));
if (!uss_status.ok()) {
LOG(ERROR) << "UserSecretStash creation failed during migration of "
"VaultKeyset with label: "
<< vault_keyset.GetLabel();
ReportVkToUssMigrationStatus(VkToUssMigrationStatus::kFailedUssCreation);
std::move(completion_callback)
.Run(/*user_secret_stash=*/nullptr,
/*uss_main_key=*/brillo::SecureBlob());
return;
}
user_secret_stash = std::move(uss_status).value();
uss_main_key = UserSecretStash::CreateRandomMainKey();
if (!AddMigrationSecretToUss(uss_main_key, *user_secret_stash)) {
ReportVkToUssMigrationStatus(
VkToUssMigrationStatus::kFailedAddingMigrationSecret);
std::move(completion_callback)
.Run(/*user_secret_stash=*/nullptr,
/*uss_main_key=*/brillo::SecureBlob());
return;
}
} else {
// Decrypt the existing UserSecretStash payload with the migration secret
// and obtain the main key.
auto uss_status = UserSecretStash::FromEncryptedContainerWithWrappingKey(
encrypted_uss.value(),
/*wrapping_id=*/kMigrationSecretLabel,
/*wrapping_key=*/*migration_secret_, &uss_main_key);
if (!uss_status.ok()) {
LOG(ERROR) << "Failed to decrypt the UserSecretStash during migration.";
ReportVkToUssMigrationStatus(VkToUssMigrationStatus::kFailedUssDecrypt);
std::move(completion_callback)
.Run(/*user_secret_stash=*/nullptr,
/*uss_main_key=*/brillo::SecureBlob());
return;
}
user_secret_stash = std::move(uss_status).value();
}
std::move(completion_callback)
.Run(std::move(user_secret_stash), std::move(uss_main_key));
}
void UssMigrator::GenerateMigrationSecret(const VaultKeyset& vault_keyset) {
migration_secret_ = std::make_unique<brillo::SecureBlob>(
HmacSha256(brillo::SecureBlob::Combine(vault_keyset.GetFek(),
vault_keyset.GetFnek()),
brillo::BlobFromString(kMigrationSecretDerivationPublicInfo)));
}
bool UssMigrator::AddMigrationSecretToUss(
const brillo::SecureBlob& uss_main_key,
UserSecretStash& user_secret_stash) {
// This wraps the USS Main Key with the migration_secret and adds the
// migration_secret key block to USS in memory.
CryptohomeStatus status = user_secret_stash.AddWrappedMainKey(
uss_main_key,
/*wrapping_id=*/kMigrationSecretLabel, *migration_secret_);
if (!status.ok()) {
LOG(ERROR) << "Failed to add the migration secret to the UserSecretStash.";
return false;
}
return true;
}
bool UssMigrator::RemoveMigrationSecretFromUss(
UserSecretStash& user_secret_stash) {
return user_secret_stash.RemoveWrappedMainKey(
/*wrapping_id=*/kMigrationSecretLabel);
}
} // namespace cryptohome