summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-11-01 19:01:08 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-11-06 02:28:13 +0000
commitad105edeb2ff0f2fbafd15655d351e8bb7522a21 (patch)
tree9e0ec3d7ad68451ba6bb70fb33f8356179d500c7
parentb885c3bd3d35284af81a83c3f23be4f02ddfbf47 (diff)
downloadvboot-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.c68
-rw-r--r--firmware/2lib/include/2common.h10
-rw-r--r--tests/vb2_common_tests.c181
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;
}