summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-10-31 11:19:14 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-11-05 06:05:16 +0000
commitc0ce70b468cc469556d0f43c63a6d63ec8280c99 (patch)
treedf3fe9fd4aee85563ce8710d34b33c118fe0420d
parent3c6ec76e32ceea9d62ca4f7bca537fdcd4b5f387 (diff)
downloadvboot-c0ce70b468cc469556d0f43c63a6d63ec8280c99.tar.gz
vboot2: add support for new vb2_signature2 struct
And assocated unit tests. BUG=chromium:423882 BRANCH=none TEST=VBOOT2=1 make runtests Change-Id: I37fccafd8ccee5c0d55e3746c1611a8dff73145a Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/226939 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r--firmware/2lib/2common2.c60
-rw-r--r--firmware/2lib/include/2common.h19
-rw-r--r--firmware/2lib/include/2return_codes.h6
-rw-r--r--tests/vb2_common2_tests.c68
-rw-r--r--tests/vb2_common_tests.c27
-rw-r--r--tests/vb2_convert_structs.c54
-rw-r--r--tests/vb2_convert_structs.h22
7 files changed, 255 insertions, 1 deletions
diff --git a/firmware/2lib/2common2.c b/firmware/2lib/2common2.c
index b65ea8fd..f35d575e 100644
--- a/firmware/2lib/2common2.c
+++ b/firmware/2lib/2common2.c
@@ -118,3 +118,63 @@ int vb2_verify_common_subobject(const void *parent,
return VB2_SUCCESS;
}
+
+uint32_t vb2_sig_size(enum vb2_signature_algorithm sig_alg,
+ enum vb2_hash_algorithm hash_alg)
+{
+ uint32_t digest_size = vb2_digest_size(hash_alg);
+
+ /* Fail if we don't support the hash algorithm */
+ if (!digest_size)
+ return 0;
+
+ /* Handle unsigned hashes */
+ if (sig_alg == VB2_SIG_NONE)
+ return digest_size;
+
+ return vb2_rsa_sig_size(sig_alg);
+}
+
+int vb2_verify_signature2(const struct vb2_signature2 *sig,
+ uint32_t size)
+{
+ uint32_t min_offset = 0;
+ uint32_t expect_sig_size;
+ int rv;
+
+ /* Check magic number */
+ if (sig->c.magic != VB2_MAGIC_SIGNATURE2)
+ return VB2_ERROR_SIG_MAGIC;
+
+ /* Make sure common header is good */
+ rv = vb2_verify_common_header(sig, 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 (sig->c.struct_version_major != VB2_SIGNATURE2_VERSION_MAJOR)
+ return VB2_ERROR_SIG_VERSION;
+
+ /* Make sure header is big enough for signature */
+ if (sig->c.fixed_size < sizeof(*sig))
+ return VB2_ERROR_SIG_HEADER_SIZE;
+
+ /* Make sure signature data is inside */
+ rv = vb2_verify_common_member(sig, &min_offset,
+ sig->sig_offset, sig->sig_size);
+ if (rv)
+ return rv;
+
+ /* Make sure signature size is correct for the algorithm */
+ expect_sig_size = vb2_sig_size(sig->sig_alg, sig->hash_alg);
+ if (!expect_sig_size)
+ return VB2_ERROR_SIG_ALGORITHM;
+ if (sig->sig_size != expect_sig_size)
+ return VB2_ERROR_SIG_SIZE;
+
+ return VB2_SUCCESS;
+}
diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h
index f92fe9e4..1c57d3fa 100644
--- a/firmware/2lib/include/2common.h
+++ b/firmware/2lib/include/2common.h
@@ -281,6 +281,25 @@ int vb2_unpack_key2(struct vb2_public_key *key,
const uint8_t *buf,
uint32_t size);
+/**
+ * Return expected signature size for a signature/hash algorithm pair
+ *
+ * @param sig_alg Signature algorithm
+ * @param hash_alg Hash algorithm
+ * @return The signature size, or zero if error / unsupported algorithm.
+ */
+uint32_t vb2_sig_size(enum vb2_signature_algorithm sig_alg,
+ enum vb2_hash_algorithm hash_alg);
+
+/**
+ * Verify the integrity of a signature struct
+ * @param sig Signature struct
+ * @param size Size of buffer containing signature struct
+ * @return VB2_SUCCESS, or non-zero if error.
+ */
+int vb2_verify_signature2(const struct vb2_signature2 *sig,
+ uint32_t size);
+
/* Size of work buffer sufficient for vb2_rsa_verify_digest() worst case */
#define VB2_VERIFY_DIGEST_WORKBUF_BYTES VB2_VERIFY_RSA_DIGEST_WORKBUF_BYTES
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index a65c334f..054655ee 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -211,6 +211,12 @@ enum vb2_return_code {
/* Signature header doesn't fit */
VB2_ERROR_SIG_HEADER_SIZE,
+ /* Signature unsupported algorithm */
+ VB2_ERROR_SIG_ALGORITHM,
+
+ /* Signature bad size for algorithm */
+ VB2_ERROR_SIG_SIZE,
+
/* Wrong amount of data signed */
VB2_ERROR_VDATA_SIZE,
diff --git a/tests/vb2_common2_tests.c b/tests/vb2_common2_tests.c
index 52a4bd76..a4760b2e 100644
--- a/tests/vb2_common2_tests.c
+++ b/tests/vb2_common2_tests.c
@@ -235,6 +235,73 @@ static void test_verify_data(struct vb2_packed_key *key1,
free(sig2);
}
+static void test_verify_signature(const struct vb2_packed_key *key1,
+ const struct vb2_signature *sig1)
+{
+ struct vb2_public_key pubk;
+ struct vb2_packed_key2 *key2;
+ struct vb2_signature2 *sig2;
+ uint8_t *buf2good, *buf2;
+ uint32_t size;
+
+ /* Unpack and convert the public key */
+ TEST_SUCC(vb2_unpack_key2(&pubk, (uint8_t *)key1,
+ key1->key_offset + key1->key_size),
+ "verify_sig vb2_unpack_key2() passthru");
+ key2 = vb2_convert_packed_key2(key1, "Test key", &size);
+ TEST_PTR_NEQ(key2, 0, "verify_sig convert pub key");
+
+ buf2good = (uint8_t *)
+ vb2_convert_signature2(sig1, "test desc", key2, &size);
+ buf2 = malloc(size);
+ sig2 = (struct vb2_signature2 *)buf2;
+
+ memcpy(buf2, buf2good, size);
+ TEST_PTR_NEQ(sig1, 0, "verify_sig convert signature");
+ TEST_SUCC(vb2_verify_signature2(sig2, size), "verify_sig ok");
+ sig2->c.magic = VB2_MAGIC_PACKED_KEY2;
+ TEST_EQ(vb2_verify_signature2(sig2, size), VB2_ERROR_SIG_MAGIC,
+ "verify_sig magic");
+
+ memcpy(buf2, buf2good, size);
+ sig2->c.total_size += 4;
+ TEST_EQ(vb2_verify_signature2(sig2, size), VB2_ERROR_COMMON_TOTAL_SIZE,
+ "verify_sig common header");
+
+ memcpy(buf2, buf2good, size);
+ sig2->c.struct_version_minor++;
+ TEST_SUCC(vb2_verify_signature2(sig2, size), "verify_sig minor ver");
+ sig2->c.struct_version_major++;
+ TEST_EQ(vb2_verify_signature2(sig2, size), VB2_ERROR_SIG_VERSION,
+ "verify_sig major ver");
+
+ memcpy(buf2, buf2good, size);
+ sig2->c.fixed_size -= 4;
+ sig2->c.desc_size += 4;
+ TEST_EQ(vb2_verify_signature2(sig2, size), VB2_ERROR_SIG_HEADER_SIZE,
+ "verify_sig header size");
+
+ memcpy(buf2, buf2good, size);
+ sig2->sig_size += 4;
+ TEST_EQ(vb2_verify_signature2(sig2, size), VB2_ERROR_COMMON_MEMBER_SIZE,
+ "verify_sig sig size");
+
+ memcpy(buf2, buf2good, size);
+ sig2->sig_alg = VB2_SIG_INVALID;
+ TEST_EQ(vb2_verify_signature2(sig2, size), VB2_ERROR_SIG_ALGORITHM,
+ "verify_sig sig alg");
+
+ memcpy(buf2, buf2good, size);
+ sig2->sig_alg = (sig2->sig_alg == VB2_SIG_NONE ?
+ VB2_SIG_RSA1024 : VB2_SIG_NONE);
+ TEST_EQ(vb2_verify_signature2(sig2, size), VB2_ERROR_SIG_SIZE,
+ "verify_sig sig size");
+
+ free(buf2);
+ free(buf2good);
+ free(key2);
+}
+
int test_algorithm(int key_algorithm, const char *keys_dir)
{
char filename[1024];
@@ -272,6 +339,7 @@ int test_algorithm(int key_algorithm, const char *keys_dir)
test_unpack_key(key1);
test_unpack_key2(key1);
test_verify_data(key1, sig);
+ test_verify_signature(key1, sig);
if (key1)
free(key1);
diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c
index 8f93a44c..d7f0762c 100644
--- a/tests/vb2_common_tests.c
+++ b/tests/vb2_common_tests.c
@@ -419,6 +419,32 @@ static void test_common_header_functions(void)
"vb2_verify_common_subobject() size");
}
+/**
+ * Signature size
+ */
+static void test_sig_size(void)
+{
+ TEST_EQ(vb2_sig_size(VB2_SIG_INVALID, VB2_HASH_SHA256), 0,
+ "vb2_sig_size() sig invalid");
+
+ TEST_EQ(vb2_sig_size(VB2_SIG_RSA2048, VB2_HASH_INVALID), 0,
+ "vb2_sig_size() hash invalid");
+
+ TEST_EQ(vb2_sig_size(VB2_SIG_RSA2048, VB2_HASH_SHA256), 2048 / 8,
+ "vb2_sig_size() RSA2048");
+ TEST_EQ(vb2_sig_size(VB2_SIG_RSA4096, VB2_HASH_SHA256), 4096 / 8,
+ "vb2_sig_size() RSA4096");
+ TEST_EQ(vb2_sig_size(VB2_SIG_RSA8192, VB2_HASH_SHA512), 8192 / 8,
+ "vb2_sig_size() RSA8192");
+
+ TEST_EQ(vb2_sig_size(VB2_SIG_NONE, VB2_HASH_SHA1),
+ VB2_SHA1_DIGEST_SIZE, "vb2_sig_size() SHA1");
+ TEST_EQ(vb2_sig_size(VB2_SIG_NONE, VB2_HASH_SHA256),
+ VB2_SHA256_DIGEST_SIZE, "vb2_sig_size() SHA256");
+ TEST_EQ(vb2_sig_size(VB2_SIG_NONE, VB2_HASH_SHA512),
+ VB2_SHA512_DIGEST_SIZE, "vb2_sig_size() SHA512");
+}
+
int main(int argc, char* argv[])
{
test_memcmp();
@@ -427,6 +453,7 @@ int main(int argc, char* argv[])
test_struct_packing();
test_helper_functions();
test_common_header_functions();
+ test_sig_size();
return gTestSuccess ? 0 : 255;
}
diff --git a/tests/vb2_convert_structs.c b/tests/vb2_convert_structs.c
index 871be735..270832a1 100644
--- a/tests/vb2_convert_structs.c
+++ b/tests/vb2_convert_structs.c
@@ -56,3 +56,57 @@ struct vb2_packed_key2 *vb2_convert_packed_key2(
/* Return the newly allocated buffer */
return (struct vb2_packed_key2 *)kbuf;
}
+
+struct vb2_signature2 *vb2_convert_signature2(
+ const struct vb2_signature *sig,
+ const char *desc,
+ const struct vb2_packed_key2 *key,
+ uint32_t *out_size)
+{
+ struct vb2_signature2 s2 = {
+ .c.magic = VB2_MAGIC_SIGNATURE2,
+ .c.struct_version_major = VB2_SIGNATURE2_VERSION_MAJOR,
+ .c.struct_version_minor = VB2_SIGNATURE2_VERSION_MINOR,
+ };
+ uint8_t *buf;
+
+ /* Calculate description size */
+ s2.c.fixed_size = sizeof(s2);
+ s2.c.desc_size = roundup32(strlen(desc) + 1);
+
+ /* Copy/initialize fields */
+ s2.sig_offset = s2.c.fixed_size + s2.c.desc_size;
+ s2.sig_size = sig->sig_size;
+ s2.c.total_size = s2.sig_offset + s2.sig_size;
+ s2.data_size = sig->data_size;
+
+ /* Copy fields from key if present */
+ if (key) {
+ s2.sig_alg = key->sig_alg;
+ s2.hash_alg = key->hash_alg;
+ memcpy(&s2.key_guid, &key->key_guid, GUID_SIZE);
+ } else {
+ s2.sig_alg = VB2_SIG_INVALID;
+ s2.hash_alg = VB2_HASH_INVALID;
+ memset(&s2.key_guid, 0, GUID_SIZE);
+ }
+
+ /* Allocate the new buffer */
+ *out_size = s2.sig_offset + s2.sig_size;
+ buf = malloc(*out_size);
+ memset(buf, 0, *out_size);
+
+ /* Copy data into the buffer */
+ memcpy(buf, &s2, sizeof(s2));
+
+ /* strcpy() is safe because we allocated above based on strlen() */
+ strcpy((char *)(buf + s2.c.fixed_size), desc);
+ buf[s2.c.fixed_size + s2.c.desc_size - 1] = 0;
+
+ memcpy(buf + s2.sig_offset,
+ (const uint8_t *)sig + sig->sig_offset,
+ sig->sig_size);
+
+ /* Return the newly allocated buffer */
+ return (struct vb2_signature2 *)buf;
+}
diff --git a/tests/vb2_convert_structs.h b/tests/vb2_convert_structs.h
index dcf15831..d810c63e 100644
--- a/tests/vb2_convert_structs.h
+++ b/tests/vb2_convert_structs.h
@@ -25,7 +25,7 @@ static __inline const uint32_t roundup32(uint32_t v)
*
* @param key Packed key in vboot1 format
* @param desc Description of packed key
- * @param out_size Size of the newly allocated buffer
+ * @param out_size Destination for size of the newly allocated buffer
* @return a newly allocated buffer with the converted key. Caller is
* responsible for freeing this buffer.
*/
@@ -33,4 +33,24 @@ struct vb2_packed_key2 *vb2_convert_packed_key2(
const struct vb2_packed_key *key,
const char *desc, uint32_t *out_size);
+/**
+ * Convert a signature from vboot data format to vboot2 data format.
+ *
+ * Intended for use by unit tests. Does NOT validate the original struct
+ * contents, just copies them.
+ *
+ * @param sig Signature in vboot1 format
+ * @param desc Description of signature
+ * @param key Key to take algorithms and GUID from. If NULL, those
+ * fields are left uninitialized.
+ * @param out_size Destination for size of the newly allocated buffer
+ * @return a newly allocated buffer with the converted signature. Caller is
+ * responsible for freeing this buffer.
+ */
+struct vb2_signature2 *vb2_convert_signature2(
+ const struct vb2_signature *sig,
+ const char *desc,
+ const struct vb2_packed_key2 *key,
+ uint32_t *out_size);
+
#endif /* VBOOT_REFERENCE_VB2_CONVERT_STRUCTS_H_ */