blob: 08da5784fb629eb01306bf078825602c999be553 [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.
#include "tpm_manager/server/tpm_manager_service.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include <base/bind.h>
#include <base/callback.h>
#include <base/command_line.h>
#include <base/message_loop/message_pump_type.h>
#include <base/strings/stringprintf.h>
#include <base/synchronization/lock.h>
#include <crypto/sha2.h>
#include <inttypes.h>
namespace {
constexpr int kDictionaryAttackResetPeriodInHours = 1;
#if USE_TPM2
// Timeout waiting for Trunks daemon readiness.
constexpr base::TimeDelta kTrunksDaemonTimeout =
base::TimeDelta::FromSeconds(30);
// Delay between subsequent attempts to initialize connection to Trunks daemon.
constexpr base::TimeDelta kTrunksDaemonInitAttemptDelay =
base::TimeDelta::FromMicroseconds(300);
#endif
// Clears owner password in |local_data| if all dependencies have been removed
// and it has not yet been cleared.
// Returns true if |local_data| has been modified, false otherwise.
bool ClearOwnerPasswordIfPossible(tpm_manager::LocalData* local_data) {
if (local_data->has_owner_password() &&
local_data->owner_dependency().empty()) {
local_data->clear_owner_password();
return true;
}
return false;
}
int GetFingerprint(uint32_t family,
uint64_t spec_level,
uint32_t manufacturer,
uint32_t tpm_model,
uint64_t firmware_version,
std::string vendor_specific) {
// The exact encoding doesn't matter as long as its unambiguous, stable and
// contains all information present in the version fields.
std::string encoded_parameters =
base::StringPrintf("%08" PRIx32 "%016" PRIx64 "%08" PRIx32 "%08" PRIx32
"%016" PRIx64 "%016zx",
family, spec_level, manufacturer, tpm_model,
firmware_version, vendor_specific.size());
encoded_parameters.append(vendor_specific);
std::string hash = crypto::SHA256HashString(encoded_parameters);
// Return the first 31 bits from |hash|.
int result =
static_cast<uint8_t>(hash[0]) | static_cast<uint8_t>(hash[1]) << 8 |
static_cast<uint8_t>(hash[2]) << 16 | static_cast<uint8_t>(hash[3]) << 24;
return result & 0x7fffffff;
}
} // namespace
namespace tpm_manager {
namespace {
GetTpmNonsensitiveStatusReply ToGetTpmNonSensitiveStatusReply(
const GetTpmStatusReply& from) {
GetTpmNonsensitiveStatusReply to;
to.set_status(from.status());
to.set_is_owned(from.owned());
to.set_is_enabled(from.enabled());
const LocalData& sensitive = from.local_data();
to.set_is_owner_password_present(!sensitive.owner_password().empty());
// This works regardless of TPM version.
to.set_has_reset_lock_permissions(
!sensitive.lockout_password().empty() ||
sensitive.owner_delegate().has_reset_lock_permissions());
return to;
}
} // namespace
TpmManagerService::TpmManagerService(bool wait_for_ownership,
bool perform_preinit,
LocalDataStore* local_data_store)
: TpmManagerService(wait_for_ownership,
perform_preinit,
local_data_store,
nullptr,
nullptr,
nullptr,
&default_tpm_manager_metrics_) {
CHECK(local_data_store_);
}
TpmManagerService::TpmManagerService(bool wait_for_ownership,
bool perform_preinit,
LocalDataStore* local_data_store,
TpmStatus* tpm_status,
TpmInitializer* tpm_initializer,
TpmNvram* tpm_nvram,
TpmManagerMetrics* tpm_manager_metrics)
: dictionary_attack_timer_(
base::TimeDelta::FromHours(kDictionaryAttackResetPeriodInHours)),
local_data_store_(local_data_store),
tpm_status_(tpm_status),
tpm_initializer_(tpm_initializer),
tpm_nvram_(tpm_nvram),
tpm_manager_metrics_(tpm_manager_metrics),
update_tpm_status_pending_(false),
update_tpm_status_cache_dirty_(true),
wait_for_ownership_(wait_for_ownership),
perform_preinit_(perform_preinit) {}
TpmManagerService::~TpmManagerService() {
worker_thread_->Stop();
}
bool TpmManagerService::Initialize() {
origin_task_runner_ = base::ThreadTaskRunnerHandle::Get();
worker_thread_.reset(
new ServiceWorkerThread("TpmManager Service Worker", this));
worker_thread_->StartWithOptions(
base::Thread::Options(base::MessagePumpType::IO, 0));
update_tpm_status_pending_ = true;
PostTaskToWorkerThreadWithoutRequest<GetTpmStatusReply>(
base::Bind(&TpmManagerService::UpdateTpmStatusCallback,
base::Unretained(this)),
&TpmManagerService::InitializeTask);
ReportVersionFingerprint();
VLOG(1) << "Worker thread started.";
return true;
}
void TpmManagerService::ReportVersionFingerprint() {
auto callback = base::Bind(
[](tpm_manager::TpmManagerMetrics* tpm_manager_metrics,
const tpm_manager::GetVersionInfoReply& reply) {
if (reply.status() == STATUS_SUCCESS) {
uint32_t family = reply.family();
uint64_t spec_level = reply.spec_level();
uint32_t manufacturer = reply.manufacturer();
uint32_t tpm_model = reply.tpm_model();
uint64_t firmware_version = reply.firmware_version();
std::string vendor_specific = reply.vendor_specific();
tpm_manager_metrics->ReportVersionFingerprint(
GetFingerprint(family, spec_level, manufacturer, tpm_model,
firmware_version, vendor_specific));
}
},
base::Unretained(tpm_manager_metrics_));
GetVersionInfo(tpm_manager::GetVersionInfoRequest(), callback);
}
void TpmManagerService::InitializeTask(
const std::shared_ptr<GetTpmStatusReply>& reply) {
VLOG(1) << "Initializing service...";
if (!tpm_status_ || !tpm_initializer_ || !tpm_nvram_) {
// Setup default objects.
#if USE_TPM2
default_trunks_factory_ = std::make_unique<trunks::TrunksFactoryImpl>();
// Tolerate some delay in trunksd being up and ready.
base::TimeTicks deadline = base::TimeTicks::Now() + kTrunksDaemonTimeout;
while (!default_trunks_factory_->Initialize() &&
base::TimeTicks::Now() < deadline) {
base::PlatformThread::Sleep(kTrunksDaemonInitAttemptDelay);
}
default_tpm_status_ =
std::make_unique<Tpm2StatusImpl>(*default_trunks_factory_);
tpm_status_ = default_tpm_status_.get();
default_tpm_initializer_ = std::make_unique<Tpm2InitializerImpl>(
*default_trunks_factory_, local_data_store_, tpm_status_);
tpm_initializer_ = default_tpm_initializer_.get();
default_tpm_nvram_ = std::make_unique<Tpm2NvramImpl>(
*default_trunks_factory_, local_data_store_, tpm_status_);
tpm_nvram_ = default_tpm_nvram_.get();
#else
default_tpm_status_ = std::make_unique<TpmStatusImpl>();
tpm_status_ = default_tpm_status_.get();
default_tpm_initializer_ =
std::make_unique<TpmInitializerImpl>(local_data_store_, tpm_status_);
tpm_initializer_ = default_tpm_initializer_.get();
default_tpm_nvram_ = std::make_unique<TpmNvramImpl>(local_data_store_);
tpm_nvram_ = default_tpm_nvram_.get();
#endif
}
if (!tpm_status_->IsTpmEnabled()) {
LOG(WARNING) << __func__ << ": TPM is disabled.";
reply->set_enabled(false);
reply->set_status(STATUS_SUCCESS);
return;
}
reply->set_enabled(true);
tpm_initializer_->VerifiedBootHelper();
TpmStatus::TpmOwnershipStatus ownership_status;
if (!tpm_status_->GetTpmOwned(&ownership_status)) {
LOG(ERROR) << __func__
<< ": failed to get tpm ownership status, maybe it's the "
"dictionary attack lockout.";
// GetStatus could fail because the TPM is under DA lockout, so we'll try to
// reset lockout then try again.
ResetDictionaryAttackCounterIfNeeded();
if (!tpm_status_->GetTpmOwned(&ownership_status)) {
LOG(ERROR) << __func__
<< ": get tpm ownership status still failed. Giving up.";
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
LOG(INFO) << __func__
<< ": get tpm ownership status suceeded after dictionary attack "
"lockout reset.";
}
// The precondition of DA reset is not satisfied; resets the timer so it
// doesn't get triggered immediately.
if (ownership_status != TpmStatus::kTpmOwned && wait_for_ownership_) {
dictionary_attack_timer_.Reset();
}
worker_thread_->task_runner()->PostTask(
FROM_HERE,
base::Bind(&TpmManagerService::PeriodicResetDictionaryAttackCounterTask,
base::Unretained(this)));
reply->set_owned(TpmStatus::kTpmOwned == ownership_status);
if (ownership_status == TpmStatus::kTpmOwned) {
VLOG(1) << "Tpm is already owned.";
if (!tpm_initializer_->EnsurePersistentOwnerDelegate()) {
// Only treat the failure as a warning because the daemon can be partly
// operational still.
LOG(WARNING)
<< __func__
<< ": Failed to ensure owner delegate is ready with ownership taken.";
}
LocalData local_data;
if (local_data_store_ && local_data_store_->Read(&local_data)) {
*(reply->mutable_local_data()) = std::move(local_data);
}
reply->set_status(STATUS_SUCCESS);
NotifyTpmIsOwned();
return;
}
// TPM is not fully owned yet. There might be stale data in the local data
// store. Checks and removes them if needed.
tpm_initializer_->PruneStoredPasswords();
tpm_nvram_->PrunePolicies();
if (!wait_for_ownership_) {
VLOG(1) << "Initializing TPM.";
if (!tpm_initializer_->InitializeTpm()) {
LOG(WARNING) << __func__ << ": TPM initialization failed.";
dictionary_attack_timer_.Reset();
reply->set_status(STATUS_NOT_AVAILABLE);
return;
}
reply->set_owned(true);
} else if (perform_preinit_) {
VLOG(1) << "Pre-initializing TPM.";
tpm_initializer_->PreInitializeTpm();
}
LocalData local_data;
if (local_data_store_ && local_data_store_->Read(&local_data)) {
*(reply->mutable_local_data()) = std::move(local_data);
}
reply->set_status(STATUS_SUCCESS);
if (reply->owned()) {
NotifyTpmIsOwned();
}
}
void TpmManagerService::NotifyTpmIsOwned() {
DCHECK_EQ(base::PlatformThread::CurrentId(), worker_thread_->GetThreadId());
if (!ownership_taken_callback_.is_null()) {
ownership_taken_callback_.Run();
ownership_taken_callback_.Reset();
}
}
void TpmManagerService::MarkTpmStatusCacheDirty() {
if (base::PlatformThread::CurrentId() == worker_thread_->GetThreadId()) {
// This should run on origin thread
origin_task_runner_->PostTask(
FROM_HERE, base::Bind(&TpmManagerService::MarkTpmStatusCacheDirty,
base::Unretained(this)));
return;
}
CHECK_NE(base::PlatformThread::CurrentId(), worker_thread_->GetThreadId());
update_tpm_status_cache_dirty_ = true;
}
void TpmManagerService::GetTpmStatus(const GetTpmStatusRequest& request,
const GetTpmStatusCallback& callback) {
if (update_tpm_status_cache_dirty_) {
get_tpm_status_waiting_callbacks_.emplace_back(std::move(callback));
} else {
callback.Run(get_tpm_status_cache_);
return;
}
if (update_tpm_status_pending_) {
return;
}
update_tpm_status_pending_ = true;
PostTaskToWorkerThread<GetTpmStatusReply>(
request,
base::Bind(&TpmManagerService::UpdateTpmStatusCallback,
base::Unretained(this)),
&TpmManagerService::GetTpmStatusTask);
}
void TpmManagerService::GetTpmNonsensitiveStatus(
const GetTpmNonsensitiveStatusRequest& request,
const GetTpmNonsensitiveStatusCallback& callback) {
// This function has a different way to proceed the request from other
// request; the callback is wrapped to `GetTpmStatusCallback` followed by a
// handle of `GetTpmStatus()`. Before sending the response,
// `ToGetTpmNonSensitiveStatusReply()` absracts the sensitive secret in
// `GetTpmStatusReply` away.
GetTpmStatusCallback wrapped_callback = base::Bind(
[](const GetTpmNonsensitiveStatusCallback& cb,
const GetTpmStatusReply& reply) {
cb.Run(ToGetTpmNonSensitiveStatusReply(reply));
},
callback);
GetTpmStatus(GetTpmStatusRequest(), wrapped_callback);
}
void TpmManagerService::UpdateTpmStatusCallback(
const GetTpmStatusReply& reply) {
DCHECK_NE(base::PlatformThread::CurrentId(), worker_thread_->GetThreadId());
update_tpm_status_cache_dirty_ = reply.status() != STATUS_SUCCESS;
update_tpm_status_pending_ = false;
get_tpm_status_cache_ = reply;
std::vector<GetTpmStatusCallback> callbacks;
callbacks.swap(get_tpm_status_waiting_callbacks_);
for (const auto& callback : callbacks) {
callback.Run(reply);
}
}
void TpmManagerService::GetTpmStatusTask(
const GetTpmStatusRequest& request,
const std::shared_ptr<GetTpmStatusReply>& reply) {
VLOG(1) << __func__;
if (!tpm_status_) {
LOG(ERROR) << __func__ << ": tpm status is uninitialized.";
reply->set_status(STATUS_NOT_AVAILABLE);
return;
}
reply->set_enabled(tpm_status_->IsTpmEnabled());
TpmStatus::TpmOwnershipStatus ownership_status;
if (!tpm_status_->GetTpmOwned(&ownership_status)) {
LOG(ERROR) << __func__ << ": failed to get tpm ownership status";
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
reply->set_owned(TpmStatus::kTpmOwned == ownership_status);
LocalData local_data;
if (local_data_store_ && local_data_store_->Read(&local_data)) {
*reply->mutable_local_data() = local_data;
}
reply->set_status(STATUS_SUCCESS);
}
void TpmManagerService::GetVersionInfo(const GetVersionInfoRequest& request,
const GetVersionInfoCallback& callback) {
{
base::AutoLock lock(version_info_cache_lock_);
if (version_info_cache_) {
callback.Run(*version_info_cache_);
return;
}
}
PostTaskToWorkerThread<GetVersionInfoReply>(
request, callback, &TpmManagerService::GetVersionInfoTask);
}
void TpmManagerService::GetVersionInfoTask(
const GetVersionInfoRequest& request,
const std::shared_ptr<GetVersionInfoReply>& reply) {
VLOG(1) << __func__;
// It's possible that cache was not available when the request came to the
// main thread but became available when the task is being processed here.
// Checks the cache again to save one TPM call.
if (version_info_cache_) {
*reply = *version_info_cache_;
return;
}
if (!tpm_status_) {
LOG(ERROR) << __func__ << ": tpm status is uninitialized.";
reply->set_status(STATUS_NOT_AVAILABLE);
return;
}
uint32_t family;
uint64_t spec_level;
uint32_t manufacturer;
uint32_t tpm_model;
uint64_t firmware_version;
std::vector<uint8_t> vendor_specific;
if (!tpm_status_->GetVersionInfo(&family, &spec_level, &manufacturer,
&tpm_model, &firmware_version,
&vendor_specific)) {
LOG(ERROR) << __func__ << ": failed to get version info from tpm status.";
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
reply->set_family(family);
reply->set_spec_level(spec_level);
reply->set_manufacturer(manufacturer);
reply->set_tpm_model(tpm_model);
reply->set_firmware_version(firmware_version);
reply->set_vendor_specific(reinterpret_cast<char*>(vendor_specific.data()),
vendor_specific.size());
reply->set_status(STATUS_SUCCESS);
{
base::AutoLock lock(version_info_cache_lock_);
version_info_cache_ = *reply;
}
}
void TpmManagerService::GetDictionaryAttackInfo(
const GetDictionaryAttackInfoRequest& request,
const GetDictionaryAttackInfoCallback& callback) {
PostTaskToWorkerThread<GetDictionaryAttackInfoReply>(
request, callback, &TpmManagerService::GetDictionaryAttackInfoTask);
}
void TpmManagerService::GetDictionaryAttackInfoTask(
const GetDictionaryAttackInfoRequest& request,
const std::shared_ptr<GetDictionaryAttackInfoReply>& reply) {
VLOG(1) << __func__;
if (!tpm_status_) {
LOG(ERROR) << __func__ << ": tpm status is uninitialized.";
reply->set_status(STATUS_NOT_AVAILABLE);
return;
}
uint32_t counter;
uint32_t threshold;
bool lockout;
uint32_t lockout_time_remaining;
if (!tpm_status_->GetDictionaryAttackInfo(&counter, &threshold, &lockout,
&lockout_time_remaining)) {
LOG(ERROR) << __func__ << ": failed to get DA info";
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
reply->set_dictionary_attack_counter(counter);
reply->set_dictionary_attack_threshold(threshold);
reply->set_dictionary_attack_lockout_in_effect(lockout);
reply->set_dictionary_attack_lockout_seconds_remaining(
lockout_time_remaining);
reply->set_status(STATUS_SUCCESS);
}
void TpmManagerService::ResetDictionaryAttackLock(
const ResetDictionaryAttackLockRequest& request,
const ResetDictionaryAttackLockCallback& callback) {
PostTaskToWorkerThread<ResetDictionaryAttackLockReply>(
request, callback, &TpmManagerService::ResetDictionaryAttackLockTask);
}
void TpmManagerService::ResetDictionaryAttackLockTask(
const ResetDictionaryAttackLockRequest& request,
const std::shared_ptr<ResetDictionaryAttackLockReply>& reply) {
VLOG(1) << __func__;
if (!tpm_initializer_) {
LOG(ERROR) << __func__ << ": request received before tpm manager service "
<< "is initialized.";
reply->set_status(STATUS_NOT_AVAILABLE);
return;
}
if (!ResetDictionaryAttackCounterIfNeeded()) {
LOG(ERROR) << __func__ << ": failed to reset DA lock.";
reply->set_status(STATUS_DEVICE_ERROR);
} else {
reply->set_status(STATUS_SUCCESS);
}
dictionary_attack_timer_.Reset();
}
void TpmManagerService::TakeOwnership(const TakeOwnershipRequest& request,
const TakeOwnershipCallback& callback) {
PostTaskToWorkerThread<TakeOwnershipReply>(
request, callback, &TpmManagerService::TakeOwnershipTask);
}
void TpmManagerService::TakeOwnershipTask(
const TakeOwnershipRequest& request,
const std::shared_ptr<TakeOwnershipReply>& reply) {
VLOG(1) << __func__;
if (!tpm_status_->IsTpmEnabled()) {
reply->set_status(STATUS_NOT_AVAILABLE);
return;
}
if (!tpm_initializer_->InitializeTpm()) {
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
MarkTpmStatusCacheDirty();
NotifyTpmIsOwned();
if (!ResetDictionaryAttackCounterIfNeeded()) {
LOG(WARNING) << __func__ << ": DA reset failed after taking ownership.";
}
dictionary_attack_timer_.Reset();
reply->set_status(STATUS_SUCCESS);
}
void TpmManagerService::RemoveOwnerDependency(
const RemoveOwnerDependencyRequest& request,
const RemoveOwnerDependencyCallback& callback) {
PostTaskToWorkerThread<RemoveOwnerDependencyReply>(
request, callback, &TpmManagerService::RemoveOwnerDependencyTask);
}
void TpmManagerService::RemoveOwnerDependencyTask(
const RemoveOwnerDependencyRequest& request,
const std::shared_ptr<RemoveOwnerDependencyReply>& reply) {
VLOG(1) << __func__;
LocalData local_data;
if (!local_data_store_->Read(&local_data)) {
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
RemoveOwnerDependencyFromLocalData(request.owner_dependency(), &local_data);
if (auto_clear_stored_owner_password_) {
ClearOwnerPasswordIfPossible(&local_data);
}
if (!local_data_store_->Write(local_data)) {
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
reply->set_status(STATUS_SUCCESS);
MarkTpmStatusCacheDirty();
}
void TpmManagerService::RemoveOwnerDependencyFromLocalData(
const std::string& owner_dependency, LocalData* local_data) {
google::protobuf::RepeatedPtrField<std::string>* dependencies =
local_data->mutable_owner_dependency();
for (int i = 0; i < dependencies->size(); i++) {
if (dependencies->Get(i) == owner_dependency) {
dependencies->SwapElements(i, (dependencies->size() - 1));
dependencies->RemoveLast();
break;
}
}
}
void TpmManagerService::ClearStoredOwnerPassword(
const ClearStoredOwnerPasswordRequest& request,
const ClearStoredOwnerPasswordCallback& callback) {
PostTaskToWorkerThread<ClearStoredOwnerPasswordReply>(
request, callback, &TpmManagerService::ClearStoredOwnerPasswordTask);
}
void TpmManagerService::ClearStoredOwnerPasswordTask(
const ClearStoredOwnerPasswordRequest& request,
const std::shared_ptr<ClearStoredOwnerPasswordReply>& reply) {
VLOG(1) << __func__;
LocalData local_data;
if (!local_data_store_->Read(&local_data)) {
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
if (ClearOwnerPasswordIfPossible(&local_data)) {
if (!local_data_store_->Write(local_data)) {
reply->set_status(STATUS_DEVICE_ERROR);
return;
}
}
reply->set_status(STATUS_SUCCESS);
MarkTpmStatusCacheDirty();
}
void TpmManagerService::DefineSpace(const DefineSpaceRequest& request,
const DefineSpaceCallback& callback) {
PostTaskToWorkerThread<DefineSpaceReply>(request, callback,
&TpmManagerService::DefineSpaceTask);
}
void TpmManagerService::DefineSpaceTask(
const DefineSpaceRequest& request,
const std::shared_ptr<DefineSpaceReply>& reply) {
VLOG(1) << __func__;
std::vector<NvramSpaceAttribute> attributes;
for (int i = 0; i < request.attributes_size(); ++i) {
attributes.push_back(request.attributes(i));
}
reply->set_result(
tpm_nvram_->DefineSpace(request.index(), request.size(), attributes,
request.authorization_value(), request.policy()));
MarkTpmStatusCacheDirty();
}
void TpmManagerService::DestroySpace(const DestroySpaceRequest& request,
const DestroySpaceCallback& callback) {
PostTaskToWorkerThread<DestroySpaceReply>(
request, callback, &TpmManagerService::DestroySpaceTask);
}
void TpmManagerService::DestroySpaceTask(
const DestroySpaceRequest& request,
const std::shared_ptr<DestroySpaceReply>& reply) {
VLOG(1) << __func__;
reply->set_result(tpm_nvram_->DestroySpace(request.index()));
MarkTpmStatusCacheDirty();
}
void TpmManagerService::WriteSpace(const WriteSpaceRequest& request,
const WriteSpaceCallback& callback) {
PostTaskToWorkerThread<WriteSpaceReply>(request, callback,
&TpmManagerService::WriteSpaceTask);
}
void TpmManagerService::WriteSpaceTask(
const WriteSpaceRequest& request,
const std::shared_ptr<WriteSpaceReply>& reply) {
VLOG(1) << __func__;
std::string authorization_value = request.authorization_value();
if (request.use_owner_authorization()) {
authorization_value = GetOwnerPassword();
if (authorization_value.empty()) {
reply->set_result(NVRAM_RESULT_ACCESS_DENIED);
return;
}
}
reply->set_result(tpm_nvram_->WriteSpace(request.index(), request.data(),
authorization_value));
}
void TpmManagerService::ReadSpace(const ReadSpaceRequest& request,
const ReadSpaceCallback& callback) {
PostTaskToWorkerThread<ReadSpaceReply>(request, callback,
&TpmManagerService::ReadSpaceTask);
}
void TpmManagerService::ReadSpaceTask(
const ReadSpaceRequest& request,
const std::shared_ptr<ReadSpaceReply>& reply) {
VLOG(1) << __func__;
std::string authorization_value = request.authorization_value();
if (request.use_owner_authorization()) {
authorization_value = GetOwnerPassword();
if (authorization_value.empty()) {
reply->set_result(NVRAM_RESULT_ACCESS_DENIED);
return;
}
}
reply->set_result(tpm_nvram_->ReadSpace(
request.index(), reply->mutable_data(), authorization_value));
}
void TpmManagerService::LockSpace(const LockSpaceRequest& request,
const LockSpaceCallback& callback) {
PostTaskToWorkerThread<LockSpaceReply>(request, callback,
&TpmManagerService::LockSpaceTask);
}
void TpmManagerService::LockSpaceTask(
const LockSpaceRequest& request,
const std::shared_ptr<LockSpaceReply>& reply) {
VLOG(1) << __func__;
std::string authorization_value = request.authorization_value();
if (request.use_owner_authorization()) {
authorization_value = GetOwnerPassword();
if (authorization_value.empty()) {
reply->set_result(NVRAM_RESULT_ACCESS_DENIED);
return;
}
}
reply->set_result(tpm_nvram_->LockSpace(request.index(), request.lock_read(),
request.lock_write(),
authorization_value));
}
void TpmManagerService::ListSpaces(const ListSpacesRequest& request,
const ListSpacesCallback& callback) {
PostTaskToWorkerThread<ListSpacesReply>(request, callback,
&TpmManagerService::ListSpacesTask);
}
void TpmManagerService::ListSpacesTask(
const ListSpacesRequest& request,
const std::shared_ptr<ListSpacesReply>& reply) {
VLOG(1) << __func__;
std::vector<uint32_t> index_list;
reply->set_result(tpm_nvram_->ListSpaces(&index_list));
if (reply->result() == NVRAM_RESULT_SUCCESS) {
for (auto index : index_list) {
reply->add_index_list(index);
}
}
}
void TpmManagerService::GetSpaceInfo(const GetSpaceInfoRequest& request,
const GetSpaceInfoCallback& callback) {
PostTaskToWorkerThread<GetSpaceInfoReply>(
request, callback, &TpmManagerService::GetSpaceInfoTask);
}
void TpmManagerService::GetSpaceInfoTask(
const GetSpaceInfoRequest& request,
const std::shared_ptr<GetSpaceInfoReply>& reply) {
VLOG(1) << __func__;
std::vector<NvramSpaceAttribute> attributes;
uint32_t size = 0;
bool is_read_locked = false;
bool is_write_locked = false;
NvramSpacePolicy policy = NVRAM_POLICY_NONE;
reply->set_result(tpm_nvram_->GetSpaceInfo(request.index(), &size,
&is_read_locked, &is_write_locked,
&attributes, &policy));
if (reply->result() == NVRAM_RESULT_SUCCESS) {
reply->set_size(size);
reply->set_is_read_locked(is_read_locked);
reply->set_is_write_locked(is_write_locked);
for (auto attribute : attributes) {
reply->add_attributes(attribute);
}
reply->set_policy(policy);
}
}
std::string TpmManagerService::GetOwnerPassword() {
LocalData local_data;
if (local_data_store_->Read(&local_data)) {
return local_data.owner_password();
}
LOG(ERROR) << "TPM owner password requested but not available.";
return std::string();
}
bool TpmManagerService::ResetDictionaryAttackCounterIfNeeded() {
uint32_t counter = 0;
uint32_t threshold = 0;
bool lockout = false;
uint32_t time_remaining = 0;
if (!tpm_status_->GetDictionaryAttackInfo(&counter, &threshold, &lockout,
&time_remaining)) {
// Reports the metrics but no early return since reset itself might work.
tpm_manager_metrics_->ReportDictionaryAttackResetStatus(
DictionaryAttackResetStatus::kCounterQueryFailed);
} else {
tpm_manager_metrics_->ReportDictionaryAttackCounter(counter);
if (counter == 0) {
tpm_manager_metrics_->ReportDictionaryAttackResetStatus(
DictionaryAttackResetStatus::kResetNotNecessary);
return true;
}
}
auto status = tpm_initializer_->ResetDictionaryAttackLock();
tpm_manager_metrics_->ReportDictionaryAttackResetStatus(status);
return status == DictionaryAttackResetStatus::kResetAttemptSucceeded;
}
void TpmManagerService::PeriodicResetDictionaryAttackCounterTask() {
VLOG(1) << __func__;
base::TimeDelta time_remaining = dictionary_attack_timer_.TimeRemaining();
// if the timer is up, run the task and reset the timer.
if (time_remaining.is_zero()) {
if (!ResetDictionaryAttackCounterIfNeeded()) {
LOG(WARNING) << __func__ << ": DA reset failed.";
} else {
LOG(INFO) << __func__ << ": DA reset succeeded.";
}
dictionary_attack_timer_.Reset();
time_remaining = dictionary_attack_timer_.TimeRemaining();
} else {
LOG(INFO) << __func__ << ": Time is not up yet.";
}
worker_thread_->task_runner()->PostDelayedTask(
FROM_HERE,
base::Bind(&TpmManagerService::PeriodicResetDictionaryAttackCounterTask,
base::Unretained(this)),
time_remaining);
}
void TpmManagerService::ShutdownTask() {
default_tpm_status_.reset();
default_tpm_initializer_.reset();
default_tpm_nvram_.reset();
#if USE_TPM2
// Resets |default_trunks_factory_| last because other components hold its
// reference.
default_trunks_factory_.reset();
#endif
}
template <typename ReplyProtobufType>
void TpmManagerService::TaskRelayCallback(
const base::Callback<void(const ReplyProtobufType&)> callback,
const std::shared_ptr<ReplyProtobufType>& reply) {
callback.Run(*reply);
}
template <typename ReplyProtobufType,
typename RequestProtobufType,
typename ReplyCallbackType,
typename TaskType>
void TpmManagerService::PostTaskToWorkerThread(
const RequestProtobufType& request,
const ReplyCallbackType& callback,
TaskType task) {
auto result = std::make_shared<ReplyProtobufType>();
base::Closure background_task =
base::Bind(task, base::Unretained(this), request, result);
base::Closure reply =
base::Bind(&TpmManagerService::TaskRelayCallback<ReplyProtobufType>,
weak_factory_.GetWeakPtr(), callback, result);
worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, background_task,
reply);
}
template <typename ReplyProtobufType,
typename ReplyCallbackType,
typename TaskType>
void TpmManagerService::PostTaskToWorkerThreadWithoutRequest(
const ReplyCallbackType& callback, TaskType task) {
auto result = std::make_shared<ReplyProtobufType>();
base::Closure background_task =
base::Bind(task, base::Unretained(this), result);
base::Closure reply =
base::Bind(&TpmManagerService::TaskRelayCallback<ReplyProtobufType>,
weak_factory_.GetWeakPtr(), callback, result);
worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, background_task,
reply);
}
} // namespace tpm_manager