OLD | NEW |
1 /* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 2010-2011 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 * Functions for querying, manipulating and locking rollback indices | 5 * Functions for querying, manipulating and locking rollback indices |
6 * stored in the TPM NVRAM. | 6 * stored in the TPM NVRAM. |
7 */ | 7 */ |
8 | 8 |
9 #include "rollback_index.h" | 9 #include "rollback_index.h" |
10 | 10 |
11 #include "tlcl.h" | 11 #include "tlcl.h" |
| 12 #include "tpm_bootmode.h" |
12 #include "tss_constants.h" | 13 #include "tss_constants.h" |
13 #include "utility.h" | 14 #include "utility.h" |
14 | 15 |
15 /* TPM PCR to use for storing dev mode measurements */ | |
16 #define DEV_REC_MODE_PCR 0 | |
17 /* Input digests for PCR extend */ | |
18 #define DEV_OFF_REC_OFF_SHA1_DIGEST ((uint8_t*) "\x14\x89\xf9\x23\xc4\xdc\xa7" \ | |
19 "\x29\x17\x8b\x3e\x32\x33\x45\x85\x50" \ | |
20 "\xd8\xdd\xdf\x29") /* SHA1("\x00\x00") */ | |
21 | |
22 #define DEV_OFF_REC_ON_SHA1_DIGEST ((uint8_t*) "\x3f\x29\x54\x64\x53\x67\x8b" \ | |
23 "\x85\x59\x31\xc1\x74\xa9\x7d\x6c\x08" \ | |
24 "\x94\xb8\xf5\x46") /* SHA1("\x00\x01") */ | |
25 | |
26 #define DEV_ON_REC_OFF_SHA1_DIGEST ((uint8_t*) "\x0e\x35\x6b\xa5\x05\x63\x1f" \ | |
27 "\xbf\x71\x57\x58\xbe\xd2\x7d\x50\x3f" \ | |
28 "\x8b\x26\x0e\x3a") /* SHA1("\x01\x00") */ | |
29 | |
30 #define DEV_ON_REC_ON_SHA1_DIGEST ((uint8_t*) "\x91\x59\xcb\x8b\xce\xe7\xfc" \ | |
31 "\xb9\x55\x82\xf1\x40\x96\x0c\xda\xe7" \ | |
32 "\x27\x88\xd3\x26") /* SHA1("\x01\x01") */ | |
33 | |
34 static int g_rollback_recovery_mode = 0; | 16 static int g_rollback_recovery_mode = 0; |
35 | 17 |
36 /* disable MSVC warning on const logical expression (as in } while(0);) */ | 18 /* disable MSVC warning on const logical expression (as in } while(0);) */ |
37 __pragma(warning (disable: 4127)) | 19 __pragma(warning (disable: 4127)) |
38 | 20 |
39 #define RETURN_ON_FAILURE(tpm_command) do { \ | 21 #define RETURN_ON_FAILURE(tpm_command) do { \ |
40 uint32_t result; \ | 22 uint32_t result; \ |
41 if ((result = (tpm_command)) != TPM_SUCCESS) { \ | 23 if ((result = (tpm_command)) != TPM_SUCCESS) { \ |
42 VBDEBUG(("Rollback: %08x returned by " #tpm_command "\n", (int)result)); \ | 24 VBDEBUG(("Rollback: %08x returned by " #tpm_command "\n", (int)result)); \ |
43 return result; \ | 25 return result; \ |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 RollbackSpaceKernel* rsk) { | 96 RollbackSpaceKernel* rsk) { |
115 static const RollbackSpaceFirmware rsf_init = { | 97 static const RollbackSpaceFirmware rsf_init = { |
116 ROLLBACK_SPACE_FIRMWARE_VERSION, 0, 0, 0}; | 98 ROLLBACK_SPACE_FIRMWARE_VERSION, 0, 0, 0}; |
117 static const RollbackSpaceKernel rsk_init = { | 99 static const RollbackSpaceKernel rsk_init = { |
118 ROLLBACK_SPACE_KERNEL_VERSION, ROLLBACK_SPACE_KERNEL_UID, 0, 0}; | 100 ROLLBACK_SPACE_KERNEL_VERSION, ROLLBACK_SPACE_KERNEL_UID, 0, 0}; |
119 TPM_PERMANENT_FLAGS pflags; | 101 TPM_PERMANENT_FLAGS pflags; |
120 uint32_t result; | 102 uint32_t result; |
121 | 103 |
122 VBDEBUG(("TPM: One-time initialization\n")); | 104 VBDEBUG(("TPM: One-time initialization\n")); |
123 | 105 |
| 106 /* Do a full test. This only happens the first time the device is turned on |
| 107 * in the factory, so performance is not an issue. This is almost certainly |
| 108 * not necessary, but it gives us more confidence about some code paths below |
| 109 * that are difficult to test---specifically the ones that set lifetime |
| 110 * flags, and are only executed once per physical TPM. */ |
| 111 result = TlclSelfTestFull(); |
| 112 if (result != TPM_SUCCESS) |
| 113 return result; |
| 114 |
124 result = TlclGetPermanentFlags(&pflags); | 115 result = TlclGetPermanentFlags(&pflags); |
125 if (result != TPM_SUCCESS) | 116 if (result != TPM_SUCCESS) |
126 return result; | 117 return result; |
127 | 118 |
128 /* TPM may come from the factory without physical presence finalized. Fix | 119 /* TPM may come from the factory without physical presence finalized. Fix |
129 * if necessary. */ | 120 * if necessary. */ |
130 VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n", | 121 VBDEBUG(("TPM: physicalPresenceLifetimeLock=%d\n", |
131 pflags.physicalPresenceLifetimeLock)); | 122 pflags.physicalPresenceLifetimeLock)); |
132 if (!pflags.physicalPresenceLifetimeLock) { | 123 if (!pflags.physicalPresenceLifetimeLock) { |
133 VBDEBUG(("TPM: Finalizing physical presence\n")); | 124 VBDEBUG(("TPM: Finalizing physical presence\n")); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 | 184 |
194 VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode)); | 185 VBDEBUG(("TPM: SetupTPM(r%d, d%d)\n", recovery_mode, developer_mode)); |
195 | 186 |
196 if (recovery_mode) | 187 if (recovery_mode) |
197 g_rollback_recovery_mode = 1; /* Global variables are usable in | 188 g_rollback_recovery_mode = 1; /* Global variables are usable in |
198 * recovery mode */ | 189 * recovery mode */ |
199 | 190 |
200 RETURN_ON_FAILURE(TlclLibInit()); | 191 RETURN_ON_FAILURE(TlclLibInit()); |
201 | 192 |
202 RETURN_ON_FAILURE(TlclStartup()); | 193 RETURN_ON_FAILURE(TlclStartup()); |
203 /* Use ContinueSelfTest rather than SelfTestFull(). It enables | 194 /* Some TPMs start the self test automatically at power on. In that case we |
204 * access to the subset of TPM commands we need in the firmware, and | 195 * don't need to call ContinueSelfTest. On some (other) TPMs, |
205 * allows the full self test to run in paralle with firmware | 196 * ContinueSelfTest may block. In that case, we definitely don't want to |
206 * startup. By the time we get to the OS, self test will have | 197 * call it here. For TPMs in the intersection of these two sets, we're |
207 * completed. */ | 198 * screwed. (In other words: TPMs that require manually starting the |
| 199 * self-test AND block will have poor performance until we split |
| 200 * TlclSendReceive() into Send() and Receive(), and have a state machine to |
| 201 * control setup.) |
| 202 * |
| 203 * This comment is likely to become obsolete in the near future, so don't |
| 204 * trust it. It may have not been updated. |
| 205 */ |
| 206 #ifdef TPM_MANUAL_SELFTEST |
| 207 #ifdef TPM_BLOCKING_CONTINUESELFTEST |
| 208 #warning "lousy TPM!" |
| 209 #endif |
208 RETURN_ON_FAILURE(TlclContinueSelfTest()); | 210 RETURN_ON_FAILURE(TlclContinueSelfTest()); |
| 211 #endif |
209 result = TlclAssertPhysicalPresence(); | 212 result = TlclAssertPhysicalPresence(); |
210 if (result != 0) { | 213 if (result != 0) { |
211 /* It is possible that the TPM was delivered with the physical presence | 214 /* It is possible that the TPM was delivered with the physical presence |
212 * command disabled. This tries enabling it, then tries asserting PP | 215 * command disabled. This tries enabling it, then tries asserting PP |
213 * again. | 216 * again. |
214 */ | 217 */ |
215 RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable()); | 218 RETURN_ON_FAILURE(TlclPhysicalPresenceCMDEnable()); |
216 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); | 219 RETURN_ON_FAILURE(TlclAssertPhysicalPresence()); |
217 } | 220 } |
218 | 221 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
287 } | 290 } |
288 | 291 |
289 uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) { | 292 uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) { |
290 #ifndef CHROMEOS_ENVIRONMENT | 293 #ifndef CHROMEOS_ENVIRONMENT |
291 /* Initializes the TPM, but ignores return codes. In ChromeOS | 294 /* Initializes the TPM, but ignores return codes. In ChromeOS |
292 * environment, doesn't even talk to the TPM. */ | 295 * environment, doesn't even talk to the TPM. */ |
293 TlclLibInit(); | 296 TlclLibInit(); |
294 TlclStartup(); | 297 TlclStartup(); |
295 TlclContinueSelfTest(); | 298 TlclContinueSelfTest(); |
296 #endif | 299 #endif |
297 | |
298 *version = 0; | 300 *version = 0; |
299 return TPM_SUCCESS; | 301 return TPM_SUCCESS; |
300 } | 302 } |
| 303 |
| 304 uint32_t RollbackFirmwareRead(uint32_t* version) { |
| 305 *version = 0; |
| 306 return TPM_SUCCESS; |
| 307 } |
301 | 308 |
302 uint32_t RollbackFirmwareWrite(uint32_t version) { | 309 uint32_t RollbackFirmwareWrite(uint32_t version) { |
303 return TPM_SUCCESS; | 310 return TPM_SUCCESS; |
304 } | 311 } |
305 | 312 |
306 uint32_t RollbackFirmwareLock(void) { | 313 uint32_t RollbackFirmwareLock(void) { |
307 return TPM_SUCCESS; | 314 return TPM_SUCCESS; |
308 } | 315 } |
309 | 316 |
310 uint32_t RollbackKernelRecovery(int developer_mode) { | 317 uint32_t RollbackKernelRecovery(int developer_mode) { |
(...skipping 30 matching lines...) Expand all Loading... |
341 /* We're on a platform where the TPM maintains power in S3, so | 348 /* We're on a platform where the TPM maintains power in S3, so |
342 it's already initialized. */ | 349 it's already initialized. */ |
343 return TPM_SUCCESS; | 350 return TPM_SUCCESS; |
344 } | 351 } |
345 return result; | 352 return result; |
346 } | 353 } |
347 | 354 |
348 | 355 |
349 uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) { | 356 uint32_t RollbackFirmwareSetup(int developer_mode, uint32_t* version) { |
350 RollbackSpaceFirmware rsf; | 357 RollbackSpaceFirmware rsf; |
351 uint8_t out_digest[20]; /* For PCR extend output */ | |
352 | 358 |
353 RETURN_ON_FAILURE(SetupTPM(0, developer_mode, &rsf)); | 359 RETURN_ON_FAILURE(SetupTPM(0, developer_mode, &rsf)); |
354 *version = rsf.fw_versions; | 360 *version = rsf.fw_versions; |
355 VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)rsf.fw_versions)); | 361 VBDEBUG(("TPM: RollbackFirmwareSetup %x\n", (int)rsf.fw_versions)); |
356 if (developer_mode) | |
357 RETURN_ON_FAILURE(TlclExtend(DEV_REC_MODE_PCR, DEV_ON_REC_OFF_SHA1_DIGEST, | |
358 out_digest)); | |
359 else | |
360 RETURN_ON_FAILURE(TlclExtend(DEV_REC_MODE_PCR, DEV_OFF_REC_OFF_SHA1_DIGEST, | |
361 out_digest)); | |
362 VBDEBUG(("TPM: RollbackFirmwareSetup dev mode PCR out_digest %02x %02x %02x " | |
363 "%02x\n", out_digest, out_digest+1, out_digest+2, out_digest+3)); | |
364 | |
365 return TPM_SUCCESS; | 362 return TPM_SUCCESS; |
366 } | 363 } |
367 | 364 |
| 365 uint32_t RollbackFirmwareRead(uint32_t* version) { |
| 366 RollbackSpaceFirmware rsf; |
| 367 |
| 368 RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf)); |
| 369 VBDEBUG(("TPM: RollbackFirmwareRead %x --> %x\n", (int)rsf.fw_versions, |
| 370 (int)version)); |
| 371 *version = rsf.fw_versions; |
| 372 VBDEBUG(("TPM: RollbackFirmwareRead %x\n", (int)rsf.fw_versions)); |
| 373 return TPM_SUCCESS; |
| 374 } |
| 375 |
368 uint32_t RollbackFirmwareWrite(uint32_t version) { | 376 uint32_t RollbackFirmwareWrite(uint32_t version) { |
369 RollbackSpaceFirmware rsf; | 377 RollbackSpaceFirmware rsf; |
370 | 378 |
371 RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf)); | 379 RETURN_ON_FAILURE(ReadSpaceFirmware(&rsf)); |
372 VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)rsf.fw_versions, | 380 VBDEBUG(("TPM: RollbackFirmwareWrite %x --> %x\n", (int)rsf.fw_versions, |
373 (int)version)); | 381 (int)version)); |
374 rsf.fw_versions = version; | 382 rsf.fw_versions = version; |
375 return WriteSpaceFirmware(&rsf); | 383 return WriteSpaceFirmware(&rsf); |
376 } | 384 } |
377 | 385 |
378 uint32_t RollbackFirmwareLock(void) { | 386 uint32_t RollbackFirmwareLock(void) { |
379 return TlclSetGlobalLock(); | 387 return TlclSetGlobalLock(); |
380 } | 388 } |
381 | 389 |
382 uint32_t RollbackKernelRecovery(int developer_mode) { | 390 uint32_t RollbackKernelRecovery(int developer_mode) { |
383 uint32_t rvs, rve; | 391 uint32_t rvs, rve; |
384 RollbackSpaceFirmware rsf; | 392 RollbackSpaceFirmware rsf; |
385 uint8_t out_digest[20]; /* For PCR extend output */ | |
386 | 393 |
387 /* In recovery mode we ignore TPM malfunctions or corruptions, and * | 394 /* In recovery mode we ignore TPM malfunctions or corruptions, and * |
388 * leave the TPM complelely unlocked; we call neither | 395 * leave the TPM complelely unlocked; we call neither |
389 * TlclSetGlobalLock() nor TlclLockPhysicalPresence(). The recovery | 396 * TlclSetGlobalLock() nor TlclLockPhysicalPresence(). The recovery |
390 * kernel will fix the TPM (if needed) and lock it ASAP. We leave | 397 * kernel will fix the TPM (if needed) and lock it ASAP. We leave |
391 * Physical Presence on in either case. */ | 398 * Physical Presence on in either case. */ |
392 rvs = SetupTPM(1, developer_mode, &rsf); | 399 rvs = SetupTPM(1, developer_mode, &rsf); |
393 if (developer_mode) | 400 rve = SetTPMBootModeState(developer_mode, |
394 rve = TlclExtend(DEV_REC_MODE_PCR, DEV_ON_REC_ON_SHA1_DIGEST, out_digest); | 401 1, /* Recovery Mode Status. */ |
395 else | 402 0); /* In recovery mode, there is no RW firmware |
396 rve = TlclExtend(DEV_REC_MODE_PCR, DEV_OFF_REC_ON_SHA1_DIGEST, out_digest); | 403 * keyblock flag. */ |
397 VBDEBUG(("TPM: RollbackKernelRecovery dev mode PCR out_digest %02x %02x %02x " | |
398 "%02x\n", out_digest, out_digest+1, out_digest+2, out_digest+3)); | |
399 return (TPM_SUCCESS == rvs) ? rve : rvs; | 404 return (TPM_SUCCESS == rvs) ? rve : rvs; |
400 } | 405 } |
401 | 406 |
402 uint32_t RollbackKernelRead(uint32_t* version) { | 407 uint32_t RollbackKernelRead(uint32_t* version) { |
403 if (g_rollback_recovery_mode) { | 408 RollbackSpaceKernel rsk; |
404 *version = 0; | 409 uint32_t perms; |
405 } else { | |
406 RollbackSpaceKernel rsk; | |
407 uint32_t perms; | |
408 | 410 |
409 /* Read the kernel space and verify its permissions. If the kernel | 411 /* Read the kernel space and verify its permissions. If the kernel |
410 * space has the wrong permission, or it doesn't contain the right | 412 * space has the wrong permission, or it doesn't contain the right |
411 * identifier, we give up. This will need to be fixed by the | 413 * identifier, we give up. This will need to be fixed by the |
412 * recovery kernel. We have to worry about this because at any time | 414 * recovery kernel. We have to worry about this because at any time |
413 * (even with PP turned off) the TPM owner can remove and redefine a | 415 * (even with PP turned off) the TPM owner can remove and redefine a |
414 * PP-protected space (but not write to it). */ | 416 * PP-protected space (but not write to it). */ |
415 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); | 417 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); |
416 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); | 418 RETURN_ON_FAILURE(TlclGetPermissions(KERNEL_NV_INDEX, &perms)); |
417 if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != rsk.uid) | 419 if (TPM_NV_PER_PPWRITE != perms || ROLLBACK_SPACE_KERNEL_UID != rsk.uid) |
418 return TPM_E_CORRUPTED_STATE; | 420 return TPM_E_CORRUPTED_STATE; |
419 | 421 |
420 *version = rsk.kernel_versions; | 422 *version = rsk.kernel_versions; |
421 VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)rsk.kernel_versions)); | 423 VBDEBUG(("TPM: RollbackKernelRead %x\n", (int)rsk.kernel_versions)); |
422 } | |
423 return TPM_SUCCESS; | 424 return TPM_SUCCESS; |
424 } | 425 } |
425 | 426 |
426 uint32_t RollbackKernelWrite(uint32_t version) { | 427 uint32_t RollbackKernelWrite(uint32_t version) { |
427 if (g_rollback_recovery_mode) { | 428 RollbackSpaceKernel rsk; |
428 return TPM_SUCCESS; | 429 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); |
429 } else { | 430 VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", (int)rsk.kernel_versions, |
430 RollbackSpaceKernel rsk; | 431 (int)version)); |
431 RETURN_ON_FAILURE(ReadSpaceKernel(&rsk)); | 432 rsk.kernel_versions = version; |
432 VBDEBUG(("TPM: RollbackKernelWrite %x --> %x\n", (int)rsk.kernel_versions, | 433 return WriteSpaceKernel(&rsk); |
433 (int)version)); | |
434 rsk.kernel_versions = version; | |
435 return WriteSpaceKernel(&rsk); | |
436 } | |
437 } | 434 } |
438 | 435 |
439 uint32_t RollbackKernelLock(void) { | 436 uint32_t RollbackKernelLock(void) { |
440 if (g_rollback_recovery_mode) { | 437 if (g_rollback_recovery_mode) { |
441 return TPM_SUCCESS; | 438 return TPM_SUCCESS; |
442 } else { | 439 } else { |
443 return TlclLockPhysicalPresence(); | 440 return TlclLockPhysicalPresence(); |
444 } | 441 } |
445 } | 442 } |
446 | 443 |
447 #endif // DISABLE_ROLLBACK_TPM | 444 #endif // DISABLE_ROLLBACK_TPM |
OLD | NEW |