| OLD | NEW |
| 1 /* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. | 1 /* Copyright (c) 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 * 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 "gbb_header.h" |
| 9 #include "load_firmware_fw.h" | 10 #include "load_firmware_fw.h" |
| 10 #include "rollback_index.h" | 11 #include "rollback_index.h" |
| 11 #include "utility.h" | 12 #include "utility.h" |
| 12 #include "vboot_common.h" | 13 #include "vboot_common.h" |
| 13 #include "vboot_nvstorage.h" | 14 #include "vboot_nvstorage.h" |
| 14 | 15 |
| 15 /* Static variables for UpdateFirmwareBodyHash(). It's less than | 16 /* Static variables for UpdateFirmwareBodyHash(). It's less than |
| 16 * optimal to have static variables in a library, but in UEFI the | 17 * optimal to have static variables in a library, but in UEFI the |
| 17 * caller is deep inside a different firmware stack and doesn't have a | 18 * caller is deep inside a different firmware stack and doesn't have a |
| 18 * good way to pass the params struct back to us. */ | 19 * good way to pass the params struct back to us. */ |
| (...skipping 13 matching lines...) Expand all Loading... |
| 32 } | 33 } |
| 33 | 34 |
| 34 | 35 |
| 35 int LoadFirmwareSetup(void) { | 36 int LoadFirmwareSetup(void) { |
| 36 /* TODO: start initializing the TPM */ | 37 /* TODO: start initializing the TPM */ |
| 37 return LOAD_FIRMWARE_SUCCESS; | 38 return LOAD_FIRMWARE_SUCCESS; |
| 38 } | 39 } |
| 39 | 40 |
| 40 | 41 |
| 41 int LoadFirmware(LoadFirmwareParams* params) { | 42 int LoadFirmware(LoadFirmwareParams* params) { |
| 42 | 43 VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob; |
| 43 VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; | 44 GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data; |
| 45 VbPublicKey* root_key; |
| 44 VbLoadFirmwareInternal* lfi; | 46 VbLoadFirmwareInternal* lfi; |
| 45 VbNvContext* vnc = params->nv_context; | 47 VbNvContext* vnc = params->nv_context; |
| 46 | 48 |
| 47 uint32_t try_b_count; | 49 uint32_t try_b_count; |
| 48 uint32_t tpm_version = 0; | 50 uint32_t tpm_version = 0; |
| 49 uint64_t lowest_version = 0xFFFFFFFF; | 51 uint64_t lowest_version = 0xFFFFFFFF; |
| 50 uint32_t status; | 52 uint32_t status; |
| 51 int good_index = -1; | 53 int good_index = -1; |
| 52 int is_dev; | 54 int is_dev; |
| 53 int index; | 55 int index; |
| 54 int i; | 56 int i; |
| 55 | 57 |
| 56 int retval = LOAD_FIRMWARE_RECOVERY; | 58 int retval = LOAD_FIRMWARE_RECOVERY; |
| 57 int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; | 59 int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; |
| 58 | 60 |
| 59 /* Clear output params in case we fail */ | 61 /* Clear output params in case we fail */ |
| 60 params->firmware_index = 0; | 62 params->firmware_index = 0; |
| 61 | 63 |
| 62 VBDEBUG(("LoadFirmware started...\n")); | 64 VBDEBUG(("LoadFirmware started...\n")); |
| 63 | 65 |
| 64 /* Setup NV storage */ | 66 /* Setup NV storage */ |
| 65 VbNvSetup(vnc); | 67 VbNvSetup(vnc); |
| 66 | 68 |
| 67 if (params->kernel_sign_key_size < sizeof(VbPublicKey)) { | 69 /* Initialize shared data structure. */ |
| 68 VBDEBUG(("Kernel sign key buffer too small\n")); | 70 if (0 != VbSharedDataInit(shared, params->shared_data_size)) { |
| 71 VBDEBUG(("Shared data init error\n")); |
| 72 recovery = VBNV_RECOVERY_RO_SHARED_DATA; |
| 69 goto LoadFirmwareExit; | 73 goto LoadFirmwareExit; |
| 70 } | 74 } |
| 71 | 75 |
| 72 /* Must have a root key */ | 76 /* Must have a root key from the GBB */ |
| 73 if (!root_key) { | 77 if (!gbb) { |
| 74 VBDEBUG(("No root key\n")); | 78 VBDEBUG(("No GBB\n")); |
| 75 goto LoadFirmwareExit; | 79 goto LoadFirmwareExit; |
| 76 } | 80 } |
| 81 root_key = (VbPublicKey*)((uint8_t*)gbb + gbb->rootkey_offset); |
| 77 | 82 |
| 78 /* Parse flags */ | 83 /* Parse flags */ |
| 79 is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0); | 84 is_dev = (params->boot_flags & BOOT_FLAG_DEVELOPER ? 1 : 0); |
| 80 | 85 |
| 81 /* Initialize the TPM and read rollback indices. */ | 86 /* Initialize the TPM and read rollback indices. */ |
| 82 VBPERFSTART("VB_TPMI"); | 87 VBPERFSTART("VB_TPMI"); |
| 83 status = RollbackFirmwareSetup(is_dev, &tpm_version); | 88 status = RollbackFirmwareSetup(is_dev, &tpm_version); |
| 84 if (0 != status) { | 89 if (0 != status) { |
| 85 VBDEBUG(("Unable to setup TPM and read stored versions.\n")); | 90 VBDEBUG(("Unable to setup TPM and read stored versions.\n")); |
| 86 VBPERFEND("VB_TPMI"); | 91 VBPERFEND("VB_TPMI"); |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 } | 233 } |
| 229 VBPERFEND("VB_VFD"); | 234 VBPERFEND("VB_VFD"); |
| 230 | 235 |
| 231 /* Done with the digest and data key, so can free them now */ | 236 /* Done with the digest and data key, so can free them now */ |
| 232 RSAPublicKeyFree(data_key); | 237 RSAPublicKeyFree(data_key); |
| 233 Free(body_digest); | 238 Free(body_digest); |
| 234 | 239 |
| 235 /* If we're still here, the firmware is valid. */ | 240 /* If we're still here, the firmware is valid. */ |
| 236 VBDEBUG(("Firmware %d is valid.\n", index)); | 241 VBDEBUG(("Firmware %d is valid.\n", index)); |
| 237 if (-1 == good_index) { | 242 if (-1 == good_index) { |
| 238 VbPublicKey *kdest = (VbPublicKey*)params->kernel_sign_key_blob; | 243 /* Save the key we actually used */ |
| 239 | 244 if (0 != VbSharedDataSetKernelKey(shared, &preamble->kernel_subkey)) { |
| 240 /* Copy the kernel sign key blob into the destination buffer */ | 245 VBDEBUG(("Unable to save kernel subkey to shared data.\n")); |
| 241 PublicKeyInit(kdest, (uint8_t*)(kdest + 1), | |
| 242 (params->kernel_sign_key_size - sizeof(VbPublicKey))); | |
| 243 | |
| 244 if (0 != PublicKeyCopy(kdest, &preamble->kernel_subkey)) { | |
| 245 VBDEBUG(("Kernel subkey too big for buffer.\n")); | |
| 246 continue; /* The firmware signature was good, but the public | 246 continue; /* The firmware signature was good, but the public |
| 247 * key was bigger that the caller can handle. */ | 247 * key was bigger that the caller can handle. */ |
| 248 } | 248 } |
| 249 | 249 |
| 250 /* Save the key size we actually used */ | |
| 251 params->kernel_sign_key_size = kdest->key_offset + kdest->key_size; | |
| 252 | |
| 253 /* Save the good index, now that we're sure we can actually use | 250 /* Save the good index, now that we're sure we can actually use |
| 254 * this firmware. That's the one we'll boot. */ | 251 * this firmware. That's the one we'll boot. */ |
| 255 good_index = index; | 252 good_index = index; |
| 256 params->firmware_index = index; | 253 params->firmware_index = index; |
| 257 | 254 |
| 258 /* If the good firmware's key version is the same as the tpm, | 255 /* If the good firmware's key version is the same as the tpm, |
| 259 * then the TPM doesn't need updating; we can stop now. | 256 * then the TPM doesn't need updating; we can stop now. |
| 260 * Otherwise, we'll check all the other headers to see if they | 257 * Otherwise, we'll check all the other headers to see if they |
| 261 * contain a newer key. */ | 258 * contain a newer key. */ |
| 262 if (combined_version == tpm_version) | 259 if (combined_version == tpm_version) |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 VBDEBUG(("Alas, no good firmware.\n")); | 304 VBDEBUG(("Alas, no good firmware.\n")); |
| 308 recovery = VBNV_RECOVERY_RO_INVALID_RW; | 305 recovery = VBNV_RECOVERY_RO_INVALID_RW; |
| 309 } | 306 } |
| 310 | 307 |
| 311 LoadFirmwareExit: | 308 LoadFirmwareExit: |
| 312 /* Store recovery request, if any, then tear down non-volatile storage */ | 309 /* Store recovery request, if any, then tear down non-volatile storage */ |
| 313 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_FIRMWARE_RECOVERY == retval ? | 310 VbNvSet(vnc, VBNV_RECOVERY_REQUEST, LOAD_FIRMWARE_RECOVERY == retval ? |
| 314 recovery : VBNV_RECOVERY_NOT_REQUESTED); | 311 recovery : VBNV_RECOVERY_NOT_REQUESTED); |
| 315 VbNvTeardown(vnc); | 312 VbNvTeardown(vnc); |
| 316 | 313 |
| 314 /* Note that we don't reduce params->shared_data_size to shared->data_used, |
| 315 * since we want to leave space for LoadKernel() to add to the shared data |
| 316 * buffer. */ |
| 317 |
| 317 return retval; | 318 return retval; |
| 318 } | 319 } |
| 319 | 320 |
| 320 | 321 |
| 321 int S3Resume(void) { | 322 int S3Resume(void) { |
| 322 /* Resume the TPM */ | 323 /* Resume the TPM */ |
| 323 uint32_t status = RollbackS3Resume(); | 324 uint32_t status = RollbackS3Resume(); |
| 324 | 325 |
| 325 /* If we can't resume, just do a full reboot. No need to go to recovery | 326 /* If we can't resume, just do a full reboot. No need to go to recovery |
| 326 * mode here, since if the TPM is really broken we'll catch it on the | 327 * mode here, since if the TPM is really broken we'll catch it on the |
| 327 * next boot. */ | 328 * next boot. */ |
| 328 if (status == TPM_SUCCESS) | 329 if (status == TPM_SUCCESS) |
| 329 return LOAD_FIRMWARE_SUCCESS; | 330 return LOAD_FIRMWARE_SUCCESS; |
| 330 else | 331 else |
| 331 return LOAD_FIRMWARE_REBOOT; | 332 return LOAD_FIRMWARE_REBOOT; |
| 332 } | 333 } |
| OLD | NEW |