OLD | NEW |
1 // Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 // Contains the implementation of class Tpm | 5 // Contains the implementation of class Tpm |
6 | 6 |
7 #include "tpm.h" | 7 #include "tpm.h" |
8 | 8 |
9 #include <base/file_util.h> | 9 #include <base/file_util.h> |
10 #include <base/platform_thread.h> | 10 #include <base/platform_thread.h> |
11 #include <base/time.h> | 11 #include <base/time.h> |
12 #include <openssl/rsa.h> | 12 #include <openssl/rsa.h> |
13 #include <trousers/tss.h> | 13 #include <trousers/tss.h> |
14 #include <trousers/trousers.h> | 14 #include <trousers/trousers.h> |
15 | 15 |
16 namespace tpm_init { | 16 namespace tpm_init { |
| 17 #define TPM_LOG(severity, result) \ |
| 18 LOG(severity) << "TPM error 0x" << std::hex << result \ |
| 19 << " (" << Trspi_Error_String(result) << "): " |
| 20 |
17 | 21 |
18 const char* kWellKnownSrkTmp = "1234567890"; | 22 const char* kWellKnownSrkTmp = "1234567890"; |
19 const int kOwnerPasswordLength = 12; | 23 const int kOwnerPasswordLength = 12; |
20 const int kMaxTimeoutRetries = 5; | 24 const int kMaxTimeoutRetries = 5; |
21 const char* kTpmCheckEnabledFile = "/sys/class/misc/tpm0/device/enabled"; | 25 const char* kTpmCheckEnabledFile = "/sys/class/misc/tpm0/device/enabled"; |
22 const char* kTpmCheckOwnedFile = "/sys/class/misc/tpm0/device/owned"; | 26 const char* kTpmCheckOwnedFile = "/sys/class/misc/tpm0/device/owned"; |
23 const char* kTpmOwnedFile = "/var/lib/.tpm_owned"; | 27 const char* kTpmOwnedFile = "/var/lib/.tpm_owned"; |
| 28 const char* kTpmStatusFile = "/var/lib/.tpm_status"; |
24 const char* kOpenCryptokiPath = "/var/lib/opencryptoki"; | 29 const char* kOpenCryptokiPath = "/var/lib/opencryptoki"; |
25 const int kTpmConnectRetries = 10; | 30 const int kTpmConnectRetries = 10; |
26 const int kTpmConnectIntervalMs = 100; | 31 const int kTpmConnectIntervalMs = 100; |
27 const char kTpmWellKnownPassword[] = TSS_WELL_KNOWN_SECRET; | 32 const char kTpmWellKnownPassword[] = TSS_WELL_KNOWN_SECRET; |
| 33 const char kTpmOwnedWithWellKnown = 'W'; |
| 34 const char kTpmOwnedWithRandom = 'R'; |
28 | 35 |
29 Tpm::Tpm() | 36 Tpm::Tpm() |
30 : context_handle_(0), | 37 : default_crypto_(new Crypto()), |
31 default_crypto_(new Crypto()), | |
32 crypto_(default_crypto_.get()), | 38 crypto_(default_crypto_.get()), |
| 39 default_platform_(new Platform()), |
| 40 platform_(default_platform_.get()), |
33 owner_password_(), | 41 owner_password_(), |
34 password_sync_lock_(), | 42 password_sync_lock_(), |
35 is_disabled_(true), | 43 is_disabled_(true), |
36 is_owned_(false), | 44 is_owned_(false), |
37 is_srk_available_(false), | 45 is_srk_available_(false), |
38 is_being_owned_(false) { | 46 is_being_owned_(false) { |
39 } | 47 } |
40 | 48 |
41 Tpm::~Tpm() { | 49 Tpm::~Tpm() { |
42 Disconnect(); | |
43 } | 50 } |
44 | 51 |
45 bool Tpm::Init() { | 52 bool Tpm::Init() { |
46 // Checking disabled and owned either via sysfs or via TSS calls will block if | 53 // Checking disabled and owned either via sysfs or via TSS calls will block if |
47 // ownership is being taken by another thread or process. So for this to work | 54 // ownership is being taken by another thread or process. So for this to work |
48 // well, Tpm::Init() needs to be called before InitializeTpm() is called. At | 55 // well, Tpm::Init() needs to be called before InitializeTpm() is called. At |
49 // that point, the public API for Tpm only checks these booleans, so other | 56 // that point, the public API for Tpm only checks these booleans, so other |
50 // threads can check without being blocked. InitializeTpm() will reset the | 57 // threads can check without being blocked. InitializeTpm() will reset the |
51 // is_owned_ bit on success. | 58 // is_owned_ bit on success. |
| 59 bool successful_check = false; |
52 if (file_util::PathExists(FilePath(kTpmCheckEnabledFile))) { | 60 if (file_util::PathExists(FilePath(kTpmCheckEnabledFile))) { |
53 is_disabled_ = IsDisabledCheckViaSysfs(); | 61 is_disabled_ = IsDisabledCheckViaSysfs(); |
54 is_owned_ = IsOwnedCheckViaSysfs(); | 62 is_owned_ = IsOwnedCheckViaSysfs(); |
| 63 successful_check = true; |
55 } else { | 64 } else { |
56 TSS_HCONTEXT context_handle; | 65 TSS_HCONTEXT context_handle; |
57 if (OpenAndConnectTpm(&context_handle)) { | 66 if (OpenAndConnectTpm(&context_handle)) { |
58 bool enabled = false; | 67 bool enabled = false; |
59 bool owned = false; | 68 bool owned = false; |
60 IsEnabledOwnedCheckViaContext(context_handle, &enabled, &owned); | 69 IsEnabledOwnedCheckViaContext(context_handle, &enabled, &owned); |
61 is_disabled_ = !enabled; | 70 is_disabled_ = !enabled; |
62 is_owned_ = owned; | 71 is_owned_ = owned; |
63 Tspi_Context_Close(context_handle); | 72 Tspi_Context_Close(context_handle); |
64 } else { | 73 successful_check = true; |
65 } | 74 } |
66 } | 75 } |
67 return true; | 76 if (successful_check && !is_owned_) { |
68 } | 77 file_util::Delete(FilePath(kOpenCryptokiPath), true); |
69 | 78 file_util::Delete(FilePath(kTpmOwnedFile), false); |
70 bool Tpm::Connect() { | 79 file_util::Delete(FilePath(kTpmStatusFile), false); |
71 if (context_handle_ == 0) { | 80 } |
72 TSS_HCONTEXT context_handle; | 81 TpmStatus tpm_status; |
73 if (!OpenAndConnectTpm(&context_handle)) { | 82 if (LoadTpmStatus(&tpm_status)) { |
74 return false; | 83 if (tpm_status.has_owner_password()) { |
| 84 SecureBlob local_owner_password; |
| 85 if (LoadOwnerPassword(tpm_status, &local_owner_password)) { |
| 86 password_sync_lock_.Acquire(); |
| 87 owner_password_.assign(local_owner_password.begin(), |
| 88 local_owner_password.end()); |
| 89 password_sync_lock_.Release(); |
| 90 } |
75 } | 91 } |
76 | |
77 context_handle_ = context_handle; | |
78 } | 92 } |
79 | 93 |
80 return true; | 94 return true; |
81 } | 95 } |
82 | 96 |
83 bool Tpm::IsConnected() { | 97 TSS_HCONTEXT Tpm::Connect() { |
84 return (context_handle_ != 0); | 98 TSS_HCONTEXT context_handle; |
| 99 if (!OpenAndConnectTpm(&context_handle)) { |
| 100 return NULL; |
| 101 } |
| 102 |
| 103 return context_handle; |
85 } | 104 } |
86 | 105 |
87 void Tpm::Disconnect() { | 106 void Tpm::Disconnect(TSS_HCONTEXT context_handle) { |
88 if (context_handle_) { | 107 if (context_handle) { |
89 Tspi_Context_Close(context_handle_); | 108 Tspi_Context_Close(context_handle); |
90 context_handle_ = 0; | |
91 } | 109 } |
92 } | 110 } |
93 | 111 |
94 int Tpm::GetMaxRsaKeyCount() { | 112 int Tpm::GetMaxRsaKeyCount() { |
95 if (context_handle_ == 0) { | 113 TSS_HCONTEXT context_handle = Connect(); |
| 114 if (!context_handle) { |
96 return -1; | 115 return -1; |
97 } | 116 } |
| 117 int count = GetMaxRsaKeyCountForContext(context_handle); |
| 118 Disconnect(context_handle); |
| 119 return count; |
| 120 } |
98 | 121 |
99 return GetMaxRsaKeyCountForContext(context_handle_); | 122 bool Tpm::IsDisabledCheckViaSysfs() { |
| 123 std::string contents; |
| 124 if (!file_util::ReadFileToString(FilePath(kTpmCheckEnabledFile), &contents)) { |
| 125 return false; |
| 126 } |
| 127 if (contents.size() < 1) { |
| 128 return false; |
| 129 } |
| 130 return (contents[0] == '0'); |
| 131 } |
| 132 |
| 133 bool Tpm::IsOwnedCheckViaSysfs() { |
| 134 std::string contents; |
| 135 if (!file_util::ReadFileToString(FilePath(kTpmCheckOwnedFile), &contents)) { |
| 136 return false; |
| 137 } |
| 138 if (contents.size() < 1) { |
| 139 return false; |
| 140 } |
| 141 return (contents[0] != '0'); |
100 } | 142 } |
101 | 143 |
102 int Tpm::GetMaxRsaKeyCountForContext(TSS_HCONTEXT context_handle) { | 144 int Tpm::GetMaxRsaKeyCountForContext(TSS_HCONTEXT context_handle) { |
103 int count = -1; | 145 int count = -1; |
104 TSS_RESULT result; | 146 TSS_RESULT result; |
105 TSS_HTPM tpm_handle; | 147 TSS_HTPM tpm_handle; |
106 if (!GetTpm(context_handle, &tpm_handle)) { | 148 if (!GetTpm(context_handle, &tpm_handle)) { |
107 return count; | 149 return count; |
108 } | 150 } |
109 | 151 |
110 UINT32 cap_length = 0; | 152 UINT32 cap_length = 0; |
111 BYTE* cap = NULL; | 153 BYTE* cap = NULL; |
112 UINT32 subcap = TSS_TPMCAP_PROP_MAXKEYS; | 154 UINT32 subcap = TSS_TPMCAP_PROP_MAXKEYS; |
113 if ((result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_PROPERTY, | 155 if ((result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_PROPERTY, |
114 sizeof(subcap), | 156 sizeof(subcap), |
115 reinterpret_cast<BYTE*>(&subcap), | 157 reinterpret_cast<BYTE*>(&subcap), |
116 &cap_length, &cap))) { | 158 &cap_length, &cap))) { |
117 LOG(ERROR) << "Error calling Tspi_TPM_GetCapability: " << result; | 159 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetCapability"; |
118 return count; | 160 return count; |
119 } | 161 } |
120 if (cap_length == sizeof(int)) { | 162 if (cap_length == sizeof(int)) { |
121 count = *(reinterpret_cast<int*>(cap)); | 163 count = *(reinterpret_cast<int*>(cap)); |
122 } | 164 } |
123 Tspi_Context_FreeMemory(context_handle, cap); | 165 Tspi_Context_FreeMemory(context_handle, cap); |
124 return count; | 166 return count; |
125 } | 167 } |
126 | 168 |
127 bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle) { | 169 bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle) { |
128 TSS_RESULT result; | 170 TSS_RESULT result; |
129 TSS_HCONTEXT local_context_handle; | 171 TSS_HCONTEXT local_context_handle; |
130 if ((result = Tspi_Context_Create(&local_context_handle))) { | 172 if ((result = Tspi_Context_Create(&local_context_handle))) { |
131 LOG(ERROR) << "Error calling Tspi_Context_Create"; | 173 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Create"; |
132 return false; | 174 return false; |
133 } | 175 } |
134 | 176 |
135 for (int i = 0; i < kTpmConnectRetries; i++) { | 177 for (int i = 0; i < kTpmConnectRetries; i++) { |
136 if ((result = Tspi_Context_Connect(local_context_handle, NULL))) { | 178 if ((result = Tspi_Context_Connect(local_context_handle, NULL))) { |
137 if (result == TSS_E_COMM_FAILURE) { | 179 if (result == TSS_E_COMM_FAILURE) { |
138 PlatformThread::Sleep(kTpmConnectIntervalMs); | 180 PlatformThread::Sleep(kTpmConnectIntervalMs); |
139 } else { | 181 } else { |
140 LOG(ERROR) << "Error calling Tspi_Context_Connect: " << result; | 182 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Connect"; |
141 Tspi_Context_Close(local_context_handle); | 183 Tspi_Context_Close(local_context_handle); |
142 return false; | 184 return false; |
143 } | 185 } |
144 } else { | 186 } else { |
145 break; | 187 break; |
146 } | 188 } |
147 } | 189 } |
148 | 190 |
149 if (result) { | 191 if (result) { |
150 LOG(ERROR) << "Error calling Tspi_Context_Connect: " << result; | 192 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_Connect"; |
151 Tspi_Context_Close(local_context_handle); | 193 Tspi_Context_Close(local_context_handle); |
152 return false; | 194 return false; |
153 } | 195 } |
154 | 196 |
155 *context_handle = local_context_handle; | 197 *context_handle = local_context_handle; |
156 return true; | 198 return true; |
157 } | 199 } |
158 | 200 |
159 bool Tpm::IsDisabledCheckViaSysfs() { | |
160 std::string contents; | |
161 if (!file_util::ReadFileToString(FilePath(kTpmCheckEnabledFile), &contents)) { | |
162 return false; | |
163 } | |
164 if (contents.size() < 1) { | |
165 return false; | |
166 } | |
167 return (contents[0] == '0'); | |
168 } | |
169 | |
170 bool Tpm::IsOwnedCheckViaSysfs() { | |
171 std::string contents; | |
172 if (!file_util::ReadFileToString(FilePath(kTpmCheckOwnedFile), &contents)) { | |
173 return false; | |
174 } | |
175 if (contents.size() < 1) { | |
176 return false; | |
177 } | |
178 return (contents[0] != '0'); | |
179 } | |
180 | |
181 void Tpm::IsEnabledOwnedCheckViaContext(TSS_HCONTEXT context_handle, | 201 void Tpm::IsEnabledOwnedCheckViaContext(TSS_HCONTEXT context_handle, |
182 bool* enabled, bool* owned) { | 202 bool* enabled, bool* owned) { |
183 *enabled = false; | 203 *enabled = false; |
184 *owned = false; | 204 *owned = false; |
185 | 205 |
186 TSS_RESULT result; | 206 TSS_RESULT result; |
187 TSS_HTPM tpm_handle; | 207 TSS_HTPM tpm_handle; |
188 if (!GetTpm(context_handle, &tpm_handle)) { | 208 if (!GetTpm(context_handle, &tpm_handle)) { |
189 return; | 209 return; |
190 } | 210 } |
(...skipping 20 matching lines...) Expand all Loading... |
211 TSS_HTPM tpm_handle; | 231 TSS_HTPM tpm_handle; |
212 if (!GetTpm(context_handle, &tpm_handle)) { | 232 if (!GetTpm(context_handle, &tpm_handle)) { |
213 return false; | 233 return false; |
214 } | 234 } |
215 | 235 |
216 TSS_HKEY local_key_handle; | 236 TSS_HKEY local_key_handle; |
217 TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_SIZE_2048; | 237 TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_SIZE_2048; |
218 if ((result = Tspi_Context_CreateObject(context_handle, | 238 if ((result = Tspi_Context_CreateObject(context_handle, |
219 TSS_OBJECT_TYPE_RSAKEY, | 239 TSS_OBJECT_TYPE_RSAKEY, |
220 init_flags, &local_key_handle))) { | 240 init_flags, &local_key_handle))) { |
221 LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result; | 241 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
222 return false; | 242 return false; |
223 } | 243 } |
224 | 244 |
225 if ((result = Tspi_TPM_CreateEndorsementKey(tpm_handle, local_key_handle, | 245 if ((result = Tspi_TPM_CreateEndorsementKey(tpm_handle, local_key_handle, |
226 NULL))) { | 246 NULL))) { |
227 LOG(ERROR) << "Error calling Tspi_TPM_CreateEndorsementKey: " << result; | 247 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_CreateEndorsementKey"; |
228 Tspi_Context_CloseObject(context_handle, local_key_handle); | 248 Tspi_Context_CloseObject(context_handle, local_key_handle); |
229 return false; | 249 return false; |
230 } | 250 } |
231 | 251 |
232 return true; | 252 return true; |
233 } | 253 } |
234 | 254 |
235 bool Tpm::IsEndorsementKeyAvailable(TSS_HCONTEXT context_handle) { | 255 bool Tpm::IsEndorsementKeyAvailable(TSS_HCONTEXT context_handle) { |
236 TSS_RESULT result; | 256 TSS_RESULT result; |
237 TSS_HTPM tpm_handle; | 257 TSS_HTPM tpm_handle; |
238 if (!GetTpm(context_handle, &tpm_handle)) { | 258 if (!GetTpm(context_handle, &tpm_handle)) { |
239 return false; | 259 return false; |
240 } | 260 } |
241 | 261 |
242 TSS_HKEY local_key_handle; | 262 TSS_HKEY local_key_handle; |
243 if ((result = Tspi_TPM_GetPubEndorsementKey(tpm_handle, false, NULL, | 263 if ((result = Tspi_TPM_GetPubEndorsementKey(tpm_handle, false, NULL, |
244 &local_key_handle))) { | 264 &local_key_handle))) { |
245 LOG(ERROR) << "Error calling Tspi_TPM_GetPubEndorsementKey: " << result; | 265 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetPubEndorsementKey"; |
246 return false; | 266 return false; |
247 } | 267 } |
248 | 268 |
249 Tspi_Context_CloseObject(context_handle, local_key_handle); | 269 Tspi_Context_CloseObject(context_handle, local_key_handle); |
250 | 270 |
251 return true; | 271 return true; |
252 } | 272 } |
253 | 273 |
254 void Tpm::CreateOwnerPassword(SecureBlob* password) { | 274 void Tpm::CreateOwnerPassword(SecureBlob* password) { |
255 SecureBlob random(kOwnerPasswordLength); | 275 // Generate a random owner password. The default is a 12-character, |
| 276 // hex-encoded password created from 6 bytes of random data. |
| 277 SecureBlob random(kOwnerPasswordLength / 2); |
256 crypto_->GetSecureRandom(static_cast<unsigned char*>(random.data()), | 278 crypto_->GetSecureRandom(static_cast<unsigned char*>(random.data()), |
257 random.size()); | 279 random.size()); |
258 SecureBlob tpm_password(kOwnerPasswordLength); | 280 SecureBlob tpm_password(kOwnerPasswordLength); |
259 crypto_->AsciiEncodeToBuffer(random, static_cast<char*>(tpm_password.data()), | 281 crypto_->AsciiEncodeToBuffer(random, static_cast<char*>(tpm_password.data()), |
260 tpm_password.size()); | 282 tpm_password.size()); |
261 password->swap(tpm_password); | 283 password->swap(tpm_password); |
262 } | 284 } |
263 | 285 |
264 bool Tpm::TakeOwnership(TSS_HCONTEXT context_handle, int max_timeout_tries, | 286 bool Tpm::TakeOwnership(TSS_HCONTEXT context_handle, int max_timeout_tries, |
265 const SecureBlob& owner_password) { | 287 const SecureBlob& owner_password) { |
266 TSS_RESULT result; | 288 TSS_RESULT result; |
267 TSS_HTPM tpm_handle; | 289 TSS_HTPM tpm_handle; |
268 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) { | 290 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) { |
269 return false; | 291 return false; |
270 } | 292 } |
271 | 293 |
272 TSS_HKEY srk_handle; | 294 TSS_HKEY srk_handle; |
273 TSS_FLAG init_flags = TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION; | 295 TSS_FLAG init_flags = TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION; |
274 if ((result = Tspi_Context_CreateObject(context_handle, | 296 if ((result = Tspi_Context_CreateObject(context_handle, |
275 TSS_OBJECT_TYPE_RSAKEY, | 297 TSS_OBJECT_TYPE_RSAKEY, |
276 init_flags, &srk_handle))) { | 298 init_flags, &srk_handle))) { |
277 LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result; | 299 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
278 return false; | 300 return false; |
279 } | 301 } |
280 | 302 |
281 TSS_HPOLICY srk_usage_policy; | 303 TSS_HPOLICY srk_usage_policy; |
282 if ((result = Tspi_GetPolicyObject(srk_handle, TSS_POLICY_USAGE, | 304 if ((result = Tspi_GetPolicyObject(srk_handle, TSS_POLICY_USAGE, |
283 &srk_usage_policy))) { | 305 &srk_usage_policy))) { |
284 LOG(ERROR) << "Error calling Tspi_GetPolicyObject: " << result; | 306 TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject"; |
285 Tspi_Context_CloseObject(context_handle, srk_handle); | 307 Tspi_Context_CloseObject(context_handle, srk_handle); |
286 return false; | 308 return false; |
287 } | 309 } |
288 | 310 |
289 if ((result = Tspi_Policy_SetSecret(srk_usage_policy, | 311 if ((result = Tspi_Policy_SetSecret(srk_usage_policy, |
290 TSS_SECRET_MODE_PLAIN, | 312 TSS_SECRET_MODE_PLAIN, |
291 strlen(kWellKnownSrkTmp), | 313 strlen(kWellKnownSrkTmp), |
292 const_cast<BYTE *>(reinterpret_cast<const BYTE *>(kWellKnownSrkTmp))))) { | 314 const_cast<BYTE *>(reinterpret_cast<const BYTE *>(kWellKnownSrkTmp))))) { |
293 LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result; | 315 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; |
294 Tspi_Context_CloseObject(context_handle, srk_handle); | 316 Tspi_Context_CloseObject(context_handle, srk_handle); |
295 return false; | 317 return false; |
296 } | 318 } |
297 | 319 |
298 int retry_count = 0; | 320 int retry_count = 0; |
299 do { | 321 do { |
300 result = Tspi_TPM_TakeOwnership(tpm_handle, srk_handle, 0); | 322 result = Tspi_TPM_TakeOwnership(tpm_handle, srk_handle, 0); |
301 retry_count++; | 323 retry_count++; |
302 } while(((result == TDDL_E_TIMEOUT) || | 324 } while(((result == TDDL_E_TIMEOUT) || |
303 (result == (TSS_LAYER_TDDL | TDDL_E_TIMEOUT)) || | 325 (result == (TSS_LAYER_TDDL | TDDL_E_TIMEOUT)) || |
304 (result == (TSS_LAYER_TDDL | TDDL_E_IOERROR))) && | 326 (result == (TSS_LAYER_TDDL | TDDL_E_IOERROR))) && |
305 (retry_count < max_timeout_tries)); | 327 (retry_count < max_timeout_tries)); |
306 | 328 |
307 if (result) { | 329 if (result) { |
308 LOG(ERROR) << "Error calling Tspi_TPM_TakeOwnership: " << result | 330 TPM_LOG(ERROR, result) |
309 << ", attempts: " << retry_count; | 331 << "Error calling Tspi_TPM_TakeOwnership, attempts: " << retry_count; |
310 Tspi_Context_CloseObject(context_handle, srk_handle); | 332 Tspi_Context_CloseObject(context_handle, srk_handle); |
311 return false; | 333 return false; |
312 } | 334 } |
313 | 335 |
314 Tspi_Context_CloseObject(context_handle, srk_handle); | 336 Tspi_Context_CloseObject(context_handle, srk_handle); |
315 | 337 |
316 return true; | 338 return true; |
317 } | 339 } |
318 | 340 |
319 bool Tpm::ZeroSrkPassword(TSS_HCONTEXT context_handle, | 341 bool Tpm::ZeroSrkPassword(TSS_HCONTEXT context_handle, |
320 const SecureBlob& owner_password) { | 342 const SecureBlob& owner_password) { |
321 TSS_RESULT result; | 343 TSS_RESULT result; |
322 TSS_HTPM tpm_handle; | 344 TSS_HTPM tpm_handle; |
323 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) { | 345 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) { |
324 return false; | 346 return false; |
325 } | 347 } |
326 | 348 |
327 TSS_HKEY srk_handle; | 349 TSS_HKEY srk_handle; |
328 TSS_UUID SRK_UUID = TSS_UUID_SRK; | 350 TSS_UUID SRK_UUID = TSS_UUID_SRK; |
329 if ((result = Tspi_Context_LoadKeyByUUID(context_handle, TSS_PS_TYPE_SYSTEM, | 351 if ((result = Tspi_Context_LoadKeyByUUID(context_handle, TSS_PS_TYPE_SYSTEM, |
330 SRK_UUID, &srk_handle))) { | 352 SRK_UUID, &srk_handle))) { |
331 LOG(ERROR) << "Error calling Tspi_Context_LoadKeyByUUID: " << result; | 353 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_LoadKeyByUUID"; |
332 return false; | 354 return false; |
333 } | 355 } |
334 | 356 |
335 TSS_HPOLICY policy_handle; | 357 TSS_HPOLICY policy_handle; |
336 if ((result = Tspi_Context_CreateObject(context_handle, | 358 if ((result = Tspi_Context_CreateObject(context_handle, |
337 TSS_OBJECT_TYPE_POLICY, | 359 TSS_OBJECT_TYPE_POLICY, |
338 TSS_POLICY_USAGE, | 360 TSS_POLICY_USAGE, |
339 &policy_handle))) { | 361 &policy_handle))) { |
340 LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result; | 362 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
341 Tspi_Context_CloseObject(context_handle, srk_handle); | 363 Tspi_Context_CloseObject(context_handle, srk_handle); |
342 return false; | 364 return false; |
343 } | 365 } |
344 | 366 |
345 BYTE new_password[0]; | 367 BYTE new_password[0]; |
346 if ((result = Tspi_Policy_SetSecret(policy_handle, TSS_SECRET_MODE_PLAIN, | 368 if ((result = Tspi_Policy_SetSecret(policy_handle, TSS_SECRET_MODE_PLAIN, |
347 0, new_password))) { | 369 0, new_password))) { |
348 LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result; | 370 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; |
349 Tspi_Context_CloseObject(context_handle, policy_handle); | 371 Tspi_Context_CloseObject(context_handle, policy_handle); |
350 Tspi_Context_CloseObject(context_handle, srk_handle); | 372 Tspi_Context_CloseObject(context_handle, srk_handle); |
351 return false; | 373 return false; |
352 } | 374 } |
353 | 375 |
354 if ((result = Tspi_ChangeAuth(srk_handle, | 376 if ((result = Tspi_ChangeAuth(srk_handle, |
355 tpm_handle, | 377 tpm_handle, |
356 policy_handle))) { | 378 policy_handle))) { |
357 LOG(ERROR) << "Error calling Tspi_ChangeAuth: " << result; | 379 TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth"; |
358 Tspi_Context_CloseObject(context_handle, policy_handle); | 380 Tspi_Context_CloseObject(context_handle, policy_handle); |
359 Tspi_Context_CloseObject(context_handle, srk_handle); | 381 Tspi_Context_CloseObject(context_handle, srk_handle); |
360 return false; | 382 return false; |
361 } | 383 } |
362 | 384 |
363 Tspi_Context_CloseObject(context_handle, policy_handle); | 385 Tspi_Context_CloseObject(context_handle, policy_handle); |
364 Tspi_Context_CloseObject(context_handle, srk_handle); | 386 Tspi_Context_CloseObject(context_handle, srk_handle); |
365 return true; | 387 return true; |
366 } | 388 } |
367 | 389 |
368 bool Tpm::UnrestrictSrk(TSS_HCONTEXT context_handle, | 390 bool Tpm::UnrestrictSrk(TSS_HCONTEXT context_handle, |
369 const SecureBlob& owner_password) { | 391 const SecureBlob& owner_password) { |
370 TSS_RESULT result; | 392 TSS_RESULT result; |
371 TSS_HTPM tpm_handle; | 393 TSS_HTPM tpm_handle; |
372 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) { | 394 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) { |
373 return false; | 395 return false; |
374 } | 396 } |
375 | 397 |
376 TSS_BOOL current_status = false; | 398 TSS_BOOL current_status = false; |
377 | 399 |
378 if ((result = Tspi_TPM_GetStatus(tpm_handle, | 400 if ((result = Tspi_TPM_GetStatus(tpm_handle, |
379 TSS_TPMSTATUS_DISABLEPUBSRKREAD, | 401 TSS_TPMSTATUS_DISABLEPUBSRKREAD, |
380 ¤t_status))) { | 402 ¤t_status))) { |
381 LOG(ERROR) << "Error calling Tspi_TPM_GetStatus: " << result; | 403 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_GetStatus"; |
382 return false; | 404 return false; |
383 } | 405 } |
384 | 406 |
385 // If it is currently owner auth (true), set it to SRK auth | 407 // If it is currently owner auth (true), set it to SRK auth |
386 if (current_status) { | 408 if (current_status) { |
387 if ((result = Tspi_TPM_SetStatus(tpm_handle, | 409 if ((result = Tspi_TPM_SetStatus(tpm_handle, |
388 TSS_TPMSTATUS_DISABLEPUBSRKREAD, | 410 TSS_TPMSTATUS_DISABLEPUBSRKREAD, |
389 false))) { | 411 false))) { |
390 LOG(ERROR) << "Error calling Tspi_TPM_SetStatus: " << result; | 412 TPM_LOG(ERROR, result) << "Error calling Tspi_TPM_SetStatus"; |
391 return false; | 413 return false; |
392 } | 414 } |
393 } | 415 } |
394 | 416 |
395 return true; | 417 return true; |
396 } | 418 } |
397 | 419 |
398 bool Tpm::ChangeOwnerPassword(TSS_HCONTEXT context_handle, | 420 bool Tpm::ChangeOwnerPassword(TSS_HCONTEXT context_handle, |
399 const SecureBlob& previous_owner_password, | 421 const SecureBlob& previous_owner_password, |
400 const SecureBlob& owner_password) { | 422 const SecureBlob& owner_password) { |
401 TSS_RESULT result; | 423 TSS_RESULT result; |
402 TSS_HTPM tpm_handle; | 424 TSS_HTPM tpm_handle; |
403 if (!GetTpmWithAuth(context_handle, previous_owner_password, &tpm_handle)) { | 425 if (!GetTpmWithAuth(context_handle, previous_owner_password, &tpm_handle)) { |
404 return false; | 426 return false; |
405 } | 427 } |
406 | 428 |
407 TSS_HPOLICY policy_handle; | 429 TSS_HPOLICY policy_handle; |
408 if ((result = Tspi_Context_CreateObject(context_handle, | 430 if ((result = Tspi_Context_CreateObject(context_handle, |
409 TSS_OBJECT_TYPE_POLICY, | 431 TSS_OBJECT_TYPE_POLICY, |
410 TSS_POLICY_USAGE, | 432 TSS_POLICY_USAGE, |
411 &policy_handle))) { | 433 &policy_handle))) { |
412 LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result; | 434 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
413 return false; | 435 return false; |
414 } | 436 } |
415 | 437 |
416 if ((result = Tspi_Policy_SetSecret(policy_handle, | 438 if ((result = Tspi_Policy_SetSecret(policy_handle, |
417 TSS_SECRET_MODE_PLAIN, | 439 TSS_SECRET_MODE_PLAIN, |
418 owner_password.size(), | 440 owner_password.size(), |
419 const_cast<BYTE *>(static_cast<const BYTE *>( | 441 const_cast<BYTE *>(static_cast<const BYTE *>( |
420 owner_password.const_data()))))) { | 442 owner_password.const_data()))))) { |
421 LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result; | 443 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; |
422 Tspi_Context_CloseObject(context_handle, policy_handle); | 444 Tspi_Context_CloseObject(context_handle, policy_handle); |
423 return false; | 445 return false; |
424 } | 446 } |
425 | 447 |
426 if ((result = Tspi_ChangeAuth(tpm_handle, 0, policy_handle))) { | 448 if ((result = Tspi_ChangeAuth(tpm_handle, 0, policy_handle))) { |
427 LOG(ERROR) << "Error calling Tspi_ChangeAuth: " << result; | 449 TPM_LOG(ERROR, result) << "Error calling Tspi_ChangeAuth"; |
428 Tspi_Context_CloseObject(context_handle, policy_handle); | 450 Tspi_Context_CloseObject(context_handle, policy_handle); |
429 return false; | 451 return false; |
430 } | 452 } |
431 | 453 |
432 return true; | 454 Tspi_Context_CloseObject(context_handle, policy_handle); |
433 } | 455 return true; |
434 | 456 } |
| 457 |
| 458 // TODO(fes): This method is borrowed from cryptohome. When the tpm_init |
| 459 // library is merged into cryptohome, these duplicate methods need to be |
| 460 // removed. Either that, or they should be moved into a separate library. |
| 461 bool Tpm::LoadFileBytes(const FilePath& path, chromeos::Blob* blob) { |
| 462 int64 file_size; |
| 463 if (!file_util::PathExists(path)) { |
| 464 return false; |
| 465 } |
| 466 if (!file_util::GetFileSize(path, &file_size)) { |
| 467 LOG(ERROR) << "Could not get size of " << path.value(); |
| 468 return false; |
| 469 } |
| 470 // Compare to the max of a 32-bit signed integer |
| 471 if (file_size > static_cast<int64>(INT_MAX)) { |
| 472 LOG(ERROR) << "File " << path.value() << " is too large: " << file_size; |
| 473 return false; |
| 474 } |
| 475 SecureBlob buf(file_size); |
| 476 int data_read = file_util::ReadFile(path, reinterpret_cast<char*>(&buf[0]), |
| 477 file_size); |
| 478 // Cast is okay because of comparison to INT_MAX above |
| 479 if (data_read != static_cast<int>(file_size)) { |
| 480 LOG(ERROR) << "Could not read entire file " << file_size; |
| 481 return false; |
| 482 } |
| 483 blob->swap(buf); |
| 484 return true; |
| 485 } |
| 486 |
| 487 bool Tpm::LoadOwnerPassword(const TpmStatus& tpm_status, |
| 488 chromeos::Blob* owner_password) { |
| 489 if (!(tpm_status.flags() & TpmStatus::OWNED_BY_THIS_INSTALL)) { |
| 490 return false; |
| 491 } |
| 492 if ((tpm_status.flags() & TpmStatus::USES_WELL_KNOWN_OWNER)) { |
| 493 SecureBlob default_owner_password(sizeof(kTpmWellKnownPassword)); |
| 494 memcpy(default_owner_password.data(), kTpmWellKnownPassword, |
| 495 sizeof(kTpmWellKnownPassword)); |
| 496 owner_password->swap(default_owner_password); |
| 497 return true; |
| 498 } |
| 499 if (!(tpm_status.flags() & TpmStatus::USES_RANDOM_OWNER) || |
| 500 !tpm_status.has_owner_password()) { |
| 501 return false; |
| 502 } |
| 503 |
| 504 TSS_HCONTEXT context_handle; |
| 505 if (!OpenAndConnectTpm(&context_handle)) { |
| 506 return false; |
| 507 } |
| 508 |
| 509 TSS_RESULT result; |
| 510 TSS_HKEY srk_handle; |
| 511 if (!LoadSrk(context_handle, &srk_handle, &result)) { |
| 512 LOG(ERROR) << "Error loading the SRK"; |
| 513 Tspi_Context_Close(context_handle); |
| 514 return false; |
| 515 } |
| 516 |
| 517 TSS_FLAG init_flags = TSS_ENCDATA_SEAL; |
| 518 TSS_HKEY enc_handle; |
| 519 if ((result = Tspi_Context_CreateObject(context_handle, |
| 520 TSS_OBJECT_TYPE_ENCDATA, |
| 521 init_flags, &enc_handle))) { |
| 522 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
| 523 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 524 Tspi_Context_Close(context_handle); |
| 525 return false; |
| 526 } |
| 527 |
| 528 SecureBlob local_owner_password(tpm_status.owner_password().length()); |
| 529 tpm_status.owner_password().copy( |
| 530 static_cast<char*>(local_owner_password.data()), |
| 531 tpm_status.owner_password().length(), 0); |
| 532 |
| 533 if ((result = Tspi_SetAttribData(enc_handle, |
| 534 TSS_TSPATTRIB_ENCDATA_BLOB, |
| 535 TSS_TSPATTRIB_ENCDATABLOB_BLOB, |
| 536 local_owner_password.size(), |
| 537 static_cast<BYTE *>(local_owner_password.data())))) { |
| 538 TPM_LOG(ERROR, result) << "Error calling Tspi_SetAttribData"; |
| 539 Tspi_Context_CloseObject(context_handle, enc_handle); |
| 540 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 541 Tspi_Context_Close(context_handle); |
| 542 return false; |
| 543 } |
| 544 |
| 545 unsigned char* dec_data = NULL; |
| 546 UINT32 dec_data_length = 0; |
| 547 if ((result = Tspi_Data_Unseal(enc_handle, srk_handle, &dec_data_length, |
| 548 &dec_data))) { |
| 549 TPM_LOG(ERROR, result) << "Error calling Tspi_Data_Unseal"; |
| 550 Tspi_Context_CloseObject(context_handle, enc_handle); |
| 551 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 552 Tspi_Context_Close(context_handle); |
| 553 return false; |
| 554 } |
| 555 |
| 556 Tspi_Context_CloseObject(context_handle, enc_handle); |
| 557 |
| 558 SecureBlob local_data(dec_data_length); |
| 559 memcpy(static_cast<char*>(local_data.data()), dec_data, dec_data_length); |
| 560 Tspi_Context_FreeMemory(context_handle, dec_data); |
| 561 |
| 562 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 563 Tspi_Context_Close(context_handle); |
| 564 |
| 565 owner_password->swap(local_data); |
| 566 |
| 567 return true; |
| 568 } |
| 569 |
| 570 bool Tpm::StoreOwnerPassword(const chromeos::Blob& owner_password, |
| 571 TpmStatus* tpm_status) { |
| 572 TSS_HCONTEXT context_handle; |
| 573 if (!OpenAndConnectTpm(&context_handle)) { |
| 574 return false; |
| 575 } |
| 576 |
| 577 TSS_RESULT result; |
| 578 TSS_HKEY srk_handle; |
| 579 if (!LoadSrk(context_handle, &srk_handle, &result)) { |
| 580 LOG(ERROR) << "Error loading the SRK"; |
| 581 Tspi_Context_Close(context_handle); |
| 582 return false; |
| 583 } |
| 584 |
| 585 // Check the SRK public key |
| 586 unsigned int size_n; |
| 587 BYTE *public_srk; |
| 588 if ((result = Tspi_Key_GetPubKey(srk_handle, &size_n, &public_srk))) { |
| 589 TPM_LOG(ERROR, result) << "Unable to get the SRK public key"; |
| 590 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 591 Tspi_Context_Close(context_handle); |
| 592 return false; |
| 593 } |
| 594 Tspi_Context_FreeMemory(context_handle, public_srk); |
| 595 |
| 596 TSS_HTPM tpm_handle; |
| 597 if (!GetTpm(context_handle, &tpm_handle)) { |
| 598 LOG(ERROR) << "Unable to get a handle to the TPM"; |
| 599 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 600 Tspi_Context_Close(context_handle); |
| 601 return false; |
| 602 } |
| 603 |
| 604 // Use PCR0 when sealing the data so that the owner password is only |
| 605 // available in the current boot mode. This helps protect the password from |
| 606 // offline attacks until it has been presented and cleared. |
| 607 TSS_HPCRS pcrs_handle; |
| 608 if ((result = Tspi_Context_CreateObject(context_handle, TSS_OBJECT_TYPE_PCRS, |
| 609 0, &pcrs_handle))) { |
| 610 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
| 611 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 612 Tspi_Context_Close(context_handle); |
| 613 return false; |
| 614 } |
| 615 |
| 616 UINT32 pcr_len; |
| 617 BYTE* pcr_value; |
| 618 Tspi_TPM_PcrRead(tpm_handle, 0, &pcr_len, &pcr_value); |
| 619 Tspi_PcrComposite_SetPcrValue(pcrs_handle, 0, pcr_len, pcr_value); |
| 620 Tspi_Context_FreeMemory(context_handle, pcr_value); |
| 621 |
| 622 TSS_FLAG init_flags = TSS_ENCDATA_SEAL; |
| 623 TSS_HKEY enc_handle; |
| 624 if ((result = Tspi_Context_CreateObject(context_handle, |
| 625 TSS_OBJECT_TYPE_ENCDATA, |
| 626 init_flags, &enc_handle))) { |
| 627 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_CreateObject"; |
| 628 Tspi_Context_CloseObject(context_handle, pcrs_handle); |
| 629 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 630 Tspi_Context_Close(context_handle); |
| 631 return false; |
| 632 } |
| 633 |
| 634 if ((result = Tspi_Data_Seal(enc_handle, srk_handle, owner_password.size(), |
| 635 const_cast<BYTE *>(&owner_password[0]), |
| 636 pcrs_handle))) { |
| 637 TPM_LOG(ERROR, result) << "Error calling Tspi_Data_Seal"; |
| 638 Tspi_Context_CloseObject(context_handle, pcrs_handle); |
| 639 Tspi_Context_CloseObject(context_handle, enc_handle); |
| 640 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 641 Tspi_Context_Close(context_handle); |
| 642 return false; |
| 643 } |
| 644 Tspi_Context_CloseObject(context_handle, pcrs_handle); |
| 645 |
| 646 unsigned char* enc_data = NULL; |
| 647 UINT32 enc_data_length = 0; |
| 648 if ((result = Tspi_GetAttribData(enc_handle, TSS_TSPATTRIB_ENCDATA_BLOB, |
| 649 TSS_TSPATTRIB_ENCDATABLOB_BLOB, |
| 650 &enc_data_length, &enc_data))) { |
| 651 TPM_LOG(ERROR, result) << "Error calling Tspi_GetAttribData"; |
| 652 Tspi_Context_CloseObject(context_handle, enc_handle); |
| 653 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 654 Tspi_Context_Close(context_handle); |
| 655 return false; |
| 656 } |
| 657 Tspi_Context_CloseObject(context_handle, enc_handle); |
| 658 |
| 659 tpm_status->set_owner_password(enc_data, enc_data_length); |
| 660 |
| 661 Tspi_Context_FreeMemory(context_handle, enc_data); |
| 662 Tspi_Context_CloseObject(context_handle, srk_handle); |
| 663 Tspi_Context_Close(context_handle); |
| 664 |
| 665 return true; |
| 666 } |
| 667 |
435 bool Tpm::GetTpm(TSS_HCONTEXT context_handle, TSS_HTPM* tpm_handle) { | 668 bool Tpm::GetTpm(TSS_HCONTEXT context_handle, TSS_HTPM* tpm_handle) { |
436 TSS_RESULT result; | 669 TSS_RESULT result; |
437 TSS_HTPM local_tpm_handle; | 670 TSS_HTPM local_tpm_handle; |
438 if ((result = Tspi_Context_GetTpmObject(context_handle, &local_tpm_handle))) { | 671 if ((result = Tspi_Context_GetTpmObject(context_handle, &local_tpm_handle))) { |
439 LOG(ERROR) << "Error calling Tspi_Context_GetTpmObject: " << result; | 672 TPM_LOG(ERROR, result) << "Error calling Tspi_Context_GetTpmObject"; |
440 return false; | 673 return false; |
441 } | 674 } |
442 | 675 |
443 *tpm_handle = local_tpm_handle; | 676 *tpm_handle = local_tpm_handle; |
444 return true; | 677 return true; |
445 } | 678 } |
446 | 679 |
447 bool Tpm::GetTpmWithAuth(TSS_HCONTEXT context_handle, | 680 bool Tpm::GetTpmWithAuth(TSS_HCONTEXT context_handle, |
448 const SecureBlob& owner_password, | 681 const SecureBlob& owner_password, |
449 TSS_HTPM* tpm_handle) { | 682 TSS_HTPM* tpm_handle) { |
450 TSS_RESULT result; | 683 TSS_RESULT result; |
451 TSS_HTPM local_tpm_handle; | 684 TSS_HTPM local_tpm_handle; |
452 if (!GetTpm(context_handle, &local_tpm_handle)) { | 685 if (!GetTpm(context_handle, &local_tpm_handle)) { |
453 return false; | 686 return false; |
454 } | 687 } |
455 | 688 |
456 TSS_HPOLICY tpm_usage_policy; | 689 TSS_HPOLICY tpm_usage_policy; |
457 if ((result = Tspi_GetPolicyObject(local_tpm_handle, TSS_POLICY_USAGE, | 690 if ((result = Tspi_GetPolicyObject(local_tpm_handle, TSS_POLICY_USAGE, |
458 &tpm_usage_policy))) { | 691 &tpm_usage_policy))) { |
459 LOG(ERROR) << "Error calling Tspi_GetPolicyObject: " << result; | 692 TPM_LOG(ERROR, result) << "Error calling Tspi_GetPolicyObject"; |
460 return false; | 693 return false; |
461 } | 694 } |
462 | 695 |
463 if ((result = Tspi_Policy_SetSecret(tpm_usage_policy, TSS_SECRET_MODE_PLAIN, | 696 if ((result = Tspi_Policy_SetSecret(tpm_usage_policy, TSS_SECRET_MODE_PLAIN, |
464 owner_password.size(), | 697 owner_password.size(), |
465 const_cast<BYTE *>(static_cast<const BYTE *>( | 698 const_cast<BYTE *>(static_cast<const BYTE *>( |
466 owner_password.const_data()))))) { | 699 owner_password.const_data()))))) { |
467 LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result; | 700 TPM_LOG(ERROR, result) << "Error calling Tspi_Policy_SetSecret"; |
468 return false; | 701 return false; |
469 } | 702 } |
470 | 703 |
471 *tpm_handle = local_tpm_handle; | 704 *tpm_handle = local_tpm_handle; |
472 return true; | 705 return true; |
473 } | 706 } |
474 | 707 |
475 bool Tpm::TestTpmAuth(TSS_HTPM tpm_handle) { | 708 bool Tpm::TestTpmAuth(TSS_HTPM tpm_handle) { |
476 // Call Tspi_TPM_GetStatus to test the authentication | 709 // Call Tspi_TPM_GetStatus to test the authentication |
477 TSS_RESULT result; | 710 TSS_RESULT result; |
(...skipping 12 matching lines...) Expand all Loading... |
490 if (owner_password_.size() != 0) { | 723 if (owner_password_.size() != 0) { |
491 owner_password->assign(owner_password_.begin(), owner_password_.end()); | 724 owner_password->assign(owner_password_.begin(), owner_password_.end()); |
492 result = true; | 725 result = true; |
493 } | 726 } |
494 password_sync_lock_.Release(); | 727 password_sync_lock_.Release(); |
495 } | 728 } |
496 return result; | 729 return result; |
497 } | 730 } |
498 | 731 |
499 bool Tpm::InitializeTpm(bool* OUT_took_ownership) { | 732 bool Tpm::InitializeTpm(bool* OUT_took_ownership) { |
| 733 TpmStatus tpm_status; |
| 734 |
| 735 if (!LoadTpmStatus(&tpm_status)) { |
| 736 tpm_status.Clear(); |
| 737 tpm_status.set_flags(TpmStatus::NONE); |
| 738 } |
| 739 |
500 if (OUT_took_ownership) { | 740 if (OUT_took_ownership) { |
501 *OUT_took_ownership = false; | 741 *OUT_took_ownership = false; |
502 } | 742 } |
503 | 743 |
504 if (!IsConnected()) { | |
505 Connect(); | |
506 } | |
507 | |
508 if (!IsConnected()) { | |
509 LOG(ERROR) << "Failed to connect to TPM"; | |
510 return false; | |
511 } | |
512 | |
513 if (is_disabled_) { | 744 if (is_disabled_) { |
514 return false; | 745 return false; |
515 } | 746 } |
516 | 747 |
| 748 TSS_HCONTEXT context_handle = Connect(); |
| 749 |
| 750 if (!context_handle) { |
| 751 LOG(ERROR) << "Failed to connect to TPM"; |
| 752 return false; |
| 753 } |
| 754 |
517 SecureBlob default_owner_password(sizeof(kTpmWellKnownPassword)); | 755 SecureBlob default_owner_password(sizeof(kTpmWellKnownPassword)); |
518 memcpy(default_owner_password.data(), kTpmWellKnownPassword, | 756 memcpy(default_owner_password.data(), kTpmWellKnownPassword, |
519 sizeof(kTpmWellKnownPassword)); | 757 sizeof(kTpmWellKnownPassword)); |
520 | 758 |
521 bool took_ownership = false; | 759 bool took_ownership = false; |
522 if (!is_owned_) { | 760 if (!is_owned_) { |
523 is_being_owned_ = true; | 761 is_being_owned_ = true; |
524 file_util::Delete(FilePath(kOpenCryptokiPath), true); | 762 file_util::Delete(FilePath(kOpenCryptokiPath), true); |
525 file_util::Delete(FilePath(kTpmOwnedFile), false); | 763 file_util::Delete(FilePath(kTpmOwnedFile), false); |
| 764 file_util::Delete(FilePath(kTpmStatusFile), false); |
526 | 765 |
527 if (!IsEndorsementKeyAvailable(context_handle_)) { | 766 if (!IsEndorsementKeyAvailable(context_handle)) { |
528 if (!CreateEndorsementKey(context_handle_)) { | 767 if (!CreateEndorsementKey(context_handle)) { |
529 LOG(ERROR) << "Failed to create endorsement key"; | 768 LOG(ERROR) << "Failed to create endorsement key"; |
530 is_being_owned_ = false; | 769 is_being_owned_ = false; |
| 770 Disconnect(context_handle); |
531 return false; | 771 return false; |
532 } | 772 } |
533 } | 773 } |
534 | 774 |
535 if (!IsEndorsementKeyAvailable(context_handle_)) { | 775 if (!IsEndorsementKeyAvailable(context_handle)) { |
536 LOG(ERROR) << "Endorsement key is not available"; | 776 LOG(ERROR) << "Endorsement key is not available"; |
537 is_being_owned_ = false; | 777 is_being_owned_ = false; |
| 778 Disconnect(context_handle); |
538 return false; | 779 return false; |
539 } | 780 } |
540 | 781 |
541 if (!TakeOwnership(context_handle_, kMaxTimeoutRetries, | 782 if (!TakeOwnership(context_handle, kMaxTimeoutRetries, |
542 default_owner_password)) { | 783 default_owner_password)) { |
543 LOG(ERROR) << "Take Ownership failed"; | 784 LOG(ERROR) << "Take Ownership failed"; |
544 is_being_owned_ = false; | 785 is_being_owned_ = false; |
| 786 Disconnect(context_handle); |
545 return false; | 787 return false; |
546 } | 788 } |
547 | 789 |
548 is_owned_ = true; | 790 is_owned_ = true; |
549 took_ownership = true; | 791 took_ownership = true; |
| 792 |
| 793 tpm_status.set_flags(TpmStatus::OWNED_BY_THIS_INSTALL | |
| 794 TpmStatus::USES_WELL_KNOWN_OWNER); |
| 795 tpm_status.clear_owner_password(); |
| 796 StoreTpmStatus(tpm_status); |
550 } | 797 } |
551 | 798 |
552 if (OUT_took_ownership) { | 799 if (OUT_took_ownership) { |
553 *OUT_took_ownership = took_ownership; | 800 *OUT_took_ownership = took_ownership; |
554 } | 801 } |
555 | 802 |
556 // Ensure the SRK is available | 803 // Ensure the SRK is available |
557 TSS_RESULT result; | 804 TSS_RESULT result; |
558 TSS_HKEY srk_handle; | 805 TSS_HKEY srk_handle; |
559 TSS_UUID SRK_UUID = TSS_UUID_SRK; | 806 TSS_UUID SRK_UUID = TSS_UUID_SRK; |
560 if ((result = Tspi_Context_LoadKeyByUUID(context_handle_, TSS_PS_TYPE_SYSTEM, | 807 if ((result = Tspi_Context_LoadKeyByUUID(context_handle, TSS_PS_TYPE_SYSTEM, |
561 SRK_UUID, &srk_handle))) { | 808 SRK_UUID, &srk_handle))) { |
562 is_srk_available_ = false; | 809 is_srk_available_ = false; |
563 } else { | 810 } else { |
564 Tspi_Context_CloseObject(context_handle_, srk_handle); | 811 Tspi_Context_CloseObject(context_handle, srk_handle); |
565 is_srk_available_ = true; | 812 is_srk_available_ = true; |
566 } | 813 } |
567 | 814 |
568 // If we can open the TPM with the default password, then we still need to | 815 // If we can open the TPM with the default password, then we still need to |
569 // zero the SRK password and unrestrict it, then change the owner password. | 816 // zero the SRK password and unrestrict it, then change the owner password. |
570 TSS_HTPM tpm_handle; | 817 TSS_HTPM tpm_handle; |
571 if (!file_util::PathExists(FilePath(kTpmOwnedFile)) && | 818 if (!file_util::PathExists(FilePath(kTpmOwnedFile)) && |
572 GetTpmWithAuth(context_handle_, default_owner_password, &tpm_handle) && | 819 GetTpmWithAuth(context_handle, default_owner_password, &tpm_handle) && |
573 TestTpmAuth(tpm_handle)) { | 820 TestTpmAuth(tpm_handle)) { |
574 if (!ZeroSrkPassword(context_handle_, default_owner_password)) { | 821 if (!ZeroSrkPassword(context_handle, default_owner_password)) { |
575 LOG(ERROR) << "Couldn't zero SRK password"; | 822 LOG(ERROR) << "Couldn't zero SRK password"; |
576 is_being_owned_ = false; | 823 is_being_owned_ = false; |
| 824 Disconnect(context_handle); |
577 return false; | 825 return false; |
578 } | 826 } |
579 | 827 |
580 if (!UnrestrictSrk(context_handle_, default_owner_password)) { | 828 if (!UnrestrictSrk(context_handle, default_owner_password)) { |
581 LOG(ERROR) << "Couldn't unrestrict the SRK"; | 829 LOG(ERROR) << "Couldn't unrestrict the SRK"; |
582 is_being_owned_ = false; | 830 is_being_owned_ = false; |
| 831 Disconnect(context_handle); |
583 return false; | 832 return false; |
584 } | 833 } |
| 834 |
585 SecureBlob owner_password; | 835 SecureBlob owner_password; |
586 CreateOwnerPassword(&owner_password); | 836 CreateOwnerPassword(&owner_password); |
587 | 837 |
588 if (!ChangeOwnerPassword(context_handle_, default_owner_password, | 838 tpm_status.set_flags(TpmStatus::OWNED_BY_THIS_INSTALL | |
589 owner_password)) { | 839 TpmStatus::USES_RANDOM_OWNER); |
590 LOG(ERROR) << "Couldn't set the owner password"; | 840 if (!StoreOwnerPassword(owner_password, &tpm_status)) { |
591 is_being_owned_ = false; | 841 tpm_status.clear_owner_password(); |
592 return false; | 842 } |
| 843 StoreTpmStatus(tpm_status); |
| 844 |
| 845 if ((result = ChangeOwnerPassword(context_handle, default_owner_password, |
| 846 owner_password))) { |
| 847 password_sync_lock_.Acquire(); |
| 848 owner_password_.assign(owner_password.begin(), owner_password.end()); |
| 849 password_sync_lock_.Release(); |
593 } | 850 } |
594 | 851 |
595 password_sync_lock_.Acquire(); | |
596 owner_password_.assign(owner_password.begin(), owner_password.end()); | |
597 password_sync_lock_.Release(); | |
598 | |
599 file_util::WriteFile(FilePath(kTpmOwnedFile), NULL, 0); | 852 file_util::WriteFile(FilePath(kTpmOwnedFile), NULL, 0); |
| 853 } else { |
| 854 // If we fall through here, then the TPM owned file doesn't exist, but we |
| 855 // couldn't auth with the well-known password. In this case, we must assume |
| 856 // that the TPM has already been owned and set to a random password, so |
| 857 // touch the TPM owned file. |
| 858 if (!file_util::PathExists(FilePath(kTpmOwnedFile))) { |
| 859 file_util::WriteFile(FilePath(kTpmOwnedFile), NULL, 0); |
| 860 } |
600 } | 861 } |
601 | 862 |
602 is_being_owned_ = false; | 863 is_being_owned_ = false; |
603 | 864 Disconnect(context_handle); |
604 return true; | 865 return true; |
605 } | 866 } |
606 | 867 |
607 bool Tpm::GetRandomData(size_t length, chromeos::Blob* data) { | 868 bool Tpm::GetRandomData(size_t length, chromeos::Blob* data) { |
608 TSS_HCONTEXT context_handle; | 869 TSS_HCONTEXT context_handle; |
609 if (!OpenAndConnectTpm(&context_handle)) { | 870 if (!OpenAndConnectTpm(&context_handle)) { |
610 LOG(ERROR) << "Could not open the TPM"; | 871 LOG(ERROR) << "Could not open the TPM"; |
611 return false; | 872 return false; |
612 } | 873 } |
613 | 874 |
614 TSS_HTPM tpm_handle; | 875 TSS_HTPM tpm_handle; |
615 if (!GetTpm(context_handle, &tpm_handle)) { | 876 if (!GetTpm(context_handle, &tpm_handle)) { |
616 LOG(ERROR) << "Could not get a handle to the TPM."; | 877 LOG(ERROR) << "Could not get a handle to the TPM."; |
617 Tspi_Context_Close(context_handle); | 878 Tspi_Context_Close(context_handle); |
618 return false; | 879 return false; |
619 } | 880 } |
620 | 881 |
621 TSS_RESULT result; | 882 TSS_RESULT result; |
622 SecureBlob random(length); | 883 SecureBlob random(length); |
623 BYTE* tpm_data = NULL; | 884 BYTE* tpm_data = NULL; |
624 if ((result = Tspi_TPM_GetRandom(tpm_handle, random.size(), &tpm_data))) { | 885 if ((result = Tspi_TPM_GetRandom(tpm_handle, random.size(), &tpm_data))) { |
625 LOG(ERROR) << "Could not get random data from the TPM: " << result; | 886 TPM_LOG(ERROR, result) << "Could not get random data from the TPM"; |
626 Tspi_Context_Close(context_handle); | 887 Tspi_Context_Close(context_handle); |
627 return false; | 888 return false; |
628 } | 889 } |
629 memcpy(random.data(), tpm_data, random.size()); | 890 memcpy(random.data(), tpm_data, random.size()); |
630 Tspi_Context_FreeMemory(context_handle, tpm_data); | 891 Tspi_Context_FreeMemory(context_handle, tpm_data); |
631 chromeos::SecureMemset(tpm_data, 0, random.size()); | 892 chromeos::SecureMemset(tpm_data, 0, random.size()); |
632 Tspi_Context_Close(context_handle); | 893 Tspi_Context_Close(context_handle); |
633 data->swap(random); | 894 data->swap(random); |
634 return true; | 895 return true; |
635 } | 896 } |
636 | 897 |
| 898 bool Tpm::LoadSrk(TSS_HCONTEXT context_handle, TSS_HKEY* srk_handle, |
| 899 TSS_RESULT* result) { |
| 900 *result = TSS_SUCCESS; |
| 901 |
| 902 // Load the Storage Root Key |
| 903 TSS_UUID SRK_UUID = TSS_UUID_SRK; |
| 904 TSS_HKEY local_srk_handle; |
| 905 if ((*result = Tspi_Context_LoadKeyByUUID(context_handle, |
| 906 TSS_PS_TYPE_SYSTEM, |
| 907 SRK_UUID, |
| 908 &local_srk_handle))) { |
| 909 return false; |
| 910 } |
| 911 |
| 912 // Check if the SRK wants a password |
| 913 UINT32 srk_authusage; |
| 914 if ((*result = Tspi_GetAttribUint32(local_srk_handle, |
| 915 TSS_TSPATTRIB_KEY_INFO, |
| 916 TSS_TSPATTRIB_KEYINFO_AUTHUSAGE, |
| 917 &srk_authusage))) { |
| 918 Tspi_Context_CloseObject(context_handle, |
| 919 local_srk_handle); |
| 920 return false; |
| 921 } |
| 922 |
| 923 // Give it the password if needed |
| 924 if (srk_authusage) { |
| 925 TSS_HPOLICY srk_usage_policy; |
| 926 if ((*result = Tspi_GetPolicyObject(local_srk_handle, |
| 927 TSS_POLICY_USAGE, |
| 928 &srk_usage_policy))) { |
| 929 Tspi_Context_CloseObject(context_handle, local_srk_handle); |
| 930 return false; |
| 931 } |
| 932 |
| 933 BYTE new_password[0]; |
| 934 if ((*result = Tspi_Policy_SetSecret(srk_usage_policy, |
| 935 TSS_SECRET_MODE_PLAIN, |
| 936 0, new_password))) { |
| 937 Tspi_Context_CloseObject(context_handle, local_srk_handle); |
| 938 return false; |
| 939 } |
| 940 } |
| 941 |
| 942 *srk_handle = local_srk_handle; |
| 943 return true; |
| 944 } |
| 945 |
| 946 void Tpm::ClearStoredOwnerPassword() { |
| 947 TpmStatus tpm_status; |
| 948 if (LoadTpmStatus(&tpm_status)) { |
| 949 if (tpm_status.has_owner_password()) { |
| 950 tpm_status.clear_owner_password(); |
| 951 StoreTpmStatus(tpm_status); |
| 952 } |
| 953 } |
| 954 password_sync_lock_.Acquire(); |
| 955 owner_password_.resize(0); |
| 956 password_sync_lock_.Release(); |
| 957 } |
| 958 |
| 959 bool Tpm::LoadTpmStatus(TpmStatus* serialized) { |
| 960 FilePath tpm_status_file(kTpmStatusFile); |
| 961 if (!file_util::PathExists(tpm_status_file)) { |
| 962 return false; |
| 963 } |
| 964 SecureBlob file_data; |
| 965 if (!LoadFileBytes(tpm_status_file, &file_data)) { |
| 966 return false; |
| 967 } |
| 968 if (!serialized->ParseFromArray( |
| 969 static_cast<const unsigned char*>(file_data.data()), |
| 970 file_data.size())) { |
| 971 return false; |
| 972 } |
| 973 return true; |
| 974 } |
| 975 |
| 976 bool Tpm::StoreTpmStatus(const TpmStatus& serialized) { |
| 977 int old_mask = platform_->SetMask(kDefaultUmask); |
| 978 FilePath tpm_status_file(kTpmStatusFile); |
| 979 if (file_util::PathExists(tpm_status_file)) { |
| 980 do { |
| 981 int64 file_size; |
| 982 if (!file_util::GetFileSize(tpm_status_file, &file_size)) { |
| 983 break; |
| 984 } |
| 985 SecureBlob random; |
| 986 if (!GetRandomData(file_size, &random)) { |
| 987 break; |
| 988 } |
| 989 FILE* file = file_util::OpenFile(tpm_status_file, "wb+"); |
| 990 if (!file) { |
| 991 break; |
| 992 } |
| 993 if (fwrite(random.const_data(), 1, random.size(), file) != |
| 994 random.size()) { |
| 995 file_util::CloseFile(file); |
| 996 break; |
| 997 } |
| 998 file_util::CloseFile(file); |
| 999 } while(false); |
| 1000 file_util::Delete(tpm_status_file, false); |
| 1001 } |
| 1002 SecureBlob final_blob(serialized.ByteSize()); |
| 1003 serialized.SerializeWithCachedSizesToArray( |
| 1004 static_cast<google::protobuf::uint8*>(final_blob.data())); |
| 1005 unsigned int data_written = file_util::WriteFile( |
| 1006 tpm_status_file, |
| 1007 static_cast<const char*>(final_blob.const_data()), |
| 1008 final_blob.size()); |
| 1009 |
| 1010 if (data_written != final_blob.size()) { |
| 1011 platform_->SetMask(old_mask); |
| 1012 return false; |
| 1013 } |
| 1014 platform_->SetMask(old_mask); |
| 1015 return true; |
| 1016 } |
| 1017 |
637 } // namespace tpm_init | 1018 } // namespace tpm_init |
OLD | NEW |