vboot2: Add code and tests for verifying vb2_fw_preamble2

This is the last low-level data structure verification code for the
new data structures.  Subsequent changes are the next level up the
food chain.

BUG=chromium:423882
BRANCH=none
TEST=VBOOT2=1 make runtests

Change-Id: I2e45106c27447eb624c1ed562e40b98088249742
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/228360
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
This commit is contained in:
Randall Spangler
2014-11-04 17:50:32 -08:00
committed by chrome-internal-fetch
parent 054c114798
commit 43e0a9ed6c
5 changed files with 277 additions and 11 deletions

View File

@@ -366,3 +366,73 @@ int vb2_verify_keyblock2(struct vb2_keyblock2 *block,
/* If we're still here, no signature matched the key GUID */ /* If we're still here, no signature matched the key GUID */
return VB2_ERROR_KEYBLOCK_SIG_GUID; return VB2_ERROR_KEYBLOCK_SIG_GUID;
} }
int vb2_verify_fw_preamble2(struct vb2_fw_preamble2 *preamble,
uint32_t size,
const struct vb2_public_key *key,
const struct vb2_workbuf *wb)
{
struct vb2_signature2 *sig;
uint32_t min_offset = 0, hash_offset;
int rv, i;
/* Check magic number */
if (preamble->c.magic != VB2_MAGIC_FW_PREAMBLE2)
return VB2_ERROR_PREAMBLE_MAGIC;
/* Make sure common header is good */
rv = vb2_verify_common_header(preamble, size);
if (rv)
return rv;
/*
* Check for compatible version. No need to check minor version, since
* that's compatible across readers matching the major version, and we
* haven't added any new fields.
*/
if (preamble->c.struct_version_major != VB2_FW_PREAMBLE2_VERSION_MAJOR)
return VB2_ERROR_PREAMBLE_HEADER_VERSION;
/* Make sure header is big enough */
if (preamble->c.fixed_size < sizeof(*preamble))
return VB2_ERROR_PREAMBLE_SIZE;
/* Make sure all hash signatures are inside */
hash_offset = preamble->hash_offset;
for (i = 0; i < preamble->hash_count; i++, hash_offset = min_offset) {
/* Make sure signature is inside preamble */
rv = vb2_verify_common_subobject(preamble, &min_offset,
hash_offset);
if (rv)
return rv;
sig = (struct vb2_signature2 *)
((uint8_t *)preamble + hash_offset);
/* Verify the signature integrity */
rv = vb2_verify_signature2(
sig, preamble->c.total_size - hash_offset);
if (rv)
return rv;
/* Hashes must all be unsigned */
if (sig->sig_alg != VB2_SIG_NONE)
return VB2_ERROR_PREAMBLE_HASH_SIGNED;
}
/* Make sure signature is inside preamble */
rv = vb2_verify_common_subobject(preamble, &min_offset,
preamble->sig_offset);
if (rv)
return rv;
/* Verify preamble signature */
sig = (struct vb2_signature2 *)((uint8_t *)preamble +
preamble->sig_offset);
rv = vb2_verify_data2(preamble, preamble->sig_offset, sig, key, wb);
if (rv)
return rv;
return VB2_SUCCESS;
}

View File

@@ -410,7 +410,10 @@ int vb2_verify_keyblock2(struct vb2_keyblock2 *block,
const struct vb2_public_key *key, const struct vb2_public_key *key,
const struct vb2_workbuf *wb); const struct vb2_workbuf *wb);
/* Size of work buffer sufficient for vb2_verify_fw_preamble() worst case */ /*
* Size of work buffer sufficient for vb2_verify_fw_preamble() or
* vb2_verify_fw_preamble2() worst case.
*/
#define VB2_VERIFY_FIRMWARE_PREAMBLE_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES #define VB2_VERIFY_FIRMWARE_PREAMBLE_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES
/** /**
@@ -429,4 +432,9 @@ int vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble,
const struct vb2_public_key *key, const struct vb2_public_key *key,
const struct vb2_workbuf *wb); const struct vb2_workbuf *wb);
int vb2_verify_fw_preamble2(struct vb2_fw_preamble2 *preamble,
uint32_t size,
const struct vb2_public_key *key,
const struct vb2_workbuf *wb);
#endif /* VBOOT_REFERENCE_VBOOT_2COMMON_H_ */ #endif /* VBOOT_REFERENCE_VBOOT_2COMMON_H_ */

View File

@@ -302,6 +302,12 @@ enum vb2_return_code {
/* Kernel subkey outside preamble */ /* Kernel subkey outside preamble */
VB2_ERROR_PREAMBLE_KERNEL_SUBKEY_OUTSIDE, VB2_ERROR_PREAMBLE_KERNEL_SUBKEY_OUTSIDE,
/* Bad magic number */
VB2_ERROR_PREAMBLE_MAGIC,
/* Hash is signed */
VB2_ERROR_PREAMBLE_HASH_SIGNED,
/********************************************************************** /**********************************************************************
* Misc higher-level code errors * Misc higher-level code errors
*/ */

View File

@@ -491,9 +491,9 @@ struct vb2_keyblock2 {
#define EXPECTED_VB2_KEYBLOCK2_SIZE (EXPECTED_VB2_STRUCT_COMMON_SIZE + 16) #define EXPECTED_VB2_KEYBLOCK2_SIZE (EXPECTED_VB2_STRUCT_COMMON_SIZE + 16)
/* Current version of vb2_preamble2 struct */ /* Current version of vb2_fw_preamble2 struct */
#define VB2_PREAMBLE2_VERSION_MAJOR 3 #define VB2_FW_PREAMBLE2_VERSION_MAJOR 3
#define VB2_PREAMBLE2_VERSION_MINOR 0 #define VB2_FW_PREAMBLE2_VERSION_MINOR 0
/* /*
* Firmware preamble * Firmware preamble
@@ -501,7 +501,7 @@ struct vb2_keyblock2 {
* The preamble data must be arranged like this: * The preamble data must be arranged like this:
* 1) vb2_fw_preamble2 header struct h * 1) vb2_fw_preamble2 header struct h
* 2) Preamble description (pointed to by h.c.fixed_size) * 2) Preamble description (pointed to by h.c.fixed_size)
* 3) Hash table (pointed to by h.hash_table_offset) * 3) Hashes (pointed to by h.hash_offset)
* 4) Signature (pointed to by h.sig_offset) * 4) Signature (pointed to by h.sig_offset)
* *
* The signature 4) must cover all the data from 1), 2), 3). * The signature 4) must cover all the data from 1), 2), 3).

View File

@@ -13,6 +13,8 @@
#include "test_common.h" #include "test_common.h"
static const uint8_t test_data[] = "This is some test data to sign.";
/** /**
* Test memory compare functions * Test memory compare functions
*/ */
@@ -449,7 +451,6 @@ static void test_sig_size(void)
*/ */
static void test_verify_hash(void) static void test_verify_hash(void)
{ {
static const uint8_t test_data[] = "This is some test data to sign.";
struct vb2_signature2 *sig; struct vb2_signature2 *sig;
struct vb2_public_key pubk = { struct vb2_public_key pubk = {
.sig_alg = VB2_SIG_NONE, .sig_alg = VB2_SIG_NONE,
@@ -535,12 +536,12 @@ static void test_verify_keyblock(void)
*/ */
kb.c.total_size = kb.sig_offset; kb.c.total_size = kb.sig_offset;
sig = vb2_create_hash_sig((const uint8_t *)desc, sizeof(desc), sig = vb2_create_hash_sig(test_data, sizeof(test_data),
VB2_HASH_SHA256); VB2_HASH_SHA256);
kb.c.total_size += sig->c.total_size; kb.c.total_size += sig->c.total_size;
free(sig); free(sig);
sig = vb2_create_hash_sig((const uint8_t *)desc, sizeof(desc), sig = vb2_create_hash_sig(test_data, sizeof(test_data),
VB2_HASH_SHA512); VB2_HASH_SHA512);
kb.c.total_size += sig->c.total_size; kb.c.total_size += sig->c.total_size;
free(sig); free(sig);
@@ -587,19 +588,19 @@ static void test_verify_keyblock(void)
memcpy(buf, buf2, buf_size); memcpy(buf, buf2, buf_size);
kbuf->c.magic = VB2_MAGIC_PACKED_KEY2; kbuf->c.magic = VB2_MAGIC_PACKED_KEY2;
TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk_not_present, &wb), TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb),
VB2_ERROR_KEYBLOCK_MAGIC, VB2_ERROR_KEYBLOCK_MAGIC,
"vb2_verify_keyblock2() magic"); "vb2_verify_keyblock2() magic");
memcpy(buf, buf2, buf_size); memcpy(buf, buf2, buf_size);
kbuf->c.fixed_size++; kbuf->c.fixed_size++;
TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk_not_present, &wb), TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb),
VB2_ERROR_COMMON_FIXED_UNALIGNED, VB2_ERROR_COMMON_FIXED_UNALIGNED,
"vb2_verify_keyblock2() header"); "vb2_verify_keyblock2() header");
memcpy(buf, buf2, buf_size); memcpy(buf, buf2, buf_size);
kbuf->c.struct_version_major++; kbuf->c.struct_version_major++;
TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk_not_present, &wb), TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb),
VB2_ERROR_KEYBLOCK_HEADER_VERSION, VB2_ERROR_KEYBLOCK_HEADER_VERSION,
"vb2_verify_keyblock2() major version"); "vb2_verify_keyblock2() major version");
@@ -656,6 +657,186 @@ static void test_verify_keyblock(void)
free(buf2); free(buf2);
} }
/**
* Verify firmware preamble
*/
static void test_verify_fw_preamble(void)
{
const char desc[16] = "test preamble";
struct vb2_signature2 *sig;
struct vb2_fw_preamble2 *pre;
uint32_t buf_size;
uint8_t *buf, *buf2, *bnext;
uint8_t workbuf[VB2_VERIFY_FIRMWARE_PREAMBLE_WORKBUF_BYTES];
struct vb2_workbuf wb;
/*
* Preambles will usually be signed with a real key not a bare hash,
* but the call to vb2_verify_data2() inside the preamble check is the
* same (and its functionality is verified separately), and using a
* bare hash here saves us from needing to have a private key to do
* this test.
*/
const struct vb2_public_key pubk = {
.sig_alg = VB2_SIG_NONE,
.hash_alg = VB2_HASH_SHA256,
.guid = vb2_hash_guid(VB2_HASH_SHA256)
};
struct vb2_fw_preamble2 fp = {
.c.magic = VB2_MAGIC_FW_PREAMBLE2,
.c.struct_version_major = VB2_FW_PREAMBLE2_VERSION_MAJOR,
.c.struct_version_minor = VB2_FW_PREAMBLE2_VERSION_MAJOR,
.c.fixed_size = sizeof(fp),
.c.desc_size = sizeof(desc),
.flags = 0,
.hash_count = 3,
};
fp.hash_offset = fp.c.fixed_size + fp.c.desc_size;
/* Create some hashes so we can calculate their sizes */
fp.c.total_size = fp.hash_offset;
sig = vb2_create_hash_sig(test_data, sizeof(test_data),
VB2_HASH_SHA512);
fp.c.total_size += sig->c.total_size;
free(sig);
sig = vb2_create_hash_sig(test_data, sizeof(test_data),
VB2_HASH_SHA256);
fp.c.total_size += 2 * sig->c.total_size;
/* Preamble signature goes after that */
fp.sig_offset = fp.c.total_size;
fp.c.total_size += sig->c.total_size;
free(sig);
/* Now that the total size is known, create the real preamble */
buf_size = fp.c.total_size;
buf = malloc(buf_size);
memset(buf, 0, buf_size);
memcpy(buf, &fp, sizeof(fp));
memcpy(buf + fp.c.fixed_size, desc, sizeof(desc));
/* And copy in the component hashes (use parts of test data) */
bnext = buf + fp.hash_offset;
sig = vb2_create_hash_sig(test_data, sizeof(test_data),
VB2_HASH_SHA256);
memset(&sig->guid, 0x01, sizeof(sig->guid));
memcpy(bnext, sig, sig->c.total_size);
bnext += sig->c.total_size;
free(sig);
sig = vb2_create_hash_sig(test_data, sizeof(test_data),
VB2_HASH_SHA512);
memset(&sig->guid, 0x03, sizeof(sig->guid));
memcpy(bnext, sig, sig->c.total_size);
bnext += sig->c.total_size;
free(sig);
sig = vb2_create_hash_sig(test_data, sizeof(test_data) - 4,
VB2_HASH_SHA256);
memset(&sig->guid, 0x02, sizeof(sig->guid));
memcpy(bnext, sig, sig->c.total_size);
bnext += sig->c.total_size;
free(sig);
/* Now sign the preamble */
sig = vb2_create_hash_sig(buf, fp.sig_offset, VB2_HASH_SHA256);
memcpy(buf + fp.sig_offset, sig, sig->c.total_size);
free(sig);
/* Make a copy of the buffer, so we can mangle it for tests */
buf2 = malloc(buf_size);
memcpy(buf2, buf, buf_size);
vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
pre = (struct vb2_fw_preamble2 *)buf;
TEST_SUCC(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
"vb2_verify_fw_preamble2()");
memcpy(buf, buf2, buf_size);
pre->c.magic = VB2_MAGIC_PACKED_KEY2;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_PREAMBLE_MAGIC,
"vb2_verify_fw_preamble2() magic");
memcpy(buf, buf2, buf_size);
pre->c.fixed_size++;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_COMMON_FIXED_UNALIGNED,
"vb2_verify_fw_preamble2() header");
memcpy(buf, buf2, buf_size);
pre->c.struct_version_major++;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_PREAMBLE_HEADER_VERSION,
"vb2_verify_fw_preamble2() major version");
memcpy(buf, buf2, buf_size);
pre->c.struct_version_minor++;
/* That changes the signature, so resign the fw_preamble */
sig = vb2_create_hash_sig(buf, fp.sig_offset, VB2_HASH_SHA256);
memcpy(buf + pre->sig_offset, sig, sig->c.total_size);
free(sig);
TEST_SUCC(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
"vb2_verify_fw_preamble2() minor version");
memcpy(buf, buf2, buf_size);
pre->c.fixed_size -= 4;
pre->c.desc_size += 4;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_PREAMBLE_SIZE,
"vb2_verify_fw_preamble2() header size");
memcpy(buf, buf2, buf_size);
sig = (struct vb2_signature2 *)(buf + fp.hash_offset);
sig->c.total_size += fp.c.total_size;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_COMMON_TOTAL_SIZE,
"vb2_verify_fw_preamble2() hash size");
memcpy(buf, buf2, buf_size);
sig = (struct vb2_signature2 *)(buf + fp.hash_offset);
sig->sig_size /= 2;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_SIG_SIZE,
"vb2_verify_fw_preamble2() hash integrity");
memcpy(buf, buf2, buf_size);
pre->hash_count++;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_COMMON_MEMBER_OVERLAP,
"vb2_verify_fw_preamble2() hash count");
memcpy(buf, buf2, buf_size);
sig = (struct vb2_signature2 *)(buf + fp.sig_offset);
sig->c.total_size += 4;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_COMMON_TOTAL_SIZE,
"vb2_verify_fw_preamble2() sig inside");
memcpy(buf, buf2, buf_size);
sig = (struct vb2_signature2 *)(buf + fp.sig_offset);
buf[fp.sig_offset + sig->sig_offset]++;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_VDATA_VERIFY_DIGEST,
"vb2_verify_fw_preamble2() sig corrupt");
memcpy(buf, buf2, buf_size);
pre->flags++;
TEST_EQ(vb2_verify_fw_preamble2(pre, buf_size, &pubk, &wb),
VB2_ERROR_VDATA_VERIFY_DIGEST,
"vb2_verify_fw_preamble2() preamble corrupt");
free(buf);
free(buf2);
}
int main(int argc, char* argv[]) int main(int argc, char* argv[])
{ {
test_memcmp(); test_memcmp();
@@ -667,6 +848,7 @@ int main(int argc, char* argv[])
test_sig_size(); test_sig_size();
test_verify_hash(); test_verify_hash();
test_verify_keyblock(); test_verify_keyblock();
test_verify_fw_preamble();
return gTestSuccess ? 0 : 255; return gTestSuccess ? 0 : 255;
} }