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 // Don't use directly, use GetDefaultOwnerPassword().
34 const char kDefaultOwnerPassword[] = TSS_WELL_KNOWN_SECRET;
35 const size_t kDefaultPasswordSize = 20;
36 const int kMaxOwnershipTimeoutRetries = 5;
37 const char* kWellKnownSrkSecret = "well_known_srk_secret";
38 
GetDefaultOwnerPassword()39 std::string GetDefaultOwnerPassword() {
40   return std::string(kDefaultOwnerPassword, kDefaultPasswordSize);
41 }
42 
43 }  // namespace
44 
45 namespace tpm_manager {
46 
TpmInitializerImpl(LocalDataStore * local_data_store,TpmStatus * tpm_status)47 TpmInitializerImpl::TpmInitializerImpl(LocalDataStore* local_data_store,
48                                        TpmStatus* tpm_status)
49     : local_data_store_(local_data_store), tpm_status_(tpm_status) {}
50 
InitializeTpm()51 bool 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 
VerifiedBootHelper()82 void TpmInitializerImpl::VerifiedBootHelper() {
83   // Nothing to do.
84 }
85 
ResetDictionaryAttackLock()86 bool TpmInitializerImpl::ResetDictionaryAttackLock() {
87   LOG(WARNING) << __func__ << ": Not implemented.";
88   return false;
89 }
90 
InitializeEndorsementKey(TpmConnection * connection)91 bool 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 
TakeOwnership(TpmConnection * connection)116 bool 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 
InitializeSrk(TpmConnection * connection)165 bool 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 
ChangeOwnerPassword(TpmConnection * connection,const std::string & owner_password)214 bool 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 
TestTpmAuth(const std::string & owner_password)243 bool 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