| OLD | NEW |
| 1 /* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 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 * High-level firmware API for loading and verifying rewritable firmware. | 5 * High-level firmware API for loading and verifying rewritable firmware. |
| 6 * (Firmware portion) | 6 * (Firmware portion) |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "load_firmware_fw.h" | 9 #include "load_firmware_fw.h" |
| 10 #include "rollback_index.h" | 10 #include "rollback_index.h" |
| 11 #include "utility.h" | 11 #include "utility.h" |
| 12 #include "vboot_common.h" | 12 #include "vboot_common.h" |
| 13 #include "vboot_nvstorage.h" |
| 13 | 14 |
| 14 /* Static variables for UpdateFirmwareBodyHash(). It's less than | 15 /* Static variables for UpdateFirmwareBodyHash(). It's less than |
| 15 * optimal to have static variables in a library, but in UEFI the | 16 * optimal to have static variables in a library, but in UEFI the |
| 16 * caller is deep inside a different firmware stack and doesn't have a | 17 * caller is deep inside a different firmware stack and doesn't have a |
| 17 * good way to pass the params struct back to us. */ | 18 * good way to pass the params struct back to us. */ |
| 18 typedef struct VbLoadFirmwareInternal { | 19 typedef struct VbLoadFirmwareInternal { |
| 19 DigestContext body_digest_context; | 20 DigestContext body_digest_context; |
| 20 uint64_t body_size_accum; | 21 uint64_t body_size_accum; |
| 21 } VbLoadFirmwareInternal; | 22 } VbLoadFirmwareInternal; |
| 22 | 23 |
| 23 | 24 |
| 24 void UpdateFirmwareBodyHash(LoadFirmwareParams* params, | 25 void UpdateFirmwareBodyHash(LoadFirmwareParams* params, |
| 25 uint8_t* data, uint64_t size) { | 26 uint8_t* data, uint64_t size) { |
| 26 VbLoadFirmwareInternal* lfi = | 27 VbLoadFirmwareInternal* lfi = |
| 27 (VbLoadFirmwareInternal*)params->load_firmware_internal; | 28 (VbLoadFirmwareInternal*)params->load_firmware_internal; |
| 28 | 29 |
| 29 DigestUpdate(&lfi->body_digest_context, data, size); | 30 DigestUpdate(&lfi->body_digest_context, data, size); |
| 30 lfi->body_size_accum += size; | 31 lfi->body_size_accum += size; |
| 31 } | 32 } |
| 32 | 33 |
| 33 | 34 |
| 35 int LoadFirmwareSetup(void) { |
| 36 /* TODO: start initializing the TPM */ |
| 37 return LOAD_FIRMWARE_SUCCESS; |
| 38 } |
| 39 |
| 40 |
| 34 int LoadFirmware(LoadFirmwareParams* params) { | 41 int LoadFirmware(LoadFirmwareParams* params) { |
| 35 | 42 |
| 36 VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; | 43 VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; |
| 37 VbLoadFirmwareInternal* lfi; | 44 VbLoadFirmwareInternal* lfi; |
| 45 VbNvContext* vnc = params->nv_context; |
| 38 | 46 |
| 47 uint32_t try_b_count; |
| 39 uint32_t tpm_version = 0; | 48 uint32_t tpm_version = 0; |
| 40 uint64_t lowest_version = 0xFFFFFFFF; | 49 uint64_t lowest_version = 0xFFFFFFFF; |
| 41 uint32_t status; | 50 uint32_t status; |
| 42 int good_index = -1; | 51 int good_index = -1; |
| 43 int is_dev; | 52 int is_dev; |
| 44 int index; | 53 int index; |
| 54 int i; |
| 55 |
| 56 int retval = LOAD_FIRMWARE_RECOVERY; |
| 57 int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; |
| 45 | 58 |
| 46 /* Clear output params in case we fail */ | 59 /* Clear output params in case we fail */ |
| 47 params->firmware_index = 0; | 60 params->firmware_index = 0; |
| 48 | 61 |
| 49 VBDEBUG(("LoadFirmware started...\n")); | 62 VBDEBUG(("LoadFirmware started...\n")); |
| 50 | 63 |
| 64 /* Setup NV storage */ |
| 65 VbNvSetup(vnc); |
| 66 |
| 51 if (params->kernel_sign_key_size < sizeof(VbPublicKey)) { | 67 if (params->kernel_sign_key_size < sizeof(VbPublicKey)) { |
| 52 VBDEBUG(("Kernel sign key buffer too small\n")); | 68 VBDEBUG(("Kernel sign key buffer too small\n")); |
| 53 return LOAD_FIRMWARE_RECOVERY; | 69 goto LoadFirmwareExit; |
| 54 } | 70 } |
| 55 | 71 |
| 56 /* Must have a root key */ | 72 /* Must have a root key */ |
| 57 if (!root_key) { | 73 if (!root_key) { |
| 58 VBDEBUG(("No root key\n")); | 74 VBDEBUG(("No root key\n")); |
| 59 return LOAD_FIRMWARE_RECOVERY; | 75 goto LoadFirmwareExit; |
| 60 } | 76 } |
| 61 | 77 |
| 62 /* Parse flags */ | 78 /* Parse flags */ |
| 63 is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0); | 79 is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0); |
| 64 | 80 |
| 65 /* Initialize the TPM and read rollback indices. */ | 81 /* Initialize the TPM and read rollback indices. */ |
| 66 VBPERFSTART("VB_TPMI"); | 82 VBPERFSTART("VB_TPMI"); |
| 67 status = RollbackFirmwareSetup(is_dev, &tpm_version); | 83 status = RollbackFirmwareSetup(is_dev, &tpm_version); |
| 68 if (0 != status) { | 84 if (0 != status) { |
| 69 VBDEBUG(("Unable to setup TPM and read stored versions.\n")); | 85 VBDEBUG(("Unable to setup TPM and read stored versions.\n")); |
| 70 VBPERFEND("VB_TPMI"); | 86 VBPERFEND("VB_TPMI"); |
| 71 return (status == TPM_E_MUST_REBOOT ? | 87 if (status == TPM_E_MUST_REBOOT) |
| 72 LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM); | 88 retval = LOAD_FIRMWARE_REBOOT; |
| 89 else |
| 90 recovery = VBNV_RECOVERY_RO_TPM_ERROR; |
| 91 goto LoadFirmwareExit; |
| 73 } | 92 } |
| 74 VBPERFEND("VB_TPMI"); | 93 VBPERFEND("VB_TPMI"); |
| 75 | 94 |
| 95 /* Read try-b count and decrement if necessary */ |
| 96 VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count); |
| 97 if (0 != try_b_count) |
| 98 VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1); |
| 99 VbNvSet(vnc, VBNV_TRIED_FIRMWARE_B, try_b_count ? 1 : 0); |
| 100 |
| 76 /* Allocate our internal data */ | 101 /* Allocate our internal data */ |
| 77 lfi = (VbLoadFirmwareInternal*)Malloc(sizeof(VbLoadFirmwareInternal)); | 102 lfi = (VbLoadFirmwareInternal*)Malloc(sizeof(VbLoadFirmwareInternal)); |
| 78 if (!lfi) | 103 if (!lfi) |
| 79 return LOAD_FIRMWARE_RECOVERY; | 104 return LOAD_FIRMWARE_RECOVERY; |
| 80 | 105 |
| 81 params->load_firmware_internal = (uint8_t*)lfi; | 106 params->load_firmware_internal = (uint8_t*)lfi; |
| 82 | 107 |
| 83 /* Loop over indices */ | 108 /* Loop over indices */ |
| 84 for (index = 0; index < 2; index++) { | 109 for (i = 0; i < 2; i++) { |
| 85 VbKeyBlockHeader* key_block; | 110 VbKeyBlockHeader* key_block; |
| 86 uint64_t vblock_size; | 111 uint64_t vblock_size; |
| 87 VbFirmwarePreambleHeader* preamble; | 112 VbFirmwarePreambleHeader* preamble; |
| 88 RSAPublicKey* data_key; | 113 RSAPublicKey* data_key; |
| 89 uint64_t key_version; | 114 uint64_t key_version; |
| 90 uint64_t combined_version; | 115 uint64_t combined_version; |
| 91 uint8_t* body_digest; | 116 uint8_t* body_digest; |
| 92 | 117 |
| 118 /* If try B count is non-zero try firmware B first */ |
| 119 index = (try_b_count ? i : 1 - i); |
| 120 |
| 93 /* Verify the key block */ | 121 /* Verify the key block */ |
| 94 VBPERFSTART("VB_VKB"); | 122 VBPERFSTART("VB_VKB"); |
| 95 if (0 == index) { | 123 if (0 == index) { |
| 96 key_block = (VbKeyBlockHeader*)params->verification_block_0; | 124 key_block = (VbKeyBlockHeader*)params->verification_block_0; |
| 97 vblock_size = params->verification_size_0; | 125 vblock_size = params->verification_size_0; |
| 98 } else { | 126 } else { |
| 99 key_block = (VbKeyBlockHeader*)params->verification_block_1; | 127 key_block = (VbKeyBlockHeader*)params->verification_block_1; |
| 100 vblock_size = params->verification_size_1; | 128 vblock_size = params->verification_size_1; |
| 101 } | 129 } |
| 102 if ((0 != KeyBlockVerify(key_block, vblock_size, root_key, 0))) { | 130 if ((0 != KeyBlockVerify(key_block, vblock_size, root_key, 0))) { |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 /* Handle finding good firmware */ | 269 /* Handle finding good firmware */ |
| 242 if (good_index >= 0) { | 270 if (good_index >= 0) { |
| 243 | 271 |
| 244 /* Update TPM if necessary */ | 272 /* Update TPM if necessary */ |
| 245 if (lowest_version > tpm_version) { | 273 if (lowest_version > tpm_version) { |
| 246 VBPERFSTART("VB_TPMU"); | 274 VBPERFSTART("VB_TPMU"); |
| 247 status = RollbackFirmwareWrite((uint32_t)lowest_version); | 275 status = RollbackFirmwareWrite((uint32_t)lowest_version); |
| 248 VBPERFEND("VB_TPMU"); | 276 VBPERFEND("VB_TPMU"); |
| 249 if (0 != status) { | 277 if (0 != status) { |
| 250 VBDEBUG(("Unable to write stored versions.\n")); | 278 VBDEBUG(("Unable to write stored versions.\n")); |
| 251 return (status == TPM_E_MUST_REBOOT ? | 279 if (status == TPM_E_MUST_REBOOT) |
| 252 LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM); | 280 retval = LOAD_FIRMWARE_REBOOT; |
| 281 else |
| 282 recovery = VBNV_RECOVERY_RO_TPM_ERROR; |
| 283 goto LoadFirmwareExit; |
| 253 } | 284 } |
| 254 } | 285 } |
| 255 | 286 |
| 256 /* Lock firmware versions in TPM */ | 287 /* Lock firmware versions in TPM */ |
| 257 VBPERFSTART("VB_TPML"); | 288 VBPERFSTART("VB_TPML"); |
| 258 status = RollbackFirmwareLock(); | 289 status = RollbackFirmwareLock(); |
| 259 VBPERFEND("VB_TPML"); | 290 VBPERFEND("VB_TPML"); |
| 260 if (0 != status) { | 291 if (0 != status) { |
| 261 VBDEBUG(("Unable to lock firmware versions.\n")); | 292 VBDEBUG(("Unable to lock firmware versions.\n")); |
| 262 return (status == TPM_E_MUST_REBOOT ? | 293 if (status == TPM_E_MUST_REBOOT) |
| 263 LOAD_FIRMWARE_REBOOT : LOAD_FIRMWARE_RECOVERY_TPM); | 294 retval = LOAD_FIRMWARE_REBOOT; |
| 295 else |
| 296 recovery = VBNV_RECOVERY_RO_TPM_ERROR; |
| 297 goto LoadFirmwareExit; |
| 264 } | 298 } |
| 265 | 299 |
| 266 /* Success */ | 300 /* Success */ |
| 267 VBDEBUG(("Will boot firmware index %d\n", (int)params->firmware_index)); | 301 VBDEBUG(("Will boot firmware index %d\n", (int)params->firmware_index)); |
| 268 return LOAD_FIRMWARE_SUCCESS; | 302 retval = LOAD_FIRMWARE_SUCCESS; |
| 303 } else { |
| 304 /* No good firmware, so go to recovery mode. */ |
| 305 VBDEBUG(("Alas, no good firmware.\n")); |
| 306 recovery = VBNV_RECOVERY_RO_INVALID_RW; |
| 269 } | 307 } |
| 270 | 308 |
| 271 /* If we're still here, no good firmware, so go to recovery mode. */ | 309 LoadFirmwareExit: |
| 272 VBDEBUG(("Alas, no good firmware.\n")); | 310 /* Store recovery request, if any, then tear down non-volatile storage */ |
| 273 return LOAD_FIRMWARE_RECOVERY; | 311 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_FIRMWARE_RECOVERY == retval ? |
| 312 recovery : VBNV_RECOVERY_NOT_REQUESTED); |
| 313 VbNvTeardown(vnc); |
| 314 |
| 315 return retval; |
| 274 } | 316 } |
| 275 | 317 |
| 276 | 318 |
| 277 int S3Resume(void) { | 319 int S3Resume(void) { |
| 278 /* Resume the TPM */ | 320 /* Resume the TPM */ |
| 279 uint32_t status = RollbackS3Resume(); | 321 uint32_t status = RollbackS3Resume(); |
| 280 | 322 |
| 323 /* If we can't resume, just do a full reboot. No need to go to recovery |
| 324 * mode here, since if the TPM is really broken we'll catch it on the |
| 325 * next boot. */ |
| 281 if (status == TPM_SUCCESS) | 326 if (status == TPM_SUCCESS) |
| 282 return LOAD_FIRMWARE_SUCCESS; | 327 return LOAD_FIRMWARE_SUCCESS; |
| 283 else if (status == TPM_E_MUST_REBOOT) | 328 else |
| 284 return LOAD_FIRMWARE_REBOOT; | 329 return LOAD_FIRMWARE_REBOOT; |
| 285 else | |
| 286 return LOAD_FIRMWARE_RECOVERY_TPM; | |
| 287 } | 330 } |
| OLD | NEW |