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 ¤t_status))) {
254 return false;
255 }
256 return true;
257 }
258
259 } // namespace tpm_manager
260