blob: c8d2f0988439f56320c4fbd59406286d523d39b0 [file] [log] [blame]
// Copyright 2015 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.
// Contains the implementation of class Tpm
#include "cryptohome/tpm2_impl.h"
#include <cinttypes>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <base/check.h>
#include <base/logging.h>
#include <base/message_loop/message_pump_type.h>
#include <base/notreached.h>
#include <base/numerics/safe_conversions.h>
#include <base/strings/stringprintf.h>
#include <crypto/libcrypto-compat.h>
#include <crypto/scoped_openssl_types.h>
#include <libhwsec/error/tpm2_error.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <tpm_manager-client/tpm_manager/dbus-constants.h>
#include <trunks/authorization_delegate.h>
#include <trunks/blob_parser.h>
#include <trunks/error_codes.h>
#include <trunks/policy_session.h>
#include <trunks/tpm_alerts.h>
#include <trunks/tpm_constants.h>
#include <trunks/trunks_dbus_proxy.h>
#include <trunks/trunks_factory.h>
#include <trunks/trunks_factory_impl.h>
#include "cryptohome/crypto/aes.h"
#include "cryptohome/crypto/rsa.h"
#include "cryptohome/crypto/sha.h"
using brillo::Blob;
using brillo::BlobFromString;
using brillo::BlobToString;
using brillo::SecureBlob;
using hwsec::error::TPM2Error;
using hwsec::error::TPMError;
using hwsec::error::TPMErrorBase;
using hwsec::error::TPMRetryAction;
using hwsec_foundation::error::CreateError;
using hwsec_foundation::error::WrapError;
using trunks::GetErrorString;
using trunks::TPM_RC_SUCCESS;
using trunks::TrunksFactory;
namespace cryptohome {
namespace {
// Returns the total number of bits set in the first |size| elements from
// |array|.
int CountSetBits(const uint8_t* array, size_t size) {
int res = 0;
for (size_t i = 0; i < size; ++i) {
for (int bit_position = 0; bit_position < 8; ++bit_position) {
if ((array[i] & (1 << bit_position)) != 0) {
++res;
}
}
}
return res;
}
std::string OwnerDependencyEnumClassToString(
Tpm::TpmOwnerDependency dependency) {
switch (dependency) {
case Tpm::TpmOwnerDependency::kInstallAttributes:
return tpm_manager::kTpmOwnerDependency_Nvram;
case Tpm::TpmOwnerDependency::kAttestation:
return tpm_manager::kTpmOwnerDependency_Attestation;
default:
NOTREACHED() << __func__ << ": Unexpected enum class value: "
<< static_cast<int>(dependency);
return "";
}
}
trunks::TpmUtility::AsymmetricKeyUsage ConvertAsymmetricKeyUsage(
AsymmetricKeyUsage usage) {
switch (usage) {
case AsymmetricKeyUsage::kDecryptKey:
return trunks::TpmUtility::AsymmetricKeyUsage::kDecryptKey;
case AsymmetricKeyUsage::kSignKey:
return trunks::TpmUtility::AsymmetricKeyUsage::kSignKey;
case AsymmetricKeyUsage::kDecryptAndSignKey:
return trunks::TpmUtility::AsymmetricKeyUsage::kDecryptAndSignKey;
default:
NOTREACHED() << __func__ << ": Unexpected enum class value: "
<< static_cast<int>(usage);
return trunks::TpmUtility::AsymmetricKeyUsage::kDecryptKey;
}
}
} // namespace
// Keep it with sync to UMA enum list
// https://chromium.googlesource.com/chromium/src/+/HEAD/tools/metrics/histograms/enums.xml
// These values are persisted to logs, and should therefore never be renumbered
// nor reused.
enum TpmAlerts {
kCamoBreach = 1,
kDmemParity = 2,
kDrfParity = 3,
kImemParity = 4,
kPgmFault = 5,
kCpuDIfBusError = 6,
kCpuDIfUpdateWatchdog = 7,
kCpuIIfBusError = 8,
kCpuIIfUpdateWatchdog = 9,
kCpuSIfBusError = 10,
kCpuSIfUpdateWatchdog = 11,
kDmaIfBusErr = 12,
kDmaIfUpdateWatchdog = 13,
kSpsIfBusErr = 14,
kSpsIfUpdateWatchdog = 15,
kUsbIfBusErr = 16,
kUsbIfUpdateWatchdog = 17,
kFuseDefaults = 18,
kDiffFail = 19,
kSoftwareAlert0 = 20,
kSoftwareAlert1 = 21,
kSoftwareAlert2 = 22,
kSoftwareAlert3 = 23,
kHearbitFail = 24,
kProcOpcodeHash = 25,
kSramParityScrub = 26,
kAesExecCtrMax = 27,
kAesHkey = 28,
kCertLookup = 29,
kFlashEntry = 30,
kPw = 31,
kShaExecCtrMax = 32,
kShaFault = 33,
kShaHkey = 34,
kPmuBatteryMon = 35,
kPmuWatchdog = 36,
kRtcDead = 37,
kTempMax = 38,
kTempMaxDiff = 39,
kTempMin = 40,
kRngOutOfSpec = 41,
kRngTimeout = 42,
kVoltageError = 43,
kXoJitteryTrim = 44,
kTPMAlertNumBuckets, // Must be the last entry.
};
static_assert(kTPMAlertNumBuckets <= trunks::kAlertsMaxSize + 1,
"Number of UMA enums less than alerts set size");
// Maps alerts identifiers received from TMP firmware to UMA identifiers
const TpmAlerts h1AlertsMap[trunks::kH1AlertsSize] = {
kCamoBreach,
kDmemParity,
kDrfParity,
kImemParity,
kPgmFault,
kCpuDIfBusError,
kCpuDIfUpdateWatchdog,
kCpuIIfBusError,
kCpuIIfUpdateWatchdog,
kCpuSIfBusError,
kCpuSIfUpdateWatchdog,
kDmaIfBusErr,
kDmaIfUpdateWatchdog,
kSpsIfBusErr,
kSpsIfUpdateWatchdog,
kUsbIfBusErr,
kUsbIfUpdateWatchdog,
kFuseDefaults,
kDiffFail,
kSoftwareAlert0,
kSoftwareAlert1,
kSoftwareAlert2,
kSoftwareAlert3,
kHearbitFail,
kProcOpcodeHash,
kSramParityScrub,
kAesExecCtrMax,
kAesHkey,
kCertLookup,
kFlashEntry,
kPw,
kShaExecCtrMax,
kShaFault,
kShaHkey,
kPmuBatteryMon,
kPmuWatchdog,
kRtcDead,
kTempMax,
kTempMaxDiff,
kTempMin,
kRngOutOfSpec,
kRngTimeout,
kVoltageError,
kXoJitteryTrim,
};
Tpm2Impl::Tpm2Impl(TrunksFactory* factory,
tpm_manager::TpmManagerUtility* tpm_manager_utility)
: tpm_manager_utility_(tpm_manager_utility),
has_external_trunks_context_(true) {
external_trunks_context_.factory = factory;
external_trunks_context_.tpm_state = factory->GetTpmState();
external_trunks_context_.tpm_utility = factory->GetTpmUtility();
}
bool Tpm2Impl::InitializeTpmManagerUtility() {
if (!tpm_manager_utility_) {
tpm_manager_utility_ = tpm_manager::TpmManagerUtility::GetSingleton();
if (!tpm_manager_utility_) {
LOG(ERROR) << __func__ << ": Failed to get TpmManagerUtility singleton!";
}
}
return tpm_manager_utility_ && tpm_manager_utility_->Initialize();
}
bool Tpm2Impl::CacheTpmManagerStatus() {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->GetTpmStatus(&is_enabled_, &is_owned_,
&last_tpm_manager_data_);
}
bool Tpm2Impl::IsEnabled() {
if (!is_enabled_) {
if (!CacheTpmManagerStatus()) {
LOG(ERROR) << __func__ << ": Failed to call |UpdateTpmStatus|.";
return false;
}
}
return is_enabled_;
}
bool Tpm2Impl::IsOwned() {
if (!is_owned_) {
if (!UpdateTpmStatus(RefreshType::REFRESH_IF_NEEDED)) {
LOG(ERROR) << __func__ << ": Failed to call |UpdateTpmStatus|.";
return false;
}
}
return is_owned_;
}
bool Tpm2Impl::IsOwnerPasswordPresent() {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": failed to initialize |TpmManagerUtility|.";
return false;
}
bool is_owner_password_present = false;
if (!tpm_manager_utility_->GetTpmNonsensitiveStatus(
nullptr, nullptr, &is_owner_password_present, nullptr)) {
LOG(ERROR) << __func__ << ": Failed to get |is_owner_password_present|.";
return false;
}
return is_owner_password_present;
}
bool Tpm2Impl::HasResetLockPermissions() {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": failed to initialize |TpmManagerUtility|.";
return false;
}
bool has_reset_lock_permissions = false;
if (!tpm_manager_utility_->GetTpmNonsensitiveStatus(
nullptr, nullptr, nullptr, &has_reset_lock_permissions)) {
LOG(ERROR) << __func__ << ": Failed to get |has_reset_lock_permissions|.";
return false;
}
return has_reset_lock_permissions;
}
hwsec::error::TPMErrorBase Tpm2Impl::GetRandomDataBlob(size_t length,
brillo::Blob* data) {
brillo::SecureBlob blob(length);
if (TPMErrorBase err = GetRandomDataSecureBlob(length, &blob)) {
return WrapError<TPMError>(std::move(err), "GetRandomDataBlob failed");
}
data->assign(blob.begin(), blob.end());
return nullptr;
}
hwsec::error::TPMErrorBase Tpm2Impl::GetRandomDataSecureBlob(
size_t length, brillo::SecureBlob* data) {
CHECK(data);
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
std::string random_data;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->GenerateRandom(
length, /* delegate */ nullptr, &random_data))) {
return WrapError<TPMError>(std::move(err), "Error getting random data");
}
if (random_data.size() != length) {
return CreateError<TPMError>(
base::StringPrintf("Error getting random data: requested length %zu"
", received length %zu",
length, random_data.size()),
TPMRetryAction::kNoRetry);
}
data->assign(random_data.begin(), random_data.end());
return nullptr;
}
hwsec::error::TPMErrorBase Tpm2Impl::GetAlertsData(Tpm::AlertsData* alerts) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
trunks::TpmAlertsData trunks_alerts;
if (auto err = CreateError<TPM2Error>(
trunks->tpm_utility->GetAlertsData(&trunks_alerts))) {
if (err->ErrorCode() == trunks::TPM_RC_NO_SUCH_COMMAND) {
return WrapError<TPMError>(
std::move(err), "TPM GetAlertsData vendor command is not implemented",
TPMRetryAction::kNoRetry);
} else {
memset(alerts, 0, sizeof(Tpm::AlertsData));
return WrapError<TPMError>(std::move(err), "Error getting alerts data");
}
} else if (trunks_alerts.chip_family != trunks::kFamilyH1) {
// Currently we support only H1 alerts
return CreateError<TPMError>(
"Unknown alerts family: " + std::to_string(trunks_alerts.chip_family),
TPMRetryAction::kNoRetry);
}
memset(alerts, 0, sizeof(Tpm::AlertsData));
for (int i = 0; i < trunks_alerts.alerts_num; i++) {
size_t uma_idx = h1AlertsMap[i];
if (uma_idx <= 0 || uma_idx >= kTPMAlertNumBuckets) {
LOG(ERROR) << "Alert index " << i << " maps into invalid UMA enum index "
<< uma_idx;
} else {
alerts->counters[uma_idx] = trunks_alerts.counters[i];
}
}
return nullptr;
}
bool Tpm2Impl::DefineNvram(uint32_t index, size_t length, uint32_t flags) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
const bool write_define = flags & Tpm::kTpmNvramWriteDefine;
const bool bind_to_pcr0 = flags & Tpm::kTpmNvramBindToPCR0;
const bool firmware_readable = flags & Tpm::kTpmNvramFirmwareReadable;
return tpm_manager_utility_->DefineSpace(index, length, write_define,
bind_to_pcr0, firmware_readable);
}
bool Tpm2Impl::DestroyNvram(uint32_t index) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->DestroySpace(index);
}
bool Tpm2Impl::WriteNvram(uint32_t index, const SecureBlob& blob) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->WriteSpace(index, blob.to_string(),
/*use_owner_auth=*/false);
}
bool Tpm2Impl::OwnerWriteNvram(uint32_t index, const SecureBlob& blob) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->WriteSpace(index, blob.to_string(),
/*use_owner_auth=*/true);
}
bool Tpm2Impl::ReadNvram(uint32_t index, SecureBlob* blob) {
if (!InitializeTpmManagerUtility()) {
return false;
}
std::string output;
const bool result = tpm_manager_utility_->ReadSpace(index, false, &output);
SecureBlob tmp(output);
blob->swap(tmp);
return result;
}
bool Tpm2Impl::IsNvramDefined(uint32_t index) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
std::vector<uint32_t> spaces;
if (!tpm_manager_utility_->ListSpaces(&spaces)) {
return false;
}
for (uint32_t space : spaces) {
if (index == space) {
return true;
}
}
return false;
}
bool Tpm2Impl::IsNvramLocked(uint32_t index) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
uint32_t size;
bool is_read_locked;
bool is_write_locked;
if (!tpm_manager_utility_->GetSpaceInfo(index, &size, &is_read_locked,
&is_write_locked,
/*attributes=*/nullptr)) {
return false;
}
return is_write_locked;
}
bool Tpm2Impl::WriteLockNvram(uint32_t index) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->LockSpace(index);
}
unsigned int Tpm2Impl::GetNvramSize(uint32_t index) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
uint32_t size;
bool is_read_locked;
bool is_write_locked;
if (!tpm_manager_utility_->GetSpaceInfo(index, &size, &is_read_locked,
&is_write_locked,
/*attributes=*/nullptr)) {
return 0;
}
return size;
}
bool Tpm2Impl::IsEndorsementKeyAvailable() {
LOG(ERROR) << __func__ << ": Not implemented.";
return true;
}
bool Tpm2Impl::CreateEndorsementKey() {
LOG(ERROR) << __func__ << ": Not implemented.";
return false;
}
bool Tpm2Impl::SealToPCR0(const brillo::SecureBlob& value,
brillo::SecureBlob* sealed_value) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
std::string policy_digest;
if (auto err = CreateError<TPM2Error>(
trunks->tpm_utility->GetPolicyDigestForPcrValues(
std::map<uint32_t, std::string>({{0, ""}}),
false /* use_auth_value */, &policy_digest))) {
LOG(ERROR) << "Error getting policy digest: " << *err;
return false;
}
std::unique_ptr<trunks::HmacSession> session =
trunks->factory->GetHmacSession();
if (auto err = CreateError<TPM2Error>(
trunks->tpm_utility->StartSession(session.get()))) {
LOG(ERROR) << "Error starting hmac session: " << *err;
return false;
}
std::string data_to_seal(value.begin(), value.end());
std::string sealed_data;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->SealData(
data_to_seal, policy_digest, "", session->GetDelegate(),
&sealed_data))) {
LOG(ERROR) << "Error sealing data to PCR0: " << *err;
return false;
}
sealed_value->assign(sealed_data.begin(), sealed_data.end());
return true;
}
bool Tpm2Impl::Unseal(const brillo::SecureBlob& sealed_value,
brillo::SecureBlob* value) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
std::unique_ptr<trunks::PolicySession> policy_session =
trunks->factory->GetPolicySession();
if (auto err = CreateError<TPM2Error>(
policy_session->StartUnboundSession(true, false))) {
LOG(ERROR) << "Error starting policy session: " << *err;
return false;
}
if (auto err = CreateError<TPM2Error>(policy_session->PolicyPCR(
std::map<uint32_t, std::string>({{0, ""}})))) {
LOG(ERROR) << "Error restricting policy to pcr 0: " << *err;
return false;
}
std::string sealed_data(sealed_value.begin(), sealed_value.end());
std::string unsealed_data;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->UnsealData(
sealed_data, policy_session->GetDelegate(), &unsealed_data))) {
LOG(ERROR) << "Error unsealing object: " << *err;
return false;
}
value->assign(unsealed_data.begin(), unsealed_data.end());
return true;
}
bool Tpm2Impl::CreateDelegate(const std::set<uint32_t>& bound_pcrs,
uint8_t delegate_family_label,
uint8_t delegate_label,
Blob* delegate_blob,
Blob* delegate_secret) {
LOG(ERROR) << __func__ << ": Not implemented.";
return false;
}
bool Tpm2Impl::TakeOwnership(int /*max_timeout_tries*/,
const SecureBlob& /*owner_password*/) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
if (IsOwned()) {
LOG(INFO) << __func__ << ": TPM is already owned.";
return true;
}
return tpm_manager_utility_->TakeOwnership();
}
bool Tpm2Impl::Sign(const SecureBlob& key_blob,
const SecureBlob& input,
uint32_t bound_pcr_index,
SecureBlob* signature) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
trunks::AuthorizationDelegate* delegate;
std::unique_ptr<trunks::PolicySession> policy_session;
std::unique_ptr<trunks::HmacSession> hmac_session;
if (bound_pcr_index != kNotBoundToPCR) {
policy_session = trunks->factory->GetPolicySession();
if (auto err = CreateError<TPM2Error>(
policy_session->StartUnboundSession(true, false))) {
LOG(ERROR) << "Error starting policy session: " << *err;
return false;
}
if (auto err = CreateError<TPM2Error>(policy_session->PolicyPCR(
std::map<uint32_t, std::string>({{bound_pcr_index, ""}})))) {
LOG(ERROR) << "Error creating PCR policy: " << *err;
return false;
}
delegate = policy_session->GetDelegate();
} else {
hmac_session = trunks->factory->GetHmacSession();
if (auto err = CreateError<TPM2Error>(
hmac_session->StartUnboundSession(true, true))) {
LOG(ERROR) << "Error starting hmac session: " << *err;
return false;
}
hmac_session->SetEntityAuthorizationValue("");
delegate = hmac_session->GetDelegate();
}
ScopedKeyHandle handle;
if (TPMErrorBase err = LoadWrappedKey(key_blob, &handle)) {
LOG(ERROR) << "Error loading pcr bound key: " << *err;
return false;
}
std::string tpm_signature;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->Sign(
handle.value(), trunks::TPM_ALG_RSASSA, trunks::TPM_ALG_SHA256,
input.to_string(), true /* generate_hash */, delegate,
&tpm_signature))) {
LOG(ERROR) << "Error signing: " << *err;
return false;
}
signature->assign(tpm_signature.begin(), tpm_signature.end());
return true;
}
bool Tpm2Impl::CreatePCRBoundKey(const std::map<uint32_t, std::string>& pcr_map,
AsymmetricKeyUsage key_type,
SecureBlob* key_blob,
SecureBlob* public_key_der,
SecureBlob* creation_blob) {
CHECK(key_blob) << "No key blob argument provided.";
CHECK(creation_blob) << "No creation blob argument provided.";
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
std::string policy_digest;
if (auto err = CreateError<TPM2Error>(
trunks->tpm_utility->GetPolicyDigestForPcrValues(
pcr_map, false /* use_auth_value */, &policy_digest))) {
LOG(ERROR) << "Error getting policy digest: " << *err;
return false;
}
std::vector<uint32_t> pcr_list;
for (const auto& map_pair : pcr_map) {
pcr_list.push_back(map_pair.first);
}
std::string tpm_key_blob;
std::string tpm_creation_blob;
std::unique_ptr<trunks::AuthorizationDelegate> delegate =
trunks->factory->GetPasswordAuthorization("");
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->CreateRSAKeyPair(
ConvertAsymmetricKeyUsage(key_type), kDefaultTpmRsaModulusSize,
kDefaultTpmPublicExponent,
"", // No authorization
policy_digest,
true, // use_only_policy_authorization
pcr_list, delegate.get(), &tpm_key_blob,
&tpm_creation_blob /* No creation_blob */))) {
LOG(ERROR) << "Error creating a pcr bound key: " << *err;
return false;
}
key_blob->assign(tpm_key_blob.begin(), tpm_key_blob.end());
creation_blob->assign(tpm_creation_blob.begin(), tpm_creation_blob.end());
// if |public_key_der| is present, create and assign it.
if (public_key_der) {
trunks::TPM2B_PUBLIC public_data;
trunks::TPM2B_PRIVATE private_data;
if (!trunks->factory->GetBlobParser()->ParseKeyBlob(
key_blob->to_string(), &public_data, &private_data)) {
return false;
}
if (!PublicAreaToPublicKeyDER(public_data.public_area, public_key_der)) {
return false;
}
}
return true;
}
bool Tpm2Impl::VerifyPCRBoundKey(const std::map<uint32_t, std::string>& pcr_map,
const SecureBlob& key_blob,
const SecureBlob& creation_blob) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
// First we verify that the PCR were in a known good state at the time of
// Key creation.
trunks::TPM2B_CREATION_DATA creation_data;
trunks::TPM2B_DIGEST creation_hash;
trunks::TPMT_TK_CREATION creation_ticket;
if (!trunks->factory->GetBlobParser()->ParseCreationBlob(
creation_blob.to_string(), &creation_data, &creation_hash,
&creation_ticket)) {
LOG(ERROR) << "Error parsing creation_blob.";
return false;
}
trunks::TPML_PCR_SELECTION& pcr_select =
creation_data.creation_data.pcr_select;
if (pcr_select.count != 1) {
LOG(ERROR) << "Creation data missing creation PCR value.";
return false;
}
if (pcr_select.pcr_selections[0].hash != trunks::TPM_ALG_SHA256) {
LOG(ERROR) << "Creation PCR extended with wrong hash algorithm.";
return false;
}
uint8_t* pcr_selections = pcr_select.pcr_selections[0].pcr_select;
if (pcr_map.size() != CountSetBits(pcr_selections, PCR_SELECT_MIN)) {
LOG(ERROR) << "Incorrect creation PCR specified.";
return false;
}
std::string concatenated_pcr_values;
for (const auto& map_pair : pcr_map) {
uint32_t pcr_index = map_pair.first;
const std::string pcr_value = map_pair.second;
if (pcr_index >= 8 * PCR_SELECT_MIN ||
(pcr_selections[pcr_index / 8] & (1 << (pcr_index % 8))) == 0) {
LOG(ERROR) << "Incorrect creation PCR specified.";
return false;
}
concatenated_pcr_values += pcr_value;
}
Blob expected_pcr_digest = Sha256(BlobFromString(concatenated_pcr_values));
if (creation_data.creation_data.pcr_digest.size !=
expected_pcr_digest.size()) {
LOG(ERROR) << "Incorrect PCR digest size.";
return false;
}
if (memcmp(creation_data.creation_data.pcr_digest.buffer,
expected_pcr_digest.data(), expected_pcr_digest.size()) != 0) {
LOG(ERROR) << "Incorrect PCR digest value.";
return false;
}
// Then we certify that the key was created by the TPM.
ScopedKeyHandle scoped_handle;
if (TPMErrorBase err = LoadWrappedKey(key_blob, &scoped_handle)) {
LOG(ERROR) << "Failed to load wrapped key: " << *err;
return false;
}
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->CertifyCreation(
scoped_handle.value(), creation_blob.to_string()))) {
LOG(ERROR) << "Error certifying that key was created by TPM: " << *err;
return false;
}
// Finally we verify that the key's policy_digest is the expected value.
std::unique_ptr<trunks::PolicySession> trial_session =
trunks->factory->GetTrialSession();
if (auto err = CreateError<TPM2Error>(
trial_session->StartUnboundSession(true, true))) {
LOG(ERROR) << "Error starting a trial session: " << *err;
return false;
}
if (auto err = CreateError<TPM2Error>(trial_session->PolicyPCR(pcr_map))) {
LOG(ERROR) << "Error restricting trial policy to pcr value: " << *err;
return false;
}
std::string policy_digest;
if (auto err =
CreateError<TPM2Error>(trial_session->GetDigest(&policy_digest))) {
LOG(ERROR) << "Error getting policy digest: " << *err;
return false;
}
trunks::TPMT_PUBLIC public_area;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->GetKeyPublicArea(
scoped_handle.value(), &public_area))) {
LOG(ERROR) << "Error getting key public area: " << *err;
return false;
}
if (public_area.auth_policy.size != policy_digest.size()) {
LOG(ERROR) << "Key auth policy and policy digest are of different length."
<< public_area.auth_policy.size << "," << policy_digest.size();
return false;
} else if (memcmp(public_area.auth_policy.buffer, policy_digest.data(),
policy_digest.size()) != 0) {
LOG(ERROR) << "Key auth policy is different from policy digest.";
return false;
} else if (public_area.object_attributes & trunks::kUserWithAuth) {
LOG(ERROR) << "Key authorization is not restricted to policy.";
return false;
}
return true;
}
bool Tpm2Impl::ExtendPCR(uint32_t pcr_index, const Blob& extension) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
std::unique_ptr<trunks::AuthorizationDelegate> delegate =
trunks->factory->GetPasswordAuthorization("");
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->ExtendPCR(
pcr_index, BlobToString(extension), delegate.get()))) {
LOG(ERROR) << "Error extending PCR: " << *err;
return false;
}
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->ExtendPCRForCSME(
pcr_index, BlobToString(extension)))) {
LOG(ERROR) << "Error extending PCR for CSME: " << *err;
return false;
}
return true;
}
bool Tpm2Impl::ReadPCR(uint32_t pcr_index, Blob* pcr_value) {
CHECK(pcr_value);
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
std::string pcr_digest;
if (auto err = CreateError<TPM2Error>(
trunks->tpm_utility->ReadPCR(pcr_index, &pcr_digest))) {
LOG(ERROR) << "Error reading from PCR: " << *err;
return false;
}
*pcr_value = BlobFromString(pcr_digest);
return true;
}
bool Tpm2Impl::WrapRsaKey(const SecureBlob& public_modulus,
const SecureBlob& prime_factor,
SecureBlob* wrapped_key) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
std::string key_blob;
std::unique_ptr<trunks::AuthorizationDelegate> delegate =
trunks->factory->GetPasswordAuthorization("");
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->ImportRSAKey(
trunks::TpmUtility::AsymmetricKeyUsage::kDecryptKey,
public_modulus.to_string(), kDefaultTpmPublicExponent,
prime_factor.to_string(),
"", // No authorization,
delegate.get(), &key_blob))) {
LOG(ERROR) << "Error creating SRK wrapped key: " << *err;
return false;
}
wrapped_key->assign(key_blob.begin(), key_blob.end());
return true;
}
TPMErrorBase Tpm2Impl::LoadWrappedKey(const SecureBlob& wrapped_key,
ScopedKeyHandle* key_handle) {
CHECK(key_handle);
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
trunks::TPM_HANDLE handle;
std::unique_ptr<trunks::AuthorizationDelegate> delegate =
trunks->factory->GetPasswordAuthorization("");
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->LoadKey(
wrapped_key.to_string(), delegate.get(), &handle))) {
return WrapError<TPMError>(std::move(err), "Error loading SRK wrapped key");
}
key_handle->reset(this, handle);
return nullptr;
}
bool Tpm2Impl::LegacyLoadCryptohomeKey(ScopedKeyHandle* key_handle,
SecureBlob* key_blob) {
// This doesn't apply to devices with TPM 2.0.
return false;
}
void Tpm2Impl::CloseHandle(TpmKeyHandle key_handle) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return;
}
trunks->factory->GetTpm()->FlushContext(
key_handle, nullptr,
base::BindRepeating(
[](TpmKeyHandle key_handle, trunks::TPM_RC result) {
if (auto err = CreateError<TPM2Error>(result)) {
LOG(WARNING) << "Error flushing tpm handle " << key_handle << ": "
<< *err;
}
},
key_handle));
}
TPMErrorBase Tpm2Impl::EncryptBlob(TpmKeyHandle key_handle,
const SecureBlob& plaintext,
const SecureBlob& key,
SecureBlob* ciphertext) {
CHECK(ciphertext);
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
std::string tpm_ciphertext;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->AsymmetricEncrypt(
key_handle, trunks::TPM_ALG_OAEP, trunks::TPM_ALG_SHA256,
plaintext.to_string(), nullptr, &tpm_ciphertext))) {
return WrapError<TPMError>(std::move(err), "Error encrypting plaintext");
}
if (!ObscureRsaMessage(SecureBlob(tpm_ciphertext), key, ciphertext)) {
return CreateError<TPMError>("Error obscuring tpm encrypted blob",
TPMRetryAction::kNoRetry);
}
return nullptr;
}
TPMErrorBase Tpm2Impl::DecryptBlob(
TpmKeyHandle key_handle,
const SecureBlob& ciphertext,
const SecureBlob& key,
const std::map<uint32_t, std::string>& pcr_map,
SecureBlob* plaintext) {
CHECK(plaintext);
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
SecureBlob local_data;
if (!UnobscureRsaMessage(ciphertext, key, &local_data)) {
return CreateError<TPMError>("Error unobscureing message",
TPMRetryAction::kNoRetry);
}
trunks::AuthorizationDelegate* delegate;
std::unique_ptr<trunks::PolicySession> policy_session;
std::unique_ptr<trunks::AuthorizationDelegate> default_delegate;
if (!pcr_map.empty()) {
policy_session = trunks->factory->GetPolicySession();
if (auto err = CreateError<TPM2Error>(
policy_session->StartUnboundSession(true, true))) {
return WrapError<TPMError>(std::move(err),
"Error starting policy session",
TPMRetryAction::kNoRetry);
}
if (auto err = CreateError<TPM2Error>(policy_session->PolicyPCR(pcr_map))) {
return WrapError<TPMError>(std::move(err), "Error creating PCR policy",
TPMRetryAction::kNoRetry);
}
delegate = policy_session->GetDelegate();
} else {
default_delegate = trunks->factory->GetPasswordAuthorization("");
delegate = default_delegate.get();
}
std::string tpm_plaintext;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->AsymmetricDecrypt(
key_handle, trunks::TPM_ALG_OAEP, trunks::TPM_ALG_SHA256,
local_data.to_string(), delegate, &tpm_plaintext))) {
return WrapError<TPMError>(std::move(err), "Error decrypting plaintext");
}
plaintext->assign(tpm_plaintext.begin(), tpm_plaintext.end());
return nullptr;
}
TPMErrorBase Tpm2Impl::SealToPcrWithAuthorization(
const SecureBlob& plaintext,
const SecureBlob& auth_value,
const std::map<uint32_t, std::string>& pcr_map,
SecureBlob* sealed_data) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
// Get the policy digest for PCR.
std::string policy_digest;
if (auto err = CreateError<TPM2Error>(
trunks->tpm_utility->GetPolicyDigestForPcrValues(
pcr_map, true /* use_auth_value */, &policy_digest))) {
return WrapError<TPMError>(std::move(err), "Error getting policy digest");
}
std::unique_ptr<trunks::HmacSession> session =
trunks->factory->GetHmacSession();
if (auto err =
CreateError<TPM2Error>(session->StartUnboundSession(true, true))) {
return WrapError<TPMError>(std::move(err), "Error starting hmac session");
}
std::string sealed_str;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->SealData(
plaintext.to_string(), policy_digest, auth_value.to_string(),
session->GetDelegate(), &sealed_str))) {
return WrapError<TPMError>(std::move(err),
"Error sealing data to PCR with authorization");
}
sealed_data->assign(sealed_str.begin(), sealed_str.end());
return nullptr;
}
TPMErrorBase Tpm2Impl::PreloadSealedData(const brillo::SecureBlob& sealed_data,
ScopedKeyHandle* preload_handle) {
if (TPMErrorBase err = LoadWrappedKey(sealed_data, preload_handle)) {
return WrapError<TPMError>(std::move(err), "Failed to load sealed data");
}
return nullptr;
}
TPMErrorBase Tpm2Impl::UnsealWithAuthorization(
base::Optional<TpmKeyHandle> preload_handle,
const SecureBlob& sealed_data,
const SecureBlob& auth_value,
const std::map<uint32_t, std::string>& pcr_map,
SecureBlob* plaintext) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
std::unique_ptr<trunks::PolicySession> policy_session =
trunks->factory->GetPolicySession();
// Use unsalted session here, to unseal faster.
if (auto err = CreateError<TPM2Error>(
policy_session->StartUnboundSession(false, false))) {
return WrapError<TPMError>(std::move(err), "Error starting policy session");
}
if (auto err = CreateError<TPM2Error>(policy_session->PolicyAuthValue())) {
return WrapError<TPMError>(std::move(err),
"Error setting session to use auth_value");
}
if (auto err = CreateError<TPM2Error>(policy_session->PolicyPCR(pcr_map))) {
return WrapError<TPMError>(std::move(err), "Error in PolicyPCR");
}
policy_session->SetEntityAuthorizationValue(auth_value.to_string());
std::string unsealed_data;
if (preload_handle) {
if (auto err =
CreateError<TPM2Error>(trunks->tpm_utility->UnsealDataWithHandle(
*preload_handle, policy_session->GetDelegate(),
&unsealed_data))) {
return WrapError<TPMError>(std::move(err),
"Error unsealing data with authorization");
}
} else {
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->UnsealData(
sealed_data.to_string(), policy_session->GetDelegate(),
&unsealed_data))) {
return WrapError<TPMError>(std::move(err),
"Error unsealing data with authorization");
}
}
plaintext->assign(unsealed_data.begin(), unsealed_data.end());
return nullptr;
}
TPMErrorBase Tpm2Impl::GetPublicKeyHash(TpmKeyHandle key_handle,
SecureBlob* hash) {
CHECK(hash);
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
trunks::TPMT_PUBLIC public_data;
if (auto err = CreateError<TPM2Error>(
trunks->tpm_utility->GetKeyPublicArea(key_handle, &public_data))) {
return WrapError<TPMError>(std::move(err), "Error getting key public area");
}
std::string public_modulus =
trunks::StringFrom_TPM2B_PUBLIC_KEY_RSA(public_data.unique.rsa);
*hash = Sha256(SecureBlob(public_modulus));
return nullptr;
}
void Tpm2Impl::GetStatus(base::Optional<TpmKeyHandle> key,
TpmStatusInfo* status) {
memset(status, 0, sizeof(TpmStatusInfo));
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return;
}
status->this_instance_has_context = true;
status->this_instance_has_key_handle = key.has_value();
status->last_tpm_error = trunks->tpm_state->Initialize();
if (status->last_tpm_error != TPM_RC_SUCCESS) {
return;
}
status->can_connect = true;
trunks::TPMT_PUBLIC public_srk;
status->last_tpm_error = trunks->tpm_utility->GetKeyPublicArea(
trunks::kStorageRootKey, &public_srk);
if (status->last_tpm_error != TPM_RC_SUCCESS) {
return;
}
status->can_load_srk = true;
status->can_load_srk_public_key = true;
status->srk_vulnerable_roca = false;
// Check the Cryptohome key by using what we have been told.
status->has_cryptohome_key = key.has_value();
if (status->has_cryptohome_key) {
// Check encryption (we don't care about the contents, just whether or not
// there was an error)
SecureBlob data(16);
SecureBlob password(16);
SecureBlob salt(8);
SecureBlob data_out(16);
memset(data.data(), 'A', data.size());
memset(password.data(), 'B', password.size());
memset(salt.data(), 'C', salt.size());
memset(data_out.data(), 'D', data_out.size());
SecureBlob aes_key;
PasskeyToAesKey(password, salt, 13, &aes_key, NULL);
if (TPMErrorBase err = EncryptBlob(key.value(), data, aes_key, &data_out)) {
LOG(ERROR) << __func__ << ": Failed to encrypt blob: " << *err;
return;
}
status->can_encrypt = true;
// Check decryption (we don't care about the contents, just whether or not
// there was an error)
if (TPMErrorBase err =
DecryptBlob(key.value(), data_out, aes_key,
std::map<uint32_t, std::string>(), &data)) {
LOG(ERROR) << __func__ << ": Failed to decrypt blob: " << *err;
return;
}
status->can_decrypt = true;
}
}
hwsec::error::TPMErrorBase Tpm2Impl::IsSrkRocaVulnerable(bool* result) {
// This doesn't apply to devices with TPM 2.0.
*result = false;
return nullptr;
}
bool Tpm2Impl::GetDictionaryAttackInfo(int* counter,
int* threshold,
bool* lockout,
int* seconds_remaining) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->GetDictionaryAttackInfo(
counter, threshold, lockout, seconds_remaining);
}
bool Tpm2Impl::ResetDictionaryAttackMitigation(
const Blob& /* delegate_blob */, const Blob& /* delegate_secret */) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->ResetDictionaryAttackLock();
}
void Tpm2Impl::DeclareTpmFirmwareStable() {
TrunksClientContext* trunks;
if (!fw_declared_stable_ && GetTrunksContext(&trunks)) {
auto err =
CreateError<TPM2Error>(trunks->tpm_utility->DeclareTpmFirmwareStable());
fw_declared_stable_ = (err == nullptr);
}
}
bool Tpm2Impl::GetTrunksContext(TrunksClientContext** trunks) {
if (has_external_trunks_context_) {
*trunks = &external_trunks_context_;
return true;
}
base::PlatformThreadId thread_id = base::PlatformThread::CurrentId();
std::map<base::PlatformThreadId,
std::unique_ptr<Tpm2Impl::TrunksClientContext>>::iterator iter;
{
base::AutoLock lock(trunks_contexts_lock_);
iter = trunks_contexts_.find(thread_id);
if (iter == trunks_contexts_.end()) {
auto result = trunks_contexts_.emplace(thread_id, nullptr);
iter = std::move(result.first);
}
}
// Different elements in the same container can be modified concurrently by
// different threads, so we don't need to lock this block.
if (!iter->second) {
std::unique_ptr<TrunksClientContext> new_context(new TrunksClientContext);
new_context->factory_impl = std::make_unique<trunks::TrunksFactoryImpl>();
if (!new_context->factory_impl->Initialize()) {
LOG(ERROR) << "Failed to initialize trunks factory.";
return false;
}
new_context->factory = new_context->factory_impl.get();
new_context->tpm_state = new_context->factory->GetTpmState();
new_context->tpm_utility = new_context->factory->GetTpmUtility();
iter->second = std::move(new_context);
}
*trunks = iter->second.get();
return true;
}
bool Tpm2Impl::LoadPublicKeyFromSpki(
const Blob& public_key_spki_der,
AsymmetricKeyUsage key_type,
trunks::TPM_ALG_ID scheme,
trunks::TPM_ALG_ID hash_alg,
trunks::AuthorizationDelegate* session_delegate,
ScopedKeyHandle* key_handle) {
// Parse the SPKI.
const unsigned char* asn1_ptr = public_key_spki_der.data();
const crypto::ScopedEVP_PKEY pkey(
d2i_PUBKEY(nullptr, &asn1_ptr, public_key_spki_der.size()));
if (!pkey) {
LOG(ERROR) << "Error parsing Subject Public Key Info DER";
return false;
}
const crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey.get()));
if (!rsa) {
LOG(ERROR) << "Error: non-RSA key was supplied";
return false;
}
SecureBlob key_modulus(RSA_size(rsa.get()));
const BIGNUM* n;
const BIGNUM* e;
RSA_get0_key(rsa.get(), &n, &e, nullptr);
if (BN_bn2bin(n, key_modulus.data()) != key_modulus.size()) {
LOG(ERROR) << "Error extracting public key modulus";
return false;
}
constexpr BN_ULONG kInvalidBnWord = ~static_cast<BN_ULONG>(0);
const BN_ULONG exponent_word = BN_get_word(e);
if (exponent_word == kInvalidBnWord ||
!base::IsValueInRangeForNumericType<uint32_t>(exponent_word)) {
LOG(ERROR) << "Error extracting public key exponent";
return false;
}
const uint32_t key_exponent = static_cast<uint32_t>(exponent_word);
// Load the key into the TPM.
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks))
return false;
trunks::TPM_HANDLE key_handle_raw = 0;
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->LoadRSAPublicKey(
ConvertAsymmetricKeyUsage(key_type), scheme, hash_alg,
key_modulus.to_string(), key_exponent, session_delegate,
&key_handle_raw))) {
LOG(ERROR) << "Error loading public key: " << *err;
return false;
}
key_handle->reset(this, key_handle_raw);
return true;
}
bool Tpm2Impl::PublicAreaToPublicKeyDER(const trunks::TPMT_PUBLIC& public_area,
brillo::SecureBlob* public_key_der) {
crypto::ScopedRSA rsa(RSA_new());
crypto::ScopedBIGNUM e(BN_new()), n(BN_new());
if (!rsa || !e || !n) {
LOG(ERROR) << "Failed to allocate RSA or BIGNUM for public key.";
return false;
}
if (!BN_set_word(e.get(), kDefaultTpmPublicExponent) ||
!BN_bin2bn(public_area.unique.rsa.buffer, public_area.unique.rsa.size,
n.get()) ||
!RSA_set0_key(rsa.get(), n.release(), e.release(), nullptr)) {
LOG(ERROR) << "Failed to set up RSA.";
return false;
}
int der_length = i2d_RSAPublicKey(rsa.get(), nullptr);
if (der_length < 0) {
LOG(ERROR) << "Failed to get DER-encoded public key length.";
return false;
}
public_key_der->resize(der_length);
unsigned char* der_buffer = public_key_der->data();
der_length = i2d_RSAPublicKey(rsa.get(), &der_buffer);
if (der_length < 0) {
LOG(ERROR) << "Failed to DER-encode public key.";
return false;
}
return true;
}
TPMErrorBase Tpm2Impl::GetAuthValue(base::Optional<TpmKeyHandle> key_handle,
const SecureBlob& pass_blob,
SecureBlob* auth_value) {
if (!key_handle) {
LOG(DFATAL) << "TPM2.0 needs a key_handle to get auth value.";
return CreateError<TPMError>("TPM2.0 needs a key_handle to get auth value",
TPMRetryAction::kNoRetry);
}
if (pass_blob.size() != kDefaultTpmRsaModulusSize / 8) {
return CreateError<TPMError>(
"Unexpected pass_blob size: " + std::to_string(pass_blob.size()),
TPMRetryAction::kNoRetry);
}
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return CreateError<TPMError>("Failed to get trunks context",
TPMRetryAction::kNoRetry);
}
// To guarantee that pass_blob is lower that public key modulus, just set the
// first byte to 0.
std::string value_to_decrypt = pass_blob.to_string();
value_to_decrypt[0] = 0;
std::string decrypted_value;
std::unique_ptr<trunks::AuthorizationDelegate> delegate =
trunks->factory->GetPasswordAuthorization("");
if (auto err = CreateError<TPM2Error>(trunks->tpm_utility->AsymmetricDecrypt(
key_handle.value(), trunks::TPM_ALG_NULL, trunks::TPM_ALG_NULL,
value_to_decrypt, delegate.get(), &decrypted_value))) {
return WrapError<TPMError>(std::move(err), "Error decrypting pass_blob");
}
*auth_value = Sha256(SecureBlob(decrypted_value));
return nullptr;
}
bool Tpm2Impl::UpdateTpmStatus(RefreshType refresh_type) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
bool is_successful = false;
bool has_received = false;
// Repeats data copy into |last_tpm_manager_data_|; reasonable trade-off due
// to low ROI to avoid that.
const bool is_connected = tpm_manager_utility_->GetOwnershipTakenSignalStatus(
&is_successful, &has_received, &last_tpm_manager_data_);
// When we need explicitly query tpm status either because the signal is not
// ready for any reason, or because the signal is not received yet so we need
// to run it once in case the signal is sent by tpm_manager before already.
if (refresh_type == RefreshType::FORCE_REFRESH || !is_connected ||
!is_successful || (!has_received && shall_cache_tpm_manager_status_)) {
// Retains |shall_cache_tpm_manager_status_| to be |true| if the signal
// cannot be relied on (yet). Actually |!is_successful| suffices to update
// |shall_cache_tpm_manager_status_|; by design, uses the redundancy just to
// avoid confusion.
shall_cache_tpm_manager_status_ &= (!is_connected || !is_successful);
return CacheTpmManagerStatus();
} else if (has_received) {
is_enabled_ = true;
is_owned_ = true;
}
return true;
}
bool Tpm2Impl::RemoveOwnerDependency(Tpm::TpmOwnerDependency dependency) {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->RemoveOwnerDependency(
OwnerDependencyEnumClassToString(dependency));
}
bool Tpm2Impl::ClearStoredPassword() {
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": Failed to initialize |TpmManagerUtility|.";
return false;
}
return tpm_manager_utility_->ClearStoredOwnerPassword();
}
bool Tpm2Impl::GetVersionInfo(TpmVersionInfo* version_info) {
if (!version_info) {
LOG(ERROR) << __func__ << "version_info is not initialized.";
return false;
}
// Version info on a device never changes. Returns from cache directly if we
// have the cache.
if (version_info_) {
*version_info = *version_info_;
return true;
}
if (!InitializeTpmManagerUtility()) {
LOG(ERROR) << __func__ << ": failed to initialize |TpmManagerUtility|.";
return false;
}
if (!tpm_manager_utility_->GetVersionInfo(
&version_info->family, &version_info->spec_level,
&version_info->manufacturer, &version_info->tpm_model,
&version_info->firmware_version, &version_info->vendor_specific)) {
LOG(ERROR) << __func__ << ": failed to get version info from tpm_manager.";
return false;
}
version_info_ = *version_info;
return true;
}
bool Tpm2Impl::GetIFXFieldUpgradeInfo(IFXFieldUpgradeInfo* info) {
return false;
}
bool Tpm2Impl::GetRsuDeviceId(std::string* device_id) {
TrunksClientContext* trunks;
if (!GetTrunksContext(&trunks)) {
return false;
}
return trunks->tpm_utility->GetRsuDeviceId(device_id) == TPM_RC_SUCCESS;
}
LECredentialBackend* Tpm2Impl::GetLECredentialBackend() {
#if USE_PINWEAVER
return &le_credential_backend_;
#else
return nullptr;
#endif
}
SignatureSealingBackend* Tpm2Impl::GetSignatureSealingBackend() {
return &signature_sealing_backend_;
}
bool Tpm2Impl::GetDelegate(brillo::Blob* /*blob*/,
brillo::Blob* /*secret*/,
bool* has_reset_lock_permissions) {
LOG(WARNING) << __func__ << ": No-ops to |blob| and |secret|.";
*has_reset_lock_permissions = true;
return true;
}
TPMErrorBase Tpm2Impl::IsDelegateBoundToPcr(bool* result) {
*result = false;
return nullptr;
}
bool Tpm2Impl::DelegateCanResetDACounter() {
return true;
}
std::map<uint32_t, std::string> Tpm2Impl::GetPcrMap(
const std::string& obfuscated_username, bool use_extended_pcr) const {
std::map<uint32_t, std::string> pcr_map;
if (use_extended_pcr) {
brillo::SecureBlob starting_value(SHA256_DIGEST_LENGTH, 0);
brillo::SecureBlob digest_value = Sha256(brillo::SecureBlob::Combine(
starting_value, Sha256(brillo::SecureBlob(obfuscated_username))));
pcr_map[kTpmSingleUserPCR] = digest_value.to_string();
} else {
pcr_map[kTpmSingleUserPCR] = std::string(SHA256_DIGEST_LENGTH, 0);
}
return pcr_map;
}
} // namespace cryptohome