| 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 |