Home | History | Annotate | Download | only in trunks
      1 //
      2 // Copyright (C) 2014 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 "trunks/tpm_state_impl.h"
     18 
     19 #include <base/logging.h>
     20 #include <brillo/bind_lambda.h>
     21 
     22 #include "trunks/error_codes.h"
     23 #include "trunks/tpm_generated.h"
     24 #include "trunks/trunks_factory.h"
     25 
     26 namespace {
     27 
     28 // From definition of TPMA_PERMANENT.
     29 const trunks::TPMA_PERMANENT kOwnerAuthSetMask = 1U;
     30 const trunks::TPMA_PERMANENT kEndorsementAuthSetMask = 1U << 1;
     31 const trunks::TPMA_PERMANENT kLockoutAuthSetMask = 1U << 2;
     32 const trunks::TPMA_PERMANENT kInLockoutMask = 1U << 9;
     33 
     34 // From definition of TPMA_STARTUP_CLEAR.
     35 const trunks::TPMA_STARTUP_CLEAR kPlatformHierarchyMask = 1U;
     36 const trunks::TPMA_STARTUP_CLEAR kStorageHierarchyMask = 1U << 1;
     37 const trunks::TPMA_STARTUP_CLEAR kEndorsementHierarchyMask = 1U << 2;
     38 const trunks::TPMA_STARTUP_CLEAR kOrderlyShutdownMask = 1U << 31;
     39 
     40 }  // namespace
     41 
     42 namespace trunks {
     43 
     44 TpmStateImpl::TpmStateImpl(const TrunksFactory& factory) : factory_(factory) {}
     45 
     46 TPM_RC TpmStateImpl::Initialize() {
     47   TPM_RC result = CacheTpmProperties();
     48   if (result != TPM_RC_SUCCESS) {
     49     LOG(ERROR) << "Failed to query TPM properties: " << GetErrorString(result);
     50     return result;
     51   }
     52   if (tpm_properties_.count(TPM_PT_PERMANENT) == 0 ||
     53       tpm_properties_.count(TPM_PT_STARTUP_CLEAR) == 0) {
     54     LOG(ERROR) << "Required properties missing!";
     55     return TRUNKS_RC_INVALID_TPM_CONFIGURATION;
     56   }
     57 
     58   result = CacheAlgorithmProperties();
     59   if (result != TPM_RC_SUCCESS) {
     60     LOG(ERROR) << "Failed to query TPM algorithms: " << GetErrorString(result);
     61     return result;
     62   }
     63   initialized_ = true;
     64   return TPM_RC_SUCCESS;
     65 }
     66 
     67 bool TpmStateImpl::IsOwnerPasswordSet() {
     68   CHECK(initialized_);
     69   return ((tpm_properties_[TPM_PT_PERMANENT] & kOwnerAuthSetMask) ==
     70           kOwnerAuthSetMask);
     71 }
     72 
     73 bool TpmStateImpl::IsEndorsementPasswordSet() {
     74   CHECK(initialized_);
     75   return ((tpm_properties_[TPM_PT_PERMANENT] & kEndorsementAuthSetMask) ==
     76           kEndorsementAuthSetMask);
     77 }
     78 
     79 bool TpmStateImpl::IsLockoutPasswordSet() {
     80   CHECK(initialized_);
     81   return ((tpm_properties_[TPM_PT_PERMANENT] & kLockoutAuthSetMask) ==
     82           kLockoutAuthSetMask);
     83 }
     84 
     85 bool TpmStateImpl::IsOwned() {
     86   return (IsOwnerPasswordSet() && IsEndorsementPasswordSet() &&
     87           IsLockoutPasswordSet());
     88 }
     89 
     90 bool TpmStateImpl::IsInLockout() {
     91   CHECK(initialized_);
     92   return ((tpm_properties_[TPM_PT_PERMANENT] & kInLockoutMask) ==
     93           kInLockoutMask);
     94 }
     95 
     96 bool TpmStateImpl::IsPlatformHierarchyEnabled() {
     97   CHECK(initialized_);
     98   return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kPlatformHierarchyMask) ==
     99           kPlatformHierarchyMask);
    100 }
    101 
    102 bool TpmStateImpl::IsStorageHierarchyEnabled() {
    103   CHECK(initialized_);
    104   return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kStorageHierarchyMask) ==
    105           kStorageHierarchyMask);
    106 }
    107 
    108 bool TpmStateImpl::IsEndorsementHierarchyEnabled() {
    109   CHECK(initialized_);
    110   return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kEndorsementHierarchyMask) ==
    111           kEndorsementHierarchyMask);
    112 }
    113 
    114 bool TpmStateImpl::IsEnabled() {
    115   return (!IsPlatformHierarchyEnabled() && IsStorageHierarchyEnabled() &&
    116           IsEndorsementHierarchyEnabled());
    117 }
    118 
    119 bool TpmStateImpl::WasShutdownOrderly() {
    120   CHECK(initialized_);
    121   return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kOrderlyShutdownMask) ==
    122           kOrderlyShutdownMask);
    123 }
    124 
    125 bool TpmStateImpl::IsRSASupported() {
    126   CHECK(initialized_);
    127   return (algorithm_properties_.count(TPM_ALG_RSA) > 0);
    128 }
    129 
    130 bool TpmStateImpl::IsECCSupported() {
    131   CHECK(initialized_);
    132   return (algorithm_properties_.count(TPM_ALG_ECC) > 0);
    133 }
    134 
    135 uint32_t TpmStateImpl::GetLockoutCounter() {
    136   CHECK(initialized_);
    137   return tpm_properties_[TPM_PT_LOCKOUT_COUNTER];
    138 }
    139 
    140 uint32_t TpmStateImpl::GetLockoutThreshold() {
    141   CHECK(initialized_);
    142   return tpm_properties_[TPM_PT_MAX_AUTH_FAIL];
    143 }
    144 
    145 uint32_t TpmStateImpl::GetLockoutInterval() {
    146   CHECK(initialized_);
    147   return tpm_properties_[TPM_PT_LOCKOUT_INTERVAL];
    148 }
    149 
    150 uint32_t TpmStateImpl::GetLockoutRecovery() {
    151   CHECK(initialized_);
    152   return tpm_properties_[TPM_PT_LOCKOUT_RECOVERY];
    153 }
    154 
    155 uint32_t TpmStateImpl::GetMaxNVSize() {
    156   CHECK(initialized_);
    157   uint32_t max_nv_size;
    158   if (!GetTpmProperty(TPM_PT_NV_INDEX_MAX, &max_nv_size)) {
    159     max_nv_size = 2048;
    160   }
    161   uint32_t max_nv_buffer;
    162   if (GetTpmProperty(TPM_PT_NV_BUFFER_MAX, &max_nv_buffer) &&
    163       max_nv_buffer < max_nv_size) {
    164     max_nv_size = max_nv_buffer;
    165   }
    166   return max_nv_size;
    167 }
    168 
    169 bool TpmStateImpl::GetTpmProperty(TPM_PT property, uint32_t* value) {
    170   CHECK(initialized_);
    171   if (tpm_properties_.count(property) == 0) {
    172     return false;
    173   }
    174   if (value) {
    175     *value = tpm_properties_[property];
    176   }
    177   return true;
    178 }
    179 
    180 bool TpmStateImpl::GetAlgorithmProperties(TPM_ALG_ID algorithm,
    181                                           TPMA_ALGORITHM* properties) {
    182   CHECK(initialized_);
    183   if (algorithm_properties_.count(algorithm) == 0) {
    184     return false;
    185   }
    186   if (properties) {
    187     *properties = algorithm_properties_[algorithm];
    188   }
    189   return true;
    190 }
    191 
    192 TPM_RC TpmStateImpl::GetCapability(const CapabilityCallback& callback,
    193                                    TPM_CAP capability,
    194                                    uint32_t property,
    195                                    uint32_t max_properties_per_call) {
    196   TPMI_YES_NO more_data = YES;
    197   while (more_data) {
    198     TPMS_CAPABILITY_DATA capability_data;
    199     TPM_RC result = factory_.GetTpm()->GetCapabilitySync(
    200         capability, property, max_properties_per_call, &more_data,
    201         &capability_data, nullptr);
    202     if (result != TPM_RC_SUCCESS) {
    203       LOG(ERROR) << __func__ << ": " << GetErrorString(result);
    204       return result;
    205     }
    206     if (capability_data.capability != capability) {
    207       LOG(ERROR) << __func__ << ": Unexpected capability data.";
    208       return SAPI_RC_MALFORMED_RESPONSE;
    209     }
    210     uint32_t next_property = callback.Run(capability_data.data);
    211     if (more_data) {
    212       if (next_property == 0) {
    213         LOG(ERROR) << __func__ << ": No properties in response.";
    214         return SAPI_RC_MALFORMED_RESPONSE;
    215       }
    216       if (next_property <= property) {
    217         LOG(ERROR) << __func__ << ": Lower properties in response.";
    218         return SAPI_RC_MALFORMED_RESPONSE;
    219       }
    220       property = next_property;
    221     }
    222   }
    223   return TPM_RC_SUCCESS;
    224 }
    225 
    226 TPM_RC TpmStateImpl::CacheTpmProperties() {
    227   CapabilityCallback callback = base::Bind(
    228       [](TpmStateImpl* impl, const TPMU_CAPABILITIES& capability_data) {
    229         uint32_t next_property = 0;
    230         for (uint32_t i = 0;
    231              i < capability_data.tpm_properties.count && i < MAX_TPM_PROPERTIES;
    232              ++i) {
    233           const TPMS_TAGGED_PROPERTY& property =
    234               capability_data.tpm_properties.tpm_property[i];
    235           VLOG(1) << "TPM Property 0x" << std::hex << property.property
    236                   << " = 0x" << property.value;
    237           impl->tpm_properties_[property.property] = property.value;
    238           next_property = property.property + 1;
    239         }
    240         return next_property;
    241       }, base::Unretained(this));
    242   if (tpm_properties_.empty()) {
    243     TPM_RC result = GetCapability(callback, TPM_CAP_TPM_PROPERTIES, PT_FIXED,
    244                                   MAX_TPM_PROPERTIES);
    245     if (result != TPM_RC_SUCCESS) {
    246       return result;
    247     }
    248   }
    249   return GetCapability(callback, TPM_CAP_TPM_PROPERTIES, PT_VAR,
    250                        MAX_TPM_PROPERTIES);
    251 }
    252 
    253 TPM_RC TpmStateImpl::CacheAlgorithmProperties() {
    254   CapabilityCallback callback = base::Bind(
    255       [](TpmStateImpl* impl, const TPMU_CAPABILITIES& capability_data) {
    256         uint32_t next_property = 0;
    257         for (uint32_t i = 0;
    258              i < capability_data.algorithms.count && i < MAX_CAP_ALGS; ++i) {
    259           const TPMS_ALG_PROPERTY& property =
    260               capability_data.algorithms.alg_properties[i];
    261           VLOG(1) << "Algorithm Properties 0x" << std::hex << property.alg
    262                   << " = 0x" << property.alg_properties;
    263           impl->algorithm_properties_[property.alg] = property.alg_properties;
    264           next_property = property.alg + 1;
    265         }
    266         return next_property;
    267       }, base::Unretained(this));
    268   if (algorithm_properties_.empty()) {
    269     return GetCapability(callback, TPM_CAP_ALGS, TPM_ALG_FIRST, MAX_CAP_ALGS);
    270   }
    271   return TPM_RC_SUCCESS;
    272 }
    273 
    274 }  // namespace trunks
    275