| // 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/error/cryptohome_tpm_error.h" |
| |
| #include <memory> |
| #include <optional> |
| #include <set> |
| #include <string> |
| #include <utility> |
| |
| #include <cryptohome/proto_bindings/UserDataAuth.pb.h> |
| #include <libhwsec/error/tpm_retry_action.h> |
| |
| #include "cryptohome/auth_blocks/tpm_auth_block_utils.h" |
| |
| namespace cryptohome { |
| |
| namespace error { |
| |
| namespace { |
| |
| using hwsec_foundation::status::NewStatus; |
| using hwsec_foundation::status::OkStatus; |
| using hwsec_foundation::status::StatusChain; |
| |
| // PopulateActionFromRetry is a helper function that converts the libhwsec |
| // TPMRetryAction into CryptohomeError's Action. |
| void PopulateActionFromRetry(const hwsec::TPMRetryAction retry, |
| std::set<CryptohomeError::Action>* actions) { |
| switch (retry) { |
| case hwsec::TPMRetryAction::kCommunication: |
| case hwsec::TPMRetryAction::kSession: |
| case hwsec::TPMRetryAction::kReboot: |
| actions->insert(ErrorAction::kReboot); |
| break; |
| case hwsec::TPMRetryAction::kLater: |
| actions->insert(ErrorAction::kRetry); |
| break; |
| case hwsec::TPMRetryAction::kDefend: |
| actions->insert(ErrorAction::kTpmLockout); |
| break; |
| case hwsec::TPMRetryAction::kUserAuth: |
| actions->insert(ErrorAction::kAuth); |
| break; |
| case hwsec::TPMRetryAction::kNoRetry: |
| actions->insert(ErrorAction::kDevCheckUnexpectedState); |
| break; |
| case hwsec::TPMRetryAction::kNone: |
| // No action. |
| break; |
| } |
| } |
| |
| // Converts a normal ErrorLocation into a Unified Error Code that this class' |
| // |loc_| expects. |
| CryptohomeError::ErrorLocationPair ErrorLocationToUnified( |
| const CryptohomeError::ErrorLocationPair& loc) { |
| DCHECK_EQ(loc.location() & (~hwsec::unified_tpm_error::kUnifiedErrorMask), 0); |
| return CryptohomeError::ErrorLocationPair( |
| loc.location() & hwsec::unified_tpm_error::kUnifiedErrorMask, loc.name()); |
| } |
| |
| StatusChain<CryptohomeTPMError> FromTPMErrorBase( |
| StatusChain<hwsec::TPMErrorBase> status) { |
| if (status.ok()) { |
| return OkStatus<CryptohomeTPMError>(); |
| } |
| |
| // Status chain currently doesn't offer a way to get the last element of the |
| // stack, so we'll need to iterate through it. |
| hwsec::TPMErrorBase const* last; |
| for (const auto& err : status.const_range()) { |
| last = err; |
| } |
| |
| // Populate the retry actions. |
| std::set<CryptohomeError::Action> actual_actions; |
| auto retry = last->ToTPMRetryAction(); |
| PopulateActionFromRetry(retry, &actual_actions); |
| |
| // Get the unified error code from the last node. |
| CryptohomeError::ErrorLocation loc = last->UnifiedErrorCode(); |
| std::string loc_str = last->ToString(); |
| return NewStatus<CryptohomeTPMError>( |
| CryptohomeError::ErrorLocationPair(loc, std::move(loc_str)), |
| std::move(actual_actions), retry, std::move(status), std::nullopt); |
| } |
| |
| } // namespace |
| |
| CryptohomeTPMError::CryptohomeTPMError( |
| const ErrorLocationPair& loc, |
| const std::set<CryptohomeError::Action>& actions, |
| const hwsec::TPMRetryAction retry, |
| std::optional<hwsec_foundation::status::StatusChain<hwsec::TPMErrorBase>> |
| tpm_error, |
| const std::optional<user_data_auth::CryptohomeErrorCode> ec) |
| : CryptohomeCryptoError( |
| loc, actions, TpmAuthBlockUtils::TPMRetryActionToCrypto(retry), ec), |
| retry_(retry), |
| tpm_error_(std::move(tpm_error)) {} |
| |
| StatusChain<CryptohomeTPMError> CryptohomeTPMError::MakeStatusTrait::operator()( |
| const ErrorLocationPair& loc, |
| std::set<CryptohomeError::Action> actions, |
| const hwsec::TPMRetryAction retry) { |
| PopulateActionFromRetry(retry, &actions); |
| auto unified = ErrorLocationToUnified(loc); |
| return NewStatus<CryptohomeTPMError>(unified, std::move(actions), retry, |
| std::nullopt, std::nullopt); |
| } |
| |
| StatusChain<CryptohomeTPMError> CryptohomeTPMError::MakeStatusTrait::operator()( |
| StatusChain<hwsec::TPMErrorBase> status) { |
| return FromTPMErrorBase(std::move(status)); |
| } |
| |
| CryptohomeTPMError::MakeStatusTrait::Unactioned |
| CryptohomeTPMError::MakeStatusTrait::operator()( |
| const ErrorLocationPair& loc, |
| const std::set<CryptohomeError::Action>& actions) { |
| return CryptohomeTPMError::MakeStatusTrait::Unactioned(loc, |
| std::move(actions)); |
| } |
| |
| CryptohomeTPMError::MakeStatusTrait::Unactioned |
| CryptohomeTPMError::MakeStatusTrait::operator()(const ErrorLocationPair& loc) { |
| return CryptohomeTPMError::MakeStatusTrait::Unactioned(loc, NoErrorAction()); |
| } |
| |
| CryptohomeTPMError::MakeStatusTrait::Unactioned::Unactioned( |
| const ErrorLocationPair& loc, |
| const std::set<CryptohomeError::Action>& actions) |
| : unified_loc_(ErrorLocationToUnified(loc)), actions_(std::move(actions)) {} |
| |
| StatusChain<CryptohomeTPMError> |
| CryptohomeTPMError::MakeStatusTrait::Unactioned::Wrap( |
| StatusChain<CryptohomeTPMError> status) && { |
| DCHECK(!status.ok()); |
| return NewStatus<CryptohomeTPMError>(unified_loc_, std::move(actions_), |
| status->ToTPMRetryAction(), std::nullopt, |
| std::nullopt) |
| .Wrap(std::move(status)); |
| } |
| |
| } // namespace error |
| |
| } // namespace cryptohome |