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
21#include "trunks/error_codes.h"
22#include "trunks/tpm_generated.h"
23#include "trunks/trunks_factory.h"
24
25namespace {
26
27// From definition of TPMA_PERMANENT.
28const trunks::TPMA_PERMANENT kOwnerAuthSetMask = 1U;
29const trunks::TPMA_PERMANENT kEndorsementAuthSetMask = 1U << 1;
30const trunks::TPMA_PERMANENT kLockoutAuthSetMask = 1U << 2;
31const trunks::TPMA_PERMANENT kInLockoutMask = 1U << 9;
32
33// From definition of TPMA_STARTUP_CLEAR.
34const trunks::TPMA_STARTUP_CLEAR kPlatformHierarchyMask = 1U;
35const trunks::TPMA_STARTUP_CLEAR kStorageHierarchyMask = 1U << 1;
36const trunks::TPMA_STARTUP_CLEAR kEndorsementHierarchyMask = 1U << 2;
37const trunks::TPMA_STARTUP_CLEAR kOrderlyShutdownMask = 1U << 31;
38
39// From definition of TPMA_ALGORITHM
40const trunks::TPMA_ALGORITHM kAsymmetricAlgMask = 1U;
41
42}  // namespace
43
44namespace trunks {
45
46TpmStateImpl::TpmStateImpl(const TrunksFactory& factory)
47    : factory_(factory),
48      initialized_(false),
49      permanent_flags_(0),
50      startup_clear_flags_(0),
51      rsa_flags_(0),
52      ecc_flags_(0) {
53}
54
55TpmStateImpl::~TpmStateImpl() {}
56
57TPM_RC TpmStateImpl::Initialize() {
58  TPM_RC result = GetTpmProperty(TPM_PT_PERMANENT, &permanent_flags_);
59  if (result != TPM_RC_SUCCESS) {
60    LOG(ERROR) << "Error getting permanent flags: " << GetErrorString(result);
61    return result;
62  }
63  result = GetTpmProperty(TPM_PT_STARTUP_CLEAR, &startup_clear_flags_);
64  if (result != TPM_RC_SUCCESS) {
65    LOG(ERROR) << "Error getting startup flags: " << GetErrorString(result);
66    return result;
67  }
68  result = GetTpmProperty(TPM_PT_LOCKOUT_COUNTER, &lockout_counter_);
69  if (result != TPM_RC_SUCCESS) {
70    LOG(ERROR) << "Error getting lockout counter: " << GetErrorString(result);
71    return result;
72  }
73  result = GetTpmProperty(TPM_PT_MAX_AUTH_FAIL, &lockout_threshold_);
74  if (result != TPM_RC_SUCCESS) {
75    LOG(ERROR) << "Error getting lockout threshold: " << GetErrorString(result);
76    return result;
77  }
78  result = GetTpmProperty(TPM_PT_LOCKOUT_INTERVAL, &lockout_interval_);
79  if (result != TPM_RC_SUCCESS) {
80    LOG(ERROR) << "Error getting lockout interval: " << GetErrorString(result);
81    return result;
82  }
83  result = GetTpmProperty(TPM_PT_LOCKOUT_RECOVERY, &lockout_recovery_);
84  if (result != TPM_RC_SUCCESS) {
85    LOG(ERROR) << "Error getting lockout recovery: " << GetErrorString(result);
86    return result;
87  }
88
89  TPMI_YES_NO more_data;
90  TPMS_CAPABILITY_DATA capability_data;
91  result = factory_.GetTpm()->GetCapabilitySync(TPM_CAP_ALGS,
92                                                TPM_ALG_RSA,
93                                                1,  // There is only one value.
94                                                &more_data,
95                                                &capability_data,
96                                                nullptr);
97  if (result) {
98    LOG(ERROR) << __func__ << ": " << GetErrorString(result);
99    return result;
100  }
101  if (capability_data.capability != TPM_CAP_ALGS ||
102      capability_data.data.algorithms.count != 1) {
103    LOG(ERROR) << __func__ << ": Unexpected capability data.";
104    return SAPI_RC_MALFORMED_RESPONSE;
105  }
106  if (capability_data.data.algorithms.alg_properties[0].alg == TPM_ALG_RSA) {
107    rsa_flags_ =
108        capability_data.data.algorithms.alg_properties[0].alg_properties;
109  }
110  result = factory_.GetTpm()->GetCapabilitySync(TPM_CAP_ALGS,
111                                                TPM_ALG_ECC,
112                                                1,  // There is only one value.
113                                                &more_data,
114                                                &capability_data,
115                                                nullptr);
116  if (result) {
117    LOG(ERROR) << __func__ << ": " << GetErrorString(result);
118    return result;
119  }
120  if (capability_data.capability != TPM_CAP_ALGS ||
121      capability_data.data.algorithms.count != 1) {
122    LOG(ERROR) << __func__ << ": Unexpected capability data.";
123    return SAPI_RC_MALFORMED_RESPONSE;
124  }
125  if (capability_data.data.algorithms.alg_properties[0].alg == TPM_ALG_ECC) {
126    ecc_flags_ =
127        capability_data.data.algorithms.alg_properties[0].alg_properties;
128  }
129  initialized_ = true;
130  return TPM_RC_SUCCESS;
131}
132
133bool TpmStateImpl::IsOwnerPasswordSet() {
134  CHECK(initialized_);
135  return ((permanent_flags_ & kOwnerAuthSetMask) == kOwnerAuthSetMask);
136}
137
138bool TpmStateImpl::IsEndorsementPasswordSet() {
139  CHECK(initialized_);
140  return ((permanent_flags_ & kEndorsementAuthSetMask) ==
141          kEndorsementAuthSetMask);
142}
143
144bool TpmStateImpl::IsLockoutPasswordSet() {
145  CHECK(initialized_);
146  return ((permanent_flags_ & kLockoutAuthSetMask) == kLockoutAuthSetMask);
147}
148
149bool TpmStateImpl::IsOwned() {
150  return (IsOwnerPasswordSet() &&
151          IsEndorsementPasswordSet() &&
152          IsLockoutPasswordSet());
153}
154
155bool TpmStateImpl::IsInLockout() {
156  CHECK(initialized_);
157  return ((permanent_flags_ & kInLockoutMask) == kInLockoutMask);
158}
159
160bool TpmStateImpl::IsPlatformHierarchyEnabled() {
161  CHECK(initialized_);
162  return ((startup_clear_flags_ & kPlatformHierarchyMask) ==
163      kPlatformHierarchyMask);
164}
165
166bool TpmStateImpl::IsStorageHierarchyEnabled() {
167  CHECK(initialized_);
168  return ((startup_clear_flags_ & kStorageHierarchyMask) ==
169      kStorageHierarchyMask);
170}
171
172bool TpmStateImpl::IsEndorsementHierarchyEnabled() {
173  CHECK(initialized_);
174  return ((startup_clear_flags_ & kEndorsementHierarchyMask) ==
175      kEndorsementHierarchyMask);
176}
177
178bool TpmStateImpl::IsEnabled() {
179  return (!IsPlatformHierarchyEnabled() &&
180          IsStorageHierarchyEnabled() &&
181          IsEndorsementHierarchyEnabled());
182}
183
184bool TpmStateImpl::WasShutdownOrderly() {
185  CHECK(initialized_);
186  return ((startup_clear_flags_ & kOrderlyShutdownMask) ==
187      kOrderlyShutdownMask);
188}
189
190bool TpmStateImpl::IsRSASupported() {
191  CHECK(initialized_);
192  return ((rsa_flags_ & kAsymmetricAlgMask) == kAsymmetricAlgMask);
193}
194
195bool TpmStateImpl::IsECCSupported() {
196  CHECK(initialized_);
197  return ((ecc_flags_ & kAsymmetricAlgMask) == kAsymmetricAlgMask);
198}
199
200uint32_t TpmStateImpl::GetLockoutCounter() {
201  CHECK(initialized_);
202  return lockout_counter_;
203}
204
205uint32_t TpmStateImpl::GetLockoutThreshold() {
206  CHECK(initialized_);
207  return lockout_threshold_;
208}
209
210uint32_t TpmStateImpl::GetLockoutInterval() {
211  CHECK(initialized_);
212  return lockout_interval_;
213}
214
215uint32_t TpmStateImpl::GetLockoutRecovery() {
216  CHECK(initialized_);
217  return lockout_recovery_;
218}
219
220TPM_RC TpmStateImpl::GetTpmProperty(uint32_t property,
221                                    uint32_t* value) {
222  CHECK(value);
223  TPMI_YES_NO more_data;
224  TPMS_CAPABILITY_DATA capability_data;
225  TPM_RC result = factory_.GetTpm()->GetCapabilitySync(TPM_CAP_TPM_PROPERTIES,
226                                                       property,
227                                                       1,  // Only one property.
228                                                       &more_data,
229                                                       &capability_data,
230                                                       nullptr);
231  if (result != TPM_RC_SUCCESS) {
232    LOG(ERROR) << __func__ << ": " << GetErrorString(result);
233    return result;
234  }
235  if (capability_data.capability != TPM_CAP_TPM_PROPERTIES ||
236      capability_data.data.tpm_properties.count != 1 ||
237      capability_data.data.tpm_properties.tpm_property[0].property !=
238      property) {
239    LOG(ERROR) << __func__ << ": Unexpected capability data.";
240    return SAPI_RC_MALFORMED_RESPONSE;
241  }
242  *value = capability_data.data.tpm_properties.tpm_property[0].value;
243  return TPM_RC_SUCCESS;
244}
245
246}  // namespace trunks
247