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 
TpmStateImpl(const TrunksFactory & factory)44 TpmStateImpl::TpmStateImpl(const TrunksFactory& factory) : factory_(factory) {}
45 
Initialize()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 
IsOwnerPasswordSet()67 bool TpmStateImpl::IsOwnerPasswordSet() {
68   CHECK(initialized_);
69   return ((tpm_properties_[TPM_PT_PERMANENT] & kOwnerAuthSetMask) ==
70           kOwnerAuthSetMask);
71 }
72 
IsEndorsementPasswordSet()73 bool TpmStateImpl::IsEndorsementPasswordSet() {
74   CHECK(initialized_);
75   return ((tpm_properties_[TPM_PT_PERMANENT] & kEndorsementAuthSetMask) ==
76           kEndorsementAuthSetMask);
77 }
78 
IsLockoutPasswordSet()79 bool TpmStateImpl::IsLockoutPasswordSet() {
80   CHECK(initialized_);
81   return ((tpm_properties_[TPM_PT_PERMANENT] & kLockoutAuthSetMask) ==
82           kLockoutAuthSetMask);
83 }
84 
IsOwned()85 bool TpmStateImpl::IsOwned() {
86   return (IsOwnerPasswordSet() && IsEndorsementPasswordSet() &&
87           IsLockoutPasswordSet());
88 }
89 
IsInLockout()90 bool TpmStateImpl::IsInLockout() {
91   CHECK(initialized_);
92   return ((tpm_properties_[TPM_PT_PERMANENT] & kInLockoutMask) ==
93           kInLockoutMask);
94 }
95 
IsPlatformHierarchyEnabled()96 bool TpmStateImpl::IsPlatformHierarchyEnabled() {
97   CHECK(initialized_);
98   return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kPlatformHierarchyMask) ==
99           kPlatformHierarchyMask);
100 }
101 
IsStorageHierarchyEnabled()102 bool TpmStateImpl::IsStorageHierarchyEnabled() {
103   CHECK(initialized_);
104   return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kStorageHierarchyMask) ==
105           kStorageHierarchyMask);
106 }
107 
IsEndorsementHierarchyEnabled()108 bool TpmStateImpl::IsEndorsementHierarchyEnabled() {
109   CHECK(initialized_);
110   return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kEndorsementHierarchyMask) ==
111           kEndorsementHierarchyMask);
112 }
113 
IsEnabled()114 bool TpmStateImpl::IsEnabled() {
115   return (!IsPlatformHierarchyEnabled() && IsStorageHierarchyEnabled() &&
116           IsEndorsementHierarchyEnabled());
117 }
118 
WasShutdownOrderly()119 bool TpmStateImpl::WasShutdownOrderly() {
120   CHECK(initialized_);
121   return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kOrderlyShutdownMask) ==
122           kOrderlyShutdownMask);
123 }
124 
IsRSASupported()125 bool TpmStateImpl::IsRSASupported() {
126   CHECK(initialized_);
127   return (algorithm_properties_.count(TPM_ALG_RSA) > 0);
128 }
129 
IsECCSupported()130 bool TpmStateImpl::IsECCSupported() {
131   CHECK(initialized_);
132   return (algorithm_properties_.count(TPM_ALG_ECC) > 0);
133 }
134 
GetLockoutCounter()135 uint32_t TpmStateImpl::GetLockoutCounter() {
136   CHECK(initialized_);
137   return tpm_properties_[TPM_PT_LOCKOUT_COUNTER];
138 }
139 
GetLockoutThreshold()140 uint32_t TpmStateImpl::GetLockoutThreshold() {
141   CHECK(initialized_);
142   return tpm_properties_[TPM_PT_MAX_AUTH_FAIL];
143 }
144 
GetLockoutInterval()145 uint32_t TpmStateImpl::GetLockoutInterval() {
146   CHECK(initialized_);
147   return tpm_properties_[TPM_PT_LOCKOUT_INTERVAL];
148 }
149 
GetLockoutRecovery()150 uint32_t TpmStateImpl::GetLockoutRecovery() {
151   CHECK(initialized_);
152   return tpm_properties_[TPM_PT_LOCKOUT_RECOVERY];
153 }
154 
GetMaxNVSize()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 
GetTpmProperty(TPM_PT property,uint32_t * value)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 
GetAlgorithmProperties(TPM_ALG_ID algorithm,TPMA_ALGORITHM * properties)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 
GetCapability(const CapabilityCallback & callback,TPM_CAP capability,uint32_t property,uint32_t max_properties_per_call)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 
CacheTpmProperties()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 
CacheAlgorithmProperties()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