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/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 
     47 TpmNvramImpl::TpmNvramImpl(LocalDataStore* local_data_store)
     48     : local_data_store_(local_data_store) {}
     49 
     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 
     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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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