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; |
+} |