1//
2// Copyright (C) 2015 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 "tpm_manager/server/tpm_initializer_impl.h"
18
19#include <string>
20
21#include <base/logging.h>
22#include <base/stl_util.h>
23#include <trousers/scoped_tss_type.h>
24
25#include "tpm_manager/server/local_data_store.h"
26#include "tpm_manager/server/tpm_connection.h"
27#include "tpm_manager/common/tpm_manager_constants.h"
28#include "tpm_manager/server/tpm_status.h"
29#include "tpm_manager/server/tpm_util.h"
30
31namespace {
32
33// Don't use directly, use GetDefaultOwnerPassword().
34const char kDefaultOwnerPassword[] = TSS_WELL_KNOWN_SECRET;
35const size_t kDefaultPasswordSize = 20;
36const int kMaxOwnershipTimeoutRetries = 5;
37const char* kWellKnownSrkSecret = "well_known_srk_secret";
38
39std::string GetDefaultOwnerPassword() {
40  return std::string(kDefaultOwnerPassword, kDefaultPasswordSize);
41}
42
43}  // namespace
44
45namespace tpm_manager {
46
47TpmInitializerImpl::TpmInitializerImpl(LocalDataStore* local_data_store,
48                                       TpmStatus* tpm_status)
49    : local_data_store_(local_data_store), tpm_status_(tpm_status) {}
50
51bool TpmInitializerImpl::InitializeTpm() {
52  if (tpm_status_->IsTpmOwned() && !TestTpmAuth(GetDefaultOwnerPassword())) {
53    // Tpm is already owned, so we do not need to do anything.
54    VLOG(1) << "Tpm already owned.";
55    return true;
56  }
57  TpmConnection connection(GetDefaultOwnerPassword());
58  if (!InitializeEndorsementKey(&connection) || !TakeOwnership(&connection) ||
59      !InitializeSrk(&connection)) {
60    return false;
61  }
62  std::string owner_password;
63  if (!openssl_util_.GetRandomBytes(kDefaultPasswordSize, &owner_password)) {
64    return false;
65  }
66  LocalData local_data;
67  local_data.clear_owner_dependency();
68  for (auto value : kInitialTpmOwnerDependencies) {
69    local_data.add_owner_dependency(value);
70  }
71  local_data.set_owner_password(owner_password);
72  if (!local_data_store_->Write(local_data)) {
73    LOG(ERROR) << "Error saving local data.";
74    return false;
75  }
76  if (!ChangeOwnerPassword(&connection, owner_password)) {
77    return false;
78  }
79  return true;
80}
81
82void TpmInitializerImpl::VerifiedBootHelper() {
83  // Nothing to do.
84}
85
86bool TpmInitializerImpl::ResetDictionaryAttackLock() {
87  LOG(WARNING) << __func__ << ": Not implemented.";
88  return false;
89}
90
91bool TpmInitializerImpl::InitializeEndorsementKey(TpmConnection* connection) {
92  trousers::ScopedTssKey local_key_handle(connection->GetContext());
93  TSS_RESULT result = Tspi_TPM_GetPubEndorsementKey(
94      connection->GetTpm(), false, nullptr, local_key_handle.ptr());
95  if (TPM_ERROR(result) == TPM_SUCCESS) {
96    // In this case the EK already exists, so we can return true here.
97    VLOG(1) << "EK already exists.";
98    return true;
99  }
100  // At this point the EK does not exist, so we create it.
101  TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_SIZE_2048;
102  if (TPM_ERROR(result = Tspi_Context_CreateObject(
103                    connection->GetContext(), TSS_OBJECT_TYPE_RSAKEY,
104                    init_flags, local_key_handle.ptr()))) {
105    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
106    return false;
107  }
108  if (TPM_ERROR(result = Tspi_TPM_CreateEndorsementKey(
109                    connection->GetTpm(), local_key_handle, NULL))) {
110    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_CreateEndorsementKey";
111    return false;
112  }
113  return true;
114}
115
116bool TpmInitializerImpl::TakeOwnership(TpmConnection* connection) {
117  if (TestTpmAuth(GetDefaultOwnerPassword())) {
118    VLOG(1) << "The Tpm already has the default owner password.";
119    return true;
120  }
121  TSS_RESULT result;
122  trousers::ScopedTssKey srk_handle(connection->GetContext());
123  TSS_FLAG init_flags = TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION;
124  if (TPM_ERROR(result = Tspi_Context_CreateObject(
125                    connection->GetContext(), TSS_OBJECT_TYPE_RSAKEY,
126                    init_flags, srk_handle.ptr()))) {
127    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
128    return false;
129  }
130  TSS_HPOLICY srk_usage_policy;
131  if (TPM_ERROR(result = Tspi_GetPolicyObject(srk_handle, TSS_POLICY_USAGE,
132                                              &srk_usage_policy))) {
133    TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject";
134    return false;
135  }
136  if (TPM_ERROR(result = Tspi_Policy_SetSecret(
137                    srk_usage_policy, TSS_SECRET_MODE_PLAIN,
138                    strlen(kWellKnownSrkSecret),
139                    const_cast<BYTE*>(
140                        reinterpret_cast<const BYTE*>(kWellKnownSrkSecret))))) {
141    TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
142    return false;
143  }
144  // Tspi_TPM_TakeOwnership can potentially take a long time to complete,
145  // so we retry if there is a timeout in any layer. I chose 5, because the
146  // longest TakeOwnership call that I have seen took ~2min, and the default
147  // TSS timeout is 30s. This means that after 5 calls, it is quite likely that
148  // this call will succeed.
149  int retry_count = 0;
150  do {
151    result = Tspi_TPM_TakeOwnership(connection->GetTpm(), srk_handle, 0);
152    retry_count++;
153  } while (((result == TDDL_E_TIMEOUT) ||
154            (result == (TSS_LAYER_TDDL | TDDL_E_TIMEOUT)) ||
155            (result == (TSS_LAYER_TDDL | TDDL_E_IOERROR))) &&
156           (retry_count < kMaxOwnershipTimeoutRetries));
157  if (result) {
158    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_TakeOwnership, attempts: "
159                           << retry_count;
160    return false;
161  }
162  return true;
163}
164
165bool TpmInitializerImpl::InitializeSrk(TpmConnection* connection) {
166  TSS_RESULT result;
167  trousers::ScopedTssKey srk_handle(connection->GetContext());
168  TSS_UUID SRK_UUID = TSS_UUID_SRK;
169  if (TPM_ERROR(result = Tspi_Context_LoadKeyByUUID(
170                    connection->GetContext(), TSS_PS_TYPE_SYSTEM, SRK_UUID,
171                    srk_handle.ptr()))) {
172    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_LoadKeyByUUID";
173    return false;
174  }
175
176  trousers::ScopedTssPolicy policy_handle(connection->GetContext());
177  if (TPM_ERROR(result = Tspi_Context_CreateObject(
178                    connection->GetContext(), TSS_OBJECT_TYPE_POLICY,
179                    TSS_POLICY_USAGE, policy_handle.ptr()))) {
180    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
181    return false;
182  }
183  BYTE new_password[0];
184  if (TPM_ERROR(result = Tspi_Policy_SetSecret(
185                    policy_handle, TSS_SECRET_MODE_PLAIN, 0, new_password))) {
186    TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
187    return false;
188  }
189
190  if (TPM_ERROR(result = Tspi_ChangeAuth(srk_handle, connection->GetTpm(),
191                                         policy_handle))) {
192    TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth";
193    return false;
194  }
195  TSS_BOOL is_srk_restricted = false;
196  if (TPM_ERROR(result = Tspi_TPM_GetStatus(connection->GetTpm(),
197                                            TSS_TPMSTATUS_DISABLEPUBSRKREAD,
198                                            &is_srk_restricted))) {
199    TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetStatus";
200    return false;
201  }
202  // If the SRK is restricted, we unrestrict it.
203  if (is_srk_restricted) {
204    if (TPM_ERROR(result = Tspi_TPM_SetStatus(connection->GetTpm(),
205                                              TSS_TPMSTATUS_DISABLEPUBSRKREAD,
206                                              false))) {
207      TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_SetStatus";
208      return false;
209    }
210  }
211  return true;
212}
213
214bool TpmInitializerImpl::ChangeOwnerPassword(
215    TpmConnection* connection,
216    const std::string& owner_password) {
217  TSS_RESULT result;
218  trousers::ScopedTssPolicy policy_handle(connection->GetContext());
219  if (TPM_ERROR(result = Tspi_Context_CreateObject(
220                    connection->GetContext(), TSS_OBJECT_TYPE_POLICY,
221                    TSS_POLICY_USAGE, policy_handle.ptr()))) {
222    TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject";
223    return false;
224  }
225  std::string mutable_owner_password(owner_password);
226  if (TPM_ERROR(result = Tspi_Policy_SetSecret(
227                    policy_handle, TSS_SECRET_MODE_PLAIN, owner_password.size(),
228                    reinterpret_cast<BYTE*>(
229                        string_as_array(&mutable_owner_password))))) {
230    TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret";
231    return false;
232  }
233
234  if (TPM_ERROR(result =
235                    Tspi_ChangeAuth(connection->GetTpm(), 0, policy_handle))) {
236    TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth";
237    return false;
238  }
239
240  return true;
241}
242
243bool TpmInitializerImpl::TestTpmAuth(const std::string& owner_password) {
244  TpmConnection connection(owner_password);
245  TSS_HTPM tpm_handle = connection.GetTpm();
246  if (tpm_handle == 0) {
247    return false;
248  }
249  // Call Tspi_TPM_GetStatus to test the |owner_password| provided.
250  TSS_RESULT result;
251  TSS_BOOL current_status = false;
252  if (TPM_ERROR(result = Tspi_TPM_GetStatus(tpm_handle, TSS_TPMSTATUS_DISABLED,
253                                            &current_status))) {
254    return false;
255  }
256  return true;
257}
258
259}  // namespace tpm_manager
260