blob: fb9ea7d4be9f1ef678c1526c2ccd8f495939d920 [file] [log] [blame]
// 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 "attestation/common/tpm_utility_common.h"
#include <memory>
#include <vector>
#include <base/bind.h>
#include <base/logging.h>
#include <crypto/scoped_openssl_types.h>
#include <crypto/sha2.h>
#include <openssl/rsa.h>
#include <tpm_manager-client/tpm_manager/dbus-constants.h>
#include "tpm_manager/client/tpm_nvram_dbus_proxy.h"
#include "tpm_manager/client/tpm_ownership_dbus_proxy.h"
namespace {
const unsigned int kWellKnownExponent = 65537;
// An authorization delegate to manage multiple authorization sessions for a
// single command.
} // namespace
namespace attestation {
TpmUtilityCommon::TpmUtilityCommon(
tpm_manager::TpmOwnershipInterface* tpm_owner,
tpm_manager::TpmNvramInterface* tpm_nvram)
: tpm_owner_(tpm_owner), tpm_nvram_(tpm_nvram) {}
TpmUtilityCommon::~TpmUtilityCommon() {}
void TpmUtilityCommon::InitializationTask(base::WaitableEvent* completion) {
CHECK(completion);
CHECK(tpm_manager_thread_.task_runner()->RunsTasksOnCurrentThread());
default_tpm_owner_ = std::make_unique<tpm_manager::TpmOwnershipDBusProxy>();
default_tpm_nvram_ = std::make_unique<tpm_manager::TpmNvramDBusProxy>();
if (default_tpm_owner_->Initialize()) {
tpm_owner_ = default_tpm_owner_.get();
}
if (default_tpm_nvram_->Initialize()) {
tpm_nvram_ = default_tpm_nvram_.get();
}
completion->Signal();
}
void TpmUtilityCommon::ShutdownTask() {
tpm_owner_ = nullptr;
tpm_nvram_ = nullptr;
default_tpm_owner_.reset(nullptr);
default_tpm_nvram_.reset(nullptr);
}
bool TpmUtilityCommon::Initialize() {
if (!tpm_manager_thread_.StartWithOptions(base::Thread::Options(
base::MessageLoopForIO::TYPE_IO, 0 /* Default stack size. */))) {
LOG(ERROR) << "Failed to start tpm_manager thread.";
return false;
}
if (!tpm_owner_ || !tpm_nvram_) {
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
tpm_manager_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&TpmUtilityCommon::InitializationTask,
base::Unretained(this), &event));
event.Wait();
}
if (!tpm_owner_ || !tpm_nvram_) {
LOG(ERROR) << "Failed to initialize tpm_managerd clients.";
return false;
}
return true;
}
bool TpmUtilityCommon::IsTpmReady() {
if (!is_ready_) {
CacheTpmState();
}
return is_ready_;
}
template <typename ReplyProtoType, typename MethodType>
void TpmUtilityCommon::SendTpmManagerRequestAndWait(
const MethodType& method, ReplyProtoType* reply_proto) {
base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED);
auto callback = base::Bind(
[](ReplyProtoType* target, base::WaitableEvent* completion,
const ReplyProtoType& reply) {
*target = reply;
completion->Signal();
},
reply_proto, &event);
tpm_manager_thread_.task_runner()->PostTask(FROM_HERE,
base::Bind(method, callback));
event.Wait();
}
bool TpmUtilityCommon::GetEndorsementPassword(std::string* password) {
if (endorsement_password_.empty()) {
if (!CacheTpmState()) {
return false;
}
if (endorsement_password_.empty()) {
LOG(WARNING) << "TPM endorsement password is not available.";
return false;
}
}
*password = endorsement_password_;
return true;
}
bool TpmUtilityCommon::GetOwnerPassword(std::string* password) {
if (owner_password_.empty()) {
if (!CacheTpmState()) {
return false;
}
if (owner_password_.empty()) {
LOG(WARNING) << "TPM owner password is not available.";
return false;
}
}
*password = owner_password_;
return true;
}
bool TpmUtilityCommon::CacheTpmState() {
tpm_manager::GetTpmStatusReply tpm_status;
SendTpmManagerRequestAndWait(
base::Bind(&tpm_manager::TpmOwnershipInterface::GetTpmStatus,
base::Unretained(tpm_owner_),
tpm_manager::GetTpmStatusRequest()),
&tpm_status);
if (tpm_status.status() != tpm_manager::STATUS_SUCCESS) {
LOG(ERROR) << __func__ << ": Failed to read TPM state from tpm_managerd.";
return false;
}
is_ready_ = tpm_status.enabled() && tpm_status.owned();
const auto& local_data = tpm_status.local_data();
endorsement_password_ = local_data.endorsement_password();
owner_password_ = local_data.owner_password();
delegate_blob_ = local_data.owner_delegate().blob();
delegate_secret_ = local_data.owner_delegate().secret();
return true;
}
bool TpmUtilityCommon::RemoveOwnerDependency() {
tpm_manager::RemoveOwnerDependencyReply reply;
tpm_manager::RemoveOwnerDependencyRequest request;
request.set_owner_dependency(tpm_manager::kTpmOwnerDependency_Attestation);
SendTpmManagerRequestAndWait(
base::Bind(&tpm_manager::TpmOwnershipInterface::RemoveOwnerDependency,
base::Unretained(tpm_owner_), request),
&reply);
if (reply.status() != tpm_manager::STATUS_SUCCESS) {
LOG(WARNING) << __func__ << ": Failed to remove the dependency.";
return false;
}
return true;
}
crypto::ScopedRSA TpmUtilityCommon::CreateRSAFromRawModulus(
uint8_t* modulus_buffer, size_t modulus_size) {
crypto::ScopedRSA rsa(RSA_new());
if (!rsa.get())
return crypto::ScopedRSA();
rsa->e = BN_new();
if (!rsa->e)
return crypto::ScopedRSA();
BN_set_word(rsa->e, kWellKnownExponent);
rsa->n = BN_bin2bn(modulus_buffer, modulus_size, NULL);
if (!rsa->n)
return crypto::ScopedRSA();
return rsa;
}
} // namespace attestation