fastboot: Add routine for verifying kernel image loaded in memory

This API allows fastboot boot from memory command to verify that the
image loaded in memory is signed properly using recovery keys. Thus,
only officially signed recovery images can be booted using fastboot
boot command in recovery mode.

However, if GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP is set, then
this routine will not perform any check and return okay for any image
sent by fastboot boot.

BUG=chrome-os-partner:40196
BRANCH=None
TEST=Compiles successfully. With GBB override for FASTBOOT_FULL_CAP
set any signed image is allowed to boot. With FASTBOOT_FULL_CAP not
set, then only officially signed image is allowed to boot. (make -j
runtests successful)

Change-Id: I78028853bd1ad09d3c610a687f327560557d5681
Signed-off-by: Furquan Shaikh <furquan@google.com>
Reviewed-on: https://chromium-review.googlesource.com/272696
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Commit-Queue: Furquan Shaikh <furquan@chromium.org>
Trybot-Ready: Furquan Shaikh <furquan@chromium.org>
Tested-by: Furquan Shaikh <furquan@chromium.org>
This commit is contained in:
Furquan Shaikh
2015-05-21 14:39:11 -07:00
committed by ChromeOS Commit Bot
parent 05371345b7
commit f274360326
4 changed files with 440 additions and 0 deletions

View File

@@ -1194,3 +1194,139 @@ VbError_t VbSelectAndLoadKernel(VbCommonParams *cparams,
/* Pass through return value from boot path */
return retval;
}
VbError_t VbVerifyMemoryBootImage(VbCommonParams *cparams,
VbSelectAndLoadKernelParams *kparams,
void *boot_image,
size_t image_size)
{
VbError_t retval;
VbPublicKey* kernel_subkey = NULL;
uint8_t *kbuf;
VbKeyBlockHeader *key_block;
VbSharedDataHeader *shared =
(VbSharedDataHeader *)cparams->shared_data_blob;
RSAPublicKey *data_key = NULL;
VbKernelPreambleHeader *preamble;
uint64_t body_offset;
int hash_only = 0;
int dev_switch;
if ((boot_image == NULL) || (image_size == 0))
return VBERROR_INVALID_PARAMETER;
/* Clear output params in case we fail. */
kparams->disk_handle = NULL;
kparams->partition_number = 0;
kparams->bootloader_address = 0;
kparams->bootloader_size = 0;
kparams->flags = 0;
Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid));
/* Populate pointers to all components in the image. */
kbuf = boot_image;
key_block = (VbKeyBlockHeader *)kbuf;
preamble = (VbKernelPreambleHeader *)(kbuf + key_block->key_block_size);
body_offset = key_block->key_block_size + preamble->preamble_size;
/* Read GBB Header */
cparams->bmp = NULL;
cparams->gbb = VbExMalloc(sizeof(*cparams->gbb));
retval = VbGbbReadHeader_static(cparams, cparams->gbb);
if (VBERROR_SUCCESS != retval) {
VBDEBUG(("Gbb read header failed.\n"));
return retval;
}
/*
* We don't care verifying the image if:
* 1. dev-mode switch is on and
* 2. GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP is set.
*
* Check only the integrity of the image.
*/
dev_switch = shared->flags & VBSD_BOOT_DEV_SWITCH_ON;
if (dev_switch && (cparams->gbb->flags &
GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP)) {
VBDEBUG(("Only performing integrity-check.\n"));
hash_only = 1;
} else {
/* Get recovery key. */
retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey);
if (VBERROR_SUCCESS != retval) {
VBDEBUG(("Gbb Read Recovery key failed.\n"));
return retval;
}
}
/* If we fail at any step, retval returned would be invalid kernel. */
retval = VBERROR_INVALID_KERNEL_FOUND;
/* Verify the key block. */
if (0 != KeyBlockVerify(key_block, image_size, kernel_subkey,
hash_only)) {
VBDEBUG(("Verifying key block signature/hash failed.\n"));
goto fail;
}
/* Check the key block flags against the current boot mode. */
if (!(key_block->key_block_flags &
(dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
KEY_BLOCK_FLAG_DEVELOPER_0))) {
VBDEBUG(("Key block developer flag mismatch.\n"));
if (hash_only == 0)
goto fail;
}
if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)) {
VBDEBUG(("Key block recovery flag mismatch.\n"));
if (hash_only == 0)
goto fail;
}
/* Get key for preamble/data verification from the key block. */
data_key = PublicKeyToRSA(&key_block->data_key);
if (!data_key) {
VBDEBUG(("Data key bad.\n"));
goto fail;
}
/* Verify the preamble, which follows the key block */
if ((0 != VerifyKernelPreamble(preamble,
image_size -
key_block->key_block_size,
data_key))) {
VBDEBUG(("Preamble verification failed.\n"));
goto fail;
}
VBDEBUG(("Kernel preamble is good.\n"));
/* Verify kernel data */
if (0 != VerifyData((const uint8_t *)(kbuf + body_offset),
image_size - body_offset,
&preamble->body_signature, data_key)) {
VBDEBUG(("Kernel data verification failed.\n"));
goto fail;
}
VBDEBUG(("Kernel is good.\n"));
/* Fill in output parameters. */
kparams->kernel_buffer = kbuf + body_offset;
kparams->kernel_buffer_size = image_size - body_offset;
kparams->bootloader_address = preamble->bootloader_address;
kparams->bootloader_size = preamble->bootloader_size;
if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
kparams->flags = preamble->flags;
retval = VBERROR_SUCCESS;
fail:
VbApiKernelFree(cparams);
if (NULL != data_key)
RSAPublicKeyFree(data_key);
if (NULL != kernel_subkey)
VbExFree(kernel_subkey);
return retval;
}