tpm_state_impl.cc revision 39e701593e712adf6edfa029710dfb7af376ad4c
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
26namespace {
27
28// From definition of TPMA_PERMANENT.
29const trunks::TPMA_PERMANENT kOwnerAuthSetMask = 1U;
30const trunks::TPMA_PERMANENT kEndorsementAuthSetMask = 1U << 1;
31const trunks::TPMA_PERMANENT kLockoutAuthSetMask = 1U << 2;
32const trunks::TPMA_PERMANENT kInLockoutMask = 1U << 9;
33
34// From definition of TPMA_STARTUP_CLEAR.
35const trunks::TPMA_STARTUP_CLEAR kPlatformHierarchyMask = 1U;
36const trunks::TPMA_STARTUP_CLEAR kStorageHierarchyMask = 1U << 1;
37const trunks::TPMA_STARTUP_CLEAR kEndorsementHierarchyMask = 1U << 2;
38const trunks::TPMA_STARTUP_CLEAR kOrderlyShutdownMask = 1U << 31;
39
40}  // namespace
41
42namespace trunks {
43
44TpmStateImpl::TpmStateImpl(const TrunksFactory& factory) : factory_(factory) {}
45
46TPM_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
67bool TpmStateImpl::IsOwnerPasswordSet() {
68  CHECK(initialized_);
69  return ((tpm_properties_[TPM_PT_PERMANENT] & kOwnerAuthSetMask) ==
70          kOwnerAuthSetMask);
71}
72
73bool TpmStateImpl::IsEndorsementPasswordSet() {
74  CHECK(initialized_);
75  return ((tpm_properties_[TPM_PT_PERMANENT] & kEndorsementAuthSetMask) ==
76          kEndorsementAuthSetMask);
77}
78
79bool TpmStateImpl::IsLockoutPasswordSet() {
80  CHECK(initialized_);
81  return ((tpm_properties_[TPM_PT_PERMANENT] & kLockoutAuthSetMask) ==
82          kLockoutAuthSetMask);
83}
84
85bool TpmStateImpl::IsOwned() {
86  return (IsOwnerPasswordSet() && IsEndorsementPasswordSet() &&
87          IsLockoutPasswordSet());
88}
89
90bool TpmStateImpl::IsInLockout() {
91  CHECK(initialized_);
92  return ((tpm_properties_[TPM_PT_PERMANENT] & kInLockoutMask) ==
93          kInLockoutMask);
94}
95
96bool TpmStateImpl::IsPlatformHierarchyEnabled() {
97  CHECK(initialized_);
98  return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kPlatformHierarchyMask) ==
99          kPlatformHierarchyMask);
100}
101
102bool TpmStateImpl::IsStorageHierarchyEnabled() {
103  CHECK(initialized_);
104  return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kStorageHierarchyMask) ==
105          kStorageHierarchyMask);
106}
107
108bool TpmStateImpl::IsEndorsementHierarchyEnabled() {
109  CHECK(initialized_);
110  return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kEndorsementHierarchyMask) ==
111          kEndorsementHierarchyMask);
112}
113
114bool TpmStateImpl::IsEnabled() {
115  return (!IsPlatformHierarchyEnabled() && IsStorageHierarchyEnabled() &&
116          IsEndorsementHierarchyEnabled());
117}
118
119bool TpmStateImpl::WasShutdownOrderly() {
120  CHECK(initialized_);
121  return ((tpm_properties_[TPM_PT_STARTUP_CLEAR] & kOrderlyShutdownMask) ==
122          kOrderlyShutdownMask);
123}
124
125bool TpmStateImpl::IsRSASupported() {
126  CHECK(initialized_);
127  return (algorithm_properties_.count(TPM_ALG_RSA) > 0);
128}
129
130bool TpmStateImpl::IsECCSupported() {
131  CHECK(initialized_);
132  return (algorithm_properties_.count(TPM_ALG_ECC) > 0);
133}
134
135uint32_t TpmStateImpl::GetLockoutCounter() {
136  CHECK(initialized_);
137  return tpm_properties_[TPM_PT_LOCKOUT_COUNTER];
138}
139
140uint32_t TpmStateImpl::GetLockoutThreshold() {
141  CHECK(initialized_);
142  return tpm_properties_[TPM_PT_MAX_AUTH_FAIL];
143}
144
145uint32_t TpmStateImpl::GetLockoutInterval() {
146  CHECK(initialized_);
147  return tpm_properties_[TPM_PT_LOCKOUT_INTERVAL];
148}
149
150uint32_t TpmStateImpl::GetLockoutRecovery() {
151  CHECK(initialized_);
152  return tpm_properties_[TPM_PT_LOCKOUT_RECOVERY];
153}
154
155uint32_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
169bool 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
180bool 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
192TPM_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
226TPM_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
253TPM_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