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/tpm_nvram_impl.h"
18
19#include <arpa/inet.h>
20
21#include <string>
22
23#include <base/logging.h>
24#include <base/stl_util.h>
25#include <trousers/scoped_tss_type.h>
26
27#include "tpm_manager/common/local_data.pb.h"
28#include "tpm_manager/server/local_data_store.h"
29#include "tpm_manager/server/tpm_util.h"
30
31namespace {
32
33// PCR0 at locality 1 is used to differentiate between developed and normal
34// mode. Restricting nvram to the PCR0 value in locality 1 prevents nvram from
35// persisting across mode switch.
36const unsigned int kTpmBootPCR = 0;
37const unsigned int kTpmPCRLocality = 1;
38
39}  // namespace
40
41namespace tpm_manager {
42
43using trousers::ScopedTssMemory;
44using trousers::ScopedTssNvStore;
45using trousers::ScopedTssPcrs;
46
47TpmNvramImpl::TpmNvramImpl(LocalDataStore* local_data_store)
48    : local_data_store_(local_data_store) {}
49
50bool TpmNvramImpl::DefineNvram(uint32_t index, size_t length) {
51  ScopedTssNvStore nv_handle(tpm_connection_.GetContext());
52  if (!(InitializeNvramHandle(&nv_handle, index) &&
53        SetOwnerPolicy(&nv_handle))) {
54    return false;
55  }
56  TSS_RESULT result;
57  result = Tspi_SetAttribUint32(nv_handle, TSS_TSPATTRIB_NV_DATASIZE,
58                                0, length);
59  if (TPM_ERROR(result)) {
60    TPM_LOG(ERROR, result) << "Could not set size on NVRAM object: " << length;
61    return false;
62  }
63  // Restrict to only one write.
64  result = Tspi_SetAttribUint32(nv_handle, TSS_TSPATTRIB_NV_PERMISSIONS,
65                                0, TPM_NV_PER_WRITEDEFINE);
66  if (TPM_ERROR(result)) {
67    TPM_LOG(ERROR, result) << "Could not set PER_WRITEDEFINE on NVRAM object";
68    return false;
69  }
70  // Restrict to writing only with owner authorization.
71  result = Tspi_SetAttribUint32(nv_handle, TSS_TSPATTRIB_NV_PERMISSIONS,
72                                0, TPM_NV_PER_OWNERWRITE);
73  if (TPM_ERROR(result)) {
74    TPM_LOG(ERROR, result) << "Could not set PER_OWNERWRITE on NVRAM object";
75    return false;
76  }
77  ScopedTssPcrs pcr_handle(tpm_connection_.GetContext());
78  if (!SetCompositePcr0(&pcr_handle)) {
79    return false;
80  }
81  result = Tspi_NV_DefineSpace(nv_handle,
82                               pcr_handle /* ReadPCRs restricted to PCR0 */,
83                               pcr_handle /* WritePCRs restricted to PCR0 */);
84  if (TPM_ERROR(result)) {
85    TPM_LOG(ERROR, result) << "Could not define NVRAM space: " << index;
86    return false;
87  }
88  return true;
89}
90
91bool TpmNvramImpl::DestroyNvram(uint32_t index) {
92  bool defined;
93  if (!IsNvramDefined(index, &defined)) {
94    return false;
95  }
96  if (!defined) {
97    // If the nvram space is not defined, we don't need to destroy it.
98    return true;
99  }
100  ScopedTssNvStore nv_handle(tpm_connection_.GetContext());
101  if (!(InitializeNvramHandle(&nv_handle, index) &&
102        SetOwnerPolicy(&nv_handle))) {
103    return false;
104  }
105  TSS_RESULT result = Tspi_NV_ReleaseSpace(nv_handle);
106  if (TPM_ERROR(result)) {
107    TPM_LOG(ERROR, result) << "Could not release NVRAM space: " << index;
108    return false;
109  }
110  return true;
111}
112
113bool TpmNvramImpl::WriteNvram(uint32_t index, const std::string& data) {
114  ScopedTssNvStore nv_handle(tpm_connection_.GetContext());
115  if (!(InitializeNvramHandle(&nv_handle, index) &&
116        SetOwnerPolicy(&nv_handle))) {
117    return false;
118  }
119  TSS_RESULT result = Tspi_NV_WriteValue(
120      nv_handle, 0 /* offset */, data.size(),
121      reinterpret_cast<BYTE *>(const_cast<char*>(data.data())));
122  if (TPM_ERROR(result)) {
123    TPM_LOG(ERROR, result) << "Could not write to NVRAM space: " << index;
124    return false;
125  }
126  return true;
127}
128
129bool TpmNvramImpl::ReadNvram(uint32_t index, std::string* data) {
130  CHECK(data);
131  TSS_RESULT result;
132  ScopedTssNvStore nv_handle(tpm_connection_.GetContext());
133  if (!InitializeNvramHandle(&nv_handle, index)) {
134    return false;
135  }
136  size_t nvram_size;
137  if (!GetNvramSize(index, &nvram_size)) {
138    return false;
139  }
140  data->resize(nvram_size);
141  // The Tpm1.2 Specification defines the maximum read size of 128 bytes.
142  // Therefore we have to loop through the data returned.
143  const size_t kMaxDataSize = 128;
144  uint32_t offset = 0;
145  while (offset < nvram_size) {
146    uint32_t chunk_size = std::max(nvram_size - offset, kMaxDataSize);
147    ScopedTssMemory space_data(tpm_connection_.GetContext());
148    if ((result = Tspi_NV_ReadValue(nv_handle, offset, &chunk_size,
149                                    space_data.ptr()))) {
150      TPM_LOG(ERROR, result) << "Could not read from NVRAM space: " << index;
151      return false;
152    }
153    if (!space_data.value()) {
154      LOG(ERROR) << "No data read from NVRAM space: " << index;
155      return false;
156    }
157    CHECK_LE((offset + chunk_size), data->size());
158    data->replace(offset,
159                  chunk_size,
160                  reinterpret_cast<char*>(space_data.value()),
161                  chunk_size);
162    offset += chunk_size;
163  }
164  return true;
165}
166
167bool TpmNvramImpl::IsNvramDefined(uint32_t index, bool* defined) {
168  CHECK(defined);
169  uint32_t nv_list_data_length = 0;
170  ScopedTssMemory nv_list_data(tpm_connection_.GetContext());
171  TSS_RESULT result = Tspi_TPM_GetCapability(tpm_connection_.GetTpm(),
172                                             TSS_TPMCAP_NV_LIST,
173                                             0,
174                                             NULL,
175                                             &nv_list_data_length,
176                                             nv_list_data.ptr());
177  if (TPM_ERROR(result)) {
178    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability";
179    return false;
180  }
181  // Walk the list and check if the index exists.
182  uint32_t* nv_list = reinterpret_cast<uint32_t*>(nv_list_data.value());
183  uint32_t nv_list_length = nv_list_data_length / sizeof(uint32_t);
184  index = htonl(index);  // TPM data is network byte order.
185  for (uint32_t i = 0; i < nv_list_length; ++i) {
186    if (index == nv_list[i]) {
187      *defined = true;
188      return true;
189    }
190  }
191  *defined = false;
192  return true;
193}
194
195bool TpmNvramImpl::IsNvramLocked(uint32_t index, bool* locked) {
196  CHECK(locked);
197  uint32_t nv_index_data_length = 0;
198  ScopedTssMemory nv_index_data(tpm_connection_.GetContext());
199  TSS_RESULT result = Tspi_TPM_GetCapability(tpm_connection_.GetTpm(),
200                                             TSS_TPMCAP_NV_INDEX,
201                                             sizeof(index),
202                                             reinterpret_cast<BYTE*>(&index),
203                                             &nv_index_data_length,
204                                             nv_index_data.ptr());
205  if (TPM_ERROR(result)) {
206    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability";
207    return false;
208  }
209  if (nv_index_data_length < (sizeof(uint32_t) + sizeof(TPM_BOOL))) {
210    return false;
211  }
212  // TPM_NV_DATA_PUBLIC->bWriteDefine is the second to last element in the
213  // struct.
214  uint32_t* nv_data_public = reinterpret_cast<uint32_t*>(
215                               nv_index_data.value() + nv_index_data_length -
216                               (sizeof(uint32_t) + sizeof(TPM_BOOL)));
217  *locked = (*nv_data_public != 0);
218  return true;
219}
220
221bool TpmNvramImpl::GetNvramSize(uint32_t index, size_t* size) {
222  CHECK(size);
223  UINT32 nv_index_data_length = 0;
224  ScopedTssMemory nv_index_data(tpm_connection_.GetContext());
225  TSS_RESULT result = Tspi_TPM_GetCapability(tpm_connection_.GetTpm(),
226                                             TSS_TPMCAP_NV_INDEX,
227                                             sizeof(index),
228                                             reinterpret_cast<BYTE*>(&index),
229                                             &nv_index_data_length,
230                                             nv_index_data.ptr());
231  if (TPM_ERROR(result)) {
232    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability";
233    return false;
234  }
235  if (nv_index_data_length < sizeof(uint32_t)) {
236    return false;
237  }
238  // TPM_NV_DATA_PUBLIC->dataSize is the last element in the struct.
239  uint32_t* nv_data_public = reinterpret_cast<uint32_t*>(
240                               nv_index_data.value() + nv_index_data_length -
241                               sizeof(uint32_t));
242  *size = htonl(*nv_data_public);
243  return true;
244}
245
246bool TpmNvramImpl::InitializeNvramHandle(ScopedTssNvStore* nv_handle,
247                                         uint32_t index) {
248
249  TSS_RESULT result = Tspi_Context_CreateObject(tpm_connection_.GetContext(),
250                                                TSS_OBJECT_TYPE_NV,
251                                                0,
252                                                nv_handle->ptr());
253  if (TPM_ERROR(result)) {
254    TPM_LOG(ERROR, result) << "Could not acquire an NVRAM object handle";
255    return false;
256  }
257  result = Tspi_SetAttribUint32(
258      nv_handle->value(), TSS_TSPATTRIB_NV_INDEX, 0, index);
259  if (TPM_ERROR(result)) {
260    TPM_LOG(ERROR, result) << "Could not set index on NVRAM object: " << index;
261    return false;
262  }
263  return true;
264}
265
266bool TpmNvramImpl::SetOwnerPolicy(ScopedTssNvStore* nv_handle) {
267  trousers::ScopedTssPolicy policy_handle(tpm_connection_.GetContext());
268  TSS_RESULT result;
269  result = Tspi_Context_CreateObject(tpm_connection_.GetContext(),
270                                     TSS_OBJECT_TYPE_POLICY,
271                                     TSS_POLICY_USAGE,
272                                     policy_handle.ptr());
273  if (TPM_ERROR(result)) {
274    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
275    return false;
276  }
277  std::string owner_password;
278  if (!GetOwnerPassword(&owner_password)) {
279    return false;
280  }
281  result = Tspi_Policy_SetSecret(
282      policy_handle,
283      TSS_SECRET_MODE_PLAIN,
284      owner_password.size(),
285      reinterpret_cast<BYTE *>(const_cast<char*>(owner_password.data())));
286  if (TPM_ERROR(result)) {
287    TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
288    return false;
289  }
290  result = Tspi_Policy_AssignToObject(policy_handle.value(),
291                                      nv_handle->value());
292  if (TPM_ERROR(result)) {
293    TPM_LOG(ERROR, result) << "Could not set NVRAM object policy.";
294    return false;
295  }
296  return true;
297}
298
299bool TpmNvramImpl::SetCompositePcr0(ScopedTssPcrs* pcr_handle) {
300  TSS_RESULT result = Tspi_Context_CreateObject(tpm_connection_.GetContext(),
301                                                TSS_OBJECT_TYPE_PCRS,
302                                                TSS_PCRS_STRUCT_INFO_SHORT,
303                                                pcr_handle->ptr());
304  if (TPM_ERROR(result)) {
305    TPM_LOG(ERROR, result) << "Could not acquire PCR object handle";
306    return false;
307  }
308  uint32_t pcr_len;
309  std::string owner_password;
310  if (!GetOwnerPassword(&owner_password)) {
311    return false;
312  }
313  ScopedTssMemory pcr_value(tpm_connection_.GetContext());
314  result = Tspi_TPM_PcrRead(tpm_connection_.GetTpmWithAuth(owner_password),
315                            kTpmBootPCR,
316                            &pcr_len,
317                            pcr_value.ptr());
318  if (TPM_ERROR(result)) {
319    TPM_LOG(ERROR, result) << "Could not read PCR0 value";
320    return false;
321  }
322  result = Tspi_PcrComposite_SetPcrValue(pcr_handle->value(),
323                                         kTpmBootPCR,
324                                         pcr_len,
325                                         pcr_value.value());
326  if (TPM_ERROR(result)) {
327    TPM_LOG(ERROR, result) << "Could not set value for PCR0 in PCR handle";
328    return false;
329  }
330  result = Tspi_PcrComposite_SetPcrLocality(pcr_handle->value(),
331                                            kTpmPCRLocality);
332  if (TPM_ERROR(result)) {
333    TPM_LOG(ERROR, result) << "Could not set locality for PCR0 in PCR handle";
334    return false;
335  }
336  return true;
337}
338
339bool TpmNvramImpl::GetOwnerPassword(std::string* owner_password) {
340  LocalData local_data;
341  if (!local_data_store_->Read(&local_data)) {
342    LOG(ERROR) << "Error reading local data for owner password.";
343    return false;
344  }
345  if (local_data.owner_password().empty()) {
346    LOG(ERROR) << "No owner password present in tpm local_data.";
347    return false;
348  }
349  owner_password->assign(local_data.owner_password());
350  return true;
351}
352
353}  // namespace tpm_manager
354