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