1//
2// Copyright (C) 2015 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "tpm_manager/server/tpm2_nvram_impl.h"
18
19#include <memory>
20#include <string>
21
22#include <base/logging.h>
23#include <trunks/error_codes.h>
24#include <trunks/tpm_constants.h>
25#include <trunks/tpm_utility.h>
26#include <trunks/trunks_factory_impl.h>
27
28namespace tpm_manager {
29
30using trunks::GetErrorString;
31using trunks::TPM_RC;
32using trunks::TPM_RC_SUCCESS;
33
34Tpm2NvramImpl::Tpm2NvramImpl(LocalDataStore* local_data_store)
35    : trunks_factory_(new trunks::TrunksFactoryImpl()),
36      local_data_store_(local_data_store),
37      initialized_(false),
38      trunks_session_(trunks_factory_->GetHmacSession()),
39      trunks_utility_(trunks_factory_->GetTpmUtility()) {}
40
41Tpm2NvramImpl::Tpm2NvramImpl(std::unique_ptr<trunks::TrunksFactory> factory,
42                             LocalDataStore* local_data_store)
43    : trunks_factory_(std::move(factory)),
44      local_data_store_(local_data_store),
45      initialized_(false),
46      trunks_session_(trunks_factory_->GetHmacSession()),
47      trunks_utility_(trunks_factory_->GetTpmUtility()) {}
48
49bool Tpm2NvramImpl::Initialize() {
50  if (initialized_) {
51    return true;
52  }
53  TPM_RC result = trunks_utility_->StartSession(trunks_session_.get());
54  if (result != TPM_RC_SUCCESS) {
55    LOG(ERROR) << "Error starting an authorization session with trunks: "
56               << GetErrorString(result);
57    return false;
58  }
59  LocalData local_data;
60  if (!local_data_store_->Read(&local_data)) {
61    LOG(ERROR) << "Error reading local tpm data.";
62    return false;
63  }
64  if (!local_data.owner_password().empty()) {
65    owner_password_.assign(local_data.owner_password());
66    initialized_ = true;
67  }
68  return true;
69}
70
71bool Tpm2NvramImpl::InitializeWithOwnerPassword() {
72  if (!Initialize()) {
73    return false;
74  }
75  if (owner_password_.empty()) {
76    LOG(ERROR) << "Error owner password not available.";
77    return false;
78  }
79  trunks_session_->SetEntityAuthorizationValue(owner_password_);
80  return true;
81}
82
83bool Tpm2NvramImpl::DefineNvram(uint32_t index, size_t length) {
84  if (!InitializeWithOwnerPassword()) {
85    return false;
86  }
87  TPM_RC result = trunks_utility_->DefineNVSpace(
88      index, length, trunks_session_->GetDelegate());
89  if (result != TPM_RC_SUCCESS) {
90    LOG(ERROR) << "Error defining nvram space: " << GetErrorString(result);
91    return false;
92  }
93  return true;
94}
95
96bool Tpm2NvramImpl::DestroyNvram(uint32_t index) {
97  if (!InitializeWithOwnerPassword()) {
98    return false;
99  }
100  TPM_RC result = trunks_utility_->DestroyNVSpace(
101      index, trunks_session_->GetDelegate());
102  if (result != TPM_RC_SUCCESS) {
103    LOG(ERROR) << "Error destroying nvram space:" << GetErrorString(result);
104    return false;
105  }
106  return true;
107}
108
109bool Tpm2NvramImpl::WriteNvram(uint32_t index, const std::string& data) {
110  if (!InitializeWithOwnerPassword()) {
111    return false;
112  }
113  TPM_RC result = trunks_utility_->WriteNVSpace(index,
114                                                0,  // offset
115                                                data,
116                                                trunks_session_->GetDelegate());
117  if (result != TPM_RC_SUCCESS) {
118    LOG(ERROR) << "Error writing to nvram space: " << GetErrorString(result);
119    return false;
120  }
121  result = trunks_utility_->LockNVSpace(index, trunks_session_->GetDelegate());
122  if (result != TPM_RC_SUCCESS) {
123    LOG(ERROR) << "Error locking nvram space: " << GetErrorString(result);
124    return false;
125  }
126  return true;
127}
128
129bool Tpm2NvramImpl::ReadNvram(uint32_t index, std::string* data) {
130  if (!Initialize()) {
131    return false;
132  }
133  size_t nvram_size;
134  if (!GetNvramSize(index, &nvram_size)) {
135    LOG(ERROR) << "Error getting size of nvram space.";
136    return false;
137  }
138  trunks_session_->SetEntityAuthorizationValue("");
139  TPM_RC result = trunks_utility_->ReadNVSpace(index,
140                                               0,  // offset
141                                               nvram_size,
142                                               data,
143                                               trunks_session_->GetDelegate());
144  if (result != TPM_RC_SUCCESS) {
145    LOG(ERROR) << "Error reading nvram space: " << GetErrorString(result);
146    return false;
147  }
148  return true;
149}
150
151bool Tpm2NvramImpl::IsNvramDefined(uint32_t index, bool* defined) {
152  trunks::TPMS_NV_PUBLIC nvram_public;
153  TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public);
154  if (trunks::GetFormatOneError(result) == trunks::TPM_RC_HANDLE) {
155    *defined = false;
156  } else if (result == TPM_RC_SUCCESS) {
157    *defined = true;
158  } else {
159    LOG(ERROR) << "Error reading NV space for index " << index
160               << " with error: " << GetErrorString(result);
161    return false;
162  }
163  return true;
164}
165
166bool Tpm2NvramImpl::IsNvramLocked(uint32_t index, bool* locked) {
167  trunks::TPMS_NV_PUBLIC nvram_public;
168  TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public);
169  if (result != TPM_RC_SUCCESS) {
170    LOG(ERROR) << "Error reading NV space for index " << index
171               << " with error: " << GetErrorString(result);
172    return false;
173  }
174  *locked = ((nvram_public.attributes & trunks::TPMA_NV_WRITELOCKED) != 0);
175  return true;
176}
177
178bool Tpm2NvramImpl::GetNvramSize(uint32_t index, size_t* size) {
179  trunks::TPMS_NV_PUBLIC nvram_public;
180  TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public);
181  if (result != TPM_RC_SUCCESS) {
182    LOG(ERROR) << "Error reading NV space for index " << index
183               << " with error: " << GetErrorString(result);
184    return false;
185  }
186  *size = nvram_public.data_size;
187  return true;
188}
189
190}  // namespace tpm_manager
191