//
// 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/tpm_constants.h>
#include <trunks/tpm_utility.h>
#include <trunks/trunks_factory_impl.h>
namespace tpm_manager {
using trunks::GetErrorString;
using trunks::TPM_RC;
using trunks::TPM_RC_SUCCESS;
Tpm2NvramImpl::Tpm2NvramImpl(LocalDataStore* local_data_store)
: trunks_factory_(new trunks::TrunksFactoryImpl()),
local_data_store_(local_data_store),
initialized_(false),
trunks_session_(trunks_factory_->GetHmacSession()),
trunks_utility_(trunks_factory_->GetTpmUtility()) {}
Tpm2NvramImpl::Tpm2NvramImpl(std::unique_ptr<trunks::TrunksFactory> factory,
LocalDataStore* local_data_store)
: trunks_factory_(std::move(factory)),
local_data_store_(local_data_store),
initialized_(false),
trunks_session_(trunks_factory_->GetHmacSession()),
trunks_utility_(trunks_factory_->GetTpmUtility()) {}
bool Tpm2NvramImpl::Initialize() {
if (initialized_) {
return true;
}
TPM_RC result = trunks_utility_->StartSession(trunks_session_.get());
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error starting an authorization session with trunks: "
<< GetErrorString(result);
return false;
}
LocalData local_data;
if (!local_data_store_->Read(&local_data)) {
LOG(ERROR) << "Error reading local tpm data.";
return false;
}
if (!local_data.owner_password().empty()) {
owner_password_.assign(local_data.owner_password());
initialized_ = true;
}
return true;
}
bool Tpm2NvramImpl::InitializeWithOwnerPassword() {
if (!Initialize()) {
return false;
}
if (owner_password_.empty()) {
LOG(ERROR) << "Error owner password not available.";
return false;
}
trunks_session_->SetEntityAuthorizationValue(owner_password_);
return true;
}
bool Tpm2NvramImpl::DefineNvram(uint32_t index, size_t length) {
if (!InitializeWithOwnerPassword()) {
return false;
}
TPM_RC result = trunks_utility_->DefineNVSpace(
index, length, trunks_session_->GetDelegate());
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error defining nvram space: " << GetErrorString(result);
return false;
}
return true;
}
bool Tpm2NvramImpl::DestroyNvram(uint32_t index) {
if (!InitializeWithOwnerPassword()) {
return false;
}
TPM_RC result = trunks_utility_->DestroyNVSpace(
index, trunks_session_->GetDelegate());
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error destroying nvram space:" << GetErrorString(result);
return false;
}
return true;
}
bool Tpm2NvramImpl::WriteNvram(uint32_t index, const std::string& data) {
if (!InitializeWithOwnerPassword()) {
return false;
}
TPM_RC result = trunks_utility_->WriteNVSpace(index,
0, // offset
data,
trunks_session_->GetDelegate());
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error writing to nvram space: " << GetErrorString(result);
return false;
}
result = trunks_utility_->LockNVSpace(index, trunks_session_->GetDelegate());
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error locking nvram space: " << GetErrorString(result);
return false;
}
return true;
}
bool Tpm2NvramImpl::ReadNvram(uint32_t index, std::string* data) {
if (!Initialize()) {
return false;
}
size_t nvram_size;
if (!GetNvramSize(index, &nvram_size)) {
LOG(ERROR) << "Error getting size of nvram space.";
return false;
}
trunks_session_->SetEntityAuthorizationValue("");
TPM_RC result = trunks_utility_->ReadNVSpace(index,
0, // offset
nvram_size,
data,
trunks_session_->GetDelegate());
if (result != TPM_RC_SUCCESS) {
LOG(ERROR) << "Error reading nvram space: " << GetErrorString(result);
return false;
}
return true;
}
bool Tpm2NvramImpl::IsNvramDefined(uint32_t index, bool* defined) {
trunks::TPMS_NV_PUBLIC nvram_public;
TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public);
if (trunks::GetFormatOneError(result) == trunks::TPM_RC_HANDLE) {
*defined = false;
} else if (result == TPM_RC_SUCCESS) {
*defined = true;
} else {
LOG(ERROR) << "Error reading NV space for index " << index
<< " with error: " << GetErrorString(result);
return false;
}
return true;
}
bool Tpm2NvramImpl::IsNvramLocked(uint32_t index, bool* locked) {
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 false;
}
*locked = ((nvram_public.attributes & trunks::TPMA_NV_WRITELOCKED) != 0);
return true;
}
bool Tpm2NvramImpl::GetNvramSize(uint32_t index, size_t* size) {
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 false;
}
*size = nvram_public.data_size;
return true;
}
} // namespace tpm_manager