vboot2: Add routines to load and verify kernel keyblock

These are slightly more complex than the firmware versions, because
they need to deal with developer-signed keyblocks and keyblock flags.

BUG=chromium:487699
BRANCH=none
TEST=make -j runtests

Change-Id: I682c14ddfe729984f2629dfbe66750e5cd5ab75e
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/272541
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
This commit is contained in:
Randall Spangler
2015-05-20 17:22:17 -07:00
committed by ChromeOS Commit Bot
parent b87d1ec118
commit 3d5cd88f90
8 changed files with 717 additions and 3 deletions

View File

@@ -722,6 +722,7 @@ TEST20_NAMES = \
tests/vb20_common2_tests \
tests/vb20_verify_fw.c \
tests/vb20_common3_tests \
tests/vb20_kernel_tests \
tests/vb20_misc_tests \
tests/vb20_rsa_padding_tests \
tests/vb20_verify_fw
@@ -1385,6 +1386,7 @@ run2tests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vb20_common_tests
${RUNTEST} ${BUILD_RUN}/tests/vb20_common2_tests ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/vb20_common3_tests ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/vb20_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vb20_misc_tests
${RUNTEST} ${BUILD_RUN}/tests/vb21_api_tests
${RUNTEST} ${BUILD_RUN}/tests/vb21_common_tests

View File

@@ -177,17 +177,27 @@ struct vb2_context {
uint8_t secdatak[VB2_SECDATAK_SIZE];
};
/* Resource index for vb2ex_read_resource() */
enum vb2_resource_index {
/* Google binary block */
VB2_RES_GBB,
/*
* Verified boot block (keyblock+preamble). Use VB2_CONTEXT_FW_SLOT_B
* to determine whether this refers to slot A or slot B; vboot will
* set that flag to the proper state before reading the vblock.
* Firmware verified boot block (keyblock+preamble). Use
* VB2_CONTEXT_FW_SLOT_B to determine whether this refers to slot A or
* slot B; vboot will set that flag to the proper state before reading
* the vblock.
*/
VB2_RES_FW_VBLOCK,
/*
* Kernel verified boot block (keyblock+preamble) for the current
* kernel partition. Used only by vb2api_kernel_load_vblock().
* Contents are allowed to change between calls to that function (to
* allow multiple kernels to be examined).
*/
VB2_RES_KERNEL_VBLOCK,
};
/* Digest ID for vbapi_get_pcr_digest() */

View File

@@ -141,4 +141,14 @@ int vb2_load_fw_keyblock(struct vb2_context *ctx);
*/
int vb2_load_fw_preamble(struct vb2_context *ctx);
/**
* Verify the kernel keyblock using the previously-loaded kernel key.
*
* After this call, the data key is stored in the work buffer.
*
* @param ctx Vboot context
* @return VB2_SUCCESS, or error code on error.
*/
int vb2_load_kernel_keyblock(struct vb2_context *ctx);
#endif /* VBOOT_REFERENCE_VBOOT_2MISC_H_ */

View File

@@ -406,6 +406,27 @@ enum vb2_return_code {
/* Not enough space in work buffer for resource object */
VB2_ERROR_READ_RESOURCE_OBJECT_BUF,
/* Work buffer too small for header in vb2_load_kernel_keyblock() */
VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF_HEADER,
/* Work buffer too small for keyblock in vb2_load_kernel_keyblock() */
VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF,
/* Keyblock version out of range in vb2_load_kernel_keyblock() */
VB2_ERROR_KERNEL_KEYBLOCK_VERSION_RANGE,
/* Keyblock version rollback in vb2_load_kernel_keyblock() */
VB2_ERROR_KERNEL_KEYBLOCK_VERSION_ROLLBACK,
/*
* Keyblock flags don't match current mode in
* vb2_load_kernel_keyblock().
*/
VB2_ERROR_KERNEL_KEYBLOCK_DEV_FLAG,
VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG,
/**********************************************************************
* API-level errors
*/

View File

@@ -31,12 +31,16 @@ enum vb2_shared_data_flags {
VB2_SD_FLAG_MANUAL_RECOVERY = (1 << 0),
/* Developer mode is enabled */
/* TODO: should have been VB2_SD_FLAG_DEV_MODE_ENABLED */
VB2_SD_DEV_MODE_ENABLED = (1 << 1),
/*
* TODO: might be nice to add flags for why dev mode is enabled - via
* gbb, virtual dev switch, or forced on for testing.
*/
/* Kernel keyblock was verified by signature (not just hash) */
VB2_SD_FLAG_KERNEL_SIGNED = (1 << 2),
};
/* Flags for vb2_shared_data.status */
@@ -100,6 +104,25 @@ struct vb2_shared_data {
*/
uint32_t status;
/**********************************************************************
* Data from kernel verification stage.
*
* TODO: shouldn't be part of the main struct, since that needlessly
* uses more memory during firmware verification.
*/
/*
* Version for the current kernel (top 16 bits = key, lower 16 bits =
* kernel preamble).
*
* TODO: Make this a union to allow getting/setting those versions
* separately?
*/
uint32_t kernel_version;
/* Kernel version from secdatak (must be <= kernel_version to boot) */
uint32_t kernel_version_secdatak;
/**********************************************************************
* Temporary variables used during firmware verification. These don't
* really need to persist through to the OS, but there's nowhere else
@@ -151,6 +174,25 @@ struct vb2_shared_data {
/* Amount of data we still expect to hash */
uint32_t hash_remaining_size;
/**********************************************************************
* Temporary variables used during kernel verification. These don't
* really need to persist through to the OS, but there's nowhere else
* we can put them.
*
* TODO: make a union with the firmware verification temp variables,
* or make both of them workbuf-allocated sub-structs, so that we can
* overlap them so kernel variables don't bloat firmware verification
* stage memory requirements.
*/
/*
* Offset and size of packed kernel key in work buffer. Size is 0 if
* subkey is not stored in the work buffer. Note that kernel key may
* be inside the firmware preamble.
*/
uint32_t workbuf_kernel_key_offset;
uint32_t workbuf_kernel_key_size;
} __attribute__((packed));
/****************************************************************************/

View File

@@ -156,6 +156,22 @@ int vb2_verify_keyblock(struct vb2_keyblock *block,
const struct vb2_public_key *key,
const struct vb2_workbuf *wb);
/**
* Verify a key block using its hash.
*
* Header fields are also checked for sanity. Does not verify key index or key
* block flags. Use this for self-signed keyblocks in developer mode.
*
* @param block Key block to verify
* @param size Size of key block buffer
* @param key Key to use to verify block
* @param wb Work buffer
* @return VB2_SUCCESS, or non-zero error code if error.
*/
int vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
uint32_t size,
const struct vb2_workbuf *wb);
/**
* Check the sanity of a firmware preamble using a public key.
*

View File

@@ -6,10 +6,229 @@
*/
#include "2sysincludes.h"
#include "2misc.h"
#include "2nvstorage.h"
#include "2rsa.h"
#include "2sha.h"
#include "vb2_common.h"
static const uint8_t *vb2_signature_data_const(const struct vb2_signature *sig)
{
return (uint8_t *)sig + sig->sig_offset;
}
int vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
uint32_t size,
const struct vb2_workbuf *wb)
{
const struct vb2_signature *sig = &block->keyblock_hash;
struct vb2_workbuf wblocal = *wb;
struct vb2_digest_context *dc;
uint8_t *digest;
uint32_t digest_size;
int rv;
/* Sanity check keyblock before attempting hash check of data */
rv = vb2_check_keyblock(block, size, sig);
if (rv)
return rv;
VB2_DEBUG("Checking key block hash...\n");
/* Digest goes at start of work buffer */
digest_size = vb2_digest_size(VB2_HASH_SHA512);
digest = vb2_workbuf_alloc(&wblocal, digest_size);
if (!digest)
return VB2_ERROR_VDATA_WORKBUF_DIGEST;
/* Hashing requires temp space for the context */
dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc));
if (!dc)
return VB2_ERROR_VDATA_WORKBUF_HASHING;
rv = vb2_digest_init(dc, VB2_HASH_SHA512);
if (rv)
return rv;
rv = vb2_digest_extend(dc, (const uint8_t *)block, sig->data_size);
if (rv)
return rv;
rv = vb2_digest_finalize(dc, digest, digest_size);
if (rv)
return rv;
if (vb2_safe_memcmp(vb2_signature_data_const(sig), digest,
digest_size) != 0) {
VB2_DEBUG("Invalid key block hash.\n");
return VB2_ERROR_KEYBLOCK_SIG_INVALID;
}
/* Success */
return VB2_SUCCESS;
}
int vb2_load_kernel_keyblock(struct vb2_context *ctx)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
struct vb2_workbuf wb;
uint8_t *key_data;
uint32_t key_size;
struct vb2_packed_key *packed_key;
struct vb2_public_key kernel_key;
struct vb2_keyblock *kb;
uint32_t block_size;
int rec_switch = (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) != 0;
int dev_switch = (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) != 0;
int need_keyblock_valid = 1;
int keyblock_is_valid = 1;
int rv;
vb2_workbuf_from_ctx(ctx, &wb);
/*
* The only time we don't need a valid keyblock is if we're in
* developer mode and not set to require a signed kernel.
*/
if (dev_switch && !rec_switch &&
!vb2_nv_get(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY))
need_keyblock_valid = 0;
/*
* Clear any previous keyblock-valid flag (for example, from a previous
* kernel where the keyblock was signed but the preamble failed
* verification).
*/
sd->flags &= ~VB2_SD_FLAG_KERNEL_SIGNED;
/* Unpack the kernel key */
key_data = ctx->workbuf + sd->workbuf_kernel_key_offset;
key_size = sd->workbuf_kernel_key_size;
rv = vb2_unpack_key(&kernel_key, key_data, key_size);
if (rv)
return rv;
/* Load the kernel keyblock header after the root key */
kb = vb2_workbuf_alloc(&wb, sizeof(*kb));
if (!kb)
return VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF_HEADER;
rv = vb2ex_read_resource(ctx, VB2_RES_KERNEL_VBLOCK, 0, kb,
sizeof(*kb));
if (rv)
return rv;
block_size = kb->keyblock_size;
/*
* Load the entire keyblock, now that we know how big it is. Note that
* we're loading the entire keyblock instead of just the piece after
* the header. That means we re-read the header. But that's a tiny
* amount of data, and it makes the code much more straightforward.
*/
kb = vb2_workbuf_realloc(&wb, sizeof(*kb), block_size);
if (!kb)
return VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF;
rv = vb2ex_read_resource(ctx, VB2_RES_KERNEL_VBLOCK, 0, kb, block_size);
if (rv)
return rv;
/* Verify the keyblock */
rv = vb2_verify_keyblock(kb, block_size, &kernel_key, &wb);
if (rv) {
keyblock_is_valid = 0;
if (need_keyblock_valid)
return rv;
/* Signature is invalid, but hash may be fine */
rv = vb2_verify_keyblock_hash(kb, block_size, &wb);
if (rv)
return rv;
}
/* Check the key block flags against the current boot mode */
if (!(kb->keyblock_flags &
(dev_switch ? VB2_KEY_BLOCK_FLAG_DEVELOPER_1 :
VB2_KEY_BLOCK_FLAG_DEVELOPER_0))) {
VB2_DEBUG("Key block developer flag mismatch.\n");
keyblock_is_valid = 0;
if (need_keyblock_valid)
return VB2_ERROR_KERNEL_KEYBLOCK_DEV_FLAG;
}
if (!(kb->keyblock_flags &
(rec_switch ? VB2_KEY_BLOCK_FLAG_RECOVERY_1 :
VB2_KEY_BLOCK_FLAG_RECOVERY_0))) {
VB2_DEBUG("Key block recovery flag mismatch.\n");
keyblock_is_valid = 0;
if (need_keyblock_valid)
return VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG;
}
/* Check for keyblock rollback if not in recovery mode */
/* Key version is the upper 16 bits of the composite version */
if (!rec_switch && kb->data_key.key_version > 0xffff) {
keyblock_is_valid = 0;
if (need_keyblock_valid)
return VB2_ERROR_KERNEL_KEYBLOCK_VERSION_RANGE;
}
if (!rec_switch && kb->data_key.key_version <
(sd->kernel_version_secdatak >> 16)) {
keyblock_is_valid = 0;
if (need_keyblock_valid)
return VB2_ERROR_KERNEL_KEYBLOCK_VERSION_ROLLBACK;
}
sd->kernel_version = kb->data_key.key_version << 16;
/*
* At this point, we've checked everything. The kernel keyblock is at
* least self-consistent, and has either a valid signature or a valid
* hash. Track if it had a valid signature (that is, would we have
* been willing to boot it even if developer mode was off).
*/
if (keyblock_is_valid)
sd->flags |= VB2_SD_FLAG_KERNEL_SIGNED;
/* Preamble follows the keyblock in the vblock */
sd->vblock_preamble_offset = kb->keyblock_size;
/*
* Keep just the data key from the vblock. This follows the kernel key
* (which we might still need to verify the next kernel, if the
* assoiciated kernel preamble and data don't verify).
*/
sd->workbuf_data_key_offset = ctx->workbuf_used;
key_data = ctx->workbuf + sd->workbuf_data_key_offset;
packed_key = (struct vb2_packed_key *)key_data;
memmove(packed_key, &kb->data_key, sizeof(*packed_key));
packed_key->key_offset = sizeof(*packed_key);
memmove(key_data + packed_key->key_offset,
(uint8_t*)&kb->data_key + kb->data_key.key_offset,
packed_key->key_size);
/* Save the packed key size */
sd->workbuf_data_key_size =
packed_key->key_offset + packed_key->key_size;
/*
* Data key will persist in the workbuf after we return.
*
* Work buffer now contains:
* - vb2_shared_data
* - kernel key
* - packed kernel data key
*/
ctx->workbuf_used = sd->workbuf_data_key_offset +
sd->workbuf_data_key_size;
return VB2_SUCCESS;
}
int vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble,
uint32_t size,
const struct vb2_public_key *key,

394
tests/vb20_kernel_tests.c Normal file
View File

@@ -0,0 +1,394 @@
/* Copyright 2015 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.
*
* Tests for kernel verification library
*/
#include <stdio.h>
#include "2sysincludes.h"
#include "2api.h"
#include "2common.h"
#include "2misc.h"
#include "2nvstorage.h"
#include "2rsa.h"
#include "2secdata.h"
#include "vb2_common.h"
#include "test_common.h"
/* Common context for tests */
static uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE]
__attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
static struct vb2_workbuf wb;
static struct vb2_context cc;
static struct vb2_shared_data *sd;
/* Mocked function data */
static struct {
struct vb2_gbb_header h;
struct vb2_packed_key recovery_key;
char recovery_key_data[32];
} mock_gbb;
static struct {
/* Keyblock */
struct {
struct vb2_keyblock kb;
char data_key_data[16];
uint8_t kbdata[128];
uint8_t hash[VB2_SHA512_DIGEST_SIZE];
} k;
/* Preamble follows keyblock */
struct {
struct vb2_kernel_preamble pre;
uint8_t predata[128];
} p;
} mock_vblock;
static int mock_read_res_fail_on_call;
static int mock_unpack_key_retval;
static int mock_verify_keyblock_retval;
/* Type of test to reset for */
enum reset_type {
FOR_KEYBLOCK,
FOR_PREAMBLE
};
static void rehash_keyblock(void)
{
struct vb2_keyblock *kb = &mock_vblock.k.kb;
struct vb2_signature *hashsig = &mock_vblock.k.kb.keyblock_hash;
struct vb2_digest_context dc;
hashsig->sig_offset = vb2_offset_of(hashsig, mock_vblock.k.hash);
hashsig->sig_size = sizeof(mock_vblock.k.hash);
hashsig->data_size = hashsig->sig_offset;
vb2_digest_init(&dc, VB2_HASH_SHA512);
vb2_digest_extend(&dc, (const uint8_t *)kb, hashsig->data_size);
vb2_digest_finalize(&dc, mock_vblock.k.hash, hashsig->sig_size);
}
static void reset_common_data(enum reset_type t)
{
struct vb2_keyblock *kb = &mock_vblock.k.kb;
struct vb2_kernel_preamble *pre = &mock_vblock.p.pre;
memset(workbuf, 0xaa, sizeof(workbuf));
memset(&cc, 0, sizeof(cc));
cc.workbuf = workbuf;
cc.workbuf_size = sizeof(workbuf);
vb2_workbuf_from_ctx(&cc, &wb);
vb2_init_context(&cc);
sd = vb2_get_sd(&cc);
vb2_nv_init(&cc);
vb2_secdatak_create(&cc);
vb2_secdatak_init(&cc);
mock_read_res_fail_on_call = 0;
mock_unpack_key_retval = VB2_SUCCESS;
mock_verify_keyblock_retval = VB2_SUCCESS;
/* Set up mock data for verifying keyblock */
sd->kernel_version_secdatak = 0x20002;
vb2_secdatak_set(&cc, VB2_SECDATAK_VERSIONS, 0x20002);
mock_gbb.recovery_key.algorithm = 11;
mock_gbb.recovery_key.key_offset =
vb2_offset_of(&mock_gbb.recovery_key,
&mock_gbb.recovery_key_data);
mock_gbb.recovery_key.key_size = sizeof(mock_gbb.recovery_key_data);
kb->keyblock_size = sizeof(mock_vblock.k);
memcpy(kb->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE);
kb->keyblock_flags = VB2_KEY_BLOCK_FLAG_DEVELOPER_1 |
VB2_KEY_BLOCK_FLAG_DEVELOPER_0 |
VB2_KEY_BLOCK_FLAG_RECOVERY_1 | VB2_KEY_BLOCK_FLAG_RECOVERY_0;
kb->header_version_major = KEY_BLOCK_HEADER_VERSION_MAJOR;
kb->header_version_minor = KEY_BLOCK_HEADER_VERSION_MINOR;
kb->data_key.algorithm = 7;
kb->data_key.key_version = 2;
kb->data_key.key_offset =
vb2_offset_of(&mock_vblock.k, &mock_vblock.k.data_key_data) -
vb2_offset_of(&mock_vblock.k, &kb->data_key);
kb->data_key.key_size = sizeof(mock_vblock.k.data_key_data);
strcpy(mock_vblock.k.data_key_data, "data key data!!");
rehash_keyblock();
pre->preamble_size = sizeof(mock_vblock.p);
pre->kernel_version = 2;
/* If verifying preamble, verify keyblock first to set up data key */
if (t == FOR_PREAMBLE)
vb2_load_kernel_keyblock(&cc);
};
/* Mocked functions */
int vb2ex_read_resource(struct vb2_context *ctx,
enum vb2_resource_index index,
uint32_t offset,
void *buf,
uint32_t size)
{
uint8_t *rptr;
uint32_t rsize;
if (--mock_read_res_fail_on_call == 0)
return VB2_ERROR_MOCK;
switch(index) {
case VB2_RES_GBB:
rptr = (uint8_t *)&mock_gbb;
rsize = sizeof(mock_gbb);
break;
case VB2_RES_KERNEL_VBLOCK:
rptr = (uint8_t *)&mock_vblock;
rsize = sizeof(mock_vblock);
break;
default:
return VB2_ERROR_EX_READ_RESOURCE_INDEX;
}
if (offset > rsize || offset + size > rsize)
return VB2_ERROR_EX_READ_RESOURCE_SIZE;
memcpy(buf, rptr + offset, size);
return VB2_SUCCESS;
}
int vb2_unpack_key(struct vb2_public_key *key,
const uint8_t *buf,
uint32_t size)
{
key->arrsize = 0;
return mock_unpack_key_retval;
}
int vb2_verify_keyblock(struct vb2_keyblock *block,
uint32_t size,
const struct vb2_public_key *key,
const struct vb2_workbuf *wb)
{
return mock_verify_keyblock_retval;
}
/* Tests */
static void verify_keyblock_hash_tests(void)
{
struct vb2_keyblock *kb = &mock_vblock.k.kb;
/* Test successful call */
reset_common_data(FOR_KEYBLOCK);
TEST_SUCC(vb2_verify_keyblock_hash(kb, kb->keyblock_size, &wb),
"Keyblock hash good");
/* Sanity check keyblock */
reset_common_data(FOR_KEYBLOCK);
kb->magic[0] ^= 0xd0;
TEST_EQ(vb2_verify_keyblock_hash(kb, kb->keyblock_size, &wb),
VB2_ERROR_KEYBLOCK_MAGIC, "Keyblock sanity check");
/*
* Sanity check should be looking at the keyblock hash struct, not the
* keyblock signature struct.
*/
reset_common_data(FOR_KEYBLOCK);
kb->keyblock_hash.data_size = sizeof(*kb) - 1;
TEST_EQ(vb2_verify_keyblock_hash(kb, kb->keyblock_size, &wb),
VB2_ERROR_KEYBLOCK_SIGNED_TOO_LITTLE,
"Keyblock check hash sig");
reset_common_data(FOR_KEYBLOCK);
wb.size = VB2_SHA512_DIGEST_SIZE - 1;
TEST_EQ(vb2_verify_keyblock_hash(kb, kb->keyblock_size, &wb),
VB2_ERROR_VDATA_WORKBUF_DIGEST,
"Keyblock check hash workbuf digest");
reset_common_data(FOR_KEYBLOCK);
wb.size = VB2_SHA512_DIGEST_SIZE +
sizeof(struct vb2_digest_context) - 1;
TEST_EQ(vb2_verify_keyblock_hash(kb, kb->keyblock_size, &wb),
VB2_ERROR_VDATA_WORKBUF_HASHING,
"Keyblock check hash workbuf hashing");
reset_common_data(FOR_KEYBLOCK);
mock_vblock.k.data_key_data[0] ^= 0xa0;
TEST_EQ(vb2_verify_keyblock_hash(kb, kb->keyblock_size, &wb),
VB2_ERROR_KEYBLOCK_SIG_INVALID,
"Keyblock check hash invalid");
}
static void load_kernel_keyblock_tests(void)
{
struct vb2_keyblock *kb = &mock_vblock.k.kb;
struct vb2_packed_key *k;
int wb_used_before;
/* Test successful call */
reset_common_data(FOR_KEYBLOCK);
wb_used_before = cc.workbuf_used;
TEST_SUCC(vb2_load_kernel_keyblock(&cc), "Kernel keyblock good");
TEST_NEQ(sd->flags & VB2_SD_FLAG_KERNEL_SIGNED, 0, " Kernel signed");
TEST_EQ(sd->kernel_version, 0x20000, "keyblock version");
TEST_EQ(sd->vblock_preamble_offset, sizeof(mock_vblock.k),
"preamble offset");
TEST_EQ(sd->workbuf_data_key_offset,
(wb_used_before + (VB2_WORKBUF_ALIGN - 1)) &
~(VB2_WORKBUF_ALIGN - 1),
"keyblock data key offset");
TEST_EQ(cc.workbuf_used,
sd->workbuf_data_key_offset + sd->workbuf_data_key_size,
"workbuf used");
/* Make sure data key was properly saved */
k = (struct vb2_packed_key *)(cc.workbuf + sd->workbuf_data_key_offset);
TEST_EQ(k->algorithm, 7, "data key algorithm");
TEST_EQ(k->key_version, 2, "data key version");
TEST_EQ(k->key_size, sizeof(mock_vblock.k.data_key_data),
"data key size");
TEST_EQ(memcmp(cc.workbuf + sd->workbuf_data_key_offset +
k->key_offset, mock_vblock.k.data_key_data,
sizeof(mock_vblock.k.data_key_data)),
0, "data key data");
TEST_EQ(cc.workbuf_used,
sd->workbuf_data_key_offset + sd->workbuf_data_key_size,
"workbuf used after");
/* Test failures */
reset_common_data(FOR_KEYBLOCK);
mock_unpack_key_retval = VB2_ERROR_MOCK;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_MOCK, "Kernel keyblock unpack key");
reset_common_data(FOR_KEYBLOCK);
cc.workbuf_used = cc.workbuf_size - (sizeof(*kb) - 1);
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF_HEADER,
"Kernel keyblock workbuf header");
reset_common_data(FOR_KEYBLOCK);
mock_read_res_fail_on_call = 1;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_MOCK, "Kernel keyblock read header");
reset_common_data(FOR_KEYBLOCK);
cc.workbuf_used = cc.workbuf_size - (kb->keyblock_size - 1);
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_KERNEL_KEYBLOCK_WORKBUF,
"Kernel keyblock workbuf");
reset_common_data(FOR_KEYBLOCK);
mock_read_res_fail_on_call = 2;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_MOCK, "Kernel keyblock read");
/* Normally, require signed keyblock */
reset_common_data(FOR_KEYBLOCK);
mock_verify_keyblock_retval = VB2_ERROR_MOCK;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_MOCK, "Verify keyblock");
/* Not in dev mode */
reset_common_data(FOR_KEYBLOCK);
cc.flags |= VB2_CONTEXT_DEVELOPER_MODE;
mock_verify_keyblock_retval = VB2_ERROR_MOCK;
TEST_SUCC(vb2_load_kernel_keyblock(&cc), "Kernel keyblock hash good");
TEST_EQ(sd->flags & VB2_SD_FLAG_KERNEL_SIGNED, 0, " Kernel signed");
/* But we do in dev+rec mode */
reset_common_data(FOR_KEYBLOCK);
cc.flags |= VB2_CONTEXT_DEVELOPER_MODE | VB2_CONTEXT_RECOVERY_MODE;
mock_verify_keyblock_retval = VB2_ERROR_MOCK;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_MOCK, "Kernel keyblock dev+rec");
/* Test keyblock flags matching mode */
reset_common_data(FOR_KEYBLOCK);
kb->keyblock_flags &= ~VB2_KEY_BLOCK_FLAG_DEVELOPER_0;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_KERNEL_KEYBLOCK_DEV_FLAG,
"Kernel keyblock dev only");
reset_common_data(FOR_KEYBLOCK);
kb->keyblock_flags &= ~VB2_KEY_BLOCK_FLAG_RECOVERY_0;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG,
"Kernel keyblock rec only");
reset_common_data(FOR_KEYBLOCK);
kb->keyblock_flags &= ~VB2_KEY_BLOCK_FLAG_RECOVERY_1;
cc.flags |= VB2_CONTEXT_RECOVERY_MODE;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_KERNEL_KEYBLOCK_REC_FLAG,
"Kernel keyblock not rec");
reset_common_data(FOR_KEYBLOCK);
kb->keyblock_flags &= ~VB2_KEY_BLOCK_FLAG_DEVELOPER_0;
kb->keyblock_flags &= ~VB2_KEY_BLOCK_FLAG_RECOVERY_0;
cc.flags |= VB2_CONTEXT_RECOVERY_MODE;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_KERNEL_KEYBLOCK_DEV_FLAG,
"Kernel keyblock rec but not dev+rec");
reset_common_data(FOR_KEYBLOCK);
kb->keyblock_flags &= ~VB2_KEY_BLOCK_FLAG_DEVELOPER_0;
kb->keyblock_flags &= ~VB2_KEY_BLOCK_FLAG_RECOVERY_0;
cc.flags |= VB2_CONTEXT_DEVELOPER_MODE | VB2_CONTEXT_RECOVERY_MODE;
TEST_SUCC(vb2_load_kernel_keyblock(&cc),
"Kernel keyblock flags dev+rec");
/* System in dev mode ignores flags */
reset_common_data(FOR_KEYBLOCK);
cc.flags |= VB2_CONTEXT_DEVELOPER_MODE;
kb->keyblock_flags = 0;
TEST_SUCC(vb2_load_kernel_keyblock(&cc), "Kernel keyblock dev flags");
/* Test rollback */
reset_common_data(FOR_KEYBLOCK);
kb->data_key.key_version = 0x10000;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_KERNEL_KEYBLOCK_VERSION_RANGE,
"Kernel keyblock version range");
reset_common_data(FOR_KEYBLOCK);
kb->data_key.key_version = 1;
TEST_EQ(vb2_load_kernel_keyblock(&cc),
VB2_ERROR_KERNEL_KEYBLOCK_VERSION_ROLLBACK,
"Kernel keyblock rollback");
/* Rollback ok in developer mode */
reset_common_data(FOR_KEYBLOCK);
kb->data_key.key_version = 1;
cc.flags |= VB2_CONTEXT_DEVELOPER_MODE;
TEST_SUCC(vb2_load_kernel_keyblock(&cc),
"Kernel keyblock rollback dev");
/*
* Recovery keyblocks aren't versioned (and even if they were, it
* wouldn't be with the same version as a normal kernel).
*/
reset_common_data(FOR_KEYBLOCK);
kb->data_key.key_version = 1;
cc.flags |= VB2_CONTEXT_RECOVERY_MODE;
TEST_SUCC(vb2_load_kernel_keyblock(&cc),
"Kernel keyblock rollback rec");
}
int main(int argc, char* argv[])
{
verify_keyblock_hash_tests();
load_kernel_keyblock_tests();
return gTestSuccess ? 0 : 255;
}