• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 namespace {
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.
36 const unsigned int kTpmBootPCR = 0;
37 const unsigned int kTpmPCRLocality = 1;
38 
39 }  // namespace
40 
41 namespace tpm_manager {
42 
43 using trousers::ScopedTssMemory;
44 using trousers::ScopedTssNvStore;
45 using trousers::ScopedTssPcrs;
46 
TpmNvramImpl(LocalDataStore * local_data_store)47 TpmNvramImpl::TpmNvramImpl(LocalDataStore* local_data_store)
48     : local_data_store_(local_data_store) {}
49 
DefineNvram(uint32_t index,size_t length)50 bool 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 
DestroyNvram(uint32_t index)91 bool 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 
WriteNvram(uint32_t index,const std::string & data)113 bool 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 
ReadNvram(uint32_t index,std::string * data)129 bool 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 
IsNvramDefined(uint32_t index,bool * defined)167 bool 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 
IsNvramLocked(uint32_t index,bool * locked)195 bool 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 
GetNvramSize(uint32_t index,size_t * size)221 bool 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 
InitializeNvramHandle(ScopedTssNvStore * nv_handle,uint32_t index)246 bool 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 
SetOwnerPolicy(ScopedTssNvStore * nv_handle)266 bool 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 
SetCompositePcr0(ScopedTssPcrs * pcr_handle)299 bool 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 
GetOwnerPassword(std::string * owner_password)339 bool 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