summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-11-04 17:50:32 -0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-11-12 19:57:57 +0000
commit43e0a9ed6c0b332631442fcf581e7456d62e4532 (patch)
treec3bc2345e722a682a4667420e777d1079b8c4da8
parent054c1147989d39a432923cc359d123f0d8e9390a (diff)
downloadvboot-43e0a9ed6c0b332631442fcf581e7456d62e4532.tar.gz
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>
-rw-r--r--firmware/2lib/2common2.c70
-rw-r--r--firmware/2lib/include/2common.h10
-rw-r--r--firmware/2lib/include/2return_codes.h6
-rw-r--r--firmware/2lib/include/2struct.h8
-rw-r--r--tests/vb2_common_tests.c194
5 files changed, 277 insertions, 11 deletions
diff --git a/firmware/2lib/2common2.c b/firmware/2lib/2common2.c
index 1dcf53d1..099f7c1f 100644
--- a/firmware/2lib/2common2.c
+++ b/firmware/2lib/2common2.c
@@ -366,3 +366,73 @@ int vb2_verify_keyblock2(struct vb2_keyblock2 *block,
/* If we're still here, no signature matched the key 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;
+}
diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h
index 0f7012cb..d26ccfce 100644
--- a/firmware/2lib/include/2common.h
+++ b/firmware/2lib/include/2common.h
@@ -410,7 +410,10 @@ int vb2_verify_keyblock2(struct vb2_keyblock2 *block,
const struct vb2_public_key *key,
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
/**
@@ -429,4 +432,9 @@ int vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble,
const struct vb2_public_key *key,
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_ */
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index 054655ee..4ff84468 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -302,6 +302,12 @@ enum vb2_return_code {
/* Kernel subkey outside preamble */
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
*/
diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h
index e988f3f9..3f208325 100644
--- a/firmware/2lib/include/2struct.h
+++ b/firmware/2lib/include/2struct.h
@@ -491,9 +491,9 @@ struct vb2_keyblock2 {
#define EXPECTED_VB2_KEYBLOCK2_SIZE (EXPECTED_VB2_STRUCT_COMMON_SIZE + 16)
-/* Current version of vb2_preamble2 struct */
-#define VB2_PREAMBLE2_VERSION_MAJOR 3
-#define VB2_PREAMBLE2_VERSION_MINOR 0
+/* Current version of vb2_fw_preamble2 struct */
+#define VB2_FW_PREAMBLE2_VERSION_MAJOR 3
+#define VB2_FW_PREAMBLE2_VERSION_MINOR 0
/*
* Firmware preamble
@@ -501,7 +501,7 @@ struct vb2_keyblock2 {
* The preamble data must be arranged like this:
* 1) vb2_fw_preamble2 header struct h
* 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)
*
* The signature 4) must cover all the data from 1), 2), 3).
diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c
index ad7635e0..d8a714bb 100644
--- a/tests/vb2_common_tests.c
+++ b/tests/vb2_common_tests.c
@@ -13,6 +13,8 @@
#include "test_common.h"
+static const uint8_t test_data[] = "This is some test data to sign.";
+
/**
* Test memory compare functions
*/
@@ -449,7 +451,6 @@ static void test_sig_size(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_public_key pubk = {
.sig_alg = VB2_SIG_NONE,
@@ -535,12 +536,12 @@ static void test_verify_keyblock(void)
*/
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);
kb.c.total_size += sig->c.total_size;
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);
kb.c.total_size += sig->c.total_size;
free(sig);
@@ -587,19 +588,19 @@ static void test_verify_keyblock(void)
memcpy(buf, buf2, buf_size);
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_verify_keyblock2() magic");
memcpy(buf, buf2, buf_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_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),
+ TEST_EQ(vb2_verify_keyblock2(kbuf, buf_size, &pubk, &wb),
VB2_ERROR_KEYBLOCK_HEADER_VERSION,
"vb2_verify_keyblock2() major version");
@@ -656,6 +657,186 @@ static void test_verify_keyblock(void)
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[])
{
test_memcmp();
@@ -667,6 +848,7 @@ int main(int argc, char* argv[])
test_sig_size();
test_verify_hash();
test_verify_keyblock();
+ test_verify_fw_preamble();
return gTestSuccess ? 0 : 255;
}