 Chromium Code Reviews
 Chromium Code Reviews Issue 2745007:
  Major refactoring of structures, with unit tests.  (Closed) 
  Base URL: ssh://gitrw.chromium.org/vboot_reference.git
    
  
    Issue 2745007:
  Major refactoring of structures, with unit tests.  (Closed) 
  Base URL: ssh://gitrw.chromium.org/vboot_reference.git| Index: vboot_firmware/lib/vboot_firmware.c | 
| diff --git a/vboot_firmware/lib/vboot_firmware.c b/vboot_firmware/lib/vboot_firmware.c | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..ce3f5290bdb6f8c48b9d4a63fce72e03f6d729bc | 
| --- /dev/null | 
| +++ b/vboot_firmware/lib/vboot_firmware.c | 
| @@ -0,0 +1,173 @@ | 
| +/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 
| + * Use of this source code is governed by a BSD-style license that can be | 
| + * found in the LICENSE file. | 
| + * | 
| + * High-level firmware API for loading and verifying rewritable firmware. | 
| + * (Firmware portion) | 
| + */ | 
| + | 
| +#include "vboot_firmware.h" | 
| + | 
| +#include "load_firmware_fw.h" | 
| +#include "rollback_index.h" | 
| +#include "utility.h" | 
| +#include "vboot_common.h" | 
| + | 
| + | 
| +void UpdateFirmwareBodyHash2(uint8_t* data, uint64_t size) { | 
| + /* TODO: actually update the hash. */ | 
| +} | 
| + | 
| + | 
| +int LoadFirmware2(LoadFirmwareParams* params) { | 
| + | 
| + VbPublicKey* root_key = (VbPublicKey*)params->firmware_root_key_blob; | 
| + | 
| + uint16_t tpm_key_version = 0; | 
| + uint16_t tpm_fw_version = 0; | 
| + uint64_t lowest_key_version = 0xFFFF; | 
| + uint64_t lowest_fw_version = 0xFFFF; | 
| + int good_index = -1; | 
| + int index; | 
| + | 
| + /* Clear output params in case we fail */ | 
| + params->firmware_index = 0; | 
| + params->kernel_sign_key_blob = NULL; | 
| + params->kernel_sign_key_size = 0; | 
| + | 
| + /* Must have a root key */ | 
| + if (!root_key) | 
| + return LOAD_FIRMWARE_RECOVERY; | 
| + | 
| + /* Initialize the TPM and read rollback indices. */ | 
| + if (0 != SetupTPM() ) | 
| + return LOAD_FIRMWARE_RECOVERY; | 
| + if (0 != GetStoredVersions(FIRMWARE_VERSIONS, | 
| + &tpm_key_version, &tpm_fw_version)) | 
| + return LOAD_FIRMWARE_RECOVERY; | 
| + | 
| + /* Loop over indices */ | 
| + for (index = 0; index < 2; index++) { | 
| + VbKeyBlockHeader* key_block; | 
| + uint64_t vblock_size; | 
| + VbFirmwarePreambleHeader* preamble; | 
| + RSAPublicKey* data_key; | 
| + uint64_t key_version; | 
| + uint8_t* body_data; | 
| + uint64_t body_size; | 
| + | 
| + /* Verify the key block */ | 
| + if (index) { | 
| 
gauravsh
2010/06/10 14:44:13
nit/suggestion: since this is not a boolean check,
 | 
| + key_block = (VbKeyBlockHeader*)params->verification_block_1; | 
| + vblock_size = params->verification_size_1; | 
| + } else { | 
| + key_block = (VbKeyBlockHeader*)params->verification_block_0; | 
| + vblock_size = params->verification_size_0; | 
| + } | 
| + if ((0 != VerifyKeyBlock(key_block, vblock_size, root_key))) | 
| + continue; | 
| + | 
| + /* Check for rollback of key version. */ | 
| + key_version = key_block->data_key.key_version; | 
| + if (key_version < tpm_key_version) | 
| + continue; | 
| + | 
| + /* Get the key for preamble/data verification from the key block. */ | 
| + data_key = PublicKeyToRSA(&key_block->data_key); | 
| + if (!data_key) | 
| + continue; | 
| + | 
| + /* Verify the preamble, which follows the key block. */ | 
| + preamble = (VbFirmwarePreambleHeader*)((uint8_t*)key_block + | 
| + key_block->key_block_size); | 
| + if ((0 != VerifyFirmwarePreamble2(preamble, | 
| + vblock_size - key_block->key_block_size, | 
| + data_key))) { | 
| + RSAPublicKeyFree(data_key); | 
| + continue; | 
| + } | 
| + | 
| + /* Check for rollback of firmware version. */ | 
| + if (key_version == tpm_key_version && | 
| + preamble->firmware_version < tpm_fw_version) { | 
| + RSAPublicKeyFree(data_key); | 
| + continue; | 
| + } | 
| + | 
| + /* Check for lowest key version from a valid header. */ | 
| + if (lowest_key_version > key_version) { | 
| + lowest_key_version = key_version; | 
| + lowest_fw_version = preamble->firmware_version; | 
| + } | 
| + else if (lowest_key_version == key_version && | 
| + lowest_fw_version > preamble->firmware_version) { | 
| + lowest_fw_version = preamble->firmware_version; | 
| + } | 
| + | 
| + /* If we already have good firmware, no need to read another one; | 
| + * we only needed to look at the versions to check for | 
| + * rollback. */ | 
| + if (-1 != good_index) | 
| + continue; | 
| + | 
| + /* Read the firmware data */ | 
| + /* TODO: should set up hash for UpdateFirmwareBodyHash(). */ | 
| + body_data = GetFirmwareBody(index, &body_size); | 
| + if (!body_data || (body_size != preamble->body_signature.data_size)) { | 
| + RSAPublicKeyFree(data_key); | 
| + continue; | 
| + } | 
| + | 
| + /* Verify firmware data */ | 
| + /* TODO: should use hash from UpdateFirmwareBodyHash() rather than | 
| + * recalculating it in VerifyData(). */ | 
| + if (0 != VerifyData(body_data, &preamble->body_signature, data_key)) { | 
| + RSAPublicKeyFree(data_key); | 
| + continue; | 
| + } | 
| + | 
| + /* Done with the data key, so can free it now */ | 
| + RSAPublicKeyFree(data_key); | 
| + | 
| + /* If we're still here, the firmware is valid. */ | 
| + /* Save the first good firmware we find; that's the one we'll boot */ | 
| + if (-1 == good_index) { | 
| + good_index = index; | 
| + params->firmware_index = index; | 
| + params->kernel_sign_key_blob = &preamble->kernel_subkey; | 
| + params->kernel_sign_key_size = (preamble->kernel_subkey.key_offset + | 
| + preamble->kernel_subkey.key_size); | 
| + | 
| + /* If the good firmware's key version is the same as the tpm, | 
| + * then the TPM doesn't need updating; we can stop now. | 
| + * Otherwise, we'll check all the other headers to see if they | 
| + * contain a newer key. */ | 
| + if (key_version == tpm_key_version && | 
| + preamble->firmware_version == tpm_fw_version) | 
| + break; | 
| + } | 
| + } | 
| + | 
| + /* Handle finding good firmware */ | 
| + if (good_index >= 0) { | 
| + | 
| + /* Update TPM if necessary */ | 
| + if ((lowest_key_version > tpm_key_version) || | 
| + (lowest_key_version == tpm_key_version && | 
| + lowest_fw_version > tpm_fw_version)) { | 
| + if (0 != WriteStoredVersions(FIRMWARE_VERSIONS, | 
| + lowest_key_version, | 
| + lowest_fw_version)) | 
| + return LOAD_FIRMWARE_RECOVERY; | 
| + } | 
| + | 
| + /* Lock Firmware TPM rollback indices from further writes. In | 
| + * this design, this is done by setting the globalLock bit, which | 
| + * is cleared only by TPM_Init at reboot. */ | 
| + if (0 != LockFirmwareVersions()) | 
| + return LOAD_FIRMWARE_RECOVERY; | 
| + } | 
| + | 
| + /* If we're still here, no good firmware, so go to recovery mode. */ | 
| + return LOAD_FIRMWARE_RECOVERY; | 
| +} |