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 |