blob: 8856fa77d920998ad618ba61bff37741ec223cf3 [file] [log] [blame]
// Copyright 2021 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/auth_factor/auth_factor_manager.h"
#include <sys/stat.h>
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <variant>
#include <base/files/file_enumerator.h>
#include <base/files/file_path.h>
#include <base/check.h>
#include <base/logging.h>
#include <brillo/secure_blob.h>
#include <flatbuffers/flatbuffers.h>
#include <libhwsec-foundation/flatbuffers/basic_objects.h>
#include <libhwsec-foundation/flatbuffers/flatbuffer_secure_allocator_bridge.h>
#include "cryptohome/auth_blocks/auth_block_utility.h"
#include "cryptohome/auth_factor/auth_factor.h"
#include "cryptohome/auth_factor/auth_factor_label.h"
#include "cryptohome/auth_factor/auth_factor_metadata.h"
#include "cryptohome/auth_factor/auth_factor_type.h"
#include "cryptohome/auth_factor_generated.h"
#include "cryptohome/error/location_utils.h"
#include "cryptohome/filesystem_layout.h"
#include "cryptohome/flatbuffer_schemas/auth_block_state_flatbuffer.h"
#include "cryptohome/platform.h"
using brillo::Blob;
using cryptohome::error::CryptohomeError;
using cryptohome::error::ErrorAction;
using cryptohome::error::ErrorActionSet;
using hwsec_foundation::status::MakeStatus;
using hwsec_foundation::status::OkStatus;
using hwsec_foundation::status::StatusChain;
namespace cryptohome {
namespace {
// Use rw------- for the auth factor files.
constexpr mode_t kAuthFactorFilePermissions = 0600;
constexpr int kFlatbufferAllocatorInitialSize = 4096;
// Checks if the provided `auth_factor_label` is valid and on success returns
// `AuthFactorPath()`.
CryptohomeStatusOr<base::FilePath> GetAuthFactorPathFromStringType(
const ObfuscatedUsername& obfuscated_username,
const std::string& auth_factor_type_string,
const std::string& auth_factor_label) {
if (!IsValidAuthFactorLabel(auth_factor_label)) {
LOG(ERROR) << "Invalid auth factor label " << auth_factor_label
<< " of type " << auth_factor_type_string;
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocGetAuthFactorPathInvalidLabel),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_INVALID_ARGUMENT);
}
return AuthFactorPath(obfuscated_username, auth_factor_type_string,
auth_factor_label);
}
// Converts `auth_factor_type` to string and on success calls
// `GetAuthFactorPathFromStringType()` method above.
CryptohomeStatusOr<base::FilePath> GetAuthFactorPath(
const ObfuscatedUsername& obfuscated_username,
const AuthFactorType auth_factor_type,
const std::string& auth_factor_label) {
const std::string type_string = AuthFactorTypeToString(auth_factor_type);
if (type_string.empty()) {
LOG(ERROR) << "Failed to convert auth factor type "
<< static_cast<int>(auth_factor_type) << " for factor called "
<< auth_factor_label;
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocGetAuthFactorPathWrongTypeString),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_INVALID_ARGUMENT);
}
return GetAuthFactorPathFromStringType(obfuscated_username, type_string,
auth_factor_label);
}
// Serializes the factor-specific metadata into the given flatbuffer builder.
// Returns the flatbuffer offset, to be used for building the outer table.
flatbuffers::Offset<SerializedCommonMetadata> SerializeCommonMetadataToOffset(
const CommonAuthFactorMetadata& common_metadata,
flatbuffers::FlatBufferBuilder& builder) {
auto chromeos_offset = hwsec_foundation::ToFlatBuffer<std::string>()(
&builder, common_metadata.chromeos_version_last_updated);
auto chrome_offset = hwsec_foundation::ToFlatBuffer<std::string>()(
&builder, common_metadata.chrome_version_last_updated);
SerializedCommonMetadataBuilder cm_builder(builder);
cm_builder.add_chromeos_version_last_updated(chromeos_offset);
cm_builder.add_chrome_version_last_updated(chrome_offset);
return cm_builder.Finish();
}
flatbuffers::Offset<SerializedPasswordMetadata> SerializeMetadataToOffset(
const PasswordAuthFactorMetadata& password_metadata,
flatbuffers::FlatBufferBuilder* builder) {
SerializedPasswordMetadataBuilder metadata_builder(*builder);
return metadata_builder.Finish();
}
flatbuffers::Offset<SerializedPinMetadata> SerializeMetadataToOffset(
const PinAuthFactorMetadata& pin_metadata,
flatbuffers::FlatBufferBuilder* builder) {
SerializedPinMetadataBuilder metadata_builder(*builder);
return metadata_builder.Finish();
}
flatbuffers::Offset<SerializedCryptohomeRecoveryMetadata>
SerializeMetadataToOffset(
const CryptohomeRecoveryAuthFactorMetadata& recovery_metadata,
flatbuffers::FlatBufferBuilder* builder) {
SerializedCryptohomeRecoveryMetadataBuilder metadata_builder(*builder);
return metadata_builder.Finish();
}
flatbuffers::Offset<SerializedKioskMetadata> SerializeMetadataToOffset(
const KioskAuthFactorMetadata& kiosk_metadata,
flatbuffers::FlatBufferBuilder* builder) {
SerializedKioskMetadataBuilder metadata_builder(*builder);
return metadata_builder.Finish();
}
flatbuffers::Offset<SerializedSmartCardMetadata> SerializeMetadataToOffset(
const SmartCardAuthFactorMetadata& smart_card_metadata,
flatbuffers::FlatBufferBuilder* builder) {
auto public_key_offset = hwsec_foundation::ToFlatBuffer<brillo::Blob>()(
builder, *smart_card_metadata.public_key_spki_der);
SerializedSmartCardMetadataBuilder metadata_builder(*builder);
metadata_builder.add_public_key_spki_der(public_key_offset);
return metadata_builder.Finish();
}
flatbuffers::Offset<SerializedFingerprintMetadata> SerializeMetadataToOffset(
const FingerprintAuthFactorMetadata& fingerprint_metadata,
flatbuffers::FlatBufferBuilder* builder) {
SerializedFingerprintMetadataBuilder metadata_builder(*builder);
return metadata_builder.Finish();
}
// Serializes the factor-specific metadata into the given flatbuffer builder.
// Returns the flatbuffer offset, to be used for building the outer table.
//
// Implemented by selecting the appropriate specific overload based on the
// factor type and delegating to it.
flatbuffers::Offset<void> SerializeMetadataToOffset(
const AuthFactorMetadata& metadata,
flatbuffers::FlatBufferBuilder* builder,
SerializedAuthFactorMetadata* metadata_type) {
if (const auto* password_metadata =
std::get_if<PasswordAuthFactorMetadata>(&metadata.metadata)) {
*metadata_type = SerializedAuthFactorMetadata::SerializedPasswordMetadata;
return SerializeMetadataToOffset(*password_metadata, builder).Union();
} else if (const auto* pin_metadata =
std::get_if<PinAuthFactorMetadata>(&metadata.metadata)) {
*metadata_type = SerializedAuthFactorMetadata::SerializedPinMetadata;
return SerializeMetadataToOffset(*pin_metadata, builder).Union();
} else if (const auto* smart_card_metadata =
std::get_if<SmartCardAuthFactorMetadata>(&metadata.metadata)) {
*metadata_type = SerializedAuthFactorMetadata::SerializedSmartCardMetadata;
return SerializeMetadataToOffset(*smart_card_metadata, builder).Union();
} else if (const auto* recovery_metadata =
std::get_if<CryptohomeRecoveryAuthFactorMetadata>(
&metadata.metadata)) {
*metadata_type =
SerializedAuthFactorMetadata::SerializedCryptohomeRecoveryMetadata;
return SerializeMetadataToOffset(*recovery_metadata, builder).Union();
} else if (const auto* kiosk_metadata =
std::get_if<KioskAuthFactorMetadata>(&metadata.metadata)) {
*metadata_type = SerializedAuthFactorMetadata::SerializedKioskMetadata;
return SerializeMetadataToOffset(*kiosk_metadata, builder).Union();
} else if (const auto* fingerprint_metadata =
std::get_if<FingerprintAuthFactorMetadata>(
&metadata.metadata)) {
*metadata_type =
SerializedAuthFactorMetadata::SerializedFingerprintMetadata;
return SerializeMetadataToOffset(*fingerprint_metadata, builder).Union();
}
LOG(ERROR) << "Missing or unexpected auth factor metadata: "
<< metadata.metadata.index();
return flatbuffers::Offset<void>();
}
// Serializes the auth factor into a flatbuffer blob. Returns null on failure.
std::optional<Blob> SerializeAuthFactor(const AuthFactor& auth_factor) {
hwsec_foundation::FlatbufferSecureAllocatorBridge allocator;
flatbuffers::FlatBufferBuilder builder(kFlatbufferAllocatorInitialSize,
&allocator);
auto auth_block_state_offset =
hwsec_foundation::ToFlatBuffer<AuthBlockState>()(
&builder, auth_factor.auth_block_state());
if (auth_block_state_offset.IsNull()) {
LOG(ERROR) << "Failed to serialize auth block state";
return std::nullopt;
}
SerializedAuthFactorMetadata metadata_type =
SerializedAuthFactorMetadata::NONE;
flatbuffers::Offset<void> metadata_offset = SerializeMetadataToOffset(
auth_factor.metadata(), &builder, &metadata_type);
if (metadata_offset.IsNull()) {
LOG(ERROR) << "Failed to serialize metadata";
return std::nullopt;
}
auto common_metadata_offset =
SerializeCommonMetadataToOffset(auth_factor.metadata().common, builder);
SerializedAuthFactorBuilder auth_factor_builder(builder);
auth_factor_builder.add_auth_block_state(auth_block_state_offset);
auth_factor_builder.add_metadata(metadata_offset);
auth_factor_builder.add_metadata_type(metadata_type);
auth_factor_builder.add_common_metadata(common_metadata_offset);
auto auth_factor_offset = auth_factor_builder.Finish();
builder.Finish(auth_factor_offset);
return Blob(builder.GetBufferPointer(),
builder.GetBufferPointer() + builder.GetSize());
}
void ConvertCommonMetadataFromFlatbuffer(
const SerializedCommonMetadata& flatbuffer_table,
AuthFactorMetadata* metadata) {
metadata->common = CommonAuthFactorMetadata{
.chromeos_version_last_updated =
hwsec_foundation::FromFlatBuffer<std::string>()(
flatbuffer_table.chromeos_version_last_updated()),
.chrome_version_last_updated =
hwsec_foundation::FromFlatBuffer<std::string>()(
flatbuffer_table.chrome_version_last_updated()),
};
}
bool ConvertPasswordMetadataFromFlatbuffer(
const SerializedPasswordMetadata& flatbuffer_table,
AuthFactorMetadata* metadata) {
// There's no password-specific metadata currently.
metadata->metadata = PasswordAuthFactorMetadata();
return true;
}
bool ConvertPinMetadataFromFlatbuffer(
const SerializedPinMetadata& flatbuffer_table,
AuthFactorMetadata* metadata) {
// There's no pin-specific metadata currently.
metadata->metadata = PinAuthFactorMetadata();
return true;
}
bool ConvertCryptohomeRecoveryMetadataFromFlatbuffer(
const SerializedCryptohomeRecoveryMetadata& flatbuffer_table,
AuthFactorMetadata* metadata) {
// There's no metadata currently.
metadata->metadata = CryptohomeRecoveryAuthFactorMetadata();
return true;
}
bool ConvertSmartCardMetadataFromFlatbuffer(
const SerializedSmartCardMetadata& flatbuffer_table,
AuthFactorMetadata* metadata) {
auto data = hwsec_foundation::FromFlatBuffer<brillo::Blob>()(
flatbuffer_table.public_key_spki_der());
metadata->metadata = SmartCardAuthFactorMetadata{.public_key_spki_der = data};
return true;
}
bool ConvertKioskMetadataFromFlatbuffer(
const SerializedKioskMetadata& flatbuffer_table,
AuthFactorMetadata* metadata) {
// There's no metadata currently.
metadata->metadata = KioskAuthFactorMetadata();
return true;
}
bool ConvertFingerprintMetadataFromFlatbuffer(
const SerializedFingerprintMetadata& flatbuffer_table,
AuthFactorMetadata* metadata) {
// There's no metadata currently.
metadata->metadata = FingerprintAuthFactorMetadata();
return true;
}
bool ParseAuthFactorFlatbuffer(const Blob& flatbuffer,
AuthBlockState* auth_block_state,
AuthFactorMetadata* metadata) {
flatbuffers::Verifier flatbuffer_verifier(flatbuffer.data(),
flatbuffer.size());
if (!VerifySerializedAuthFactorBuffer(flatbuffer_verifier)) {
LOG(ERROR) << "The SerializedAuthFactor flatbuffer is invalid";
return false;
}
auto auth_factor_table = GetSerializedAuthFactor(flatbuffer.data());
// Extract the auth block state from the serialized data.
if (!auth_factor_table->auth_block_state()) {
LOG(ERROR) << "SerializedAuthFactor has no auth block state";
return false;
}
*auth_block_state = hwsec_foundation::FromFlatBuffer<AuthBlockState>()(
auth_factor_table->auth_block_state());
// Extract the common metadata from the serialized data.
if (!auth_factor_table->common_metadata()) {
// This is not an error, old auth factors have no common metadata.
LOG(WARNING) << "SerializedAuthFactor has no common metadata";
} else {
ConvertCommonMetadataFromFlatbuffer(*auth_factor_table->common_metadata(),
metadata);
}
// Extract the factor-specific metadata from the serialized data.
if (!auth_factor_table->metadata()) {
LOG(ERROR) << "SerializedAuthFactor has no metadata";
return false;
}
if (const SerializedPasswordMetadata* password_metadata =
auth_factor_table->metadata_as_SerializedPasswordMetadata()) {
if (!ConvertPasswordMetadataFromFlatbuffer(*password_metadata, metadata)) {
LOG(ERROR) << "Failed to convert SerializedAuthFactor password metadata";
return false;
}
} else if (const SerializedPinMetadata* pin_metadata =
auth_factor_table->metadata_as_SerializedPinMetadata()) {
if (!ConvertPinMetadataFromFlatbuffer(*pin_metadata, metadata)) {
LOG(ERROR) << "Failed to convert SerializedAuthFactor pin metadata";
return false;
}
} else if (const SerializedCryptohomeRecoveryMetadata* recovery_metadata =
auth_factor_table
->metadata_as_SerializedCryptohomeRecoveryMetadata()) {
if (!ConvertCryptohomeRecoveryMetadataFromFlatbuffer(*recovery_metadata,
metadata)) {
LOG(ERROR) << "Failed to convert SerializedAuthFactor recovery metadata";
return false;
}
} else if (const SerializedSmartCardMetadata* smart_card_metadata =
auth_factor_table->metadata_as_SerializedSmartCardMetadata()) {
if (!ConvertSmartCardMetadataFromFlatbuffer(*smart_card_metadata,
metadata)) {
LOG(ERROR)
<< "Failed to convert SerializedAuthFactor smart card metadata";
return false;
}
} else if (const SerializedKioskMetadata* kiosk_metadata =
auth_factor_table->metadata_as_SerializedKioskMetadata()) {
if (!ConvertKioskMetadataFromFlatbuffer(*kiosk_metadata, metadata)) {
LOG(ERROR) << "Failed to convert SerializedAuthFactor kiosk metadata";
return false;
}
} else if (const SerializedFingerprintMetadata* fingerprint_metadata =
auth_factor_table
->metadata_as_SerializedFingerprintMetadata()) {
if (!ConvertFingerprintMetadataFromFlatbuffer(*fingerprint_metadata,
metadata)) {
LOG(ERROR)
<< "Failed to convert SerializedAuthFactor fingerprint metadata";
return false;
}
} else {
LOG(ERROR) << "SerializedAuthFactor has unknown metadata";
return false;
}
return true;
}
} // namespace
AuthFactorManager::AuthFactorManager(Platform* platform) : platform_(platform) {
DCHECK(platform_);
}
AuthFactorManager::~AuthFactorManager() = default;
CryptohomeStatus AuthFactorManager::SaveAuthFactor(
const ObfuscatedUsername& obfuscated_username,
const AuthFactor& auth_factor) {
CryptohomeStatusOr<base::FilePath> file_path = GetAuthFactorPath(
obfuscated_username, auth_factor.type(), auth_factor.label());
if (!file_path.ok()) {
LOG(ERROR) << "Failed to get auth factor path in Save.";
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerGetPathFailedInSave),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_INVALID_ARGUMENT);
}
// Create a flatbuffer to be persisted.
std::optional<Blob> flatbuffer = SerializeAuthFactor(auth_factor);
if (!flatbuffer.has_value()) {
LOG(ERROR) << "Failed to serialize auth factor " << auth_factor.label()
<< " of type " << AuthFactorTypeToString(auth_factor.type());
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerSerializeFailedInSave),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE);
}
// Write the file.
if (!platform_->WriteFileAtomicDurable(file_path.value(), flatbuffer.value(),
kAuthFactorFilePermissions)) {
LOG(ERROR) << "Failed to persist auth factor " << auth_factor.label()
<< " of type " << AuthFactorTypeToString(auth_factor.type())
<< " for " << obfuscated_username;
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerWriteFailedInSave),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE);
}
return OkStatus<CryptohomeError>();
}
CryptohomeStatusOr<std::unique_ptr<AuthFactor>>
AuthFactorManager::LoadAuthFactor(const ObfuscatedUsername& obfuscated_username,
AuthFactorType auth_factor_type,
const std::string& auth_factor_label) {
CryptohomeStatusOr<base::FilePath> file_path = GetAuthFactorPath(
obfuscated_username, auth_factor_type, auth_factor_label);
if (!file_path.ok()) {
LOG(ERROR) << "Failed to get auth factor path in Load.";
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerGetPathFailedInLoad),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_INVALID_ARGUMENT);
}
Blob file_contents;
if (!platform_->ReadFile(file_path.value(), &file_contents)) {
LOG(ERROR) << "Failed to load persisted auth factor " << auth_factor_label
<< " of type " << AuthFactorTypeToString(auth_factor_type)
<< " for " << obfuscated_username;
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerReadFailedInLoad),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE);
}
// This check is redundant to the flatbuffer parsing below, but we check it
// here in order to distinguish "empty file" from "corrupted file" in metrics
// and logs.
if (file_contents.empty()) {
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerEmptyReadInLoad),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE);
}
AuthBlockState auth_block_state;
AuthFactorMetadata auth_factor_metadata;
if (!ParseAuthFactorFlatbuffer(file_contents, &auth_block_state,
&auth_factor_metadata)) {
LOG(ERROR) << "Failed to parse persisted auth factor " << auth_factor_label
<< " of type " << AuthFactorTypeToString(auth_factor_type)
<< " for " << obfuscated_username;
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerParseFailedInLoad),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE);
}
return std::make_unique<AuthFactor>(auth_factor_type, auth_factor_label,
auth_factor_metadata, auth_block_state);
}
std::map<std::string, std::unique_ptr<AuthFactor>>
AuthFactorManager::LoadAllAuthFactors(
const ObfuscatedUsername& obfuscated_username) {
std::map<std::string, std::unique_ptr<AuthFactor>> label_to_auth_factor;
for (const auto& [label, auth_factor_type] :
ListAuthFactors(obfuscated_username)) {
CryptohomeStatusOr<std::unique_ptr<AuthFactor>> auth_factor =
LoadAuthFactor(obfuscated_username, auth_factor_type, label);
if (!auth_factor.ok()) {
LOG(WARNING) << "Skipping malformed auth factor " << label;
continue;
}
label_to_auth_factor.emplace(label, std::move(auth_factor).value());
}
return label_to_auth_factor;
}
AuthFactorManager::LabelToTypeMap AuthFactorManager::ListAuthFactors(
const ObfuscatedUsername& obfuscated_username) {
LabelToTypeMap label_to_type_map;
std::unique_ptr<FileEnumerator> file_enumerator(platform_->GetFileEnumerator(
AuthFactorsDirPath(obfuscated_username), /*recursive=*/false,
base::FileEnumerator::FILES));
base::FilePath next_path;
while (!(next_path = file_enumerator->Next()).empty()) {
const base::FilePath base_name = next_path.BaseName();
if (!base_name.RemoveFinalExtension().FinalExtension().empty()) {
// Silently ignore files that have multiple extensions; to note, a
// legitimate case of such files is the checksum file
// ("<type>.<label>.sum").
continue;
}
// Parse and sanitize the type.
const std::string auth_factor_type_string =
base_name.RemoveExtension().value();
const std::optional<AuthFactorType> auth_factor_type =
AuthFactorTypeFromString(auth_factor_type_string);
if (!auth_factor_type.has_value()) {
LOG(WARNING) << "Unknown auth factor type: file name = "
<< base_name.value();
continue;
}
// Parse and sanitize the label. Note that `FilePath::Extension()` returns a
// string with a leading dot.
const std::string extension = base_name.Extension();
if (extension.length() <= 1 ||
extension[0] != base::FilePath::kExtensionSeparator) {
LOG(WARNING) << "Missing auth factor label: file name = "
<< base_name.value();
continue;
}
const std::string auth_factor_label = extension.substr(1);
if (!IsValidAuthFactorLabel(auth_factor_label)) {
LOG(WARNING) << "Invalid auth factor label: file name = "
<< base_name.value();
continue;
}
// Check for label clashes.
if (label_to_type_map.count(auth_factor_label)) {
const AuthFactorType previous_type = label_to_type_map[auth_factor_label];
LOG(WARNING) << "Ignoring duplicate auth factor: label = "
<< auth_factor_label << " type = " << auth_factor_type_string
<< " previous type = "
<< AuthFactorTypeToString(previous_type);
continue;
}
// All checks passed - add the factor.
label_to_type_map.insert({auth_factor_label, auth_factor_type.value()});
}
return label_to_type_map;
}
CryptohomeStatus AuthFactorManager::RemoveAuthFactor(
const ObfuscatedUsername& obfuscated_username,
const AuthFactor& auth_factor,
AuthBlockUtility* auth_block_utility) {
CryptohomeStatusOr<base::FilePath> file_path = GetAuthFactorPath(
obfuscated_username, auth_factor.type(), auth_factor.label());
if (!file_path.ok()) {
LOG(ERROR) << "Failed to get auth factor path in Remove.";
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerGetPathFailedInRemove),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
user_data_auth::CRYPTOHOME_ERROR_INVALID_ARGUMENT);
}
CryptohomeStatus status = auth_block_utility->PrepareAuthBlockForRemoval(
auth_factor.auth_block_state());
if (!status.ok()) {
LOG(WARNING) << "Failed to prepare for removal for auth factor "
<< auth_factor.label() << " of type "
<< AuthFactorTypeToString(auth_factor.type()) << " for "
<< obfuscated_username;
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(
kLocAuthFactorManagerPrepareForRemovalFailedInRemove),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}))
.Wrap(std::move(status));
}
// Remove the file.
if (!platform_->DeleteFileSecurely(file_path.value())) {
LOG(WARNING) << "Failed to securely delete from disk auth factor "
<< auth_factor.label() << " of type "
<< AuthFactorTypeToString(auth_factor.type()) << " for "
<< obfuscated_username
<< ". Attempting to delete without zeroization.";
if (!platform_->DeleteFile(file_path.value())) {
LOG(ERROR) << "Failed to delete from disk auth factor "
<< auth_factor.label() << " of type "
<< AuthFactorTypeToString(auth_factor.type()) << " for "
<< obfuscated_username;
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerDeleteFailedInRemove),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState,
ErrorAction::kRetry, ErrorAction::kReboot}),
user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE);
}
}
LOG(INFO) << "Deleted from disk auth factor label: " << auth_factor.label();
return OkStatus<CryptohomeError>();
}
CryptohomeStatus AuthFactorManager::UpdateAuthFactor(
const ObfuscatedUsername& obfuscated_username,
const std::string& auth_factor_label,
AuthFactor& auth_factor,
AuthBlockUtility* auth_block_utility) {
// 1. Load the old auth factor state from disk.
CryptohomeStatusOr<std::unique_ptr<AuthFactor>> existing_auth_factor =
LoadAuthFactor(obfuscated_username, auth_factor.type(),
auth_factor_label);
if (!existing_auth_factor.ok()) {
LOG(ERROR) << "Failed to load persisted auth factor " << auth_factor_label
<< " of type " << AuthFactorTypeToString(auth_factor.type())
<< " for " << obfuscated_username << " in Update.";
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerLoadFailedInUpdate),
user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE)
.Wrap(std::move(existing_auth_factor).err_status());
}
// 2. Save auth factor to disk - the old auth factor state will be overridden
// and accessible only from `existing_auth_factor` object.
CryptohomeStatus save_result =
SaveAuthFactor(obfuscated_username, auth_factor);
if (!save_result.ok()) {
LOG(ERROR) << "Failed to save auth factor " << auth_factor.label()
<< " of type " << AuthFactorTypeToString(auth_factor.type())
<< " for " << obfuscated_username << " in Update.";
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(kLocAuthFactorManagerSaveFailedInUpdate),
user_data_auth::CRYPTOHOME_ERROR_BACKING_STORE_FAILURE)
.Wrap(std::move(save_result));
}
// 3. The old auth factor state was removed from disk. Call
// `PrepareForRemoval()` to complete the removal.
CryptohomeStatus status = auth_block_utility->PrepareAuthBlockForRemoval(
existing_auth_factor.value()->auth_block_state());
if (!status.ok()) {
LOG(WARNING) << "PrepareForRemoval failed for auth factor "
<< auth_factor.label() << " of type "
<< AuthFactorTypeToString(auth_factor.type()) << " for "
<< obfuscated_username << " in Update.";
return MakeStatus<CryptohomeError>(
CRYPTOHOME_ERR_LOC(
kLocAuthFactorManagerPrepareForRemovalFailedInUpdate),
user_data_auth::CRYPTOHOME_ERROR_INVALID_ARGUMENT)
.Wrap(std::move(status));
}
return OkStatus<CryptohomeError>();
}
} // namespace cryptohome