Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(170)

Side by Side Diff: tpm.cc

Issue 3048029: Initial version of tpm_init, a library for taking ownership of the TPM. (Closed) Base URL: ssh://git@chromiumos-git/tpm_init.git
Patch Set: Minor fix to the error code check from TakeOwnership. Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tpm.h ('k') | tpm_init.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 // Contains the implementation of class Tpm
6
7 #include "tpm.h"
8
9 #include <base/file_util.h>
10 #include <base/platform_thread.h>
11 #include <base/time.h>
12 #include <openssl/rsa.h>
13 #include <trousers/tss.h>
14 #include <trousers/trousers.h>
15
16 namespace tpm_init {
17
18 const char* kWellKnownSrkTmp = "1234567890";
19 const int kOwnerPasswordLength = 12;
20 const int kMaxTimeoutRetries = 5;
21 const char* kTpmCheckEnabledFile = "/sys/class/misc/tpm0/device/enabled";
22 const char* kTpmCheckOwnedFile = "/sys/class/misc/tpm0/device/owned";
23 const char* kTpmOwnedFile = "/var/lib/.tpm_owned";
24 const char* kOpenCryptokiPath = "/var/lib/opencryptoki";
25 const int kTpmConnectRetries = 10;
26 const int kTpmConnectIntervalMs = 100;
27
28 Tpm::Tpm()
29 : context_handle_(0),
30 default_crypto_(new Crypto()),
31 crypto_(default_crypto_.get()),
32 owner_password_(),
33 password_sync_lock_(),
34 is_disabled_(true),
35 is_owned_(false) {
36 }
37
38 Tpm::~Tpm() {
39 Disconnect();
40 }
41
42 bool Tpm::Init() {
43 // Checking disabled and owned either via sysfs or via TSS calls will block if
44 // ownership is being taken by another thread or process. So for this to work
45 // well, Tpm::Init() needs to be called before InitializeTpm() is called. At
46 // that point, the public API for Tpm only checks these booleans, so other
47 // threads can check without being blocked. InitializeTpm() will reset the
48 // is_owned_ bit on success.
49 is_disabled_ = IsDisabledCheckViaSysfs();
50 is_owned_ = IsOwnedCheckViaSysfs();
51 return true;
52 }
53
54 bool Tpm::Connect() {
55 if (context_handle_ == 0) {
56 TSS_HCONTEXT context_handle;
57 if (!OpenAndConnectTpm(&context_handle)) {
58 return false;
59 }
60
61 context_handle_ = context_handle;
62 }
63
64 return true;
65 }
66
67 bool Tpm::IsConnected() {
68 return (context_handle_ != 0);
69 }
70
71 void Tpm::Disconnect() {
72 if (context_handle_) {
73 Tspi_Context_Close(context_handle_);
74 context_handle_ = 0;
75 }
76 }
77
78 int Tpm::GetMaxRsaKeyCount() {
79 if (context_handle_ == 0) {
80 return -1;
81 }
82
83 return GetMaxRsaKeyCountForContext(context_handle_);
84 }
85
86 int Tpm::GetMaxRsaKeyCountForContext(TSS_HCONTEXT context_handle) {
87 int count = -1;
88 TSS_RESULT result;
89 TSS_HTPM tpm_handle;
90 if (!GetTpm(context_handle, &tpm_handle)) {
91 return count;
92 }
93
94 UINT32 cap_length = 0;
95 BYTE* cap = NULL;
96 UINT32 subcap = TSS_TPMCAP_PROP_MAXKEYS;
97 if ((result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_PROPERTY,
98 sizeof(subcap),
99 reinterpret_cast<BYTE*>(&subcap),
100 &cap_length, &cap))) {
101 LOG(ERROR) << "Error calling Tspi_TPM_GetCapability: " << result;
102 return count;
103 }
104 if (cap_length == sizeof(int)) {
105 count = *(reinterpret_cast<int*>(cap));
106 }
107 Tspi_Context_FreeMemory(context_handle, cap);
108 return count;
109 }
110
111 bool Tpm::OpenAndConnectTpm(TSS_HCONTEXT* context_handle) {
112 TSS_RESULT result;
113 TSS_HCONTEXT local_context_handle;
114 if ((result = Tspi_Context_Create(&local_context_handle))) {
115 LOG(ERROR) << "Error calling Tspi_Context_Create";
116 return false;
117 }
118
119 for (int i = 0; i < kTpmConnectRetries; i++) {
120 if ((result = Tspi_Context_Connect(local_context_handle, NULL))) {
121 if (result == TSS_E_COMM_FAILURE) {
122 PlatformThread::Sleep(kTpmConnectIntervalMs);
123 } else {
124 LOG(ERROR) << "Error calling Tspi_Context_Connect: " << result;
125 Tspi_Context_Close(local_context_handle);
126 return false;
127 }
128 } else {
129 break;
130 }
131 }
132
133 if (result) {
134 LOG(ERROR) << "Error calling Tspi_Context_Connect: " << result;
135 Tspi_Context_Close(local_context_handle);
136 return false;
137 }
138
139 *context_handle = local_context_handle;
140 return true;
141 }
142
143 bool Tpm::IsDisabledCheckViaSysfs() {
144 std::string contents;
145 if (!file_util::ReadFileToString(FilePath(kTpmCheckEnabledFile), &contents)) {
146 return false;
147 }
148 if (contents.size() < 1) {
149 return false;
150 }
151 return (contents[0] == '0');
152 }
153
154 bool Tpm::IsOwnedCheckViaSysfs() {
155 std::string contents;
156 if (!file_util::ReadFileToString(FilePath(kTpmCheckOwnedFile), &contents)) {
157 return false;
158 }
159 if (contents.size() < 1) {
160 return false;
161 }
162 return (contents[0] != '0');
163 }
164
165 bool Tpm::IsDisabledCheckViaContext(TSS_HCONTEXT context_handle) {
166 bool value = true;
167 TSS_RESULT result;
168 TSS_HTPM tpm_handle;
169 if (!GetTpm(context_handle, &tpm_handle)) {
170 return value;
171 }
172
173 UINT32 cap_length = 0;
174 BYTE* cap = NULL;
175 if ((result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_FLAG,
176 0, NULL, &cap_length, &cap))) {
177 LOG(ERROR) << "Error calling Tspi_TPM_GetCapability: " << result;
178 return value;
179 }
180 if (cap_length >= (2 * sizeof(int))) {
181 value = (((*(reinterpret_cast<int*>(cap))) & TPM_PF_DISABLE) != 0);
182 }
183 Tspi_Context_FreeMemory(context_handle, cap);
184 return value;
185 }
186
187 bool Tpm::IsOwnedCheckViaContext(TSS_HCONTEXT context_handle) {
188 bool value = true;
189 TSS_RESULT result;
190 TSS_HTPM tpm_handle;
191 if (!GetTpm(context_handle, &tpm_handle)) {
192 LOG(ERROR) << "Error calling Tspi_Context_GetTpmObject: " << result;
193 return value;
194 }
195
196 UINT32 cap_length = 0;
197 BYTE* cap = NULL;
198 if ((result = Tspi_TPM_GetCapability(tpm_handle, TSS_TPMCAP_FLAG,
199 0, NULL, &cap_length, &cap))) {
200 LOG(ERROR) << "Error calling Tspi_TPM_GetCapability: " << result;
201 return value;
202 }
203 if (cap_length >= (2 * sizeof(int))) {
204 value = (((*(reinterpret_cast<int*>(cap))) & TPM_PF_OWNERSHIP) != 0);
205 }
206 Tspi_Context_FreeMemory(context_handle, cap);
207 return value;
208 }
209
210 bool Tpm::CreateEndorsementKey(TSS_HCONTEXT context_handle) {
211 TSS_RESULT result;
212 TSS_HTPM tpm_handle;
213 if (!GetTpm(context_handle, &tpm_handle)) {
214 return false;
215 }
216
217 TSS_HKEY local_key_handle;
218 TSS_FLAG init_flags = TSS_KEY_TYPE_LEGACY | TSS_KEY_SIZE_2048;
219 if ((result = Tspi_Context_CreateObject(context_handle,
220 TSS_OBJECT_TYPE_RSAKEY,
221 init_flags, &local_key_handle))) {
222 LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result;
223 return false;
224 }
225
226 if ((result = Tspi_TPM_CreateEndorsementKey(tpm_handle, local_key_handle,
227 NULL))) {
228 LOG(ERROR) << "Error calling Tspi_TPM_CreateEndorsementKey: " << result;
229 Tspi_Context_CloseObject(context_handle, local_key_handle);
230 return false;
231 }
232
233 return true;
234 }
235
236 bool Tpm::IsEndorsementKeyAvailable(TSS_HCONTEXT context_handle) {
237 TSS_RESULT result;
238 TSS_HTPM tpm_handle;
239 if (!GetTpm(context_handle, &tpm_handle)) {
240 return false;
241 }
242
243 TSS_HKEY local_key_handle;
244 if ((result = Tspi_TPM_GetPubEndorsementKey(tpm_handle, false, NULL,
245 &local_key_handle))) {
246 LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result;
247 return false;
248 }
249
250 Tspi_Context_CloseObject(context_handle, local_key_handle);
251
252 return true;
253 }
254
255 void Tpm::CreateOwnerPassword(SecureBlob* password) {
256 SecureBlob random(kOwnerPasswordLength);
257 crypto_->GetSecureRandom(static_cast<unsigned char*>(random.data()),
258 random.size());
259 SecureBlob tpm_password(kOwnerPasswordLength);
260 crypto_->AsciiEncodeToBuffer(random, static_cast<char*>(tpm_password.data()),
261 tpm_password.size());
262 password->swap(tpm_password);
263 }
264
265 bool Tpm::TakeOwnership(TSS_HCONTEXT context_handle, int max_timeout_tries) {
266 SecureBlob owner_password;
267 CreateOwnerPassword(&owner_password);
268
269 TSS_RESULT result;
270 TSS_HTPM tpm_handle;
271 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) {
272 return false;
273 }
274
275 TSS_HKEY srk_handle;
276 TSS_FLAG init_flags = TSS_KEY_TSP_SRK | TSS_KEY_AUTHORIZATION;
277 if ((result = Tspi_Context_CreateObject(context_handle,
278 TSS_OBJECT_TYPE_RSAKEY,
279 init_flags, &srk_handle))) {
280 LOG(ERROR) << "Error calling Tspi_Context_CreateObject: " << result;
281 return false;
282 }
283
284 TSS_HPOLICY srk_usage_policy;
285 if ((result = Tspi_GetPolicyObject(srk_handle, TSS_POLICY_USAGE,
286 &srk_usage_policy))) {
287 LOG(ERROR) << "Error calling Tspi_GetPolicyObject: " << result;
288 Tspi_Context_CloseObject(context_handle, srk_handle);
289 return false;
290 }
291
292 if ((result = Tspi_Policy_SetSecret(srk_usage_policy,
293 TSS_SECRET_MODE_PLAIN,
294 strlen(kWellKnownSrkTmp),
295 const_cast<BYTE *>(reinterpret_cast<const BYTE *>(kWellKnownSrkTmp))))) {
296 LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result;
297 Tspi_Context_CloseObject(context_handle, srk_handle);
298 return false;
299 }
300
301 int retry_count = 0;
302 do {
303 result = Tspi_TPM_TakeOwnership(tpm_handle, srk_handle, 0);
304 retry_count++;
305 } while(((result == TDDL_E_TIMEOUT) ||
306 (result == (TSS_LAYER_TDDL | TDDL_E_TIMEOUT)) ||
307 (result == (TSS_LAYER_TDDL | TDDL_E_IOERROR))) &&
308 (retry_count < max_timeout_tries));
309
310 if (result) {
311 LOG(ERROR) << "Error calling Tspi_TPM_TakeOwnership: " << result
312 << ", attempts: " << retry_count;
313 Tspi_Context_CloseObject(context_handle, srk_handle);
314 return false;
315 }
316
317 Tspi_Context_CloseObject(context_handle, srk_handle);
318
319 password_sync_lock_.Acquire();
320 owner_password_.swap(owner_password);
321 password_sync_lock_.Release();
322
323 return true;
324 }
325
326 bool Tpm::ZeroSrkPassword(TSS_HCONTEXT context_handle,
327 const SecureBlob& owner_password) {
328 TSS_RESULT result;
329 TSS_HTPM tpm_handle;
330 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) {
331 return false;
332 }
333
334 TSS_HKEY srk_handle;
335 TSS_UUID SRK_UUID = TSS_UUID_SRK;
336 if ((result = Tspi_Context_LoadKeyByUUID(context_handle, TSS_PS_TYPE_SYSTEM,
337 SRK_UUID, &srk_handle))) {
338 LOG(ERROR) << "Couldn't load SRK: " << result;
339 return false;
340 }
341
342 TSS_HPOLICY policy_handle;
343 if ((result = Tspi_Context_CreateObject(context_handle,
344 TSS_OBJECT_TYPE_POLICY,
345 TSS_POLICY_USAGE,
346 &policy_handle))) {
347 LOG(ERROR) << "Error creating policy object: " << result;
348 Tspi_Context_CloseObject(context_handle, srk_handle);
349 return false;
350 }
351
352 BYTE new_password[0];
353 if ((result = Tspi_Policy_SetSecret(policy_handle, TSS_SECRET_MODE_PLAIN,
354 0, new_password))) {
355 LOG(ERROR) << "Error setting srk password: " << result;
356 Tspi_Context_CloseObject(context_handle, policy_handle);
357 Tspi_Context_CloseObject(context_handle, srk_handle);
358 return false;
359 }
360
361 if ((result = Tspi_ChangeAuth(srk_handle,
362 tpm_handle,
363 policy_handle))) {
364 LOG(ERROR) << "Error creating policy object: " << result;
365 Tspi_Context_CloseObject(context_handle, policy_handle);
366 Tspi_Context_CloseObject(context_handle, srk_handle);
367 return false;
368 }
369
370 Tspi_Context_CloseObject(context_handle, policy_handle);
371 Tspi_Context_CloseObject(context_handle, srk_handle);
372 return true;
373 }
374
375 bool Tpm::UnrestrictSrk(TSS_HCONTEXT context_handle,
376 const SecureBlob& owner_password) {
377 TSS_RESULT result;
378 TSS_HTPM tpm_handle;
379 if (!GetTpmWithAuth(context_handle, owner_password, &tpm_handle)) {
380 return false;
381 }
382
383 if ((result = Tspi_TPM_SetStatus(tpm_handle,
384 TSS_TPMSTATUS_DISABLEPUBSRKREAD,
385 false))) {
386 LOG(ERROR) << "Error calling Tspi_TPM_SetStatus: " << result;
387 return false;
388 }
389
390 return true;
391 }
392
393 bool Tpm::GetTpm(TSS_HCONTEXT context_handle, TSS_HTPM* tpm_handle) {
394 TSS_RESULT result;
395 TSS_HTPM local_tpm_handle;
396 if ((result = Tspi_Context_GetTpmObject(context_handle, &local_tpm_handle))) {
397 LOG(ERROR) << "Error calling Tspi_Context_GetTpmObject: " << result;
398 return false;
399 }
400
401 *tpm_handle = local_tpm_handle;
402 return true;
403 }
404
405 bool Tpm::GetTpmWithAuth(TSS_HCONTEXT context_handle,
406 const SecureBlob& owner_password,
407 TSS_HTPM* tpm_handle) {
408 TSS_RESULT result;
409 TSS_HTPM local_tpm_handle;
410 if (!GetTpm(context_handle, &local_tpm_handle)) {
411 LOG(ERROR) << "Error getting TPM handle";
412 return false;
413 }
414
415 TSS_HPOLICY tpm_usage_policy;
416 if ((result = Tspi_GetPolicyObject(local_tpm_handle, TSS_POLICY_USAGE,
417 &tpm_usage_policy))) {
418 LOG(ERROR) << "Error calling Tspi_GetPolicyObject: " << result;
419 return false;
420 }
421
422 if ((result = Tspi_Policy_SetSecret(tpm_usage_policy, TSS_SECRET_MODE_PLAIN,
423 owner_password.size(),
424 const_cast<BYTE *>(static_cast<const BYTE *>(
425 owner_password.const_data()))))) {
426 LOG(ERROR) << "Error calling Tspi_Policy_SetSecret: " << result;
427 return false;
428 }
429
430 *tpm_handle = local_tpm_handle;
431 return true;
432 }
433
434 bool Tpm::GetOwnerPassword(chromeos::Blob* owner_password) {
435 bool result = false;
436 if (password_sync_lock_.Try()) {
437 if (owner_password_.size() != 0) {
438 owner_password->assign(owner_password_.begin(), owner_password_.end());
439 result = true;
440 }
441 password_sync_lock_.Release();
442 }
443 return result;
444 }
445
446 bool Tpm::InitializeTpm() {
447 if (!IsConnected()) {
448 Connect();
449 }
450
451 if (!IsConnected()) {
452 LOG(ERROR) << "Failed to connect to TPM";
453 return false;
454 }
455
456 if (is_disabled_) {
457 LOG(ERROR) << "Error TPM is disabled";
458 return false;
459 }
460
461 if (is_owned_) {
462 return false;
463 }
464
465 file_util::Delete(FilePath(kOpenCryptokiPath), true);
466 file_util::Delete(FilePath(kTpmOwnedFile), false);
467
468 if (!IsEndorsementKeyAvailable(context_handle_)) {
469 if (!CreateEndorsementKey(context_handle_)) {
470 LOG(ERROR) << "Failed to create endorsement key";
471 return false;
472 }
473 }
474
475 if (!IsEndorsementKeyAvailable(context_handle_)) {
476 LOG(ERROR) << "Endorsement key is not available";
477 return false;
478 }
479
480 if (!TakeOwnership(context_handle_, kMaxTimeoutRetries)) {
481 LOG(ERROR) << "Take Ownership failed";
482 return false;
483 }
484
485 SecureBlob owner_password;
486 password_sync_lock_.Acquire();
487 owner_password.assign(owner_password_.begin(), owner_password_.end());
488 password_sync_lock_.Release();
489
490 if (!ZeroSrkPassword(context_handle_, owner_password)) {
491 LOG(ERROR) << "Couldn't zero SRK password";
492 return false;
493 }
494
495 if (!UnrestrictSrk(context_handle_, owner_password)) {
496 LOG(ERROR) << "Couldn't unrestrict the SRK";
497 return false;
498 }
499
500 is_owned_ = true;
501
502 file_util::WriteFile(FilePath(kTpmOwnedFile), NULL, 0);
503
504 return true;
505 }
506
507 } // namespace tpm_init
OLDNEW
« no previous file with comments | « tpm.h ('k') | tpm_init.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698