diff options
author | Randall Spangler <rspangler@chromium.org> | 2014-11-01 19:01:08 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-11-06 02:28:13 +0000 |
commit | ad105edeb2ff0f2fbafd15655d351e8bb7522a21 (patch) | |
tree | 9e0ec3d7ad68451ba6bb70fb33f8356179d500c7 | |
parent | b885c3bd3d35284af81a83c3f23be4f02ddfbf47 (diff) | |
download | vboot-ad105edeb2ff0f2fbafd15655d351e8bb7522a21.tar.gz |
vboot2: add code to verify vb2_keyblock2
Now supports multiple signatures per keyblock.
And associated unit tests.
BUG=chromium:423882
BRANCH=none
TEST=VBOOT2=1 make runtests
Change-Id: I7f2ef216e3689a22ed86c34763f68345d4080e04
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/227181
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r-- | firmware/2lib/2common2.c | 68 | ||||
-rw-r--r-- | firmware/2lib/include/2common.h | 10 | ||||
-rw-r--r-- | tests/vb2_common_tests.c | 181 |
3 files changed, 258 insertions, 1 deletions
diff --git a/firmware/2lib/2common2.c b/firmware/2lib/2common2.c index 32d218d8..52b4e238 100644 --- a/firmware/2lib/2common2.c +++ b/firmware/2lib/2common2.c @@ -298,3 +298,71 @@ int vb2_verify_data2(const void *data, return vb2_verify_digest2(key, sig, digest, &wblocal); } + +int vb2_verify_keyblock2(struct vb2_keyblock2 *block, + uint32_t size, + const struct vb2_public_key *key, + struct vb2_workbuf *wb) +{ + uint32_t min_offset = 0, sig_offset; + int rv, i; + + /* Check magic number */ + if (block->c.magic != VB2_MAGIC_KEYBLOCK2) + return VB2_ERROR_KEYBLOCK_MAGIC; + + /* Make sure common header is good */ + rv = vb2_verify_common_header(block, 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 (block->c.struct_version_major != VB2_KEYBLOCK2_VERSION_MAJOR) + return VB2_ERROR_KEYBLOCK_HEADER_VERSION; + + /* Make sure header is big enough */ + if (block->c.fixed_size < sizeof(*block)) + return VB2_ERROR_KEYBLOCK_SIZE; + + /* Make sure data key is inside */ + rv = vb2_verify_common_subobject(block, &min_offset, block->key_offset); + if (rv) + return rv; + + /* Loop over signatures */ + sig_offset = block->sig_offset; + for (i = 0; i < block->sig_count; i++, sig_offset = min_offset) { + struct vb2_signature2 *sig; + + /* Make sure signature is inside keyblock */ + rv = vb2_verify_common_subobject(block, &min_offset, + sig_offset); + if (rv) + return rv; + + sig = (struct vb2_signature2 *)((uint8_t *)block + sig_offset); + + /* Verify the signature integrity */ + rv = vb2_verify_signature2(sig, + block->c.total_size - sig_offset); + if (rv) + return rv; + + /* Skip signature if it doesn't match the key GUID */ + if (memcmp(&sig->key_guid, key->guid, GUID_SIZE)) + continue; + + /* Make sure we signed the right amount of data */ + if (sig->data_size != block->sig_offset) + return VB2_ERROR_KEYBLOCK_SIGNED_SIZE; + + return vb2_verify_data2(block, block->sig_offset, sig, key, wb); + } + + /* If we're still here, no signature matched the key GUID */ + return VB2_ERROR_KEYBLOCK_SIG_GUID; +} diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h index 219a5f0f..74c7f420 100644 --- a/firmware/2lib/include/2common.h +++ b/firmware/2lib/include/2common.h @@ -375,7 +375,10 @@ int vb2_verify_data2(const void *data, const struct vb2_public_key *key, struct vb2_workbuf *wb); -/* Size of work buffer sufficient for vb2_verify_keyblock() worst case */ +/* + * Size of work buffer sufficient for vb2_verify_keyblock() or + * vb2_verify_keyblock2() worst case. + */ #define VB2_KEY_BLOCK_VERIFY_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES /** @@ -395,6 +398,11 @@ int vb2_verify_keyblock(struct vb2_keyblock *block, const struct vb2_public_key *key, struct vb2_workbuf *wb); +int vb2_verify_keyblock2(struct vb2_keyblock2 *block, + uint32_t size, + const struct vb2_public_key *key, + struct vb2_workbuf *wb); + /* Size of work buffer sufficient for vb2_verify_fw_preamble() worst case */ #define VB2_VERIFY_FIRMWARE_PREAMBLE_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c index c1d229c6..e8c7d1f2 100644 --- a/tests/vb2_common_tests.c +++ b/tests/vb2_common_tests.c @@ -479,6 +479,186 @@ static void test_verify_hash(void) free(sig); } +/** + * Verify keyblock + */ +static void test_verify_keyblock(void) +{ + const char desc[16] = "test keyblock"; + struct vb2_signature2 *sig; + struct vb2_keyblock2 *kbuf; + uint32_t buf_size; + uint8_t *buf, *buf2, *bnext; + + uint8_t workbuf[VB2_KEY_BLOCK_VERIFY_WORKBUF_BYTES]; + struct vb2_workbuf wb; + + const struct vb2_public_key pubk = { + .sig_alg = VB2_SIG_NONE, + .hash_alg = VB2_HASH_SHA256, + .guid = vb2_hash_guid(VB2_HASH_SHA256) + }; + const struct vb2_public_key pubk2 = { + .sig_alg = VB2_SIG_NONE, + .hash_alg = VB2_HASH_SHA512, + .guid = vb2_hash_guid(VB2_HASH_SHA512) + }; + const struct vb2_public_key pubk_not_present = { + .sig_alg = VB2_SIG_NONE, + .hash_alg = VB2_HASH_SHA1, + .guid = vb2_hash_guid(VB2_HASH_SHA1) + }; + + /* + * Test packed key only needs to initialize the fields used by keyblock + * verification. + */ + const struct vb2_packed_key2 pkey = { + .c.fixed_size = sizeof(pkey), + .c.desc_size = 0, + .c.total_size = sizeof(pkey) + }; + + struct vb2_keyblock2 kb = { + .c.magic = VB2_MAGIC_KEYBLOCK2, + .c.struct_version_major = VB2_KEYBLOCK2_VERSION_MAJOR, + .c.struct_version_minor = VB2_KEYBLOCK2_VERSION_MAJOR, + .c.fixed_size = sizeof(kb), + .c.desc_size = sizeof(desc), + .flags = 0, + .sig_count = 2, + }; + + kb.key_offset = kb.c.fixed_size + kb.c.desc_size; + kb.sig_offset = kb.key_offset + pkey.c.total_size; + + /* + * Sign some dummy data with the right algorithms and descritions, to + * determine signature sizes. + */ + kb.c.total_size = kb.sig_offset; + + sig = vb2_create_hash_sig((const uint8_t *)desc, sizeof(desc), + VB2_HASH_SHA256); + kb.c.total_size += sig->c.total_size; + free(sig); + + sig = vb2_create_hash_sig((const uint8_t *)desc, sizeof(desc), + VB2_HASH_SHA512); + kb.c.total_size += sig->c.total_size; + free(sig); + + /* Now that the keyblock size is known, create the real keyblock */ + buf_size = kb.c.total_size; + buf = malloc(buf_size); + memset(buf, 0, buf_size); + memcpy(buf, &kb, sizeof(kb)); + memcpy(buf + kb.c.fixed_size, desc, sizeof(desc)); + memcpy(buf + kb.key_offset, &pkey, pkey.c.total_size); + + /* And copy in the signatures */ + bnext = buf + kb.sig_offset; + + sig = vb2_create_hash_sig(buf, kb.sig_offset, VB2_HASH_SHA256); + memcpy(bnext, sig, sig->c.total_size); + bnext += sig->c.total_size; + free(sig); + + sig = vb2_create_hash_sig(buf, kb.sig_offset, VB2_HASH_SHA512); + memcpy(bnext, sig, sig->c.total_size); + bnext += 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)); + kbuf = (struct vb2_keyblock2 *)buf; + + TEST_SUCC(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb), + "vb2_verify_keyblock2()"); + + memcpy(buf, buf2, buf_size); + TEST_SUCC(vb2_verify_keyblock2(kbuf, buf_size, &pubk2, &wb), + "vb2_verify_keyblock2() key 2"); + + memcpy(buf, buf2, buf_size); + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk_not_present, &wb), + VB2_ERROR_KEYBLOCK_SIG_GUID, + "vb2_verify_keyblock2() key not present"); + + memcpy(buf, buf2, buf_size); + kbuf->c.magic = VB2_MAGIC_PACKED_KEY2; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk_not_present, &wb), + VB2_ERROR_KEYBLOCK_MAGIC, + "vb2_verify_keyblock2() magic"); + + memcpy(buf, buf2, buf_size); + kbuf->c.fixed_size++; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk_not_present, &wb), + VB2_ERROR_COMMON_FIXED_UNALIGNED, + "vb2_verify_keyblock2() header"); + + memcpy(buf, buf2, buf_size); + kbuf->c.struct_version_major++; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk_not_present, &wb), + VB2_ERROR_KEYBLOCK_HEADER_VERSION, + "vb2_verify_keyblock2() major version"); + + memcpy(buf, buf2, buf_size); + kbuf->c.struct_version_minor++; + /* That changes the signature, so resign the keyblock */ + sig = vb2_create_hash_sig(buf, kb.sig_offset, VB2_HASH_SHA256); + memcpy(buf + kbuf->sig_offset, sig, sig->c.total_size); + free(sig); + TEST_SUCC(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb), + "vb2_verify_keyblock2() minor version"); + + memcpy(buf, buf2, buf_size); + kbuf->c.fixed_size -= 4; + kbuf->c.desc_size += 4; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb), + VB2_ERROR_KEYBLOCK_SIZE, + "vb2_verify_keyblock2() header size"); + + memcpy(buf, buf2, buf_size); + kbuf->key_offset = kbuf->c.total_size - 4; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb), + VB2_ERROR_COMMON_MEMBER_SIZE, + "vb2_verify_keyblock2() data key outside"); + + memcpy(buf, buf2, buf_size); + sig = (struct vb2_signature2 *)(buf + kbuf->sig_offset); + sig->data_size--; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb), + VB2_ERROR_KEYBLOCK_SIGNED_SIZE, + "vb2_verify_keyblock2() signed wrong size"); + + memcpy(buf, buf2, buf_size); + sig = (struct vb2_signature2 *)(buf + kbuf->sig_offset); + sig->c.total_size = kbuf->c.total_size - 4; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb), + VB2_ERROR_COMMON_TOTAL_SIZE, + "vb2_verify_keyblock2() key outside keyblock"); + + memcpy(buf, buf2, buf_size); + sig = (struct vb2_signature2 *)(buf + kbuf->sig_offset); + sig->c.struct_version_major++; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb), + VB2_ERROR_SIG_VERSION, + "vb2_verify_keyblock2() corrupt key"); + + memcpy(buf, buf2, buf_size); + kbuf->c.struct_version_minor++; + TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb), + VB2_ERROR_VDATA_VERIFY_DIGEST, + "vb2_verify_keyblock2() corrupt"); + + free(buf); + free(buf2); +} + int main(int argc, char* argv[]) { test_memcmp(); @@ -489,6 +669,7 @@ int main(int argc, char* argv[]) test_common_header_functions(); test_sig_size(); test_verify_hash(); + test_verify_keyblock(); return gTestSuccess ? 0 : 255; } |