blob: 796c857c8607f88e0e48ddc84a784b616dcf068c [file] [log] [blame]
// Copyright 2022 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/auth_blocks/auth_block_utility_impl.h"
#include <stdint.h>
#include <memory>
#include <optional>
#include <utility>
#include <variant>
#include <vector>
#include <base/check.h>
#include <base/logging.h>
#include <brillo/cryptohome.h>
#include <chromeos/constants/cryptohome.h>
#include <libhwsec-foundation/status/status_chain_or.h>
#include "cryptohome/auth_blocks/async_challenge_credential_auth_block.h"
#include "cryptohome/auth_blocks/auth_block.h"
#include "cryptohome/auth_blocks/auth_block_state.h"
#include "cryptohome/auth_blocks/auth_block_type.h"
#include "cryptohome/auth_blocks/auth_block_utils.h"
#include "cryptohome/auth_blocks/challenge_credential_auth_block.h"
#include "cryptohome/auth_blocks/double_wrapped_compat_auth_block.h"
#include "cryptohome/auth_blocks/libscrypt_compat_auth_block.h"
#include "cryptohome/auth_blocks/pin_weaver_auth_block.h"
#include "cryptohome/auth_blocks/sync_to_async_auth_block_adapter.h"
#include "cryptohome/auth_blocks/tpm_bound_to_pcr_auth_block.h"
#include "cryptohome/auth_blocks/tpm_ecc_auth_block.h"
#include "cryptohome/auth_blocks/tpm_not_bound_to_pcr_auth_block.h"
#include "cryptohome/auth_factor/auth_factor_type.h"
#include "cryptohome/credentials.h"
#include "cryptohome/crypto.h"
#include "cryptohome/crypto_error.h"
#include "cryptohome/cryptohome_metrics.h"
#include "cryptohome/cryptorecovery/recovery_crypto.h"
#include "cryptohome/cryptorecovery/recovery_crypto_hsm_cbor_serialization.h"
#include "cryptohome/cryptorecovery/recovery_crypto_impl.h"
#include "cryptohome/cryptorecovery/recovery_crypto_util.h"
#include "cryptohome/error/location_utils.h"
#include "cryptohome/error/utilities.h"
#include "cryptohome/key_objects.h"
#include "cryptohome/keyset_management.h"
#include "cryptohome/tpm.h"
#include "cryptohome/vault_keyset.h"
using cryptohome::error::ContainsActionInStack;
using cryptohome::error::CryptohomeCryptoError;
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 {
AuthBlockUtilityImpl::AuthBlockUtilityImpl(KeysetManagement* keyset_management,
Crypto* crypto,
Platform* platform)
: keyset_management_(keyset_management),
crypto_(crypto),
platform_(platform),
challenge_credentials_helper_(nullptr),
key_challenge_service_(nullptr) {
DCHECK(keyset_management);
DCHECK(crypto_);
DCHECK(platform_);
}
AuthBlockUtilityImpl::AuthBlockUtilityImpl(
KeysetManagement* keyset_management,
Crypto* crypto,
Platform* platform,
ChallengeCredentialsHelper* credentials_helper,
std::unique_ptr<KeyChallengeService> key_challenge_service,
const std::string& account_id)
: keyset_management_(keyset_management),
crypto_(crypto),
platform_(platform),
challenge_credentials_helper_(credentials_helper),
key_challenge_service_(std::move(key_challenge_service)),
account_id_(account_id) {
DCHECK(keyset_management);
DCHECK(crypto_);
DCHECK(platform_);
DCHECK(challenge_credentials_helper_);
DCHECK(key_challenge_service_);
}
AuthBlockUtilityImpl::~AuthBlockUtilityImpl() = default;
bool AuthBlockUtilityImpl::GetLockedToSingleUser() const {
return platform_->FileExists(base::FilePath(kLockedToSingleUserFile));
}
CryptoStatus AuthBlockUtilityImpl::CreateKeyBlobsWithAuthBlock(
AuthBlockType auth_block_type,
const Credentials& credentials,
const std::optional<brillo::SecureBlob>& reset_secret,
AuthBlockState& out_state,
KeyBlobs& out_key_blobs) const {
CryptoStatusOr<std::unique_ptr<SyncAuthBlock>> auth_block =
GetAuthBlockWithType(auth_block_type);
if (!auth_block.ok()) {
LOG(ERROR) << "Failed to retrieve auth block.";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(kLocAuthBlockUtilNoAuthBlockInCreateKeyBlobs))
.Wrap(std::move(auth_block).status());
}
ReportCreateAuthBlock(auth_block_type);
// |reset_secret| is not processed in the AuthBlocks, the value is copied to
// the |out_key_blobs| directly. |reset_secret| will be added to the
// |out_key_blobs| in the VaultKeyset, if missing.
AuthInput user_input = {
credentials.passkey(),
/*locked_to_single_user*=*/std::nullopt,
brillo::cryptohome::home::SanitizeUserName(credentials.username()),
reset_secret};
CryptoStatus error =
auth_block.value()->Create(user_input, &out_state, &out_key_blobs);
if (!error.ok()) {
LOG(ERROR) << "Failed to create per credential secret: " << error;
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilCreateFailedInCreateKeyBlobs))
.Wrap(std::move(error));
}
ReportWrappingKeyDerivationType(auth_block.value()->derivation_type(),
CryptohomePhase::kCreated);
return OkStatus<CryptohomeCryptoError>();
}
bool AuthBlockUtilityImpl::CreateKeyBlobsWithAuthBlockAsync(
AuthBlockType auth_block_type,
const AuthInput& auth_input,
AuthBlock::CreateCallback create_callback) {
CryptoStatusOr<std::unique_ptr<AuthBlock>> auth_block =
GetAsyncAuthBlockWithType(auth_block_type);
if (!auth_block.ok()) {
LOG(ERROR) << "Failed to retrieve auth block.";
std::move(create_callback)
.Run(MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilNoAuthBlockInCreateKeyBlobsAsync))
.Wrap(std::move(auth_block).status()),
nullptr, nullptr);
return false;
}
ReportCreateAuthBlock(auth_block_type);
auth_block.value()->Create(auth_input, std::move(create_callback));
// TODO(b/225001347): Move this report to the caller. Here this is always
// reported independent of the error status.
ReportWrappingKeyDerivationType(auth_block.value()->derivation_type(),
CryptohomePhase::kCreated);
return true;
}
CryptoStatus AuthBlockUtilityImpl::DeriveKeyBlobsWithAuthBlock(
AuthBlockType auth_block_type,
const Credentials& credentials,
const AuthBlockState& auth_state,
KeyBlobs& out_key_blobs) const {
DCHECK_NE(auth_block_type, AuthBlockType::kMaxValue);
AuthInput auth_input = {credentials.passkey(),
/*locked_to_single_user=*/std::nullopt};
auth_input.locked_to_single_user = GetLockedToSingleUser();
CryptoStatusOr<std::unique_ptr<SyncAuthBlock>> auth_block =
GetAuthBlockWithType(auth_block_type);
if (!auth_block.ok()) {
LOG(ERROR) << "Keyset wrapped with unknown method.";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(kLocAuthBlockUtilNoAuthBlockInDeriveKeyBlobs))
.Wrap(std::move(auth_block).status());
}
ReportDeriveAuthBlock(auth_block_type);
CryptoStatus error =
auth_block.value()->Derive(auth_input, auth_state, &out_key_blobs);
if (error.ok()) {
ReportWrappingKeyDerivationType(auth_block.value()->derivation_type(),
CryptohomePhase::kMounted);
return OkStatus<CryptohomeCryptoError>();
}
LOG(ERROR) << "Failed to derive per credential secret: " << error;
// For LE credentials, if deriving the key blobs failed due to too many
// attempts, set auth_locked=true in the corresponding keyset. Then save it
// for future callers who can Load it w/o Decrypt'ing to check that flag.
// When the pin is entered wrong and AuthBlock fails to derive the KeyBlobs
// it doesn't make it into the VaultKeyset::Decrypt(); so auth_lock should
// be set here.
if (auth_block_type == AuthBlockType::kPinWeaver &&
ContainsActionInStack(error, ErrorAction::kTpmLockout)) {
// Get the corresponding encrypted vault keyset for the user and the label
// to set the auth_locked.
std::unique_ptr<VaultKeyset> vk = keyset_management_->GetVaultKeyset(
brillo::cryptohome::home::SanitizeUserName(credentials.username()),
credentials.key_data().label());
if (vk == nullptr) {
LOG(ERROR)
<< "No vault keyset is found on disk for the given label. Cannot "
"decide on the AuthBlock type without vault keyset metadata.";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(kLocAuthBlockUtilNoVaultKeysetInDeriveKeyBlobs),
ErrorActionSet({ErrorAction::kAuth, ErrorAction::kReboot}),
CryptoError::CE_OTHER_CRYPTO);
}
vk->SetAuthLocked(true);
vk->Save(vk->GetSourceFile());
}
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(kLocAuthBlockUtilDeriveFailedInDeriveKeyBlobs))
.Wrap(std::move(error));
}
bool AuthBlockUtilityImpl::DeriveKeyBlobsWithAuthBlockAsync(
AuthBlockType auth_block_type,
const AuthInput& auth_input,
const AuthBlockState& auth_state,
AuthBlock::DeriveCallback derive_callback) {
DCHECK_NE(auth_block_type, AuthBlockType::kMaxValue);
CryptoStatusOr<std::unique_ptr<AuthBlock>> auth_block =
GetAsyncAuthBlockWithType(auth_block_type);
if (!auth_block.ok()) {
LOG(ERROR) << "Failed to retrieve auth block.";
std::move(derive_callback)
.Run(MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilNoAuthBlockInDeriveKeyBlobsAsync))
.Wrap(std::move(auth_block).status()),
nullptr);
return false;
}
ReportCreateAuthBlock(auth_block_type);
auth_block.value()->Derive(auth_input, auth_state,
std::move(derive_callback));
return true;
}
AuthBlockType AuthBlockUtilityImpl::GetAuthBlockTypeForCreation(
const bool is_le_credential, const bool is_challenge_credential) const {
if (is_le_credential) {
return AuthBlockType::kPinWeaver;
}
if (is_challenge_credential) {
return AuthBlockType::kChallengeCredential;
}
bool use_tpm = crypto_->tpm() && crypto_->tpm()->IsOwned();
bool with_user_auth = crypto_->CanUnsealWithUserAuth();
bool has_ecc_key = crypto_->cryptohome_keys_manager() &&
crypto_->cryptohome_keys_manager()->HasCryptohomeKey(
CryptohomeKeyType::kECC);
if (use_tpm && with_user_auth && has_ecc_key) {
return AuthBlockType::kTpmEcc;
}
if (use_tpm && with_user_auth && !has_ecc_key) {
return AuthBlockType::kTpmBoundToPcr;
}
if (use_tpm && !with_user_auth) {
return AuthBlockType::kTpmNotBoundToPcr;
}
return AuthBlockType::kLibScryptCompat;
}
AuthBlockType AuthBlockUtilityImpl::GetAuthBlockTypeForDerivation(
const std::string& label, const std::string& obfuscated_username) const {
std::unique_ptr<VaultKeyset> vk =
keyset_management_->GetVaultKeyset(obfuscated_username, label);
// If there is no keyset on the disk for the given user and label (or for the
// empty label as a wildcard), key derivation type cannot be obtained.
if (vk == nullptr) {
LOG(ERROR)
<< "No vault keyset is found on disk for the given label. Cannot "
"decide on the AuthBlock type without vault keyset metadata.";
return AuthBlockType::kMaxValue;
}
int32_t vk_flags = vk->GetFlags();
AuthBlockType auth_block_type = AuthBlockType::kMaxValue;
if (!FlagsToAuthBlockType(vk_flags, auth_block_type)) {
LOG(WARNING) << "Failed to get the AuthBlock type for key derivation";
}
return auth_block_type;
}
CryptoStatusOr<std::unique_ptr<SyncAuthBlock>>
AuthBlockUtilityImpl::GetAuthBlockWithType(
const AuthBlockType& auth_block_type) const {
switch (auth_block_type) {
case AuthBlockType::kPinWeaver:
return std::make_unique<PinWeaverAuthBlock>(
crypto_->le_manager(), crypto_->cryptohome_keys_manager());
case AuthBlockType::kChallengeCredential:
return std::make_unique<ChallengeCredentialAuthBlock>();
case AuthBlockType::kDoubleWrappedCompat:
return std::make_unique<DoubleWrappedCompatAuthBlock>(
crypto_->tpm(), crypto_->cryptohome_keys_manager());
case AuthBlockType::kTpmEcc:
return std::make_unique<TpmEccAuthBlock>(
crypto_->tpm(), crypto_->cryptohome_keys_manager());
case AuthBlockType::kTpmBoundToPcr:
return std::make_unique<TpmBoundToPcrAuthBlock>(
crypto_->tpm(), crypto_->cryptohome_keys_manager());
case AuthBlockType::kTpmNotBoundToPcr:
return std::make_unique<TpmNotBoundToPcrAuthBlock>(
crypto_->tpm(), crypto_->cryptohome_keys_manager());
case AuthBlockType::kLibScryptCompat:
return std::make_unique<LibScryptCompatAuthBlock>();
case AuthBlockType::kCryptohomeRecovery:
LOG(ERROR)
<< "CryptohomeRecovery is not a supported AuthBlockType for now.";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilCHRecoveryUnsupportedInGetAuthBlockWithType),
ErrorActionSet(
{ErrorAction::kDevCheckUnexpectedState, ErrorAction::kAuth}),
CryptoError::CE_OTHER_CRYPTO);
case AuthBlockType::kMaxValue:
LOG(ERROR) << "Unsupported AuthBlockType.";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilMaxValueUnsupportedInGetAuthBlockWithType),
ErrorActionSet(
{ErrorAction::kDevCheckUnexpectedState, ErrorAction::kAuth}),
CryptoError::CE_OTHER_CRYPTO);
}
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilUnknownUnsupportedInGetAuthBlockWithType),
ErrorActionSet(
{ErrorAction::kDevCheckUnexpectedState, ErrorAction::kAuth}),
CryptoError::CE_OTHER_CRYPTO);
}
CryptoStatusOr<std::unique_ptr<AuthBlock>>
AuthBlockUtilityImpl::GetAsyncAuthBlockWithType(
const AuthBlockType& auth_block_type) {
switch (auth_block_type) {
case AuthBlockType::kPinWeaver:
return std::make_unique<SyncToAsyncAuthBlockAdapter>(
std::make_unique<PinWeaverAuthBlock>(
crypto_->le_manager(), crypto_->cryptohome_keys_manager()));
case AuthBlockType::kChallengeCredential:
if (key_challenge_service_ && challenge_credentials_helper_ &&
account_id_.has_value()) {
return std::make_unique<AsyncChallengeCredentialAuthBlock>(
crypto_->tpm(), challenge_credentials_helper_,
std::move(key_challenge_service_), account_id_.value());
}
LOG(ERROR) << "No valid ChallengeCredentialsHelper, "
"KeyChallengeService, or account id in AuthBlockUtility";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilNoChalInGetAsyncAuthBlockWithType),
ErrorActionSet(
{ErrorAction::kDevCheckUnexpectedState, ErrorAction::kAuth}),
CryptoError::CE_OTHER_CRYPTO);
case AuthBlockType::kDoubleWrappedCompat:
return std::make_unique<SyncToAsyncAuthBlockAdapter>(
std::make_unique<DoubleWrappedCompatAuthBlock>(
crypto_->tpm(), crypto_->cryptohome_keys_manager()));
case AuthBlockType::kTpmEcc:
return std::make_unique<SyncToAsyncAuthBlockAdapter>(
std::make_unique<TpmEccAuthBlock>(
crypto_->tpm(), crypto_->cryptohome_keys_manager()));
case AuthBlockType::kTpmBoundToPcr:
return std::make_unique<SyncToAsyncAuthBlockAdapter>(
std::make_unique<TpmBoundToPcrAuthBlock>(
crypto_->tpm(), crypto_->cryptohome_keys_manager()));
case AuthBlockType::kTpmNotBoundToPcr:
return std::make_unique<SyncToAsyncAuthBlockAdapter>(
std::make_unique<TpmNotBoundToPcrAuthBlock>(
crypto_->tpm(), crypto_->cryptohome_keys_manager()));
case AuthBlockType::kLibScryptCompat:
return std::make_unique<SyncToAsyncAuthBlockAdapter>(
std::make_unique<LibScryptCompatAuthBlock>());
case AuthBlockType::kCryptohomeRecovery:
LOG(ERROR)
<< "CryptohomeRecovery is not a supported AuthBlockType for now.";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilCHUnsupportedInGetAsyncAuthBlockWithType),
ErrorActionSet(
{ErrorAction::kDevCheckUnexpectedState, ErrorAction::kAuth}),
CryptoError::CE_OTHER_CRYPTO);
case AuthBlockType::kMaxValue:
LOG(ERROR) << "Unsupported AuthBlockType.";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilMaxValueUnsupportedInGetAsyncAuthBlockWithType),
ErrorActionSet(
{ErrorAction::kDevCheckUnexpectedState, ErrorAction::kAuth}),
CryptoError::CE_OTHER_CRYPTO);
}
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilUnknownUnsupportedInGetAsyncAuthBlockWithType),
ErrorActionSet(
{ErrorAction::kDevCheckUnexpectedState, ErrorAction::kAuth}),
CryptoError::CE_OTHER_CRYPTO);
}
bool AuthBlockUtilityImpl::GetAuthBlockStateFromVaultKeyset(
const std::string& label,
const std::string& obfuscated_username,
AuthBlockState& out_state) const {
std::unique_ptr<VaultKeyset> vault_keyset =
keyset_management_->GetVaultKeyset(obfuscated_username, label);
// If there is no keyset on the disk for the given user and label (or for the
// empty label as a wildcard), AuthBlock state cannot be obtained.
if (vault_keyset == nullptr) {
LOG(ERROR)
<< "No vault keyset is found on disk for the given label. Cannot "
"obtain AuthBlockState without vault keyset metadata.";
return false;
}
return GetAuthBlockState(*vault_keyset, out_state);
}
void AuthBlockUtilityImpl::AssignAuthBlockStateToVaultKeyset(
const AuthBlockState& auth_state, VaultKeyset& vault_keyset) const {
if (const auto* state =
std::get_if<TpmNotBoundToPcrAuthBlockState>(&auth_state.state)) {
vault_keyset.SetTpmNotBoundToPcrState(*state);
} else if (const auto* state =
std::get_if<TpmBoundToPcrAuthBlockState>(&auth_state.state)) {
vault_keyset.SetTpmBoundToPcrState(*state);
} else if (const auto* state =
std::get_if<PinWeaverAuthBlockState>(&auth_state.state)) {
vault_keyset.SetPinWeaverState(*state);
} else if (const auto* state = std::get_if<LibScryptCompatAuthBlockState>(
&auth_state.state)) {
vault_keyset.SetLibScryptCompatState(*state);
} else if (const auto* state = std::get_if<ChallengeCredentialAuthBlockState>(
&auth_state.state)) {
vault_keyset.SetChallengeCredentialState(*state);
} else if (const auto* state =
std::get_if<TpmEccAuthBlockState>(&auth_state.state)) {
vault_keyset.SetTpmEccState(*state);
} else {
LOG(ERROR) << "Invalid auth block state type";
return;
}
}
CryptoStatus AuthBlockUtilityImpl::CreateKeyBlobsWithAuthFactorType(
AuthFactorType auth_factor_type,
const AuthInput& auth_input,
AuthBlockState& out_auth_block_state,
KeyBlobs& out_key_blobs) const {
bool is_le_credential = auth_factor_type == AuthFactorType::kPin;
AuthBlockType auth_block_type =
GetAuthBlockTypeForCreation(is_le_credential,
/*is_challenge_credential =*/false);
if (auth_block_type == AuthBlockType::kChallengeCredential) {
LOG(ERROR) << "Unsupported auth factor type";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocAuthBlockUtilChalCredUnsupportedInCreateKeyBlobsAuthFactor),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
CryptoError::CE_OTHER_CRYPTO);
}
// TODO(b/216804305): Stop hardcoding the auth block.
CryptoStatusOr<std::unique_ptr<SyncAuthBlock>> auth_block =
GetAuthBlockWithType(auth_block_type);
return auth_block.value()->Create(auth_input, &out_auth_block_state,
&out_key_blobs);
}
AuthBlockType AuthBlockUtilityImpl::GetAuthBlockTypeForDerive(
const AuthBlockState& auth_block_state) const {
AuthBlockType auth_block_type = AuthBlockType::kMaxValue;
if (const auto* state = std::get_if<TpmNotBoundToPcrAuthBlockState>(
&auth_block_state.state)) {
auth_block_type = AuthBlockType::kTpmNotBoundToPcr;
} else if (const auto* state = std::get_if<TpmBoundToPcrAuthBlockState>(
&auth_block_state.state)) {
auth_block_type = AuthBlockType::kTpmBoundToPcr;
} else if (const auto* state = std::get_if<PinWeaverAuthBlockState>(
&auth_block_state.state)) {
auth_block_type = AuthBlockType::kPinWeaver;
} else if (const auto* state = std::get_if<LibScryptCompatAuthBlockState>(
&auth_block_state.state)) {
auth_block_type = AuthBlockType::kLibScryptCompat;
} else if (const auto* state =
std::get_if<TpmEccAuthBlockState>(&auth_block_state.state)) {
auth_block_type = AuthBlockType::kTpmEcc;
} else if (const auto& state = std::get_if<ChallengeCredentialAuthBlockState>(
&auth_block_state.state)) {
auth_block_type = AuthBlockType::kChallengeCredential;
}
return auth_block_type;
}
CryptoStatus AuthBlockUtilityImpl::DeriveKeyBlobs(
const AuthInput& auth_input,
const AuthBlockState& auth_block_state,
KeyBlobs& out_key_blobs) const {
AuthBlockType auth_block_type = GetAuthBlockTypeForDerive(auth_block_state);
if (auth_block_type == AuthBlockType::kMaxValue ||
auth_block_type == AuthBlockType::kChallengeCredential) {
LOG(ERROR) << "Unsupported auth factor type";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(kLocAuthBlockUtilUnsupportedInDeriveKeyBlobs),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
CryptoError::CE_OTHER_CRYPTO);
}
CryptoStatusOr<std::unique_ptr<SyncAuthBlock>> auth_block =
GetAuthBlockWithType(auth_block_type);
return auth_block.value()->Derive(auth_input, auth_block_state,
&out_key_blobs);
}
CryptoStatus AuthBlockUtilityImpl::GenerateRecoveryRequest(
const cryptorecovery::RequestMetadata& request_metadata,
const brillo::Blob& epoch_response,
const CryptohomeRecoveryAuthBlockState& state,
Tpm* tpm,
brillo::SecureBlob* out_recovery_request,
brillo::SecureBlob* out_ephemeral_pub_key) const {
// Check if the required fields are set on CryptohomeRecoveryAuthBlockState.
if (!state.hsm_payload.has_value() || !state.channel_pub_key.has_value() ||
!state.channel_priv_key.has_value()) {
LOG(ERROR) << "CryptohomeRecoveryAuthBlockState is invalid";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(kLocAuthBlockStateInvalidInGenerateRecoveryRequest),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
CryptoError::CE_OTHER_CRYPTO);
}
// Deserialize HSM payload from CryptohomeRecoveryAuthBlockState.
cryptorecovery::HsmPayload hsm_payload;
if (!cryptorecovery::DeserializeHsmPayloadFromCbor(state.hsm_payload.value(),
&hsm_payload)) {
LOG(ERROR) << "Failed to deserialize HSM payload";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocFailedDeserializeHsmPayloadInGenerateRecoveryRequest),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
CryptoError::CE_OTHER_CRYPTO);
}
// Parse epoch response, which is sent from Chrome, to proto.
cryptorecovery::CryptoRecoveryEpochResponse epoch_response_proto;
if (!epoch_response_proto.ParseFromString(
brillo::BlobToString(epoch_response))) {
LOG(ERROR) << "Failed to parse epoch response";
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocFailedParseEpochResponseInGenerateRecoveryRequest),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
CryptoError::CE_OTHER_CRYPTO);
}
if (!tpm->GetRecoveryCryptoBackend()) {
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(
kLocFailedToGetRecoveryCryptoBackendInGenerateRecoveryRequest),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
CryptoError::CE_OTHER_CRYPTO);
}
std::unique_ptr<cryptorecovery::RecoveryCryptoImpl> recovery =
cryptorecovery::RecoveryCryptoImpl::Create(
tpm->GetRecoveryCryptoBackend());
// Generate recovery request proto which will be sent back to Chrome, and then
// to the recovery server.
cryptorecovery::CryptoRecoveryRpcRequest recovery_request;
// TODO(b/196191918): Get rsa_priv_key from CryptohomeRecoveryAuthBlockState.
if (!recovery->GenerateRecoveryRequest(
hsm_payload, request_metadata, epoch_response_proto,
brillo::SecureBlob() /*rsa_priv_key*/, state.channel_priv_key.value(),
state.channel_pub_key.value(), &recovery_request,
out_ephemeral_pub_key)) {
LOG(ERROR) << "Call to GenerateRecoveryRequest failed";
// TODO(b/231297066): send more specific error.
return MakeStatus<CryptohomeCryptoError>(
CRYPTOHOME_ERR_LOC(kLocFailedGenerateRecoveryRequest),
ErrorActionSet({ErrorAction::kDevCheckUnexpectedState}),
CryptoError::CE_OTHER_CRYPTO);
}
// Serialize recovery request proto.
*out_recovery_request =
brillo::SecureBlob(recovery_request.SerializeAsString());
return OkStatus<CryptohomeCryptoError>();
}
} // namespace cryptohome