blob: 361fa0e13b9ca82cc6bf4774bf7e4d569985bc06 [file] [log] [blame] [edit]
// Copyright 2018 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 "libtpmcrypto/tpm2_impl.h"
#include <base/logging.h>
#include <base/threading/platform_thread.h>
#include <brillo/secure_blob.h>
#include <trunks/error_codes.h>
using brillo::Blob;
using brillo::SecureBlob;
using trunks::AuthorizationDelegate;
using trunks::GetErrorString;
using trunks::HmacSession;
using trunks::PolicySession;
using trunks::TPM_RC;
using trunks::TPM_RC_SUCCESS;
using trunks::TPMS_NV_PUBLIC;
using trunks::TrunksFactoryImpl;
namespace tpmcrypto {
using PcrMap = std::map<uint32_t, std::string>;
Tpm2Impl::Tpm2Impl() = default;
Tpm2Impl::~Tpm2Impl() = default;
std::unique_ptr<Tpm> CreateTpmInstance() {
return std::make_unique<Tpm2Impl>();
}
bool Tpm2Impl::SealToPCR0(const SecureBlob& value, SecureBlob* sealed_value) {
CHECK(sealed_value);
std::string policy_digest;
std::unique_ptr<HmacSession> session;
return EnsureInitialized() && CreatePcr0PolicyDigest(&policy_digest) &&
CreateHmacSession(&session) &&
SealData(session->GetDelegate(), policy_digest, value, sealed_value);
}
bool Tpm2Impl::Unseal(const SecureBlob& sealed_value, SecureBlob* value) {
CHECK(value);
std::unique_ptr<PolicySession> policy_session;
return EnsureInitialized() && CreatePolicySessionForPCR0(&policy_session) &&
UnsealData(policy_session->GetDelegate(), sealed_value, value);
}
bool Tpm2Impl::EnsureInitialized() {
if (is_initialized_) {
return true;
}
// Create and initialize trunks factory.
factory_impl_ = std::make_unique<TrunksFactoryImpl>();
if (!factory_impl_->Initialize()) {
LOG(ERROR) << "Failed to initialize trunks factory.";
factory_impl_.reset();
return false;
}
// Create TPM utility using trunks factory.
tpm_utility_ = factory_impl_->GetTpmUtility();
if (!tpm_utility_) {
return false;
}
is_initialized_ = true;
return true;
}
bool Tpm2Impl::CreatePcr0PolicyDigest(std::string* policy_digest) {
TPM_RC result = tpm_utility_->GetPolicyDigestForPcrValues(
PcrMap({{0, ""}}), false /* use_auth_value */, policy_digest);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error getting policy digest: " << GetErrorString(result);
return false;
}
return true;
}
bool Tpm2Impl::CreateHmacSession(std::unique_ptr<HmacSession>* hmac_session) {
std::unique_ptr<HmacSession> session = factory_impl_->GetHmacSession();
if (tpm_utility_->StartSession(session.get()) != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error starting hmac session.";
return false;
}
hmac_session->swap(session);
return true;
}
bool Tpm2Impl::CreatePolicySessionForPCR0(
std::unique_ptr<PolicySession>* policy_session) {
std::unique_ptr<PolicySession> session = factory_impl_->GetPolicySession();
TPM_RC result = session->StartUnboundSession(false /* salted */,
false /* enable_encryption */);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error starting policy session: " << GetErrorString(result);
return false;
}
result = session->PolicyPCR(PcrMap({{0, ""}}));
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error restricting policy to pcr 0: "
<< GetErrorString(result);
return false;
}
policy_session->swap(session);
return true;
}
bool Tpm2Impl::SealData(AuthorizationDelegate* session_delegate,
const std::string& policy_digest,
const SecureBlob& value,
SecureBlob* sealed_value) {
const std::string data_to_seal(value.begin(), value.end());
std::string sealed_data_str;
TPM_RC result = tpm_utility_->SealData(data_to_seal, policy_digest, "",
session_delegate, &sealed_data_str);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error sealing data: " << GetErrorString(result);
return false;
}
sealed_value->assign(sealed_data_str.begin(), sealed_data_str.end());
return true;
}
bool Tpm2Impl::UnsealData(AuthorizationDelegate* policy_delegate,
const SecureBlob& sealed_value,
SecureBlob* value) {
const std::string sealed_data(sealed_value.begin(), sealed_value.end());
std::string unsealed_data;
TPM_RC result =
tpm_utility_->UnsealData(sealed_data, policy_delegate, &unsealed_data);
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error unsealing data: " << GetErrorString(result);
return false;
}
value->assign(unsealed_data.begin(), unsealed_data.end());
return true;
}
bool Tpm2Impl::GetNVAttributes(uint32_t index, uint32_t* attributes) {
CHECK(attributes);
if (!EnsureInitialized()) {
return false;
}
TPMS_NV_PUBLIC space_info;
TPM_RC result = tpm_utility_->GetNVSpacePublicArea(index, &space_info);
if (result != trunks::TPM_RC_SUCCESS) {
PLOG(ERROR) << "Failed to get the NVRAM space attributes";
return false;
}
*attributes = space_info.attributes;
return true;
}
bool Tpm2Impl::NVReadNoAuth(uint32_t index,
uint32_t offset,
size_t size,
std::string* data) {
CHECK(data);
if (!EnsureInitialized()) {
return false;
}
const std::string kWellKnownPassword = "";
auto pw_auth = factory_impl_->GetPasswordAuthorization(kWellKnownPassword);
trunks::TPM_RC result = tpm_utility_->ReadNVSpace(
index, offset, size, false /* using_owner_authorization */, data,
pw_auth.get());
if (result != trunks::TPM_RC_SUCCESS) {
PLOG(ERROR) << "Failed to read TPM space index: " << index;
return false;
}
return true;
}
} // namespace tpmcrypto