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 
31 namespace {
32 
33 const char kDefaultOwnerPassword[] = TSS_WELL_KNOWN_SECRET;
34 const size_t kDefaultPasswordSize = 20;
35 const int kMaxOwnershipTimeoutRetries = 5;
36 const char* kWellKnownSrkSecret = "well_known_srk_secret";
37 
38 }  // namespace
39 
40 namespace tpm_manager {
41 
TpmInitializerImpl(LocalDataStore * local_data_store,TpmStatus * tpm_status)42 TpmInitializerImpl::TpmInitializerImpl(LocalDataStore* local_data_store,
43                                        TpmStatus* tpm_status)
44     : local_data_store_(local_data_store),
45       tpm_status_(tpm_status) {}
46 
InitializeTpm()47 bool 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 
InitializeEndorsementKey(TSS_HTPM tpm_handle)82 bool 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 
TakeOwnership(TSS_HTPM tpm_handle)110 bool 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 
InitializeSrk(TSS_HTPM tpm_handle)162 bool 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 
ChangeOwnerPassword(TSS_HTPM tpm_handle,const std::string & owner_password)217 bool 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 
TestTpmAuth(const std::string & owner_password)245 bool 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