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