From b885c3bd3d35284af81a83c3f23be4f02ddfbf47 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Sat, 1 Nov 2014 17:56:46 -0700 Subject: vboot2: add support for verify data / digest using new signature struct This adds the vb2_signature2 equivalents of vb2_verify_digest() and vb2_verify_data(), including support for bare hash signatures. BUG=chromium:423882 BRANCH=none TEST=VBOOT2=1 make runtests Change-Id: I372c9e5f0be926a833e4ca8f84665cfb05907481 Reviewed-on: https://chromium-review.googlesource.com/226950 Tested-by: Randall Spangler Reviewed-by: Bill Richardson Commit-Queue: Randall Spangler --- firmware/2lib/2common2.c | 120 ++++++++++++++++++++++++++++++++++++++++ firmware/2lib/include/2common.h | 39 ++++++++++++- tests/vb2_common2_tests.c | 78 ++++++++++++++++++++++++++ tests/vb2_common_tests.c | 35 ++++++++++++ tests/vb2_convert_structs.c | 43 ++++++++++++++ tests/vb2_convert_structs.h | 12 ++++ 6 files changed, 325 insertions(+), 2 deletions(-) diff --git a/firmware/2lib/2common2.c b/firmware/2lib/2common2.c index f35d575e..32d218d8 100644 --- a/firmware/2lib/2common2.c +++ b/firmware/2lib/2common2.c @@ -135,6 +135,37 @@ uint32_t vb2_sig_size(enum vb2_signature_algorithm sig_alg, return vb2_rsa_sig_size(sig_alg); } +const struct vb2_guid *vb2_hash_guid(enum vb2_hash_algorithm hash_alg) +{ + switch(hash_alg) { +#ifdef VB2_SUPPORT_SHA1 + case VB2_HASH_SHA1: + { + static const struct vb2_guid guid = VB2_GUID_NONE_SHA1; + return &guid; + } +#endif +#ifdef VB2_SUPPORT_SHA256 + case VB2_HASH_SHA256: + { + static const struct vb2_guid guid = + VB2_GUID_NONE_SHA256; + return &guid; + } +#endif +#ifdef VB2_SUPPORT_SHA512 + case VB2_HASH_SHA512: + { + static const struct vb2_guid guid = + VB2_GUID_NONE_SHA512; + return &guid; + } +#endif + default: + return NULL; + } +} + int vb2_verify_signature2(const struct vb2_signature2 *sig, uint32_t size) { @@ -178,3 +209,92 @@ int vb2_verify_signature2(const struct vb2_signature2 *sig, return VB2_SUCCESS; } + +/** + * Return the signature data for a signature + */ +static uint8_t *vb2_signature2_data(struct vb2_signature2 *sig) +{ + return (uint8_t *)sig + sig->sig_offset; +} + +int vb2_verify_digest2(const struct vb2_public_key *key, + struct vb2_signature2 *sig, + const uint8_t *digest, + struct vb2_workbuf *wb) +{ + uint32_t key_sig_size = vb2_sig_size(key->sig_alg, key->hash_alg); + + /* If we can't figure out the signature size, key algorithm was bad */ + if (!key_sig_size) + return VB2_ERROR_VDATA_ALGORITHM; + + /* Make sure the signature and key algorithms match */ + if (key->sig_alg != sig->sig_alg || key->hash_alg != sig->hash_alg) + return VB2_ERROR_VDATA_ALGORITHM_MISMATCH; + + if (sig->sig_size != key_sig_size) + return VB2_ERROR_VDATA_SIG_SIZE; + + if (key->sig_alg == VB2_SIG_NONE) { + /* Bare hash */ + if (vb2_safe_memcmp(vb2_signature2_data(sig), + digest, key_sig_size)) + return VB2_ERROR_VDATA_VERIFY_DIGEST; + + return VB2_SUCCESS; + } else { + /* RSA-signed digest */ + return vb2_rsa_verify_digest(key, + vb2_signature2_data(sig), + digest, wb); + } +} + +int vb2_verify_data2(const void *data, + uint32_t size, + struct vb2_signature2 *sig, + const struct vb2_public_key *key, + struct vb2_workbuf *wb) +{ + struct vb2_workbuf wblocal = *wb; + struct vb2_digest_context *dc; + uint8_t *digest; + uint32_t digest_size; + int rv; + + if (sig->data_size != size) { + VB2_DEBUG("Wrong amount of data signed.\n"); + return VB2_ERROR_VDATA_SIZE; + } + + /* Digest goes at start of work buffer */ + digest_size = vb2_digest_size(key->hash_alg); + if (!digest_size) + return VB2_ERROR_VDATA_DIGEST_SIZE; + + digest = vb2_workbuf_alloc(&wblocal, digest_size); + if (!digest) + return VB2_ERROR_VDATA_WORKBUF_DIGEST; + + /* Hashing requires temp space for the context */ + dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc)); + if (!dc) + return VB2_ERROR_VDATA_WORKBUF_HASHING; + + rv = vb2_digest_init(dc, key->hash_alg); + if (rv) + return rv; + + rv = vb2_digest_extend(dc, data, size); + if (rv) + return rv; + + rv = vb2_digest_finalize(dc, digest, digest_size); + if (rv) + return rv; + + vb2_workbuf_free(&wblocal, sizeof(*dc)); + + return vb2_verify_digest2(key, sig, digest, &wblocal); +} diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h index 1c57d3fa..219a5f0f 100644 --- a/firmware/2lib/include/2common.h +++ b/firmware/2lib/include/2common.h @@ -291,6 +291,15 @@ int vb2_unpack_key2(struct vb2_public_key *key, uint32_t vb2_sig_size(enum vb2_signature_algorithm sig_alg, enum vb2_hash_algorithm hash_alg); +/** + * Return a key_guid for an unsigned hash algorithm. + * + * @param hash_alg Hash algorithm to return key for + * @return A pointer to the key_guid for that hash algorithm and + * sig_alg=VB2_SIG_NONE, or NULL if error. + */ +const struct vb2_guid *vb2_hash_guid(enum vb2_hash_algorithm hash_alg); + /** * Verify the integrity of a signature struct * @param sig Signature struct @@ -300,7 +309,10 @@ uint32_t vb2_sig_size(enum vb2_signature_algorithm sig_alg, int vb2_verify_signature2(const struct vb2_signature2 *sig, uint32_t size); -/* Size of work buffer sufficient for vb2_rsa_verify_digest() worst case */ +/* + * Size of work buffer sufficient for vb2_verify_digest() or + * vb2_verify_digest2() worst case. + */ #define VB2_VERIFY_DIGEST_WORKBUF_BYTES VB2_VERIFY_RSA_DIGEST_WORKBUF_BYTES /** @@ -317,7 +329,24 @@ int vb2_verify_digest(const struct vb2_public_key *key, const uint8_t *digest, struct vb2_workbuf *wb); -/* Size of work buffer sufficient for vb2_verify_data() worst case */ +/** + * Verify a signature against an expected hash digest. + * + * @param key Key to use in signature verification + * @param sig Signature to verify (may be destroyed in process) + * @param digest Digest of signed data + * @param wb Work buffer + * @return VB2_SUCCESS, or non-zero if error. + */ +int vb2_verify_digest2(const struct vb2_public_key *key, + struct vb2_signature2 *sig, + const uint8_t *digest, + struct vb2_workbuf *wb); + +/* + * Size of work buffer sufficient for vb2_verify_data() or vb2_verify_data2() + * worst case. + */ #define VB2_VERIFY_DATA_WORKBUF_BYTES \ (VB2_SHA512_DIGEST_SIZE + \ VB2_MAX(VB2_VERIFY_DIGEST_WORKBUF_BYTES, \ @@ -340,6 +369,12 @@ int vb2_verify_data(const uint8_t *data, const struct vb2_public_key *key, struct vb2_workbuf *wb); +int vb2_verify_data2(const void *data, + uint32_t size, + struct vb2_signature2 *sig, + const struct vb2_public_key *key, + struct vb2_workbuf *wb); + /* Size of work buffer sufficient for vb2_verify_keyblock() worst case */ #define VB2_KEY_BLOCK_VERIFY_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES diff --git a/tests/vb2_common2_tests.c b/tests/vb2_common2_tests.c index a4760b2e..8c8f6430 100644 --- a/tests/vb2_common2_tests.c +++ b/tests/vb2_common2_tests.c @@ -302,6 +302,83 @@ static void test_verify_signature(const struct vb2_packed_key *key1, free(key2); } +static void test_verify_data2(struct vb2_packed_key *key1, + const struct vb2_signature *sig1) +{ + uint8_t workbuf[VB2_VERIFY_DATA_WORKBUF_BYTES]; + struct vb2_workbuf wb; + + struct vb2_public_key pubk, pubk_orig; + struct vb2_packed_key2 *key2; + struct vb2_signature2 *sig2; + uint8_t *buf2good, *buf2; + uint32_t size; + + vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); + + /* Unpack and convert the public key */ + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + TEST_PTR_NEQ(key2, 0, "verify_data convert pub key"); + TEST_SUCC(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + "verify_data2 unpack key"); + pubk_orig = pubk; + + /* Convert signature and allocate copy for tests */ + buf2good = (uint8_t *) + vb2_convert_signature2(sig1, "test desc", key2, &size); + buf2 = malloc(size); + sig2 = (struct vb2_signature2 *)buf2; + + memcpy(buf2, buf2good, size); + pubk.sig_alg = VB2_SIG_INVALID; + TEST_EQ(vb2_verify_data2(test_data, test_size, sig2, &pubk, &wb), + VB2_ERROR_VDATA_ALGORITHM, "vb2_verify_data2() bad sig alg"); + pubk.sig_alg = pubk_orig.sig_alg; + + memcpy(buf2, buf2good, size); + pubk.hash_alg = VB2_HASH_INVALID; + TEST_EQ(vb2_verify_data2(test_data, test_size, sig2, &pubk, &wb), + VB2_ERROR_VDATA_DIGEST_SIZE, + "vb2_verify_data2() bad hash alg"); + pubk.hash_alg = pubk_orig.hash_alg; + + vb2_workbuf_init(&wb, workbuf, 4); + memcpy(buf2, buf2good, size); + TEST_EQ(vb2_verify_data2(test_data, test_size, sig2, &pubk, &wb), + VB2_ERROR_VDATA_WORKBUF_DIGEST, + "vb2_verify_data2() workbuf too small"); + vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); + + memcpy(buf2, buf2good, size); + TEST_EQ(vb2_verify_data2(test_data, test_size, sig2, &pubk, &wb), + 0, "vb2_verify_data2() ok"); + + memcpy(buf2, buf2good, size); + sig2->sig_size -= 16; + TEST_EQ(vb2_verify_data2(test_data, test_size, sig2, &pubk, &wb), + VB2_ERROR_VDATA_SIG_SIZE, "vb2_verify_data2() wrong sig size"); + + memcpy(buf2, buf2good, size); + TEST_EQ(vb2_verify_data2(test_data, test_size - 1, sig2, &pubk, &wb), + VB2_ERROR_VDATA_SIZE, "vb2_verify_data2() wrong data size"); + + memcpy(buf2, buf2good, size); + sig2->hash_alg = (sig2->hash_alg == VB2_HASH_SHA1 ? + VB2_HASH_SHA256 : VB2_HASH_SHA1); + TEST_EQ(vb2_verify_data2(test_data, test_size, sig2, &pubk, &wb), + VB2_ERROR_VDATA_ALGORITHM_MISMATCH, + "vb2_verify_data2() alg mismatch"); + + + memcpy(buf2, buf2good, size); + buf2[sig2->sig_offset] ^= 0x5A; + TEST_EQ(vb2_verify_data2(test_data, test_size, sig2, &pubk, &wb), + VB2_ERROR_RSA_PADDING, "vb2_verify_data2() wrong sig"); + + free(buf2); + free(buf2good); +} + int test_algorithm(int key_algorithm, const char *keys_dir) { char filename[1024]; @@ -339,6 +416,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_data2(key1, sig); test_verify_signature(key1, sig); if (key1) diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c index d7f0762c..c1d229c6 100644 --- a/tests/vb2_common_tests.c +++ b/tests/vb2_common_tests.c @@ -7,6 +7,8 @@ #include "2sysincludes.h" #include "2common.h" +#include "2rsa.h" +#include "vb2_convert_structs.h" #include "vboot_struct.h" /* For old struct sizes */ #include "test_common.h" @@ -445,6 +447,38 @@ static void test_sig_size(void) VB2_SHA512_DIGEST_SIZE, "vb2_sig_size() SHA512"); } +/** + * Verify data on bare hash + */ +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, + .hash_alg = VB2_HASH_SHA256, + .guid = vb2_hash_guid(VB2_HASH_SHA256) + }; + uint8_t workbuf[VB2_VERIFY_DATA_WORKBUF_BYTES]; + struct vb2_workbuf wb; + + vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); + + /* Create the signature */ + sig = vb2_create_hash_sig(test_data, sizeof(test_data), pubk.hash_alg); + TEST_PTR_NEQ(sig, NULL, "create hash sig"); + + TEST_SUCC(vb2_verify_data2(test_data, sizeof(test_data), + sig, &pubk, &wb), + "vb2_verify_data2() hash ok"); + + *((uint8_t *)sig + sig->sig_offset) ^= 0xab; + TEST_EQ(vb2_verify_data2(test_data, sizeof(test_data), sig, &pubk, &wb), + VB2_ERROR_VDATA_VERIFY_DIGEST, "vb2_verify_data2() hash bad"); + + free(sig); +} + int main(int argc, char* argv[]) { test_memcmp(); @@ -454,6 +488,7 @@ int main(int argc, char* argv[]) test_helper_functions(); test_common_header_functions(); test_sig_size(); + test_verify_hash(); return gTestSuccess ? 0 : 255; } diff --git a/tests/vb2_convert_structs.c b/tests/vb2_convert_structs.c index 270832a1..777c7389 100644 --- a/tests/vb2_convert_structs.c +++ b/tests/vb2_convert_structs.c @@ -110,3 +110,46 @@ struct vb2_signature2 *vb2_convert_signature2( /* Return the newly allocated buffer */ return (struct vb2_signature2 *)buf; } + +struct vb2_signature2 *vb2_create_hash_sig(const uint8_t *data, + uint32_t size, + enum vb2_hash_algorithm hash_alg) +{ + const char desc[12] = "hash sig"; + struct vb2_signature2 s = { + .c.magic = VB2_MAGIC_SIGNATURE2, + .c.struct_version_major = VB2_SIGNATURE2_VERSION_MAJOR, + .c.struct_version_minor = VB2_SIGNATURE2_VERSION_MINOR, + .c.fixed_size = sizeof(s), + .c.desc_size = sizeof(desc), + .sig_alg = VB2_SIG_NONE, + .hash_alg = hash_alg, + .sig_size = vb2_sig_size(VB2_SIG_NONE, hash_alg), + .data_size = size, + }; + const struct vb2_guid *hash_guid = vb2_hash_guid(hash_alg); + struct vb2_digest_context dc; + uint8_t *buf; + + /* Make sure hash algorithm was supported */ + if (!hash_guid || !s.sig_size) + return NULL; + + memcpy(&s.key_guid, hash_guid, sizeof(s.key_guid)); + s.sig_offset = s.c.fixed_size + s.c.desc_size; + s.c.total_size = s.sig_offset + s.sig_size; + + buf = malloc(s.c.total_size); + memset(buf, 0, s.c.total_size); + memcpy(buf, &s, sizeof(s)); + memcpy(buf + s.c.fixed_size, desc, sizeof(desc)); + + if (vb2_digest_init(&dc, hash_alg) || + vb2_digest_extend(&dc, data, size) || + vb2_digest_finalize(&dc, buf + s.sig_offset, s.sig_size)) { + free(buf); + return NULL; + } + + return (struct vb2_signature2 *)buf; +} diff --git a/tests/vb2_convert_structs.h b/tests/vb2_convert_structs.h index d810c63e..032b5bfb 100644 --- a/tests/vb2_convert_structs.h +++ b/tests/vb2_convert_structs.h @@ -53,4 +53,16 @@ struct vb2_signature2 *vb2_convert_signature2( const struct vb2_packed_key2 *key, uint32_t *out_size); +/** + * Create an unsigned hash signature of the data. + * + * @param data Data to sign + * @param size Size of data in bytes + * @return a newly-allocated signature, which the caller must free, or NULL if + * error. + */ +struct vb2_signature2 *vb2_create_hash_sig(const uint8_t *data, + uint32_t size, + enum vb2_hash_algorithm hash_alg); + #endif /* VBOOT_REFERENCE_VB2_CONVERT_STRUCTS_H_ */ -- cgit v1.2.1