17993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * Use of this source code is governed by a BSD-style license that can be
3d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * found in the LICENSE file.
4d183644564ec27c106a3eb1931f565fae167a058Randall Spangler *
5d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * Functions for loading a kernel from disk.
6d183644564ec27c106a3eb1931f565fae167a058Randall Spangler * (Firmware portion)
7d183644564ec27c106a3eb1931f565fae167a058Randall Spangler */
8d183644564ec27c106a3eb1931f565fae167a058Randall Spangler
90c3ba249abb1dc60f5ebabccf84ff13206440b83Bill Richardson#include "sysincludes.h"
101b1998dff0002f20b3f27a21e6e79d8951e64684Randall Spangler
11d183644564ec27c106a3eb1931f565fae167a058Randall Spangler#include "cgptlib.h"
125deb67f22507481cf5cb8f991976a9969fa90a22Bill Richardson#include "cgptlib_internal.h"
13527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "region.h"
14527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass#include "gbb_access.h"
1595c4031ce903258036beeed0705d25c7e9d25da0Randall Spangler#include "gbb_header.h"
167c2beb08380410ca6847abdac23e11ded2d1b625Dan Ehrenberg#include "gpt_misc.h"
17d183644564ec27c106a3eb1931f565fae167a058Randall Spangler#include "load_kernel_fw.h"
18d183644564ec27c106a3eb1931f565fae167a058Randall Spangler#include "utility.h"
19e49e8af65fce38da7a308305566f8a14f102254aRandall Spangler#include "vboot_api.h"
2083c88cfa6920711b8a7823e1e3fc0efe8b71a04cRandall Spangler#include "vboot_common.h"
21e49e8af65fce38da7a308305566f8a14f102254aRandall Spangler#include "vboot_kernel.h"
22e49e8af65fce38da7a308305566f8a14f102254aRandall Spangler
23d183644564ec27c106a3eb1931f565fae167a058Randall Spangler#define KBUF_SIZE 65536  /* Bytes to read at start of kernel partition */
2455db6a67176a4933427d2ee556180f6e814f60d9Stefan Reinauer#define LOWEST_TPM_VERSION 0xffffffff
25d183644564ec27c106a3eb1931f565fae167a058Randall Spangler
26640fb51d866e7ac8a92f61a2f69145bfe6b13699Randall Spanglertypedef enum BootMode {
277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	kBootRecovery = 0,  /* Recovery firmware, any dev switch position */
287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	kBootNormal = 1,    /* Normal boot - kernel must be verified */
297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	kBootDev = 2        /* Developer boot - self-signed kernel ok */
30640fb51d866e7ac8a92f61a2f69145bfe6b13699Randall Spangler} BootMode;
31640fb51d866e7ac8a92f61a2f69145bfe6b13699Randall Spangler
32527ba810eff4006cf69579f6b96cb4350cb1e189Simon GlassVbError_t LoadKernel(LoadKernelParams *params, VbCommonParams *cparams)
337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler{
347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	VbSharedDataHeader *shared =
357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		(VbSharedDataHeader *)params->shared_data_blob;
367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	VbSharedDataKernelCall *shcall = NULL;
377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	VbNvContext* vnc = params->nv_context;
38527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	VbPublicKey* kernel_subkey = NULL;
39527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	int free_kernel_subkey = 0;
407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	GptData gpt;
417993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	uint64_t part_start, part_size;
427993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	uint64_t blba;
437993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	uint64_t kbuf_sectors;
447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	uint8_t* kbuf = NULL;
457993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	int found_partitions = 0;
467993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	int good_partition = -1;
477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	int good_partition_key_block_valid = 0;
487993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	uint32_t lowest_version = LOWEST_TPM_VERSION;
497993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	int rec_switch, dev_switch;
507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	BootMode boot_mode;
517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	uint32_t require_official_os = 0;
524184e626336fa8d794a21208387226f154d77d0fRandall Spangler	uint32_t body_toread;
534184e626336fa8d794a21208387226f154d77d0fRandall Spangler	uint8_t *body_readptr;
547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	VbError_t retval = VBERROR_UNKNOWN;
567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	int recovery = VBNV_RECOVERY_LK_UNSPECIFIED;
577993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
587993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Sanity Checks */
597993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (!params->bytes_per_lba ||
603f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg	    !params->streaming_lba_count) {
617993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("LoadKernel() called with invalid params\n"));
627993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		retval = VBERROR_INVALID_PARAMETER;
637993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		goto LoadKernelExit;
647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	}
657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
667993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Clear output params in case we fail */
677993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	params->partition_number = 0;
687993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	params->bootloader_address = 0;
697993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	params->bootloader_size = 0;
70b7d1f03e368b146d11eab511cd6a573a528bc728Furquan Shaikh	params->flags = 0;
717993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
727993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Calculate switch positions and boot mode */
737993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	rec_switch = (BOOT_FLAG_RECOVERY & params->boot_flags ? 1 : 0);
747993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	dev_switch = (BOOT_FLAG_DEVELOPER & params->boot_flags ? 1 : 0);
757993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (rec_switch) {
767993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		boot_mode = kBootRecovery;
777993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	} else if (dev_switch) {
787993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		boot_mode = kBootDev;
797993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VbNvGet(vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os);
807993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	} else {
817993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		boot_mode = kBootNormal;
827993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	}
837993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
847993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/*
857993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	 * Set up tracking for this call.  This wraps around if called many
867993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	 * times, so we need to initialize the call entry each time.
877993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	 */
887993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	shcall = shared->lk_calls + (shared->lk_call_count
897993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				     & (VBSD_MAX_KERNEL_CALLS - 1));
907993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	Memset(shcall, 0, sizeof(VbSharedDataKernelCall));
917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	shcall->boot_flags = (uint32_t)params->boot_flags;
927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	shcall->boot_mode = boot_mode;
937993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	shcall->sector_size = (uint32_t)params->bytes_per_lba;
943f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg	shcall->sector_count = params->streaming_lba_count;
957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	shared->lk_call_count++;
967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Initialization */
987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	blba = params->bytes_per_lba;
997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	kbuf_sectors = KBUF_SIZE / blba;
1007993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (0 == kbuf_sectors) {
1017993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("LoadKernel() called with sector size > KBUF_SIZE\n"));
1027993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		retval = VBERROR_INVALID_PARAMETER;
1037993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		goto LoadKernelExit;
1047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	}
1057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (kBootRecovery == boot_mode) {
1077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Use the recovery key to verify the kernel */
108527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey);
109527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		if (VBERROR_SUCCESS != retval)
110527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass			goto LoadKernelExit;
111527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		free_kernel_subkey = 1;
1127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	} else {
1137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Use the kernel subkey passed from LoadFirmware(). */
1147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		kernel_subkey = &shared->kernel_subkey;
1157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	}
1167993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Read GPT data */
1187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	gpt.sector_bytes = (uint32_t)blba;
1193f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg	gpt.streaming_drive_sectors = params->streaming_lba_count;
1203f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg	gpt.gpt_drive_sectors = params->gpt_lba_count;
1213f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg	gpt.flags = params->boot_flags & BOOT_FLAG_EXTERNAL_GPT
1223f4d8d05ba4e32990c8584bd47cdf082d4604232Dan Ehrenberg			? GPT_FLAG_EXTERNAL : 0;
1237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) {
1247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("Unable to read GPT data\n"));
1257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR;
1267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		goto bad_gpt;
1277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	}
1287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Initialize GPT library */
1307993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (GPT_SUCCESS != GptInit(&gpt)) {
1317993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("Error parsing GPT\n"));
1327993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shcall->check_result = VBSD_LKC_CHECK_GPT_PARSE_ERROR;
1337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		goto bad_gpt;
1347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	}
1357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Allocate kernel header buffers */
1377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	kbuf = (uint8_t*)VbExMalloc(KBUF_SIZE);
1387993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (!kbuf)
1397993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		goto bad_gpt;
1407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1417993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler        /* Loop over candidate kernel partitions */
1427993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler        while (GPT_SUCCESS ==
1437993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	       GptNextKernelEntry(&gpt, &part_start, &part_size)) {
1447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VbSharedDataKernelPart *shpart = NULL;
1457993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VbKeyBlockHeader *key_block;
1467993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VbKernelPreambleHeader *preamble;
1477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		RSAPublicKey *data_key = NULL;
1484184e626336fa8d794a21208387226f154d77d0fRandall Spangler		VbExStream_t stream = NULL;
1497993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		uint64_t key_version;
1507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		uint32_t combined_version;
1517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		uint64_t body_offset;
1527993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		int key_block_valid = 1;
1537993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("Found kernel entry at %" PRIu64 " size %" PRIu64 "\n",
1557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			 part_start, part_size));
1567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1577993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
1587993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * Set up tracking for this partition.  This wraps around if
1597993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * called many times, so initialize the partition entry each
1607993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * time.
1617993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
1627993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shpart = shcall->parts + (shcall->kernel_parts_found
1637993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					  & (VBSD_MAX_KERNEL_PARTS - 1));
1647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		Memset(shpart, 0, sizeof(VbSharedDataKernelPart));
1657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shpart->sector_start = part_start;
1667993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shpart->sector_count = part_size;
1677993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
1687993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * TODO: GPT partitions start at 1, but cgptlib starts them at
1697993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * 0.  Adjust here, until cgptlib is fixed.
1707993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
1717993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shpart->gpt_index = (uint8_t)(gpt.current_kernel + 1);
1727993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shcall->kernel_parts_found++;
1737993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1747993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Found at least one kernel partition. */
1757993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		found_partitions++;
1767993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1774184e626336fa8d794a21208387226f154d77d0fRandall Spangler		/* Set up the stream */
1784184e626336fa8d794a21208387226f154d77d0fRandall Spangler		if (VbExStreamOpen(params->disk_handle,
1794184e626336fa8d794a21208387226f154d77d0fRandall Spangler				   part_start, part_size, &stream)) {
1804184e626336fa8d794a21208387226f154d77d0fRandall Spangler			VBDEBUG(("Partition error getting stream.\n"));
1817993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_TOO_SMALL;
1827993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			goto bad_kernel;
1837993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
1847993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1854184e626336fa8d794a21208387226f154d77d0fRandall Spangler		if (0 != VbExStreamRead(stream, KBUF_SIZE, kbuf)) {
1867993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Unable to read start of partition.\n"));
1877993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_READ_START;
1887993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			goto bad_kernel;
1897993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
190d183644564ec27c106a3eb1931f565fae167a058Randall Spangler
1917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Verify the key block. */
1927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		key_block = (VbKeyBlockHeader*)kbuf;
1937993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (0 != KeyBlockVerify(key_block, KBUF_SIZE,
1947993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					kernel_subkey, 0)) {
1957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Verifying key block signature failed.\n"));
1967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_KEY_BLOCK_SIG;
1977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			key_block_valid = 0;
1987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
1997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			/* If not in developer mode, this kernel is bad. */
2007993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			if (kBootDev != boot_mode)
2017993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				goto bad_kernel;
2027993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
2037993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			/*
2047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			 * In developer mode, we can explictly disallow
2057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			 * self-signed kernels
2067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			 */
2077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			if (require_official_os) {
2087993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				VBDEBUG(("Self-signed kernels not enabled.\n"));
2097993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				shpart->check_result =
2107993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					VBSD_LKP_CHECK_SELF_SIGNED;
2117993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				goto bad_kernel;
2127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			}
2137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
2147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			/*
2157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			 * Allow the kernel if the SHA-512 hash of the key
2167993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			 * block is valid.
2177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			 */
2187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			if (0 != KeyBlockVerify(key_block, KBUF_SIZE,
2197993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler						kernel_subkey, 1)) {
2207993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				VBDEBUG(("Verifying key block hash failed.\n"));
2217993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				shpart->check_result =
2227993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					VBSD_LKP_CHECK_KEY_BLOCK_HASH;
2237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				goto bad_kernel;
2247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			}
2257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
2267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
2277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Check the key block flags against the current boot mode. */
2287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (!(key_block->key_block_flags &
2297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		      (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 :
2307993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		       KEY_BLOCK_FLAG_DEVELOPER_0))) {
2317993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Key block developer flag mismatch.\n"));
2327993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_DEV_MISMATCH;
2337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			key_block_valid = 0;
2347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
2357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (!(key_block->key_block_flags &
2367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		      (rec_switch ? KEY_BLOCK_FLAG_RECOVERY_1 :
2377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		       KEY_BLOCK_FLAG_RECOVERY_0))) {
2387993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Key block recovery flag mismatch.\n"));
2397993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_REC_MISMATCH;
2407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			key_block_valid = 0;
2417993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
2427993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
2437993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Check for rollback of key version except in recovery mode. */
2447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		key_version = key_block->data_key.key_version;
2457993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (kBootRecovery != boot_mode) {
2467993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			if (key_version < (shared->kernel_version_tpm >> 16)) {
2477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				VBDEBUG(("Key version too old.\n"));
2487993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				shpart->check_result =
2497993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					VBSD_LKP_CHECK_KEY_ROLLBACK;
2507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				key_block_valid = 0;
2517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			}
2527993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			if (key_version > 0xFFFF) {
2537993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				/*
2547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				 * Key version is stored in 16 bits in the TPM,
2557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				 * so key versions greater than 0xFFFF can't be
2567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				 * stored properly.
2577993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				 */
2587993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				VBDEBUG(("Key version > 0xFFFF.\n"));
2597993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				shpart->check_result =
2607993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					VBSD_LKP_CHECK_KEY_ROLLBACK;
2617993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				key_block_valid = 0;
2627993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			}
2637993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
2647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
2657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* If not in developer mode, key block required to be valid. */
2667993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (kBootDev != boot_mode && !key_block_valid) {
2677993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Key block is invalid.\n"));
2687993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			goto bad_kernel;
2697993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
2707993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
2717993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Get key for preamble/data verification from the key block. */
2727993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		data_key = PublicKeyToRSA(&key_block->data_key);
2737993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (!data_key) {
2747993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Data key bad.\n"));
2757993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_DATA_KEY_PARSE;
2767993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			goto bad_kernel;
2777993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
2787993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
2797993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Verify the preamble, which follows the key block */
2807993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		preamble = (VbKernelPreambleHeader *)
2817993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			(kbuf + key_block->key_block_size);
2827993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if ((0 != VerifyKernelPreamble(
2837993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					preamble,
2847993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					KBUF_SIZE - key_block->key_block_size,
2857993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					data_key))) {
2867993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Preamble verification failed.\n"));
2877993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_VERIFY_PREAMBLE;
2887993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			goto bad_kernel;
2897993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
2907993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
2917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
2927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * If the key block is valid and we're not in recovery mode,
2937993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * check for rollback of the kernel version.
2947993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
2957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		combined_version = (uint32_t)(
2967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				(key_version << 16) |
2977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				(preamble->kernel_version & 0xFFFF));
2987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shpart->combined_version = combined_version;
2997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (key_block_valid && kBootRecovery != boot_mode) {
3007993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			if (combined_version < shared->kernel_version_tpm) {
3017993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				VBDEBUG(("Kernel version too low.\n"));
3027993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				shpart->check_result =
3037993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					VBSD_LKP_CHECK_KERNEL_ROLLBACK;
3047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				/*
3057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				 * If not in developer mode, kernel version
3067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				 * must be valid.
3077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				 */
3087993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				if (kBootDev != boot_mode)
3097993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler					goto bad_kernel;
3107993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			}
3117993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
3127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
3137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("Kernel preamble is good.\n"));
3147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shpart->check_result = VBSD_LKP_CHECK_PREAMBLE_VALID;
3157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
3167993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Check for lowest version from a valid header. */
3177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (key_block_valid && lowest_version > combined_version)
3187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			lowest_version = combined_version;
3197993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		else {
3207993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Key block valid: %d\n", key_block_valid));
3217993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Combined version: %u\n",
3227993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				 (unsigned) combined_version));
3237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
3247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
3257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
3267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * If we already have a good kernel, no need to read another
3277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * one; we only needed to look at the versions to check for
3287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * rollback.  So skip to the next kernel preamble.
3297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
3304184e626336fa8d794a21208387226f154d77d0fRandall Spangler		if (-1 != good_partition) {
3314184e626336fa8d794a21208387226f154d77d0fRandall Spangler			VbExStreamClose(stream);
3324184e626336fa8d794a21208387226f154d77d0fRandall Spangler			stream = NULL;
3337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			continue;
3344184e626336fa8d794a21208387226f154d77d0fRandall Spangler		}
3357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
3367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		body_offset = key_block->key_block_size +
3377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			preamble->preamble_size;
3384184e626336fa8d794a21208387226f154d77d0fRandall Spangler
3394184e626336fa8d794a21208387226f154d77d0fRandall Spangler		/*
3404184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * Make sure the kernel starts at or before what we already
3414184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * read into kbuf.
3424184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 *
3434184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * We could deal with a larger offset by reading and discarding
3444184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * the data in between the vblock and the kernel data.
3454184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 */
3464184e626336fa8d794a21208387226f154d77d0fRandall Spangler		if (body_offset > KBUF_SIZE) {
3477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_BODY_OFFSET;
3484184e626336fa8d794a21208387226f154d77d0fRandall Spangler			VBDEBUG(("Kernel body offset is %d > 64KB.\n",
3494184e626336fa8d794a21208387226f154d77d0fRandall Spangler				 (int)body_offset));
3507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			goto bad_kernel;
3517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
3527993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
3537993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (!params->kernel_buffer) {
3547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			/* Get kernel load address and size from the header. */
3557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			params->kernel_buffer =
3567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				(void *)((long)preamble->body_load_address);
3574184e626336fa8d794a21208387226f154d77d0fRandall Spangler			params->kernel_buffer_size =
3584184e626336fa8d794a21208387226f154d77d0fRandall Spangler				preamble->body_signature.data_size;
3594184e626336fa8d794a21208387226f154d77d0fRandall Spangler		} else if (preamble->body_signature.data_size >
3604184e626336fa8d794a21208387226f154d77d0fRandall Spangler			   params->kernel_buffer_size) {
3614184e626336fa8d794a21208387226f154d77d0fRandall Spangler			VBDEBUG(("Kernel body doesn't fit in memory.\n"));
3624184e626336fa8d794a21208387226f154d77d0fRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_BODY_EXCEEDS_MEM;
3634184e626336fa8d794a21208387226f154d77d0fRandall Spangler			goto bad_kernel;
3647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
3657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
3664184e626336fa8d794a21208387226f154d77d0fRandall Spangler		/*
3674184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * Body signature data size is 64 bit and toread is 32 bit so
3684184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * this could technically cause us to read less data.  That's
3694184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * fine, because a 4 GB kernel is implausible, and if we did
3704184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * have one that big, we'd simply read too little data and fail
3714184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * to verify it.
3724184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 */
3734184e626336fa8d794a21208387226f154d77d0fRandall Spangler		body_toread = preamble->body_signature.data_size;
3744184e626336fa8d794a21208387226f154d77d0fRandall Spangler		body_readptr = params->kernel_buffer;
3754184e626336fa8d794a21208387226f154d77d0fRandall Spangler
3764184e626336fa8d794a21208387226f154d77d0fRandall Spangler		/*
3774184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * If we've already read part of the kernel, copy that to the
3784184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 * beginning of the kernel buffer.
3794184e626336fa8d794a21208387226f154d77d0fRandall Spangler		 */
3804184e626336fa8d794a21208387226f154d77d0fRandall Spangler		if (body_offset < KBUF_SIZE) {
3814184e626336fa8d794a21208387226f154d77d0fRandall Spangler			uint32_t body_copied = KBUF_SIZE - body_offset;
3824184e626336fa8d794a21208387226f154d77d0fRandall Spangler
3834184e626336fa8d794a21208387226f154d77d0fRandall Spangler			/* If the kernel is tiny, don't over-copy */
3844184e626336fa8d794a21208387226f154d77d0fRandall Spangler			if (body_copied > body_toread)
3854184e626336fa8d794a21208387226f154d77d0fRandall Spangler				body_copied = body_toread;
3864184e626336fa8d794a21208387226f154d77d0fRandall Spangler
3874184e626336fa8d794a21208387226f154d77d0fRandall Spangler			Memcpy(body_readptr, kbuf + body_offset, body_copied);
3884184e626336fa8d794a21208387226f154d77d0fRandall Spangler			body_toread -= body_copied;
3894184e626336fa8d794a21208387226f154d77d0fRandall Spangler			body_readptr += body_copied;
3907993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
3917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
3927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Read the kernel data */
3934184e626336fa8d794a21208387226f154d77d0fRandall Spangler		if (body_toread &&
3944184e626336fa8d794a21208387226f154d77d0fRandall Spangler		    0 != VbExStreamRead(stream, body_toread, body_readptr)) {
3957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Unable to read kernel data.\n"));
3967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_READ_DATA;
3977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			goto bad_kernel;
3987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
3997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4004184e626336fa8d794a21208387226f154d77d0fRandall Spangler		/* Close the stream; we're done with it */
4014184e626336fa8d794a21208387226f154d77d0fRandall Spangler		VbExStreamClose(stream);
4024184e626336fa8d794a21208387226f154d77d0fRandall Spangler		stream = NULL;
4034184e626336fa8d794a21208387226f154d77d0fRandall Spangler
4047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Verify kernel data */
4057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (0 != VerifyData((const uint8_t *)params->kernel_buffer,
4067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				    params->kernel_buffer_size,
4077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler				    &preamble->body_signature, data_key)) {
4087993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Kernel data verification failed.\n"));
4097993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->check_result = VBSD_LKP_CHECK_VERIFY_DATA;
4107993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			goto bad_kernel;
4117993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
4127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Done with the kernel signing key, so can free it now */
4147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		RSAPublicKeyFree(data_key);
4157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		data_key = NULL;
416d183644564ec27c106a3eb1931f565fae167a058Randall Spangler
4177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
4187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * If we're still here, the kernel is valid.  Save the first
4197993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * good partition we find; that's the one we'll boot.
4207993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
4217993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("Partition is good.\n"));
4227993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shpart->check_result = VBSD_LKP_CHECK_KERNEL_GOOD;
4237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (key_block_valid)
4247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shpart->flags |= VBSD_LKP_FLAG_KEY_BLOCK_VALID;
4257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		good_partition_key_block_valid = key_block_valid;
4277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
4287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * TODO: GPT partitions start at 1, but cgptlib starts them at
4297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * 0.  Adjust here, until cgptlib is fixed.
4307993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
4317993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		good_partition = gpt.current_kernel + 1;
4327993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		params->partition_number = gpt.current_kernel + 1;
4337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		GetCurrentKernelUniqueGuid(&gpt, &params->partition_guid);
4347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
4357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * TODO: GetCurrentKernelUniqueGuid() should take a destination
4367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * size, or the dest should be a struct, so we know it's big
4377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * enough.
4387993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
4397993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		params->bootloader_address = preamble->bootloader_address;
4407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		params->bootloader_size = preamble->bootloader_size;
441b7d1f03e368b146d11eab511cd6a573a528bc728Furquan Shaikh		if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
442b7d1f03e368b146d11eab511cd6a573a528bc728Furquan Shaikh			params->flags = preamble->flags;
443741d2b2f8d8f155c4960214fc40097eb143b6ef0Randall Spangler
4447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Update GPT to note this is the kernel we're trying */
4457993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_TRY);
4467993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4477993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
4487993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * If we're in recovery mode or we're about to boot a
4497993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * dev-signed kernel, there's no rollback protection, so we can
4507993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * stop at the first valid kernel.
4517993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
4527993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (kBootRecovery == boot_mode || !key_block_valid) {
4537993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("In recovery mode or dev-signed kernel\n"));
4547993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			break;
4557993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
4567993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4577993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
4587993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * Otherwise, we do care about the key index in the TPM.  If
4597993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * the good partition's key version is the same as the tpm,
4607993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * then the TPM doesn't need updating; we can stop now.
4617993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * Otherwise, we'll check all the other headers to see if they
4627993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * contain a newer key.
4637993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
4647993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (combined_version == shared->kernel_version_tpm) {
4657993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			VBDEBUG(("Same kernel version\n"));
4667993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			break;
4677993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		}
4687993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4697993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Continue, so that we skip the error handling code below */
4707993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		continue;
4717993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4727993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	bad_kernel:
4737993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Handle errors parsing this kernel */
4744184e626336fa8d794a21208387226f154d77d0fRandall Spangler		if (NULL != stream)
4754184e626336fa8d794a21208387226f154d77d0fRandall Spangler			VbExStreamClose(stream);
4767993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (NULL != data_key)
4777993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			RSAPublicKeyFree(data_key);
4787993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4797993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("Marking kernel as invalid.\n"));
4807993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		GptUpdateKernelEntry(&gpt, GPT_UPDATE_ENTRY_BAD);
4817993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4827993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4837993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler        } /* while(GptNextKernelEntry) */
4847993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4857993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler bad_gpt:
4867993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4877993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Free kernel buffer */
4887993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (kbuf)
4897993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VbExFree(kbuf);
4907993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4917993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Write and free GPT data */
4927993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	WriteAndFreeGptData(params->disk_handle, &gpt);
4937993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
4947993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Handle finding a good partition */
4957993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (good_partition >= 0) {
4967993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		VBDEBUG(("Good_partition >= 0\n"));
4977993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shcall->check_result = VBSD_LKC_CHECK_GOOD_PARTITION;
4987993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shared->kernel_version_lowest = lowest_version;
4997993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/*
5007993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * Sanity check - only store a new TPM version if we found one.
5017993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * If lowest_version is still at its initial value, we didn't
5027993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * find one; for example, we're in developer mode and just
5037993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 * didn't look.
5047993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		 */
5057993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		if (lowest_version != LOWEST_TPM_VERSION &&
5067993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		    lowest_version > shared->kernel_version_tpm)
5077993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler			shared->kernel_version_tpm = lowest_version;
5087993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
5097993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		/* Success! */
5107993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		retval = VBERROR_SUCCESS;
5117993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	} else if (found_partitions > 0) {
5127993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shcall->check_result = VBSD_LKC_CHECK_INVALID_PARTITIONS;
5137993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		recovery = VBNV_RECOVERY_RW_INVALID_OS;
5147993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		retval = VBERROR_INVALID_KERNEL_FOUND;
5157993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	} else {
5167993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shcall->check_result = VBSD_LKC_CHECK_NO_PARTITIONS;
5177993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		recovery = VBNV_RECOVERY_RW_NO_OS;
5187993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		retval = VBERROR_NO_KERNEL_FOUND;
5197993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	}
5207993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
5217993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler LoadKernelExit:
5227993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
5237993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Store recovery request, if any */
5247993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	VbNvSet(vnc, VBNV_RECOVERY_REQUEST, VBERROR_SUCCESS != retval ?
5257993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		recovery : VBNV_RECOVERY_NOT_REQUESTED);
5267993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
5277993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/*
5287993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	 * If LoadKernel() was called with bad parameters, shcall may not be
5297993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	 * initialized.
5307993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	 */
5317993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (shcall)
5327993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shcall->return_code = (uint8_t)retval;
5337993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
5347993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Save whether the good partition's key block was fully verified */
5357993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	if (good_partition_key_block_valid)
5367993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler		shared->flags |= VBSD_KERNEL_KEY_VERIFIED;
5377993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
5387993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	/* Store how much shared data we used, if any */
5397993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	params->shared_data_size = shared->data_used;
5407993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler
541527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass	if (free_kernel_subkey)
542527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass		VbExFree(kernel_subkey);
543527ba810eff4006cf69579f6b96cb4350cb1e189Simon Glass
5447993f257af87c7c38cdc71b76bc67cde6c3cdbcaRandall Spangler	return retval;
545d183644564ec27c106a3eb1931f565fae167a058Randall Spangler}
546