blob: b7d6a90b50cf236a70c50f4b25ea873705f839d5 [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libhwsec/backend/tpm1/config.h"
#include <cstdint>
#include <string>
#include <base/hash/sha1.h>
#include <base/strings/stringprintf.h>
#include <crypto/sha2.h>
#include <libhwsec-foundation/crypto/sha.h>
#include <libhwsec-foundation/status/status_chain_macros.h>
#include <openssl/sha.h>
#include "libhwsec/error/tpm1_error.h"
#include "libhwsec/overalls/overalls.h"
#include "libhwsec/status.h"
using brillo::BlobFromString;
using brillo::BlobToString;
using hwsec_foundation::Sha1;
using hwsec_foundation::status::MakeStatus;
namespace hwsec {
const int kCurrentUserPcrTpm1 = USE_TPM_DYNAMIC ? 11 : 4;
namespace {
constexpr int kBootModePcr = 0;
constexpr int kDeviceModelPcr = 1;
constexpr DeviceConfig kSupportConfigs[] = {
DeviceConfig::kBootMode,
DeviceConfig::kDeviceModel,
DeviceConfig::kCurrentUser,
};
StatusOr<int> DeviceConfigToPcr(DeviceConfig config) {
switch (config) {
case DeviceConfig::kBootMode:
return kBootModePcr;
case DeviceConfig::kDeviceModel:
return kDeviceModelPcr;
case DeviceConfig::kCurrentUser:
return kCurrentUserPcrTpm1;
}
return MakeStatus<TPMError>("Unknown device config",
TPMRetryAction::kNoRetry);
}
} // namespace
StatusOr<OperationPolicy> ConfigTpm1::ToOperationPolicy(
const OperationPolicySetting& policy) {
DeviceConfigs configs;
const DeviceConfigSettings& settings = policy.device_config_settings;
if (settings.boot_mode.has_value()) {
configs[DeviceConfig::kBootMode] = true;
}
if (settings.device_model.has_value()) {
configs[DeviceConfig::kDeviceModel] = true;
}
if (settings.current_user.has_value()) {
configs[DeviceConfig::kCurrentUser] = true;
}
return OperationPolicy{
.device_configs = configs,
.permission = policy.permission,
};
}
Status ConfigTpm1::SetCurrentUser(const std::string& current_user) {
ASSIGN_OR_RETURN(TSS_HCONTEXT context, tss_helper_.GetTssContext());
ASSIGN_OR_RETURN(TSS_HTPM tpm_handle, tss_helper_.GetUserTpmHandle());
brillo::Blob extention = Sha1(brillo::BlobFromString(current_user));
uint32_t new_pcr_value_length = 0;
ScopedTssMemory new_pcr_value(overalls_, context);
RETURN_IF_ERROR(
MakeStatus<TPM1Error>(overalls_.Ospi_TPM_PcrExtend(
tpm_handle, kCurrentUserPcrTpm1, extention.size(), extention.data(),
nullptr, &new_pcr_value_length, new_pcr_value.ptr())))
.WithStatus<TPMError>("Failed to call Ospi_TPM_PcrExtend");
return OkStatus();
}
StatusOr<bool> ConfigTpm1::IsCurrentUserSet() {
ASSIGN_OR_RETURN(brillo::Blob && value, ReadPcr(kCurrentUserPcrTpm1),
_.WithStatus<TPMError>("Failed to read boot mode PCR"));
return value != brillo::Blob(SHA_DIGEST_LENGTH, 0);
}
StatusOr<ConfigTpm1::QuoteResult> ConfigTpm1::Quote(DeviceConfigs device_config,
Key key) {
return MakeStatus<TPMError>("Unimplemented", TPMRetryAction::kNoRetry);
}
StatusOr<ConfigTpm1::PcrMap> ConfigTpm1::ToPcrMap(
const DeviceConfigs& device_config) {
PcrMap result;
for (DeviceConfig config : kSupportConfigs) {
if (device_config[config]) {
ASSIGN_OR_RETURN(int pcr, DeviceConfigToPcr(config),
_.WithStatus<TPMError>("Failed to convert to PCR"));
result[pcr] = brillo::Blob();
}
}
return result;
}
StatusOr<ConfigTpm1::PcrMap> ConfigTpm1::ToCurrentPcrValueMap(
const DeviceConfigs& device_config) {
PcrMap result;
for (DeviceConfig config : kSupportConfigs) {
if (device_config[config]) {
ASSIGN_OR_RETURN(int pcr, DeviceConfigToPcr(config),
_.WithStatus<TPMError>("Failed to convert to PCR"));
ASSIGN_OR_RETURN(result[pcr], ReadPcr(pcr),
_.WithStatus<TPMError>(base::StringPrintf(
"Failed to read PCR %d value", pcr)));
}
}
return result;
}
StatusOr<brillo::Blob> ConfigTpm1::ReadPcr(uint32_t pcr_index) {
ASSIGN_OR_RETURN(TSS_HCONTEXT context, tss_helper_.GetTssContext());
ASSIGN_OR_RETURN(TSS_HTPM tpm_handle, tss_helper_.GetUserTpmHandle());
uint32_t length = 0;
ScopedTssMemory buffer(overalls_, context);
RETURN_IF_ERROR(MakeStatus<TPM1Error>(overalls_.Ospi_TPM_PcrRead(
tpm_handle, pcr_index, &length, buffer.ptr())))
.WithStatus<TPMError>("Failed to call Ospi_TPM_PcrRead");
return brillo::Blob(buffer.value(), buffer.value() + length);
}
StatusOr<ConfigTpm1::PcrMap> ConfigTpm1::ToSettingsPcrMap(
const DeviceConfigSettings& settings) {
PcrMap result;
if (settings.boot_mode.has_value()) {
const auto& mode = settings.boot_mode->mode;
if (mode.has_value()) {
return MakeStatus<TPMError>("Unsupported settings",
TPMRetryAction::kNoRetry);
} else {
ASSIGN_OR_RETURN(brillo::Blob && value, ReadPcr(kBootModePcr),
_.WithStatus<TPMError>("Failed to read boot mode PCR"));
result[kBootModePcr] = std::move(value);
}
}
if (settings.device_model.has_value()) {
const auto& hardware_id = settings.device_model->hardware_id;
if (hardware_id.has_value()) {
return MakeStatus<TPMError>("Unsupported settings",
TPMRetryAction::kNoRetry);
} else {
ASSIGN_OR_RETURN(
brillo::Blob && value, ReadPcr(kDeviceModelPcr),
_.WithStatus<TPMError>("Failed to read device model PCR"));
result[kDeviceModelPcr] = std::move(value);
}
}
if (settings.current_user.has_value()) {
const auto& username = settings.current_user->username;
brillo::Blob digest_value(SHA_DIGEST_LENGTH, 0);
if (username.has_value()) {
digest_value = Sha1(brillo::CombineBlobs(
{digest_value, Sha1(BlobFromString(username.value()))}));
}
result[kCurrentUserPcrTpm1] = digest_value;
}
return result;
}
} // namespace hwsec