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/policy_session.h>
25 #include <trunks/tpm_constants.h>
26 #include <trunks/tpm_utility.h>
27 
28 namespace tpm_manager {
29 
30 using trunks::GetErrorString;
31 using trunks::TPM_RC;
32 using trunks::TPM_RC_SUCCESS;
33 
34 namespace {
35 
MapAttributesFromTpm(trunks::TPMA_NV tpm_flags,std::vector<NvramSpaceAttribute> * attributes)36 void MapAttributesFromTpm(trunks::TPMA_NV tpm_flags,
37                           std::vector<NvramSpaceAttribute>* attributes) {
38   if (tpm_flags & trunks::TPMA_NV_WRITEDEFINE)
39     attributes->push_back(NVRAM_PERSISTENT_WRITE_LOCK);
40   if (tpm_flags & trunks::TPMA_NV_WRITE_STCLEAR)
41     attributes->push_back(NVRAM_BOOT_WRITE_LOCK);
42   if (tpm_flags & trunks::TPMA_NV_READ_STCLEAR)
43     attributes->push_back(NVRAM_BOOT_READ_LOCK);
44   if (tpm_flags & (trunks::TPMA_NV_AUTHWRITE))
45     attributes->push_back(NVRAM_WRITE_AUTHORIZATION);
46   if (tpm_flags & (trunks::TPMA_NV_AUTHREAD))
47     attributes->push_back(NVRAM_READ_AUTHORIZATION);
48   if (tpm_flags & trunks::TPMA_NV_GLOBALLOCK)
49     attributes->push_back(NVRAM_GLOBAL_LOCK);
50   if (tpm_flags & trunks::TPMA_NV_PPWRITE)
51     attributes->push_back(NVRAM_PLATFORM_WRITE);
52   if (tpm_flags & trunks::TPMA_NV_OWNERWRITE)
53     attributes->push_back(NVRAM_OWNER_WRITE);
54   if (tpm_flags & trunks::TPMA_NV_OWNERREAD)
55     attributes->push_back(NVRAM_OWNER_READ);
56   if (tpm_flags & trunks::TPMA_NV_EXTEND)
57     attributes->push_back(NVRAM_WRITE_EXTEND);
58 }
59 
MapAttributesToTpm(const std::vector<NvramSpaceAttribute> & attributes,trunks::TPMA_NV * tpm_flags,bool * world_read_allowed,bool * world_write_allowed)60 bool MapAttributesToTpm(
61     const std::vector<NvramSpaceAttribute>& attributes,
62     trunks::TPMA_NV* tpm_flags,
63     bool* world_read_allowed,
64     bool* world_write_allowed) {
65   // Always require policy, even if it's an empty policy.
66   *tpm_flags = trunks::TPMA_NV_POLICYWRITE | trunks::TPMA_NV_POLICYREAD;
67   *world_read_allowed = true;
68   *world_write_allowed = true;
69   for (auto attribute : attributes) {
70     switch (attribute) {
71       case NVRAM_PERSISTENT_WRITE_LOCK:
72         *tpm_flags |= trunks::TPMA_NV_WRITEDEFINE;
73         break;
74       case NVRAM_BOOT_WRITE_LOCK:
75         *tpm_flags |= trunks::TPMA_NV_WRITE_STCLEAR;
76         break;
77       case NVRAM_BOOT_READ_LOCK:
78         *tpm_flags |= trunks::TPMA_NV_READ_STCLEAR;
79         break;
80       case NVRAM_WRITE_AUTHORIZATION:
81         *world_write_allowed = false;
82         break;
83       case NVRAM_READ_AUTHORIZATION:
84         *world_read_allowed = false;
85         break;
86       case NVRAM_WRITE_EXTEND:
87         *tpm_flags |= trunks::TPMA_NV_EXTEND;
88         break;
89       case NVRAM_GLOBAL_LOCK:
90       case NVRAM_PLATFORM_WRITE:
91       case NVRAM_OWNER_WRITE:
92       case NVRAM_OWNER_READ:
93         return false;
94       default:
95         break;
96     }
97   }
98   return true;
99 }
100 
MapTpmError(TPM_RC tpm_error)101 NvramResult MapTpmError(TPM_RC tpm_error) {
102   switch (trunks::GetFormatOneError(tpm_error)) {
103     case trunks::TPM_RC_SUCCESS:
104       return NVRAM_RESULT_SUCCESS;
105     case trunks::TPM_RC_NV_RANGE:
106     case trunks::TPM_RC_NV_SIZE:
107     case trunks::TPM_RC_ATTRIBUTES:
108       return NVRAM_RESULT_INVALID_PARAMETER;
109     case trunks::TPM_RC_NV_LOCKED:
110     case trunks::TPM_RC_NV_UNINITIALIZED:
111       return NVRAM_RESULT_OPERATION_DISABLED;
112     case trunks::TPM_RC_NV_AUTHORIZATION:
113     case trunks::TPM_RC_BAD_AUTH:
114     case trunks::TPM_RC_AUTH_FAIL:
115     case trunks::TPM_RC_POLICY_FAIL:
116       return NVRAM_RESULT_ACCESS_DENIED;
117     case trunks::TPM_RC_NV_SPACE:
118       return NVRAM_RESULT_INSUFFICIENT_SPACE;
119     case trunks::TPM_RC_NV_DEFINED:
120       return NVRAM_RESULT_SPACE_ALREADY_EXISTS;
121     case trunks::TPM_RC_HANDLE:
122       return NVRAM_RESULT_SPACE_DOES_NOT_EXIST;
123   }
124   return NVRAM_RESULT_DEVICE_ERROR;
125 }
126 
127 }  // namespace
128 
Tpm2NvramImpl(const trunks::TrunksFactory & factory,LocalDataStore * local_data_store)129 Tpm2NvramImpl::Tpm2NvramImpl(const trunks::TrunksFactory& factory,
130                              LocalDataStore* local_data_store)
131     : trunks_factory_(factory),
132       local_data_store_(local_data_store),
133       initialized_(false),
134       trunks_session_(trunks_factory_.GetHmacSession()),
135       trunks_utility_(trunks_factory_.GetTpmUtility()) {}
136 
DefineSpace(uint32_t index,size_t size,const std::vector<NvramSpaceAttribute> & attributes,const std::string & authorization_value,NvramSpacePolicy policy)137 NvramResult Tpm2NvramImpl::DefineSpace(
138     uint32_t index,
139     size_t size,
140     const std::vector<NvramSpaceAttribute>& attributes,
141     const std::string& authorization_value,
142     NvramSpacePolicy policy) {
143   if (!Initialize()) {
144     return NVRAM_RESULT_DEVICE_ERROR;
145   }
146   if (!SetupOwnerSession()) {
147     return NVRAM_RESULT_OPERATION_DISABLED;
148   }
149   trunks::TPMA_NV attribute_flags = 0;
150   bool world_read_allowed = false;
151   bool world_write_allowed = false;
152   if (!MapAttributesToTpm(attributes, &attribute_flags, &world_read_allowed,
153                           &world_write_allowed)) {
154     return NVRAM_RESULT_INVALID_PARAMETER;
155   }
156   NvramPolicyRecord policy_record;
157   policy_record.set_index(index);
158   policy_record.set_policy(policy);
159   policy_record.set_world_read_allowed(world_read_allowed);
160   policy_record.set_world_write_allowed(world_write_allowed);
161   std::string policy_digest;
162   if (!ComputePolicyDigest(&policy_record, &policy_digest)) {
163     LOG(ERROR) << "Failed to compute policy digest.";
164     return NVRAM_RESULT_DEVICE_ERROR;
165   }
166   TPM_RC result = trunks_utility_->DefineNVSpace(
167       index, size, attribute_flags, authorization_value, policy_digest,
168       trunks_session_->GetDelegate());
169   if (result != TPM_RC_SUCCESS) {
170     LOG(ERROR) << "Error defining nvram space: " << GetErrorString(result);
171     return MapTpmError(result);
172   }
173   if (!SavePolicyRecord(policy_record)) {
174     trunks_utility_->DestroyNVSpace(index, trunks_session_->GetDelegate());
175     return NVRAM_RESULT_DEVICE_ERROR;
176   }
177   return NVRAM_RESULT_SUCCESS;
178 }
179 
DestroySpace(uint32_t index)180 NvramResult Tpm2NvramImpl::DestroySpace(uint32_t index) {
181   if (!Initialize()) {
182     return NVRAM_RESULT_DEVICE_ERROR;
183   }
184   if (!SetupOwnerSession()) {
185     return NVRAM_RESULT_OPERATION_DISABLED;
186   }
187   TPM_RC result =
188       trunks_utility_->DestroyNVSpace(index, trunks_session_->GetDelegate());
189   if (result != TPM_RC_SUCCESS) {
190     LOG(ERROR) << "Error destroying nvram space:" << GetErrorString(result);
191     return MapTpmError(result);
192   }
193   DeletePolicyRecord(index);
194   return NVRAM_RESULT_SUCCESS;
195 }
196 
WriteSpace(uint32_t index,const std::string & data,const std::string & authorization_value)197 NvramResult Tpm2NvramImpl::WriteSpace(uint32_t index,
198                                       const std::string& data,
199                                       const std::string& authorization_value) {
200   if (!Initialize()) {
201     return NVRAM_RESULT_DEVICE_ERROR;
202   }
203   trunks::TPMS_NV_PUBLIC nvram_public;
204   TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public);
205   if (result != TPM_RC_SUCCESS) {
206     LOG(ERROR) << "Error reading nvram space public area: "
207                << GetErrorString(result);
208     return MapTpmError(result);
209   }
210   if (nvram_public.attributes & trunks::TPMA_NV_WRITELOCKED) {
211     return NVRAM_RESULT_OPERATION_DISABLED;
212   }
213   trunks::AuthorizationDelegate* authorization = nullptr;
214   std::unique_ptr<trunks::PolicySession> policy_session =
215       trunks_factory_.GetPolicySession();
216   bool using_owner_authorization = false;
217   bool extend = (nvram_public.attributes & trunks::TPMA_NV_EXTEND) != 0;
218   if (nvram_public.attributes & trunks::TPMA_NV_POLICYWRITE) {
219     NvramPolicyRecord policy_record;
220     if (!GetPolicyRecord(index, &policy_record)) {
221       LOG(ERROR) << "Policy record missing.";
222       return NVRAM_RESULT_INVALID_PARAMETER;
223     }
224     if (!SetupPolicySession(
225             policy_record, authorization_value,
226             extend ? trunks::TPM_CC_NV_Extend : trunks::TPM_CC_NV_Write,
227             policy_session.get())) {
228       // This will fail if policy is not met, e.g. a PCR value is not the
229       // required value.
230       return NVRAM_RESULT_ACCESS_DENIED;
231     }
232     authorization = policy_session->GetDelegate();
233   } else if (nvram_public.attributes & trunks::TPMA_NV_AUTHWRITE) {
234     trunks_session_->SetEntityAuthorizationValue(authorization_value);
235     authorization = trunks_session_->GetDelegate();
236   } else if (nvram_public.attributes & trunks::TPMA_NV_OWNERWRITE) {
237     if (!SetupOwnerSession()) {
238       // The owner password has been destroyed.
239       return NVRAM_RESULT_OPERATION_DISABLED;
240     }
241     using_owner_authorization = true;
242     authorization = trunks_session_->GetDelegate();
243   } else {
244     // TPMA_NV_PPWRITE: Platform authorization is long gone.
245     return NVRAM_RESULT_OPERATION_DISABLED;
246   }
247   result = trunks_utility_->WriteNVSpace(index, 0 /* offset */, data,
248                                          using_owner_authorization, extend,
249                                          authorization);
250   if (result != TPM_RC_SUCCESS) {
251     LOG(ERROR) << "Error writing to nvram space: " << GetErrorString(result);
252     return MapTpmError(result);
253   }
254   return NVRAM_RESULT_SUCCESS;
255 }
256 
ReadSpace(uint32_t index,std::string * data,const std::string & authorization_value)257 NvramResult Tpm2NvramImpl::ReadSpace(uint32_t index,
258                                      std::string* data,
259                                      const std::string& authorization_value) {
260   if (!Initialize()) {
261     return NVRAM_RESULT_DEVICE_ERROR;
262   }
263   trunks::TPMS_NV_PUBLIC nvram_public;
264   TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public);
265   if (result != TPM_RC_SUCCESS) {
266     LOG(ERROR) << "Error reading nvram space public area: "
267                << GetErrorString(result);
268     return MapTpmError(result);
269   }
270   if (nvram_public.attributes & trunks::TPMA_NV_READLOCKED) {
271     return NVRAM_RESULT_OPERATION_DISABLED;
272   }
273   // Handle the case when the space has never been written to.
274   if ((nvram_public.attributes & trunks::TPMA_NV_WRITTEN) == 0) {
275     *data = std::string(nvram_public.data_size, 0);
276     return NVRAM_RESULT_SUCCESS;
277   }
278   trunks::AuthorizationDelegate* authorization = nullptr;
279   std::unique_ptr<trunks::PolicySession> policy_session =
280       trunks_factory_.GetPolicySession();
281   bool using_owner_authorization = false;
282   if (nvram_public.attributes & trunks::TPMA_NV_POLICYREAD) {
283     NvramPolicyRecord policy_record;
284     if (!GetPolicyRecord(index, &policy_record)) {
285       LOG(ERROR) << "Policy record missing.";
286       return NVRAM_RESULT_INVALID_PARAMETER;
287     }
288     if (!SetupPolicySession(policy_record, authorization_value,
289                             trunks::TPM_CC_NV_Read, policy_session.get())) {
290       // This will fail if policy is not met, e.g. a PCR value is not the
291       // required value.
292       return NVRAM_RESULT_ACCESS_DENIED;
293     }
294     authorization = policy_session->GetDelegate();
295   } else if (nvram_public.attributes & trunks::TPMA_NV_AUTHREAD) {
296     trunks_session_->SetEntityAuthorizationValue(authorization_value);
297     authorization = trunks_session_->GetDelegate();
298   } else if (nvram_public.attributes & trunks::TPMA_NV_OWNERREAD) {
299     if (!SetupOwnerSession()) {
300       // The owner password has been destroyed.
301       return NVRAM_RESULT_OPERATION_DISABLED;
302     }
303     using_owner_authorization = true;
304     authorization = trunks_session_->GetDelegate();
305   } else {
306     // TPMA_NV_PPREAD: Platform authorization is long gone.
307     return NVRAM_RESULT_OPERATION_DISABLED;
308   }
309   result = trunks_utility_->ReadNVSpace(
310       index, 0 /* offset */, nvram_public.data_size, using_owner_authorization,
311       data, authorization);
312   if (result != TPM_RC_SUCCESS) {
313     LOG(ERROR) << "Error reading nvram space: " << GetErrorString(result);
314     return MapTpmError(result);
315   }
316   return NVRAM_RESULT_SUCCESS;
317 }
318 
LockSpace(uint32_t index,bool lock_read,bool lock_write,const std::string & authorization_value)319 NvramResult Tpm2NvramImpl::LockSpace(uint32_t index,
320                                      bool lock_read,
321                                      bool lock_write,
322                                      const std::string& authorization_value) {
323   if (!Initialize()) {
324     return NVRAM_RESULT_DEVICE_ERROR;
325   }
326   trunks::TPMS_NV_PUBLIC nvram_public;
327   TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public);
328   if (result != TPM_RC_SUCCESS) {
329     LOG(ERROR) << "Error reading nvram space public area: "
330                << GetErrorString(result);
331     return MapTpmError(result);
332   }
333   bool is_read_locked =
334       ((nvram_public.attributes & trunks::TPMA_NV_READLOCKED) != 0);
335   bool is_write_locked =
336       ((nvram_public.attributes & trunks::TPMA_NV_WRITELOCKED) != 0);
337   if ((!lock_read || is_read_locked) && (!lock_write || is_write_locked)) {
338     // Already locked.
339     return NVRAM_RESULT_SUCCESS;
340   }
341   // Handle locking read and write separately because the authorization might be
342   // different.
343   if (lock_read && !is_read_locked) {
344     trunks::AuthorizationDelegate* authorization = nullptr;
345     std::unique_ptr<trunks::PolicySession> policy_session =
346         trunks_factory_.GetPolicySession();
347     bool using_owner_authorization = false;
348     if (nvram_public.attributes & trunks::TPMA_NV_POLICYREAD) {
349       NvramPolicyRecord policy_record;
350       if (!GetPolicyRecord(index, &policy_record)) {
351         LOG(ERROR) << "Policy record missing.";
352         return NVRAM_RESULT_INVALID_PARAMETER;
353       }
354       if (!SetupPolicySession(policy_record, authorization_value,
355                               trunks::TPM_CC_NV_ReadLock,
356                               policy_session.get())) {
357         // This will fail if policy is not met, e.g. a PCR value is not the
358         // required value.
359         return NVRAM_RESULT_ACCESS_DENIED;
360       }
361       authorization = policy_session->GetDelegate();
362     } else if (nvram_public.attributes & trunks::TPMA_NV_AUTHREAD) {
363       trunks_session_->SetEntityAuthorizationValue(authorization_value);
364       authorization = trunks_session_->GetDelegate();
365     } else if (nvram_public.attributes & trunks::TPMA_NV_OWNERREAD) {
366       if (!SetupOwnerSession()) {
367         // The owner password has been destroyed.
368         return NVRAM_RESULT_OPERATION_DISABLED;
369       }
370       using_owner_authorization = true;
371       authorization = trunks_session_->GetDelegate();
372     } else {
373       // TPMA_NV_PPREAD: Platform authorization is long gone.
374       return NVRAM_RESULT_OPERATION_DISABLED;
375     }
376     result = trunks_utility_->LockNVSpace(
377         index, true /* lock_read */, false /* lock_write */,
378         using_owner_authorization, authorization);
379     if (result != TPM_RC_SUCCESS) {
380       LOG(ERROR) << "Error locking nvram space: " << GetErrorString(result);
381       return MapTpmError(result);
382     }
383   }
384   if (lock_write && !is_write_locked) {
385     trunks::AuthorizationDelegate* authorization = nullptr;
386     std::unique_ptr<trunks::PolicySession> policy_session =
387         trunks_factory_.GetPolicySession();
388     bool using_owner_authorization = false;
389     if (nvram_public.attributes & trunks::TPMA_NV_POLICYWRITE) {
390       NvramPolicyRecord policy_record;
391       if (!GetPolicyRecord(index, &policy_record)) {
392         LOG(ERROR) << "Policy record missing.";
393         return NVRAM_RESULT_INVALID_PARAMETER;
394       }
395       if (!SetupPolicySession(policy_record, authorization_value,
396                               trunks::TPM_CC_NV_WriteLock,
397                               policy_session.get())) {
398         // This will fail if policy is not met, e.g. a PCR value is not the
399         // required value.
400         return NVRAM_RESULT_ACCESS_DENIED;
401       }
402       authorization = policy_session->GetDelegate();
403     } else if (nvram_public.attributes & trunks::TPMA_NV_AUTHWRITE) {
404       trunks_session_->SetEntityAuthorizationValue(authorization_value);
405       authorization = trunks_session_->GetDelegate();
406     } else if (nvram_public.attributes & trunks::TPMA_NV_OWNERWRITE) {
407       if (!SetupOwnerSession()) {
408         // The owner password has been destroyed.
409         return NVRAM_RESULT_OPERATION_DISABLED;
410       }
411       using_owner_authorization = true;
412       authorization = trunks_session_->GetDelegate();
413     } else {
414       // TPMA_NV_PPWRITE: Platform authorization is long gone.
415       return NVRAM_RESULT_OPERATION_DISABLED;
416     }
417     result = trunks_utility_->LockNVSpace(
418         index, false /* lock_read */, true /* lock_write */,
419         using_owner_authorization, authorization);
420     if (result != TPM_RC_SUCCESS) {
421       LOG(ERROR) << "Error locking nvram space: " << GetErrorString(result);
422       return MapTpmError(result);
423     }
424   }
425   return NVRAM_RESULT_SUCCESS;
426 }
427 
ListSpaces(std::vector<uint32_t> * index_list)428 NvramResult Tpm2NvramImpl::ListSpaces(std::vector<uint32_t>* index_list) {
429   return MapTpmError(trunks_utility_->ListNVSpaces(index_list));
430 }
431 
GetSpaceInfo(uint32_t index,size_t * size,bool * is_read_locked,bool * is_write_locked,std::vector<NvramSpaceAttribute> * attributes,NvramSpacePolicy * policy)432 NvramResult Tpm2NvramImpl::GetSpaceInfo(
433     uint32_t index,
434     size_t* size,
435     bool* is_read_locked,
436     bool* is_write_locked,
437     std::vector<NvramSpaceAttribute>* attributes,
438     NvramSpacePolicy* policy) {
439   trunks::TPMS_NV_PUBLIC nvram_public;
440   TPM_RC result = trunks_utility_->GetNVSpacePublicArea(index, &nvram_public);
441   if (result != TPM_RC_SUCCESS) {
442     LOG(ERROR) << "Error reading NV space for index " << index
443                << " with error: " << GetErrorString(result);
444     return MapTpmError(result);
445   }
446   *size = nvram_public.data_size;
447   *is_read_locked =
448       ((nvram_public.attributes & trunks::TPMA_NV_READLOCKED) != 0);
449   *is_write_locked =
450       ((nvram_public.attributes & trunks::TPMA_NV_WRITELOCKED) != 0);
451   MapAttributesFromTpm(nvram_public.attributes, attributes);
452   *policy = NVRAM_POLICY_NONE;
453   NvramPolicyRecord policy_record;
454   if (GetPolicyRecord(index, &policy_record)) {
455     *policy = policy_record.policy();
456     if (!policy_record.world_read_allowed()) {
457       attributes->push_back(NVRAM_READ_AUTHORIZATION);
458     }
459     if (!policy_record.world_write_allowed()) {
460       attributes->push_back(NVRAM_WRITE_AUTHORIZATION);
461     }
462   }
463   return NVRAM_RESULT_SUCCESS;
464 }
465 
Initialize()466 bool Tpm2NvramImpl::Initialize() {
467   if (initialized_) {
468     return true;
469   }
470   TPM_RC result =
471       trunks_session_->StartUnboundSession(true /* enable_encryption */);
472   if (result != TPM_RC_SUCCESS) {
473     LOG(ERROR) << "Error starting a default authorization session: "
474                << GetErrorString(result);
475     return false;
476   }
477   initialized_ = true;
478   return true;
479 }
480 
GetOwnerPassword()481 std::string Tpm2NvramImpl::GetOwnerPassword() {
482   LocalData local_data;
483   if (local_data_store_ && local_data_store_->Read(&local_data)) {
484     return local_data.owner_password();
485   }
486   LOG(ERROR) << "TPM owner password requested but not available.";
487   return std::string();
488 }
489 
SetupOwnerSession()490 bool Tpm2NvramImpl::SetupOwnerSession() {
491   std::string owner_password = GetOwnerPassword();
492   if (owner_password.empty()) {
493     LOG(ERROR) << "Owner authorization required but not available.";
494     return false;
495   }
496   trunks_session_->SetEntityAuthorizationValue(owner_password);
497   return true;
498 }
499 
SetupPolicySession(const NvramPolicyRecord & policy_record,const std::string & authorization_value,trunks::TPM_CC command_code,trunks::PolicySession * session)500 bool Tpm2NvramImpl::SetupPolicySession(
501     const NvramPolicyRecord& policy_record,
502     const std::string& authorization_value,
503     trunks::TPM_CC command_code,
504     trunks::PolicySession* session) {
505   TPM_RC result = session->StartUnboundSession(true /* enable_encryption */);
506   if (result != TPM_RC_SUCCESS) {
507     LOG(ERROR) << "Error starting a policy authorization session: "
508                << GetErrorString(result);
509     return false;
510   }
511   session->SetEntityAuthorizationValue(authorization_value);
512   if (!AddPoliciesForCommand(policy_record, command_code, session)) {
513     return false;
514   }
515   if (!AddPolicyOR(policy_record, session)) {
516     return false;
517   }
518   return true;
519 }
520 
AddPoliciesForCommand(const NvramPolicyRecord & policy_record,trunks::TPM_CC command_code,trunks::PolicySession * session)521 bool Tpm2NvramImpl::AddPoliciesForCommand(
522     const NvramPolicyRecord& policy_record,
523     trunks::TPM_CC command_code,
524     trunks::PolicySession* session) {
525   TPM_RC result = session->PolicyCommandCode(command_code);
526   if (result != TPM_RC_SUCCESS) {
527     LOG(ERROR) << "Failed to setup command code policy.";
528     return false;
529   }
530   bool is_write_command = (command_code == trunks::TPM_CC_NV_Write ||
531                            command_code == trunks::TPM_CC_NV_WriteLock ||
532                            command_code == trunks::TPM_CC_NV_Extend);
533   bool is_read_command = !is_write_command;
534   // Check if this operation requires an authorization value.
535   if ((is_read_command && !policy_record.world_read_allowed()) ||
536       (is_write_command && !policy_record.world_write_allowed())) {
537     result = session->PolicyAuthValue();
538     if (result != TPM_RC_SUCCESS) {
539       LOG(ERROR) << "Failed to setup auth policy.";
540       return false;
541     }
542   }
543   if (policy_record.policy() == NVRAM_POLICY_PCR0) {
544     std::string current_pcr_value;
545     result = trunks_utility_->ReadPCR(0, &current_pcr_value);
546     if (result != TPM_RC_SUCCESS) {
547       LOG(ERROR) << "Failed to read the current PCR value.";
548       return false;
549     }
550     result = session->PolicyPCR(0, current_pcr_value);
551     if (result != TPM_RC_SUCCESS) {
552       LOG(ERROR) << "Failed to setup PCR policy.";
553       return false;
554     }
555   }
556   return true;
557 }
558 
AddPolicyOR(const NvramPolicyRecord & policy_record,trunks::PolicySession * session)559 bool Tpm2NvramImpl::AddPolicyOR(
560     const NvramPolicyRecord& policy_record,
561     trunks::PolicySession* session) {
562   std::vector<std::string> digests;
563   for (int i = 0; i < policy_record.policy_digests_size(); ++i) {
564     digests.push_back(policy_record.policy_digests(i));
565   }
566   TPM_RC result = session->PolicyOR(digests);
567   if (result != TPM_RC_SUCCESS) {
568     LOG(ERROR) << "Failed to setup OR policy.";
569     return false;
570   }
571   return true;
572 }
573 
ComputePolicyDigest(NvramPolicyRecord * policy_record,std::string * digest)574 bool Tpm2NvramImpl::ComputePolicyDigest(NvramPolicyRecord* policy_record,
575                                         std::string* digest) {
576   // Compute a policy digest for each command then OR them all together. This
577   // approach gives flexibility to have different requirements for read and
578   // write operations, and the ability to support authorization values combined
579   // with other policies.
580   std::unique_ptr<trunks::PolicySession> trial_session;
581   for (trunks::TPM_CC command_code :
582        {trunks::TPM_CC_NV_Extend, trunks::TPM_CC_NV_Write,
583         trunks::TPM_CC_NV_WriteLock, trunks::TPM_CC_NV_Read,
584         trunks::TPM_CC_NV_ReadLock, trunks::TPM_CC_NV_Certify}) {
585     trial_session = trunks_factory_.GetTrialSession();
586     if (trial_session->StartUnboundSession(false /* enable_encryption */) !=
587         TPM_RC_SUCCESS) {
588       return false;
589     }
590     if (!AddPoliciesForCommand(*policy_record, command_code,
591                                trial_session.get())) {
592       return false;
593     }
594     if (trial_session->GetDigest(digest) != TPM_RC_SUCCESS) {
595       return false;
596     }
597     policy_record->add_policy_digests(*digest);
598   }
599   if (!AddPolicyOR(*policy_record, trial_session.get())) {
600     return false;
601   }
602   if (trial_session->GetDigest(digest) != TPM_RC_SUCCESS) {
603     return false;
604   }
605   return true;
606 }
607 
GetPolicyRecord(uint32_t index,NvramPolicyRecord * record)608 bool Tpm2NvramImpl::GetPolicyRecord(uint32_t index, NvramPolicyRecord* record) {
609   LocalData local_data;
610   if (local_data_store_ && local_data_store_->Read(&local_data)) {
611     for (int i = 0; i < local_data.nvram_policy_size(); ++i) {
612       if (local_data.nvram_policy(i).index() == index) {
613         *record = local_data.nvram_policy(i);
614         return true;
615       }
616     }
617   }
618   return false;
619 }
620 
SavePolicyRecord(const NvramPolicyRecord & record)621 bool Tpm2NvramImpl::SavePolicyRecord(const NvramPolicyRecord& record) {
622   LocalData local_data;
623   if (!local_data_store_ || !local_data_store_->Read(&local_data)) {
624     LOG(ERROR) << "Failed to read local data.";
625     return false;
626   }
627   LocalData new_local_data = local_data;
628   new_local_data.clear_nvram_policy();
629   for (int i = 0; i < local_data.nvram_policy_size(); ++i) {
630     // Keep only the ones that don't match |record|.
631     if (local_data.nvram_policy(i).index() != record.index()) {
632       *new_local_data.add_nvram_policy() = local_data.nvram_policy(i);
633     }
634   }
635   *new_local_data.add_nvram_policy() = record;
636   if (!local_data_store_->Write(new_local_data)) {
637     LOG(ERROR) << "Failed to write local data.";
638     return false;
639   }
640   return true;
641 }
642 
DeletePolicyRecord(uint32_t index)643 void Tpm2NvramImpl::DeletePolicyRecord(uint32_t index) {
644   LocalData local_data;
645   if (local_data_store_ && local_data_store_->Read(&local_data)) {
646     LocalData new_local_data = local_data;
647     new_local_data.clear_nvram_policy();
648     for (int i = 0; i < local_data.nvram_policy_size(); ++i) {
649       // Keep only the ones that don't match |index|.
650       if (local_data.nvram_policy(i).index() != index) {
651         *new_local_data.add_nvram_policy() = local_data.nvram_policy(i);
652       }
653     }
654     local_data_store_->Write(new_local_data);
655   }
656 }
657 
658 }  // namespace tpm_manager
659