diff options
author | Utkarsh Sanghi <usanghi@google.com> | 2015-10-06 16:45:49 -0700 |
---|---|---|
committer | Utkarsh Sanghi <usanghi@google.com> | 2015-10-21 22:52:13 -0700 |
commit | 42987bddf07f1efaa78ffa883254d8ee03cb7901 (patch) | |
tree | 68ffffe71d11a83e38ab092cb91d9a7c4a2a9e31 | |
parent | 644d8287015a0be315a49863b005f1237c280d6b (diff) | |
download | tpm_manager-42987bddf07f1efaa78ffa883254d8ee03cb7901.tar.gz |
tpm_manager: Add an implementation for TpmNvram for Tpm1.2
This CL implements the TpmNvram interface for Tpm1.2. A lot of
the implementation is adapted from tpm_impl.cc in cryptohome.
Bug: 24059574
TEST=ran nvram methods on an owned tpm1.2
Change-Id: Ica3490cff76bb087d8d26f59440ca150b6c9833d
-rw-r--r-- | server/main.cc | 2 | ||||
-rw-r--r-- | server/tpm_nvram_impl.cc | 353 | ||||
-rw-r--r-- | server/tpm_nvram_impl.h | 77 | ||||
-rw-r--r-- | tpm_manager.gyp | 5 |
4 files changed, 435 insertions, 2 deletions
diff --git a/server/main.cc b/server/main.cc index ce87bc0..300629c 100644 --- a/server/main.cc +++ b/server/main.cc @@ -34,6 +34,7 @@ #include "tpm_manager/server/tpm2_status_impl.h" #else #include "tpm_manager/server/tpm_initializer_impl.h" +#include "tpm_manager/server/tpm_nvram_impl.h" #include "tpm_manager/server/tpm_status_impl.h" #endif @@ -59,6 +60,7 @@ class TpmManagerDaemon : public chromeos::DBusServiceDaemon { tpm_initializer_.reset(new tpm_manager::TpmInitializerImpl( local_data_store_.get(), tpm_status_.get())); + tpm_nvram_.reset(new tpm_manager::TpmNvramImpl(local_data_store_.get())); #endif tpm_manager_service_.reset(new tpm_manager::TpmManagerService( command_line->HasSwitch(kWaitForOwnershipTriggerSwitch), diff --git a/server/tpm_nvram_impl.cc b/server/tpm_nvram_impl.cc new file mode 100644 index 0000000..598959a --- /dev/null +++ b/server/tpm_nvram_impl.cc @@ -0,0 +1,353 @@ +// +// 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/tpm_nvram_impl.h" + +#include <arpa/inet.h> + +#include <string> + +#include <base/logging.h> +#include <base/stl_util.h> +#include <trousers/scoped_tss_type.h> + +#include "tpm_manager/common/local_data.pb.h" +#include "tpm_manager/server/local_data_store.h" +#include "tpm_manager/server/tpm_util.h" + +namespace { + +// PCR0 at locality 1 is used to differentiate between developed and normal +// mode. Restricting nvram to the PCR0 value in locality 1 prevents nvram from +// persisting across mode switch. +const unsigned int kTpmBootPCR = 0; +const unsigned int kTpmPCRLocality = 1; + +} // namespace + +namespace tpm_manager { + +using trousers::ScopedTssMemory; +using trousers::ScopedTssNvStore; +using trousers::ScopedTssPcrs; + +TpmNvramImpl::TpmNvramImpl(LocalDataStore* local_data_store) + : local_data_store_(local_data_store) {} + +bool TpmNvramImpl::DefineNvram(uint32_t index, size_t length) { + ScopedTssNvStore nv_handle(tpm_connection_.GetContext()); + if (!(InitializeNvramHandle(&nv_handle, index) && + SetOwnerPolicy(&nv_handle))) { + return false; + } + TSS_RESULT result; + result = Tspi_SetAttribUint32(nv_handle, TSS_TSPATTRIB_NV_DATASIZE, + 0, length); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not set size on NVRAM object: " << length; + return false; + } + // Restrict to only one write. + result = Tspi_SetAttribUint32(nv_handle, TSS_TSPATTRIB_NV_PERMISSIONS, + 0, TPM_NV_PER_WRITEDEFINE); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not set PER_WRITEDEFINE on NVRAM object"; + return false; + } + // Restrict to writing only with owner authorization. + result = Tspi_SetAttribUint32(nv_handle, TSS_TSPATTRIB_NV_PERMISSIONS, + 0, TPM_NV_PER_OWNERWRITE); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not set PER_OWNERWRITE on NVRAM object"; + return false; + } + ScopedTssPcrs pcr_handle(tpm_connection_.GetContext()); + if (!SetCompositePcr0(&pcr_handle)) { + return false; + } + result = Tspi_NV_DefineSpace(nv_handle, + pcr_handle /* ReadPCRs restricted to PCR0 */, + pcr_handle /* WritePCRs restricted to PCR0 */); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not define NVRAM space: " << index; + return false; + } + return true; +} + +bool TpmNvramImpl::DestroyNvram(uint32_t index) { + bool defined; + if (!IsNvramDefined(index, &defined)) { + return false; + } + if (!defined) { + // If the nvram space is not defined, we don't need to destroy it. + return true; + } + ScopedTssNvStore nv_handle(tpm_connection_.GetContext()); + if (!(InitializeNvramHandle(&nv_handle, index) && + SetOwnerPolicy(&nv_handle))) { + return false; + } + TSS_RESULT result = Tspi_NV_ReleaseSpace(nv_handle); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not release NVRAM space: " << index; + return false; + } + return true; +} + +bool TpmNvramImpl::WriteNvram(uint32_t index, const std::string& data) { + ScopedTssNvStore nv_handle(tpm_connection_.GetContext()); + if (!(InitializeNvramHandle(&nv_handle, index) && + SetOwnerPolicy(&nv_handle))) { + return false; + } + TSS_RESULT result = Tspi_NV_WriteValue( + nv_handle, 0 /* offset */, data.size(), + reinterpret_cast<BYTE *>(const_cast<char*>(data.data()))); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not write to NVRAM space: " << index; + return false; + } + return true; +} + +bool TpmNvramImpl::ReadNvram(uint32_t index, std::string* data) { + CHECK(data); + TSS_RESULT result; + ScopedTssNvStore nv_handle(tpm_connection_.GetContext()); + if (!InitializeNvramHandle(&nv_handle, index)) { + return false; + } + size_t nvram_size; + if (!GetNvramSize(index, &nvram_size)) { + return false; + } + data->resize(nvram_size); + // The Tpm1.2 Specification defines the maximum read size of 128 bytes. + // Therefore we have to loop through the data returned. + const size_t kMaxDataSize = 128; + uint32_t offset = 0; + while (offset < nvram_size) { + uint32_t chunk_size = std::max(nvram_size - offset, kMaxDataSize); + ScopedTssMemory space_data(tpm_connection_.GetContext()); + if ((result = Tspi_NV_ReadValue(nv_handle, offset, &chunk_size, + space_data.ptr()))) { + TPM_LOG(ERROR, result) << "Could not read from NVRAM space: " << index; + return false; + } + if (!space_data.value()) { + LOG(ERROR) << "No data read from NVRAM space: " << index; + return false; + } + CHECK_LE((offset + chunk_size), data->size()); + data->replace(offset, + chunk_size, + reinterpret_cast<char*>(space_data.value()), + chunk_size); + offset += chunk_size; + } + return true; +} + +bool TpmNvramImpl::IsNvramDefined(uint32_t index, bool* defined) { + CHECK(defined); + uint32_t nv_list_data_length = 0; + ScopedTssMemory nv_list_data(tpm_connection_.GetContext()); + TSS_RESULT result = Tspi_TPM_GetCapability(tpm_connection_.GetTpm(), + TSS_TPMCAP_NV_LIST, + 0, + NULL, + &nv_list_data_length, + nv_list_data.ptr()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability"; + return false; + } + // Walk the list and check if the index exists. + uint32_t* nv_list = reinterpret_cast<uint32_t*>(nv_list_data.value()); + uint32_t nv_list_length = nv_list_data_length / sizeof(uint32_t); + index = htonl(index); // TPM data is network byte order. + for (uint32_t i = 0; i < nv_list_length; ++i) { + if (index == nv_list[i]) { + *defined = true; + return true; + } + } + *defined = false; + return true; +} + +bool TpmNvramImpl::IsNvramLocked(uint32_t index, bool* locked) { + CHECK(locked); + uint32_t nv_index_data_length = 0; + ScopedTssMemory nv_index_data(tpm_connection_.GetContext()); + TSS_RESULT result = Tspi_TPM_GetCapability(tpm_connection_.GetTpm(), + TSS_TPMCAP_NV_INDEX, + sizeof(index), + reinterpret_cast<BYTE*>(&index), + &nv_index_data_length, + nv_index_data.ptr()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability"; + return false; + } + if (nv_index_data_length < (sizeof(uint32_t) + sizeof(TPM_BOOL))) { + return false; + } + // TPM_NV_DATA_PUBLIC->bWriteDefine is the second to last element in the + // struct. + uint32_t* nv_data_public = reinterpret_cast<uint32_t*>( + nv_index_data.value() + nv_index_data_length - + (sizeof(uint32_t) + sizeof(TPM_BOOL))); + *locked = (*nv_data_public != 0); + return true; +} + +bool TpmNvramImpl::GetNvramSize(uint32_t index, size_t* size) { + CHECK(size); + UINT32 nv_index_data_length = 0; + ScopedTssMemory nv_index_data(tpm_connection_.GetContext()); + TSS_RESULT result = Tspi_TPM_GetCapability(tpm_connection_.GetTpm(), + TSS_TPMCAP_NV_INDEX, + sizeof(index), + reinterpret_cast<BYTE*>(&index), + &nv_index_data_length, + nv_index_data.ptr()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability"; + return false; + } + if (nv_index_data_length < sizeof(uint32_t)) { + return false; + } + // TPM_NV_DATA_PUBLIC->dataSize is the last element in the struct. + uint32_t* nv_data_public = reinterpret_cast<uint32_t*>( + nv_index_data.value() + nv_index_data_length - + sizeof(uint32_t)); + *size = htonl(*nv_data_public); + return true; +} + +bool TpmNvramImpl::InitializeNvramHandle(ScopedTssNvStore* nv_handle, + uint32_t index) { + + TSS_RESULT result = Tspi_Context_CreateObject(tpm_connection_.GetContext(), + TSS_OBJECT_TYPE_NV, + 0, + nv_handle->ptr()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not acquire an NVRAM object handle"; + return false; + } + result = Tspi_SetAttribUint32( + nv_handle->value(), TSS_TSPATTRIB_NV_INDEX, 0, index); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not set index on NVRAM object: " << index; + return false; + } + return true; +} + +bool TpmNvramImpl::SetOwnerPolicy(ScopedTssNvStore* nv_handle) { + trousers::ScopedTssPolicy policy_handle(tpm_connection_.GetContext()); + TSS_RESULT result; + result = Tspi_Context_CreateObject(tpm_connection_.GetContext(), + TSS_OBJECT_TYPE_POLICY, + TSS_POLICY_USAGE, + policy_handle.ptr()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; + return false; + } + std::string owner_password; + if (!GetOwnerPassword(&owner_password)) { + return false; + } + result = Tspi_Policy_SetSecret( + policy_handle, + TSS_SECRET_MODE_PLAIN, + owner_password.size(), + reinterpret_cast<BYTE *>(const_cast<char*>(owner_password.data()))); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; + return false; + } + result = Tspi_Policy_AssignToObject(policy_handle.value(), + nv_handle->value()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not set NVRAM object policy."; + return false; + } + return true; +} + +bool TpmNvramImpl::SetCompositePcr0(ScopedTssPcrs* pcr_handle) { + TSS_RESULT result = Tspi_Context_CreateObject(tpm_connection_.GetContext(), + TSS_OBJECT_TYPE_PCRS, + TSS_PCRS_STRUCT_INFO_SHORT, + pcr_handle->ptr()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not acquire PCR object handle"; + return false; + } + uint32_t pcr_len; + std::string owner_password; + if (!GetOwnerPassword(&owner_password)) { + return false; + } + ScopedTssMemory pcr_value(tpm_connection_.GetContext()); + result = Tspi_TPM_PcrRead(tpm_connection_.GetTpmWithAuth(owner_password), + kTpmBootPCR, + &pcr_len, + pcr_value.ptr()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not read PCR0 value"; + return false; + } + result = Tspi_PcrComposite_SetPcrValue(pcr_handle->value(), + kTpmBootPCR, + pcr_len, + pcr_value.value()); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not set value for PCR0 in PCR handle"; + return false; + } + result = Tspi_PcrComposite_SetPcrLocality(pcr_handle->value(), + kTpmPCRLocality); + if (TPM_ERROR(result)) { + TPM_LOG(ERROR, result) << "Could not set locality for PCR0 in PCR handle"; + return false; + } + return true; +} + +bool TpmNvramImpl::GetOwnerPassword(std::string* owner_password) { + LocalData local_data; + if (!local_data_store_->Read(&local_data)) { + LOG(ERROR) << "Error reading local data for owner password."; + return false; + } + if (local_data.owner_password().empty()) { + LOG(ERROR) << "No owner password present in tpm local_data."; + return false; + } + owner_password->assign(local_data.owner_password()); + return true; +} + +} // namespace tpm_manager diff --git a/server/tpm_nvram_impl.h b/server/tpm_nvram_impl.h new file mode 100644 index 0000000..ebe379b --- /dev/null +++ b/server/tpm_nvram_impl.h @@ -0,0 +1,77 @@ +// +// 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. +// + +#ifndef TPM_MANAGER_SERVER_TPM_NVRAM_IMPL_H_ +#define TPM_MANAGER_SERVER_TPM_NVRAM_IMPL_H_ + +#include "tpm_manager/server/tpm_nvram.h" + +#include <stdint.h> + +#include <string> + +#include <base/macros.h> +#include <trousers/scoped_tss_type.h> +#include <trousers/tss.h> + +#include "tpm_manager/server/tpm_connection.h" + +namespace tpm_manager { + +class LocalDataStore; + +class TpmNvramImpl : public TpmNvram { + public: + TpmNvramImpl(LocalDataStore* local_data_store); + ~TpmNvramImpl() override = default; + + // TpmNvram methods. + bool DefineNvram(uint32_t index, size_t length) override; + bool DestroyNvram(uint32_t index) override; + bool WriteNvram(uint32_t index, const std::string& data) override; + bool ReadNvram(uint32_t index, std::string* data) override; + bool IsNvramDefined(uint32_t index, bool* defined) override; + bool IsNvramLocked(uint32_t index, bool* locked) override; + bool GetNvramSize(uint32_t index, size_t* size) override; + + private: + // This method creates and initializes the nvram object associated with + // |handle| at |index|. Returns true on success, else false. + bool InitializeNvramHandle(trousers::ScopedTssNvStore* nv_handle, + uint32_t index); + + // This method injects a tpm policy with the owner password. Returns true + // on success. + bool SetOwnerPolicy(trousers::ScopedTssNvStore* nv_handle); + + // This method sets up the composite pcr provided by |pcr_handle| with the + // value of PCR0 at locality 1. Returns true on success. + bool SetCompositePcr0(trousers::ScopedTssPcrs* pcr_handle); + + // This method gets the owner password stored on disk and returns it via the + // out argument |owner_password|. Returns true if we were able to read a + // non empty owner_password off disk, else false. + bool GetOwnerPassword(std::string* owner_password); + + LocalDataStore* local_data_store_; + TpmConnection tpm_connection_; + + DISALLOW_COPY_AND_ASSIGN(TpmNvramImpl); +}; + +} // namespace tpm_manager + +#endif // TPM_MANAGER_SERVER_TPM_NVRAM_IMPL_H_ diff --git a/tpm_manager.gyp b/tpm_manager.gyp index 01f715f..c10d8a8 100644 --- a/tpm_manager.gyp +++ b/tpm_manager.gyp @@ -85,8 +85,8 @@ 'conditions': [ ['USE_tpm2 == 1', { 'sources': [ - 'server/tpm2_status_impl.cc', 'server/tpm2_initializer_impl.cc', + 'server/tpm2_status_impl.cc', ], 'all_dependent_settings': { 'libraries': [ @@ -97,8 +97,9 @@ ['USE_tpm2 == 0', { 'sources': [ 'server/tpm_connection.cc', - 'server/tpm_status_impl.cc', 'server/tpm_initializer_impl.cc', + 'server/tpm_nvram_impl.cc', + 'server/tpm_status_impl.cc', ], 'all_dependent_settings': { 'libraries': [ |