Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 * found in the LICENSE file. | |
| 4 * | |
| 5 * High-level firmware API for loading and verifying rewritable firmware. | |
| 6 * (Firmware portion) | |
| 7 */ | |
| 8 | |
| 9 #include "vboot_firmware.h" | |
| 10 | |
| 11 #include "load_firmware_fw.h" | |
| 12 #include "rollback_index.h" | |
| 13 #include "utility.h" | |
| 14 #include "vboot_common.h" | |
| 15 | |
| 16 | |
| 17 void UpdateFirmwareBodyHash2(uint8_t* data, uint64_t size) { | |
| 18 /* TODO: actually update the hash. */ | |
| 19 } | |
| 20 | |
| 21 | |
| 22 int LoadFirmware2(LoadFirmwareParams* params) { | |
| 23 | |
| 24 VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; | |
| 25 | |
| 26 uint16_t tpm_key_version = 0; | |
| 27 uint16_t tpm_fw_version = 0; | |
| 28 uint64_t lowest_key_version = 0xFFFF; | |
| 29 uint64_t lowest_fw_version = 0xFFFF; | |
| 30 int good_index = -1; | |
| 31 int index; | |
| 32 | |
| 33 /* Clear output params in case we fail */ | |
| 34 params->firmware_index = 0; | |
| 35 params->kernel_sign_key_blob = NULL; | |
| 36 params->kernel_sign_key_size = 0; | |
| 37 | |
| 38 /* Must have a root key */ | |
| 39 if (!root_key) | |
| 40 return LOAD_FIRMWARE_RECOVERY; | |
| 41 | |
| 42 /* Initialize the TPM and read rollback indices. */ | |
| 43 if (0 != SetupTPM() ) | |
| 44 return LOAD_FIRMWARE_RECOVERY; | |
| 45 if (0 != GetStoredVersions(FIRMWARE_VERSIONS, | |
| 46 &tpm_key_version, &tpm_fw_version)) | |
| 47 return LOAD_FIRMWARE_RECOVERY; | |
| 48 | |
| 49 /* Loop over indices */ | |
| 50 for (index = 0; index < 2; index++) { | |
| 51 VbKeyBlockHeader* key_block; | |
| 52 uint64_t vblock_size; | |
| 53 VbFirmwarePreambleHeader* preamble; | |
| 54 RSAPublicKey* data_key; | |
| 55 uint64_t key_version; | |
| 56 uint8_t* body_data; | |
| 57 uint64_t body_size; | |
| 58 | |
| 59 /* Verify the key block */ | |
| 60 if (index) { | |
|
gauravsh
2010/06/10 14:44:13
nit/suggestion: since this is not a boolean check,
| |
| 61 key_block = (VbKeyBlockHeader*)params->verification_block_1; | |
| 62 vblock_size = params->verification_size_1; | |
| 63 } else { | |
| 64 key_block = (VbKeyBlockHeader*)params->verification_block_0; | |
| 65 vblock_size = params->verification_size_0; | |
| 66 } | |
| 67 if ((0 != VerifyKeyBlock(key_block, vblock_size, root_key))) | |
| 68 continue; | |
| 69 | |
| 70 /* Check for rollback of key version. */ | |
| 71 key_version = key_block->data_key.key_version; | |
| 72 if (key_version < tpm_key_version) | |
| 73 continue; | |
| 74 | |
| 75 /* Get the key for preamble/data verification from the key block. */ | |
| 76 data_key = PublicKeyToRSA(&key_block->data_key); | |
| 77 if (!data_key) | |
| 78 continue; | |
| 79 | |
| 80 /* Verify the preamble, which follows the key block. */ | |
| 81 preamble = (VbFirmwarePreambleHeader*)((uint8_t*)key_block + | |
| 82 key_block->key_block_size); | |
| 83 if ((0 != VerifyFirmwarePreamble2(preamble, | |
| 84 vblock_size - key_block->key_block_size, | |
| 85 data_key))) { | |
| 86 RSAPublicKeyFree(data_key); | |
| 87 continue; | |
| 88 } | |
| 89 | |
| 90 /* Check for rollback of firmware version. */ | |
| 91 if (key_version == tpm_key_version && | |
| 92 preamble->firmware_version < tpm_fw_version) { | |
| 93 RSAPublicKeyFree(data_key); | |
| 94 continue; | |
| 95 } | |
| 96 | |
| 97 /* Check for lowest key version from a valid header. */ | |
| 98 if (lowest_key_version > key_version) { | |
| 99 lowest_key_version = key_version; | |
| 100 lowest_fw_version = preamble->firmware_version; | |
| 101 } | |
| 102 else if (lowest_key_version == key_version && | |
| 103 lowest_fw_version > preamble->firmware_version) { | |
| 104 lowest_fw_version = preamble->firmware_version; | |
| 105 } | |
| 106 | |
| 107 /* If we already have good firmware, no need to read another one; | |
| 108 * we only needed to look at the versions to check for | |
| 109 * rollback. */ | |
| 110 if (-1 != good_index) | |
| 111 continue; | |
| 112 | |
| 113 /* Read the firmware data */ | |
| 114 /* TODO: should set up hash for UpdateFirmwareBodyHash(). */ | |
| 115 body_data = GetFirmwareBody(index, &body_size); | |
| 116 if (!body_data || (body_size != preamble->body_signature.data_size)) { | |
| 117 RSAPublicKeyFree(data_key); | |
| 118 continue; | |
| 119 } | |
| 120 | |
| 121 /* Verify firmware data */ | |
| 122 /* TODO: should use hash from UpdateFirmwareBodyHash() rather than | |
| 123 * recalculating it in VerifyData(). */ | |
| 124 if (0 != VerifyData(body_data, &preamble->body_signature, data_key)) { | |
| 125 RSAPublicKeyFree(data_key); | |
| 126 continue; | |
| 127 } | |
| 128 | |
| 129 /* Done with the data key, so can free it now */ | |
| 130 RSAPublicKeyFree(data_key); | |
| 131 | |
| 132 /* If we're still here, the firmware is valid. */ | |
| 133 /* Save the first good firmware we find; that's the one we'll boot */ | |
| 134 if (-1 == good_index) { | |
| 135 good_index = index; | |
| 136 params->firmware_index = index; | |
| 137 params->kernel_sign_key_blob = &preamble->kernel_subkey; | |
| 138 params->kernel_sign_key_size = (preamble->kernel_subkey.key_offset + | |
| 139 preamble->kernel_subkey.key_size); | |
| 140 | |
| 141 /* If the good firmware's key version is the same as the tpm, | |
| 142 * then the TPM doesn't need updating; we can stop now. | |
| 143 * Otherwise, we'll check all the other headers to see if they | |
| 144 * contain a newer key. */ | |
| 145 if (key_version == tpm_key_version && | |
| 146 preamble->firmware_version == tpm_fw_version) | |
| 147 break; | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 /* Handle finding good firmware */ | |
| 152 if (good_index >= 0) { | |
| 153 | |
| 154 /* Update TPM if necessary */ | |
| 155 if ((lowest_key_version > tpm_key_version) || | |
| 156 (lowest_key_version == tpm_key_version && | |
| 157 lowest_fw_version > tpm_fw_version)) { | |
| 158 if (0 != WriteStoredVersions(FIRMWARE_VERSIONS, | |
| 159 lowest_key_version, | |
| 160 lowest_fw_version)) | |
| 161 return LOAD_FIRMWARE_RECOVERY; | |
| 162 } | |
| 163 | |
| 164 /* Lock Firmware TPM rollback indices from further writes. In | |
| 165 * this design, this is done by setting the globalLock bit, which | |
| 166 * is cleared only by TPM_Init at reboot. */ | |
| 167 if (0 != LockFirmwareVersions()) | |
| 168 return LOAD_FIRMWARE_RECOVERY; | |
| 169 } | |
| 170 | |
| 171 /* If we're still here, no good firmware, so go to recovery mode. */ | |
| 172 return LOAD_FIRMWARE_RECOVERY; | |
| 173 } | |
| OLD | NEW |