blob: 6eba2260a9c909b1fdf1c4faee0e0f009b7bed28 [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.
#ifndef LIBHWSEC_ERROR_TPM_ERROR_H_
#define LIBHWSEC_ERROR_TPM_ERROR_H_
#include <memory>
#include <string>
#include <utility>
#include <libhwsec/error/error.h>
#include "libhwsec/error/tpm_retry_action.h"
#include "libhwsec/hwsec_export.h"
/* The most important function of TPM error is representing a TPM retry action.
*
* MakeStatus<TPM1Error>/MakeStatus<TPM2Error> converts the raw error code from
* the daemon to a Status object.
*
* For example:
* StatusChain<TPM1Error> status = MakeStatus<TPM1Error>(
* Tspi_TPM_CreateEndorsementKey(tpm_handle, local_key_handle, NULL));
*
* And it could also creating software based TPM error.
*
* For example:
* StatusChain<TPMError> status =
* MakeStatus<TPMError>("Failed to get trunks context",
* TPMRetryAction::kNoRetry);
*
* Using Wrap() could wrap a TPM error into a new TPM error, and it
* would transfer the retry action to the new TPM error (due to Wrap
* overload).
*
* For example:
* if (StatusChain<TPMErrorBase> status = GetPublicKeyBlob(...))) {
* return MakeStatus<TPMError>("Failed to get TPM public key hash")
* .Wrap(std::move(status));
* }
*
* And it could also overwrite the original retry action.
*
* For example:
* if (StatusChain<TPM2Error> status = MakeStatus<TPM2Error>(...)) {
* return MakeStatus<TPMError>(
* "Error ...", TPMRetryAction::kNoRetry).Wrap(std::move(status));
* }
*
* It can also be used with status_macros helpers. For more info see
* `platform2/libhwsec-foundation/error/status_macros.h`.
*
* RETURN_IF_ERROR(
* MakeStatus<TPM1Error>(
* Tspi_TPM_CreateEndorsementKey(tpm_handle, local_key_handle, NULL),
* AsStatusChain<TPMError>("Failed to create endorsement key")));
*/
namespace hwsec {
// A base class for TPM errors.
class HWSEC_EXPORT TPMErrorBase : public Error {
public:
using MakeStatusTrait = ForbidMakeStatus;
explicit TPMErrorBase(std::string message);
~TPMErrorBase() override = default;
// Returns what the action should do after this error happen.
virtual TPMRetryAction ToTPMRetryAction() const = 0;
};
// A TPM error which contains error message and retry action. Doesn't contain
// an error code on its own.
class HWSEC_EXPORT TPMError : public TPMErrorBase {
public:
// Overload MakeStatus to prevent issuing un-actioned TPMErrors. Attempting to
// create a StatusChain<TPMError> without an action will create a stub object
// that caches the message and waits for the Wrap call with an appropriate
// Status to complete the definition and construct a proper TPMError. That
// intends to ensure that all TPMError object propagated contain an action
// either explicitly specified or inherited from a specific tpm-type dependent
// error object.
struct MakeStatusTrait {
class Unactioned {
public:
explicit Unactioned(std::string error_message)
: error_message_(error_message) {}
// Wrap will convert the stab into the appropriate Status type.
auto Wrap(StatusChain<TPMErrorBase> status) && {
return NewStatus<TPMError>(error_message_, status->ToTPMRetryAction())
.Wrap(std::move(status));
}
private:
const std::string error_message_;
};
// Returns a stub that doesn't convert to Status. The stub will wait for a
// Wrap.
auto operator()(std::string error_message) {
return Unactioned(error_message);
}
// If we get action as an argument - create the Status directly.
auto operator()(std::string error_message, TPMRetryAction action) {
return NewStatus<TPMError>(error_message, action);
}
};
TPMError(std::string error_message, TPMRetryAction action);
~TPMError() override = default;
TPMRetryAction ToTPMRetryAction() const override { return retry_action_; }
private:
const TPMRetryAction retry_action_;
};
} // namespace hwsec
#endif // LIBHWSEC_ERROR_TPM_ERROR_H_