diff options
-rw-r--r-- | firmware/2lib/2common2.c | 60 | ||||
-rw-r--r-- | firmware/2lib/include/2common.h | 19 | ||||
-rw-r--r-- | firmware/2lib/include/2return_codes.h | 6 | ||||
-rw-r--r-- | tests/vb2_common2_tests.c | 68 | ||||
-rw-r--r-- | tests/vb2_common_tests.c | 27 | ||||
-rw-r--r-- | tests/vb2_convert_structs.c | 54 | ||||
-rw-r--r-- | tests/vb2_convert_structs.h | 22 |
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_ */ |