Home | History | Annotate | Download | only in server
      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 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    428 NvramResult Tpm2NvramImpl::ListSpaces(std::vector<uint32_t>* index_list) {
    429   return MapTpmError(trunks_utility_->ListNVSpaces(index_list));
    430 }
    431 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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