You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
658 lines
24 KiB
658 lines
24 KiB
// |
|
// Copyright (C) 2015 The Android Open Source Project |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
// |
|
|
|
#include "tpm_manager/server/tpm2_nvram_impl.h" |
|
|
|
#include <memory> |
|
#include <string> |
|
|
|
#include <base/logging.h> |
|
#include <trunks/error_codes.h> |
|
#include <trunks/policy_session.h> |
|
#include <trunks/tpm_constants.h> |
|
#include <trunks/tpm_utility.h> |
|
|
|
namespace tpm_manager { |
|
|
|
using trunks::GetErrorString; |
|
using trunks::TPM_RC; |
|
using trunks::TPM_RC_SUCCESS; |
|
|
|
namespace { |
|
|
|
void MapAttributesFromTpm(trunks::TPMA_NV tpm_flags, |
|
std::vector<NvramSpaceAttribute>* attributes) { |
|
if (tpm_flags & trunks::TPMA_NV_WRITEDEFINE) |
|
attributes->push_back(NVRAM_PERSISTENT_WRITE_LOCK); |
|
if (tpm_flags & trunks::TPMA_NV_WRITE_STCLEAR) |
|
attributes->push_back(NVRAM_BOOT_WRITE_LOCK); |
|
if (tpm_flags & trunks::TPMA_NV_READ_STCLEAR) |
|
attributes->push_back(NVRAM_BOOT_READ_LOCK); |
|
if (tpm_flags & (trunks::TPMA_NV_AUTHWRITE)) |
|
attributes->push_back(NVRAM_WRITE_AUTHORIZATION); |
|
if (tpm_flags & (trunks::TPMA_NV_AUTHREAD)) |
|
attributes->push_back(NVRAM_READ_AUTHORIZATION); |
|
if (tpm_flags & trunks::TPMA_NV_GLOBALLOCK) |
|
attributes->push_back(NVRAM_GLOBAL_LOCK); |
|
if (tpm_flags & trunks::TPMA_NV_PPWRITE) |
|
attributes->push_back(NVRAM_PLATFORM_WRITE); |
|
if (tpm_flags & trunks::TPMA_NV_OWNERWRITE) |
|
attributes->push_back(NVRAM_OWNER_WRITE); |
|
if (tpm_flags & trunks::TPMA_NV_OWNERREAD) |
|
attributes->push_back(NVRAM_OWNER_READ); |
|
if (tpm_flags & trunks::TPMA_NV_EXTEND) |
|
attributes->push_back(NVRAM_WRITE_EXTEND); |
|
} |
|
|
|
bool MapAttributesToTpm( |
|
const std::vector<NvramSpaceAttribute>& attributes, |
|
trunks::TPMA_NV* tpm_flags, |
|
bool* world_read_allowed, |
|
bool* world_write_allowed) { |
|
// Always require policy, even if it's an empty policy. |
|
*tpm_flags = trunks::TPMA_NV_POLICYWRITE | trunks::TPMA_NV_POLICYREAD; |
|
*world_read_allowed = true; |
|
*world_write_allowed = true; |
|
for (auto attribute : attributes) { |
|
switch (attribute) { |
|
case NVRAM_PERSISTENT_WRITE_LOCK: |
|
*tpm_flags |= trunks::TPMA_NV_WRITEDEFINE; |
|
break; |
|
case NVRAM_BOOT_WRITE_LOCK: |
|
*tpm_flags |= trunks::TPMA_NV_WRITE_STCLEAR; |
|
break; |
|
case NVRAM_BOOT_READ_LOCK: |
|
*tpm_flags |= trunks::TPMA_NV_READ_STCLEAR; |
|
break; |
|
case NVRAM_WRITE_AUTHORIZATION: |
|
*world_write_allowed = false; |
|
break; |
|
case NVRAM_READ_AUTHORIZATION: |
|
*world_read_allowed = false; |
|
break; |
|
case NVRAM_WRITE_EXTEND: |
|
*tpm_flags |= trunks::TPMA_NV_EXTEND; |
|
break; |
|
case NVRAM_GLOBAL_LOCK: |
|
case NVRAM_PLATFORM_WRITE: |
|
case NVRAM_OWNER_WRITE: |
|
case NVRAM_OWNER_READ: |
|
return false; |
|
default: |
|
break; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
NvramResult MapTpmError(TPM_RC tpm_error) { |
|
switch (trunks::GetFormatOneError(tpm_error)) { |
|
case trunks::TPM_RC_SUCCESS: |
|
return NVRAM_RESULT_SUCCESS; |
|
case trunks::TPM_RC_NV_RANGE: |
|
case trunks::TPM_RC_NV_SIZE: |
|
case trunks::TPM_RC_ATTRIBUTES: |
|
return NVRAM_RESULT_INVALID_PARAMETER; |
|
case trunks::TPM_RC_NV_LOCKED: |
|
case trunks::TPM_RC_NV_UNINITIALIZED: |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
case trunks::TPM_RC_NV_AUTHORIZATION: |
|
case trunks::TPM_RC_BAD_AUTH: |
|
case trunks::TPM_RC_AUTH_FAIL: |
|
case trunks::TPM_RC_POLICY_FAIL: |
|
return NVRAM_RESULT_ACCESS_DENIED; |
|
case trunks::TPM_RC_NV_SPACE: |
|
return NVRAM_RESULT_INSUFFICIENT_SPACE; |
|
case trunks::TPM_RC_NV_DEFINED: |
|
return NVRAM_RESULT_SPACE_ALREADY_EXISTS; |
|
case trunks::TPM_RC_HANDLE: |
|
return NVRAM_RESULT_SPACE_DOES_NOT_EXIST; |
|
} |
|
return NVRAM_RESULT_DEVICE_ERROR; |
|
} |
|
|
|
} // namespace |
|
|
|
Tpm2NvramImpl::Tpm2NvramImpl(const trunks::TrunksFactory& factory, |
|
LocalDataStore* local_data_store) |
|
: trunks_factory_(factory), |
|
local_data_store_(local_data_store), |
|
initialized_(false), |
|
trunks_session_(trunks_factory_.GetHmacSession()), |
|
trunks_utility_(trunks_factory_.GetTpmUtility()) {} |
|
|
|
NvramResult Tpm2NvramImpl::DefineSpace( |
|
uint32_t index, |
|
size_t size, |
|
const std::vector<NvramSpaceAttribute>& attributes, |
|
const std::string& authorization_value, |
|
NvramSpacePolicy policy) { |
|
if (!Initialize()) { |
|
return NVRAM_RESULT_DEVICE_ERROR; |
|
} |
|
if (!SetupOwnerSession()) { |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
trunks::TPMA_NV attribute_flags = 0; |
|
bool world_read_allowed = false; |
|
bool world_write_allowed = false; |
|
if (!MapAttributesToTpm(attributes, &attribute_flags, &world_read_allowed, |
|
&world_write_allowed)) { |
|
return NVRAM_RESULT_INVALID_PARAMETER; |
|
} |
|
NvramPolicyRecord policy_record; |
|
policy_record.set_index(index); |
|
policy_record.set_policy(policy); |
|
policy_record.set_world_read_allowed(world_read_allowed); |
|
policy_record.set_world_write_allowed(world_write_allowed); |
|
std::string policy_digest; |
|
if (!ComputePolicyDigest(&policy_record, &policy_digest)) { |
|
LOG(ERROR) << "Failed to compute policy digest."; |
|
return NVRAM_RESULT_DEVICE_ERROR; |
|
} |
|
TPM_RC result = trunks_utility_->DefineNVSpace( |
|
index, size, attribute_flags, authorization_value, policy_digest, |
|
trunks_session_->GetDelegate()); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error defining nvram space: " << GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
if (!SavePolicyRecord(policy_record)) { |
|
trunks_utility_->DestroyNVSpace(index, trunks_session_->GetDelegate()); |
|
return NVRAM_RESULT_DEVICE_ERROR; |
|
} |
|
return NVRAM_RESULT_SUCCESS; |
|
} |
|
|
|
NvramResult Tpm2NvramImpl::DestroySpace(uint32_t index) { |
|
if (!Initialize()) { |
|
return NVRAM_RESULT_DEVICE_ERROR; |
|
} |
|
if (!SetupOwnerSession()) { |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
TPM_RC result = |
|
trunks_utility_->DestroyNVSpace(index, trunks_session_->GetDelegate()); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error destroying nvram space:" << GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
DeletePolicyRecord(index); |
|
return NVRAM_RESULT_SUCCESS; |
|
} |
|
|
|
NvramResult Tpm2NvramImpl::WriteSpace(uint32_t index, |
|
const std::string& data, |
|
const std::string& authorization_value) { |
|
if (!Initialize()) { |
|
return NVRAM_RESULT_DEVICE_ERROR; |
|
} |
|
trunks::TPMS_NV_PUBLIC nvram_public; |
|
TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error reading nvram space public area: " |
|
<< GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
if (nvram_public.attributes & trunks::TPMA_NV_WRITELOCKED) { |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
trunks::AuthorizationDelegate* authorization = nullptr; |
|
std::unique_ptr<trunks::PolicySession> policy_session = |
|
trunks_factory_.GetPolicySession(); |
|
bool using_owner_authorization = false; |
|
bool extend = (nvram_public.attributes & trunks::TPMA_NV_EXTEND) != 0; |
|
if (nvram_public.attributes & trunks::TPMA_NV_POLICYWRITE) { |
|
NvramPolicyRecord policy_record; |
|
if (!GetPolicyRecord(index, &policy_record)) { |
|
LOG(ERROR) << "Policy record missing."; |
|
return NVRAM_RESULT_INVALID_PARAMETER; |
|
} |
|
if (!SetupPolicySession( |
|
policy_record, authorization_value, |
|
extend ? trunks::TPM_CC_NV_Extend : trunks::TPM_CC_NV_Write, |
|
policy_session.get())) { |
|
// This will fail if policy is not met, e.g. a PCR value is not the |
|
// required value. |
|
return NVRAM_RESULT_ACCESS_DENIED; |
|
} |
|
authorization = policy_session->GetDelegate(); |
|
} else if (nvram_public.attributes & trunks::TPMA_NV_AUTHWRITE) { |
|
trunks_session_->SetEntityAuthorizationValue(authorization_value); |
|
authorization = trunks_session_->GetDelegate(); |
|
} else if (nvram_public.attributes & trunks::TPMA_NV_OWNERWRITE) { |
|
if (!SetupOwnerSession()) { |
|
// The owner password has been destroyed. |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
using_owner_authorization = true; |
|
authorization = trunks_session_->GetDelegate(); |
|
} else { |
|
// TPMA_NV_PPWRITE: Platform authorization is long gone. |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
result = trunks_utility_->WriteNVSpace(index, 0 /* offset */, data, |
|
using_owner_authorization, extend, |
|
authorization); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error writing to nvram space: " << GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
return NVRAM_RESULT_SUCCESS; |
|
} |
|
|
|
NvramResult Tpm2NvramImpl::ReadSpace(uint32_t index, |
|
std::string* data, |
|
const std::string& authorization_value) { |
|
if (!Initialize()) { |
|
return NVRAM_RESULT_DEVICE_ERROR; |
|
} |
|
trunks::TPMS_NV_PUBLIC nvram_public; |
|
TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error reading nvram space public area: " |
|
<< GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
if (nvram_public.attributes & trunks::TPMA_NV_READLOCKED) { |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
// Handle the case when the space has never been written to. |
|
if ((nvram_public.attributes & trunks::TPMA_NV_WRITTEN) == 0) { |
|
*data = std::string(nvram_public.data_size, 0); |
|
return NVRAM_RESULT_SUCCESS; |
|
} |
|
trunks::AuthorizationDelegate* authorization = nullptr; |
|
std::unique_ptr<trunks::PolicySession> policy_session = |
|
trunks_factory_.GetPolicySession(); |
|
bool using_owner_authorization = false; |
|
if (nvram_public.attributes & trunks::TPMA_NV_POLICYREAD) { |
|
NvramPolicyRecord policy_record; |
|
if (!GetPolicyRecord(index, &policy_record)) { |
|
LOG(ERROR) << "Policy record missing."; |
|
return NVRAM_RESULT_INVALID_PARAMETER; |
|
} |
|
if (!SetupPolicySession(policy_record, authorization_value, |
|
trunks::TPM_CC_NV_Read, policy_session.get())) { |
|
// This will fail if policy is not met, e.g. a PCR value is not the |
|
// required value. |
|
return NVRAM_RESULT_ACCESS_DENIED; |
|
} |
|
authorization = policy_session->GetDelegate(); |
|
} else if (nvram_public.attributes & trunks::TPMA_NV_AUTHREAD) { |
|
trunks_session_->SetEntityAuthorizationValue(authorization_value); |
|
authorization = trunks_session_->GetDelegate(); |
|
} else if (nvram_public.attributes & trunks::TPMA_NV_OWNERREAD) { |
|
if (!SetupOwnerSession()) { |
|
// The owner password has been destroyed. |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
using_owner_authorization = true; |
|
authorization = trunks_session_->GetDelegate(); |
|
} else { |
|
// TPMA_NV_PPREAD: Platform authorization is long gone. |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
result = trunks_utility_->ReadNVSpace( |
|
index, 0 /* offset */, nvram_public.data_size, using_owner_authorization, |
|
data, authorization); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error reading nvram space: " << GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
return NVRAM_RESULT_SUCCESS; |
|
} |
|
|
|
NvramResult Tpm2NvramImpl::LockSpace(uint32_t index, |
|
bool lock_read, |
|
bool lock_write, |
|
const std::string& authorization_value) { |
|
if (!Initialize()) { |
|
return NVRAM_RESULT_DEVICE_ERROR; |
|
} |
|
trunks::TPMS_NV_PUBLIC nvram_public; |
|
TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error reading nvram space public area: " |
|
<< GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
bool is_read_locked = |
|
((nvram_public.attributes & trunks::TPMA_NV_READLOCKED) != 0); |
|
bool is_write_locked = |
|
((nvram_public.attributes & trunks::TPMA_NV_WRITELOCKED) != 0); |
|
if ((!lock_read || is_read_locked) && (!lock_write || is_write_locked)) { |
|
// Already locked. |
|
return NVRAM_RESULT_SUCCESS; |
|
} |
|
// Handle locking read and write separately because the authorization might be |
|
// different. |
|
if (lock_read && !is_read_locked) { |
|
trunks::AuthorizationDelegate* authorization = nullptr; |
|
std::unique_ptr<trunks::PolicySession> policy_session = |
|
trunks_factory_.GetPolicySession(); |
|
bool using_owner_authorization = false; |
|
if (nvram_public.attributes & trunks::TPMA_NV_POLICYREAD) { |
|
NvramPolicyRecord policy_record; |
|
if (!GetPolicyRecord(index, &policy_record)) { |
|
LOG(ERROR) << "Policy record missing."; |
|
return NVRAM_RESULT_INVALID_PARAMETER; |
|
} |
|
if (!SetupPolicySession(policy_record, authorization_value, |
|
trunks::TPM_CC_NV_ReadLock, |
|
policy_session.get())) { |
|
// This will fail if policy is not met, e.g. a PCR value is not the |
|
// required value. |
|
return NVRAM_RESULT_ACCESS_DENIED; |
|
} |
|
authorization = policy_session->GetDelegate(); |
|
} else if (nvram_public.attributes & trunks::TPMA_NV_AUTHREAD) { |
|
trunks_session_->SetEntityAuthorizationValue(authorization_value); |
|
authorization = trunks_session_->GetDelegate(); |
|
} else if (nvram_public.attributes & trunks::TPMA_NV_OWNERREAD) { |
|
if (!SetupOwnerSession()) { |
|
// The owner password has been destroyed. |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
using_owner_authorization = true; |
|
authorization = trunks_session_->GetDelegate(); |
|
} else { |
|
// TPMA_NV_PPREAD: Platform authorization is long gone. |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
result = trunks_utility_->LockNVSpace( |
|
index, true /* lock_read */, false /* lock_write */, |
|
using_owner_authorization, authorization); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error locking nvram space: " << GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
} |
|
if (lock_write && !is_write_locked) { |
|
trunks::AuthorizationDelegate* authorization = nullptr; |
|
std::unique_ptr<trunks::PolicySession> policy_session = |
|
trunks_factory_.GetPolicySession(); |
|
bool using_owner_authorization = false; |
|
if (nvram_public.attributes & trunks::TPMA_NV_POLICYWRITE) { |
|
NvramPolicyRecord policy_record; |
|
if (!GetPolicyRecord(index, &policy_record)) { |
|
LOG(ERROR) << "Policy record missing."; |
|
return NVRAM_RESULT_INVALID_PARAMETER; |
|
} |
|
if (!SetupPolicySession(policy_record, authorization_value, |
|
trunks::TPM_CC_NV_WriteLock, |
|
policy_session.get())) { |
|
// This will fail if policy is not met, e.g. a PCR value is not the |
|
// required value. |
|
return NVRAM_RESULT_ACCESS_DENIED; |
|
} |
|
authorization = policy_session->GetDelegate(); |
|
} else if (nvram_public.attributes & trunks::TPMA_NV_AUTHWRITE) { |
|
trunks_session_->SetEntityAuthorizationValue(authorization_value); |
|
authorization = trunks_session_->GetDelegate(); |
|
} else if (nvram_public.attributes & trunks::TPMA_NV_OWNERWRITE) { |
|
if (!SetupOwnerSession()) { |
|
// The owner password has been destroyed. |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
using_owner_authorization = true; |
|
authorization = trunks_session_->GetDelegate(); |
|
} else { |
|
// TPMA_NV_PPWRITE: Platform authorization is long gone. |
|
return NVRAM_RESULT_OPERATION_DISABLED; |
|
} |
|
result = trunks_utility_->LockNVSpace( |
|
index, false /* lock_read */, true /* lock_write */, |
|
using_owner_authorization, authorization); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error locking nvram space: " << GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
} |
|
return NVRAM_RESULT_SUCCESS; |
|
} |
|
|
|
NvramResult Tpm2NvramImpl::ListSpaces(std::vector<uint32_t>* index_list) { |
|
return MapTpmError(trunks_utility_->ListNVSpaces(index_list)); |
|
} |
|
|
|
NvramResult Tpm2NvramImpl::GetSpaceInfo( |
|
uint32_t index, |
|
size_t* size, |
|
bool* is_read_locked, |
|
bool* is_write_locked, |
|
std::vector<NvramSpaceAttribute>* attributes, |
|
NvramSpacePolicy* policy) { |
|
trunks::TPMS_NV_PUBLIC nvram_public; |
|
TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error reading NV space for index " << index |
|
<< " with error: " << GetErrorString(result); |
|
return MapTpmError(result); |
|
} |
|
*size = nvram_public.data_size; |
|
*is_read_locked = |
|
((nvram_public.attributes & trunks::TPMA_NV_READLOCKED) != 0); |
|
*is_write_locked = |
|
((nvram_public.attributes & trunks::TPMA_NV_WRITELOCKED) != 0); |
|
MapAttributesFromTpm(nvram_public.attributes, attributes); |
|
*policy = NVRAM_POLICY_NONE; |
|
NvramPolicyRecord policy_record; |
|
if (GetPolicyRecord(index, &policy_record)) { |
|
*policy = policy_record.policy(); |
|
if (!policy_record.world_read_allowed()) { |
|
attributes->push_back(NVRAM_READ_AUTHORIZATION); |
|
} |
|
if (!policy_record.world_write_allowed()) { |
|
attributes->push_back(NVRAM_WRITE_AUTHORIZATION); |
|
} |
|
} |
|
return NVRAM_RESULT_SUCCESS; |
|
} |
|
|
|
bool Tpm2NvramImpl::Initialize() { |
|
if (initialized_) { |
|
return true; |
|
} |
|
TPM_RC result = |
|
trunks_session_->StartUnboundSession(true /* enable_encryption */); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error starting a default authorization session: " |
|
<< GetErrorString(result); |
|
return false; |
|
} |
|
initialized_ = true; |
|
return true; |
|
} |
|
|
|
std::string Tpm2NvramImpl::GetOwnerPassword() { |
|
LocalData local_data; |
|
if (local_data_store_ && local_data_store_->Read(&local_data)) { |
|
return local_data.owner_password(); |
|
} |
|
LOG(ERROR) << "TPM owner password requested but not available."; |
|
return std::string(); |
|
} |
|
|
|
bool Tpm2NvramImpl::SetupOwnerSession() { |
|
std::string owner_password = GetOwnerPassword(); |
|
if (owner_password.empty()) { |
|
LOG(ERROR) << "Owner authorization required but not available."; |
|
return false; |
|
} |
|
trunks_session_->SetEntityAuthorizationValue(owner_password); |
|
return true; |
|
} |
|
|
|
bool Tpm2NvramImpl::SetupPolicySession( |
|
const NvramPolicyRecord& policy_record, |
|
const std::string& authorization_value, |
|
trunks::TPM_CC command_code, |
|
trunks::PolicySession* session) { |
|
TPM_RC result = session->StartUnboundSession(true /* enable_encryption */); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Error starting a policy authorization session: " |
|
<< GetErrorString(result); |
|
return false; |
|
} |
|
session->SetEntityAuthorizationValue(authorization_value); |
|
if (!AddPoliciesForCommand(policy_record, command_code, session)) { |
|
return false; |
|
} |
|
if (!AddPolicyOR(policy_record, session)) { |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
bool Tpm2NvramImpl::AddPoliciesForCommand( |
|
const NvramPolicyRecord& policy_record, |
|
trunks::TPM_CC command_code, |
|
trunks::PolicySession* session) { |
|
TPM_RC result = session->PolicyCommandCode(command_code); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Failed to setup command code policy."; |
|
return false; |
|
} |
|
bool is_write_command = (command_code == trunks::TPM_CC_NV_Write || |
|
command_code == trunks::TPM_CC_NV_WriteLock || |
|
command_code == trunks::TPM_CC_NV_Extend); |
|
bool is_read_command = !is_write_command; |
|
// Check if this operation requires an authorization value. |
|
if ((is_read_command && !policy_record.world_read_allowed()) || |
|
(is_write_command && !policy_record.world_write_allowed())) { |
|
result = session->PolicyAuthValue(); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Failed to setup auth policy."; |
|
return false; |
|
} |
|
} |
|
if (policy_record.policy() == NVRAM_POLICY_PCR0) { |
|
std::string current_pcr_value; |
|
result = trunks_utility_->ReadPCR(0, ¤t_pcr_value); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Failed to read the current PCR value."; |
|
return false; |
|
} |
|
result = session->PolicyPCR(0, current_pcr_value); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Failed to setup PCR policy."; |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
bool Tpm2NvramImpl::AddPolicyOR( |
|
const NvramPolicyRecord& policy_record, |
|
trunks::PolicySession* session) { |
|
std::vector<std::string> digests; |
|
for (int i = 0; i < policy_record.policy_digests_size(); ++i) { |
|
digests.push_back(policy_record.policy_digests(i)); |
|
} |
|
TPM_RC result = session->PolicyOR(digests); |
|
if (result != TPM_RC_SUCCESS) { |
|
LOG(ERROR) << "Failed to setup OR policy."; |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
bool Tpm2NvramImpl::ComputePolicyDigest(NvramPolicyRecord* policy_record, |
|
std::string* digest) { |
|
// Compute a policy digest for each command then OR them all together. This |
|
// approach gives flexibility to have different requirements for read and |
|
// write operations, and the ability to support authorization values combined |
|
// with other policies. |
|
std::unique_ptr<trunks::PolicySession> trial_session; |
|
for (trunks::TPM_CC command_code : |
|
{trunks::TPM_CC_NV_Extend, trunks::TPM_CC_NV_Write, |
|
trunks::TPM_CC_NV_WriteLock, trunks::TPM_CC_NV_Read, |
|
trunks::TPM_CC_NV_ReadLock, trunks::TPM_CC_NV_Certify}) { |
|
trial_session = trunks_factory_.GetTrialSession(); |
|
if (trial_session->StartUnboundSession(false /* enable_encryption */) != |
|
TPM_RC_SUCCESS) { |
|
return false; |
|
} |
|
if (!AddPoliciesForCommand(*policy_record, command_code, |
|
trial_session.get())) { |
|
return false; |
|
} |
|
if (trial_session->GetDigest(digest) != TPM_RC_SUCCESS) { |
|
return false; |
|
} |
|
policy_record->add_policy_digests(*digest); |
|
} |
|
if (!AddPolicyOR(*policy_record, trial_session.get())) { |
|
return false; |
|
} |
|
if (trial_session->GetDigest(digest) != TPM_RC_SUCCESS) { |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
bool Tpm2NvramImpl::GetPolicyRecord(uint32_t index, NvramPolicyRecord* record) { |
|
LocalData local_data; |
|
if (local_data_store_ && local_data_store_->Read(&local_data)) { |
|
for (int i = 0; i < local_data.nvram_policy_size(); ++i) { |
|
if (local_data.nvram_policy(i).index() == index) { |
|
*record = local_data.nvram_policy(i); |
|
return true; |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
bool Tpm2NvramImpl::SavePolicyRecord(const NvramPolicyRecord& record) { |
|
LocalData local_data; |
|
if (!local_data_store_ || !local_data_store_->Read(&local_data)) { |
|
LOG(ERROR) << "Failed to read local data."; |
|
return false; |
|
} |
|
LocalData new_local_data = local_data; |
|
new_local_data.clear_nvram_policy(); |
|
for (int i = 0; i < local_data.nvram_policy_size(); ++i) { |
|
// Keep only the ones that don't match |record|. |
|
if (local_data.nvram_policy(i).index() != record.index()) { |
|
*new_local_data.add_nvram_policy() = local_data.nvram_policy(i); |
|
} |
|
} |
|
*new_local_data.add_nvram_policy() = record; |
|
if (!local_data_store_->Write(new_local_data)) { |
|
LOG(ERROR) << "Failed to write local data."; |
|
return false; |
|
} |
|
return true; |
|
} |
|
|
|
void Tpm2NvramImpl::DeletePolicyRecord(uint32_t index) { |
|
LocalData local_data; |
|
if (local_data_store_ && local_data_store_->Read(&local_data)) { |
|
LocalData new_local_data = local_data; |
|
new_local_data.clear_nvram_policy(); |
|
for (int i = 0; i < local_data.nvram_policy_size(); ++i) { |
|
// Keep only the ones that don't match |index|. |
|
if (local_data.nvram_policy(i).index() != index) { |
|
*new_local_data.add_nvram_policy() = local_data.nvram_policy(i); |
|
} |
|
} |
|
local_data_store_->Write(new_local_data); |
|
} |
|
} |
|
|
|
} // namespace tpm_manager
|
|
|