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