diff options
Diffstat (limited to 'firmware/lib/vboot_firmware.c')
-rw-r--r-- | firmware/lib/vboot_firmware.c | 368 |
1 files changed, 0 insertions, 368 deletions
diff --git a/firmware/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c deleted file mode 100644 index bfabfd48..00000000 --- a/firmware/lib/vboot_firmware.c +++ /dev/null @@ -1,368 +0,0 @@ -/* Copyright (c) 2013 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 "sysincludes.h" -#include "2sysincludes.h" - -#include "2common.h" -#include "2sha.h" -#include "region.h" -#include "gbb_access.h" -#include "gbb_header.h" -#include "load_firmware_fw.h" -#include "utility.h" -#include "vboot_api.h" -#include "vboot_common.h" -#include "vboot_nvstorage.h" - -/* - * Static variables for UpdateFirmwareBodyHash(). It's less than optimal to - * have static variables in a library, but in UEFI the caller is deep inside a - * different firmware stack and doesn't have a good way to pass the params - * struct back to us. - */ -typedef struct VbLoadFirmwareInternal { - struct vb2_digest_context body_digest_context; - uint32_t body_size_accum; -} VbLoadFirmwareInternal; - -void VbUpdateFirmwareBodyHash(VbCommonParams *cparams, uint8_t *data, - uint32_t size) -{ - VbLoadFirmwareInternal *lfi = - (VbLoadFirmwareInternal*)cparams->vboot_context; - - vb2_digest_extend(&lfi->body_digest_context, data, size); - lfi->body_size_accum += size; -} - -int LoadFirmware(VbCommonParams *cparams, VbSelectFirmwareParams *fparams, - VbNvContext *vnc) -{ - VbSharedDataHeader *shared = - (VbSharedDataHeader *)cparams->shared_data_blob; - GoogleBinaryBlockHeader *gbb = cparams->gbb; - VbPublicKey *root_key = NULL; - VbLoadFirmwareInternal *lfi; - - uint32_t try_b_count; - uint32_t lowest_version = 0xFFFFFFFF; - int good_index = -1; - int is_dev; - int index; - int i; - - int retval = VBERROR_UNKNOWN; - int recovery = VBNV_RECOVERY_RO_UNSPECIFIED; - - /* Clear output params in case we fail */ - shared->firmware_index = 0xFF; - - VBDEBUG(("LoadFirmware started...\n")); - - /* Must have a root key from the GBB */ - retval = VbGbbReadRootKey(cparams, &root_key); - if (retval) { - VBDEBUG(("No GBB\n")); - retval = VBERROR_INVALID_GBB; - goto LoadFirmwareExit; - } - - /* Parse flags */ - is_dev = (shared->flags & VBSD_BOOT_DEV_SWITCH_ON ? 1 : 0); - if (is_dev) - shared->flags |= VBSD_LF_DEV_SWITCH_ON; - - /* Read try-b count and decrement if necessary */ - VbNvGet(vnc, VBNV_TRY_B_COUNT, &try_b_count); - if (0 != try_b_count) { - if (!(shared->flags & VBSD_NOFAIL_BOOT)) - VbNvSet(vnc, VBNV_TRY_B_COUNT, try_b_count - 1); - shared->flags |= VBSD_FWB_TRIED; - } - - /* Allocate our internal data */ - lfi = (VbLoadFirmwareInternal *) - VbExMalloc(sizeof(VbLoadFirmwareInternal)); - cparams->vboot_context = lfi; - - /* Loop over indices */ - for (i = 0; i < 2; i++) { - VbKeyBlockHeader *key_block; - uint32_t vblock_size; - VbFirmwarePreambleHeader *preamble; - RSAPublicKey *data_key; - uint64_t key_version; - uint32_t combined_version; - uint8_t *check_result; - - /* If try B count is non-zero try firmware B first */ - index = (try_b_count ? 1 - i : i); - if (0 == index) { - key_block = (VbKeyBlockHeader *) - fparams->verification_block_A; - vblock_size = fparams->verification_size_A; - check_result = &shared->check_fw_a_result; - } else { - key_block = (VbKeyBlockHeader *) - fparams->verification_block_B; - vblock_size = fparams->verification_size_B; - check_result = &shared->check_fw_b_result; - } - - /* - * Check the key block flags against the current boot mode. Do - * this before verifying the key block, since flags are faster - * to check than the RSA signature. - */ - if (!(key_block->key_block_flags & - (is_dev ? KEY_BLOCK_FLAG_DEVELOPER_1 : - KEY_BLOCK_FLAG_DEVELOPER_0))) { - VBDEBUG(("Developer flag mismatch.\n")); - *check_result = VBSD_LF_CHECK_DEV_MISMATCH; - continue; - } - - /* RW firmware never runs in recovery mode. */ - if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)) { - VBDEBUG(("Recovery flag mismatch.\n")); - *check_result = VBSD_LF_CHECK_REC_MISMATCH; - continue; - } - - /* Verify the key block */ - if ((0 != KeyBlockVerify(key_block, vblock_size, - root_key, 0))) { - VBDEBUG(("Key block verification failed.\n")); - *check_result = VBSD_LF_CHECK_VERIFY_KEYBLOCK; - continue; - } - - /* Check for rollback of key version. */ - key_version = key_block->data_key.key_version; - if (!(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) { - if (key_version < (shared->fw_version_tpm >> 16)) { - VBDEBUG(("Key rollback detected.\n")); - *check_result = VBSD_LF_CHECK_KEY_ROLLBACK; - continue; - } - if (key_version > 0xFFFF) { - /* - * Key version is stored in 16 bits in the TPM, - * so key versions greater than 0xFFFF can't be - * stored properly. - */ - VBDEBUG(("Key version > 0xFFFF.\n")); - *check_result = VBSD_LF_CHECK_KEY_ROLLBACK; - continue; - } - } - - /* Get key for preamble/data verification from the key block. */ - data_key = PublicKeyToRSA(&key_block->data_key); - if (!data_key) { - VBDEBUG(("Unable to parse data key.\n")); - *check_result = VBSD_LF_CHECK_DATA_KEY_PARSE; - continue; - } - - /* Verify the preamble, which follows the key block. */ - preamble = (VbFirmwarePreambleHeader *) - ((uint8_t *)key_block + key_block->key_block_size); - if ((0 != VerifyFirmwarePreamble( - preamble, - vblock_size - key_block->key_block_size, - data_key))) { - VBDEBUG(("Preamble verfication failed.\n")); - *check_result = VBSD_LF_CHECK_VERIFY_PREAMBLE; - RSAPublicKeyFree(data_key); - continue; - } - - /* Check for rollback of firmware version. */ - combined_version = (uint32_t)((key_version << 16) | - (preamble->firmware_version & 0xFFFF)); - if (combined_version < shared->fw_version_tpm && - !(gbb->flags & GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK)) { - VBDEBUG(("Firmware version rollback detected.\n")); - *check_result = VBSD_LF_CHECK_FW_ROLLBACK; - RSAPublicKeyFree(data_key); - continue; - } - - /* Header for this firmware is valid */ - *check_result = VBSD_LF_CHECK_HEADER_VALID; - - /* Check for lowest key version from a valid header. */ - if (lowest_version > combined_version) - lowest_version = combined_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) { - RSAPublicKeyFree(data_key); - continue; - } - - /* Handle preamble flag for using the RO normal/dev code path */ - VBDEBUG(("Preamble flags %#x\n", VbGetFirmwarePreambleFlags(preamble))); - if (VbGetFirmwarePreambleFlags(preamble) & - VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) { - - /* Fail if calling firmware doesn't support RO normal */ - if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT)) { - VBDEBUG(("No RO normal support.\n")); - *check_result = VBSD_LF_CHECK_NO_RO_NORMAL; - RSAPublicKeyFree(data_key); - continue; - } - - /* Use the RO normal code path */ - shared->flags |= VBSD_LF_USE_RO_NORMAL; - - } else { - VbError_t rv; - - /* Read the firmware data */ - vb2_digest_init(&lfi->body_digest_context, - vb2_crypto_to_hash(data_key->algorithm)); - lfi->body_size_accum = 0; - rv = VbExHashFirmwareBody( - cparams, - (index ? VB_SELECT_FIRMWARE_B : - VB_SELECT_FIRMWARE_A)); - if (VBERROR_SUCCESS != rv) { - VBDEBUG(("VbExHashFirmwareBody() failed for " - "index %d\n", index)); - *check_result = VBSD_LF_CHECK_GET_FW_BODY; - RSAPublicKeyFree(data_key); - continue; - } - if (lfi->body_size_accum != - preamble->body_signature.data_size) { - VBDEBUG(("Hashed %d bytes but expected %d\n", - (int)lfi->body_size_accum, - (int)preamble->body_signature.data_size)); - *check_result = VBSD_LF_CHECK_HASH_WRONG_SIZE; - RSAPublicKeyFree(data_key); - continue; - } - - /* Verify firmware data */ - uint8_t body_digest[VB2_MAX_DIGEST_SIZE]; - vb2_digest_finalize(&lfi->body_digest_context, - body_digest, sizeof(body_digest)); - if (0 != VerifyDigest(body_digest, - &preamble->body_signature, - data_key)) { - VBDEBUG(("FW body verification failed.\n")); - *check_result = VBSD_LF_CHECK_VERIFY_BODY; - 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. */ - VBDEBUG(("Firmware %d is valid.\n", index)); - *check_result = VBSD_LF_CHECK_VALID; - if (-1 == good_index) { - /* Save the key we actually used */ - if (0 != VbSharedDataSetKernelKey( - shared, &preamble->kernel_subkey)) { - /* - * The firmware signature was good, but the - * public key was bigger that the caller can - * handle. - */ - VBDEBUG(("Unable to save kernel subkey.\n")); - continue; - } - - /* - * Save the good index, now that we're sure we can - * actually use this firmware. That's the one we'll - * boot. - */ - good_index = index; - shared->firmware_index = (uint8_t)index; - shared->fw_keyblock_flags = key_block->key_block_flags; - - /* - * 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 (combined_version == shared->fw_version_tpm) - break; - } - } - - /* Free internal data */ - VbExFree(lfi); - cparams->vboot_context = NULL; - - /* Handle finding good firmware */ - if (good_index >= 0) { - - /* Save versions we found */ - shared->fw_version_lowest = lowest_version; - if (lowest_version > shared->fw_version_tpm) - shared->fw_version_tpm = lowest_version; - - /* Success */ - VBDEBUG(("Will boot firmware index %d\n", - (int)shared->firmware_index)); - retval = VBERROR_SUCCESS; - - } else { - uint8_t a = shared->check_fw_a_result; - uint8_t b = shared->check_fw_b_result; - uint8_t best_check; - - /* No good firmware, so go to recovery mode. */ - VBDEBUG(("Alas, no good firmware.\n")); - recovery = VBNV_RECOVERY_RO_INVALID_RW; - retval = VBERROR_LOAD_FIRMWARE; - - /* - * If the best check result fits in the range of recovery - * reasons, provide more detail on how far we got in - * validation. - */ - best_check = (a > b ? a : b) + - VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN; - if (best_check >= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MIN && - best_check <= VBNV_RECOVERY_RO_INVALID_RW_CHECK_MAX) - recovery = best_check; - } - - LoadFirmwareExit: - VbExFree(root_key); - - /* Store recovery request, if any */ - VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ? - recovery : VBNV_RECOVERY_NOT_REQUESTED); - /* If the system does not support RO_NORMAL and LoadFirmware() - * encountered an error, update the shared recovery reason if - * recovery was not previously requested. */ - if (!(shared->flags & VBSD_BOOT_RO_NORMAL_SUPPORT) && - VBNV_RECOVERY_NOT_REQUESTED == shared->recovery_reason && - VBERROR_SUCCESS != retval) { - VBDEBUG(("RO normal but we got an error.\n")); - shared->recovery_reason = recovery; - } - - return retval; -} |