diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | firmware/2lib/2misc.c | 2 | ||||
-rw-r--r-- | firmware/2lib/2packed_key.c | 2 | ||||
-rw-r--r-- | firmware/2lib/2packed_key2.c | 109 | ||||
-rw-r--r-- | firmware/2lib/include/2common.h | 17 | ||||
-rw-r--r-- | firmware/2lib/include/2return_codes.h | 3 | ||||
-rw-r--r-- | firmware/2lib/include/2rsa.h | 3 | ||||
-rw-r--r-- | tests/vb2_common2_tests.c | 109 | ||||
-rw-r--r-- | tests/vb2_convert_structs.c | 57 | ||||
-rw-r--r-- | tests/vb2_convert_structs.h | 36 |
10 files changed, 341 insertions, 3 deletions
@@ -287,6 +287,7 @@ FWLIB2_SRCS = \ firmware/2lib/2misc.c \ firmware/2lib/2nvstorage.c \ firmware/2lib/2packed_key.c \ + firmware/2lib/2packed_key2.c \ firmware/2lib/2rsa.c \ firmware/2lib/2secdata.c \ firmware/2lib/2sha1.c \ @@ -579,6 +580,11 @@ TESTLIB_SRCS = \ tests/timer_utils.c \ tests/crc32_test.c +ifneq (${VBOOT2},) +TESTLIB_SRCS += \ + tests/vb2_convert_structs.c +endif + TESTLIB_OBJS = ${TESTLIB_SRCS:%.c=${BUILD}/%.o} TEST_OBJS += ${TESTLIB_OBJS} diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index 3986e1ff..c36372bf 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -127,7 +127,7 @@ int vb2_init_context(struct vb2_context *ctx) */ if (ctx->workbuf_size < sizeof(*sd)) return VB2_ERROR_INITCTX_WORKBUF_SMALL; - if (!vb_aligned(ctx->workbuf, VB2_WORKBUF_ALIGN)) + if (!vb2_aligned(ctx->workbuf, VB2_WORKBUF_ALIGN)) return VB2_ERROR_INITCTX_WORKBUF_ALIGN; /* Initialize the shared data at the start of the work buffer */ diff --git a/firmware/2lib/2packed_key.c b/firmware/2lib/2packed_key.c index fe6bab53..098296e4 100644 --- a/firmware/2lib/2packed_key.c +++ b/firmware/2lib/2packed_key.c @@ -59,7 +59,7 @@ int vb2_unpack_key(struct vb2_public_key *key, /* Make sure source buffer is 32-bit aligned */ buf32 = (const uint32_t *)vb2_packed_key_data(packed_key); - if (!vb_aligned(buf32, sizeof(uint32_t))) + if (!vb2_aligned(buf32, sizeof(uint32_t))) return VB2_ERROR_UNPACK_KEY_ALIGN; /* Sanity check key array size */ diff --git a/firmware/2lib/2packed_key2.c b/firmware/2lib/2packed_key2.c new file mode 100644 index 00000000..306206ee --- /dev/null +++ b/firmware/2lib/2packed_key2.c @@ -0,0 +1,109 @@ +/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Key unpacking functions + */ + +#include "2sysincludes.h" +#include "2common.h" +#include "2rsa.h" + +const uint8_t *vb2_packed_key2_data(const struct vb2_packed_key2 *key) +{ + return (const uint8_t *)key + key->key_offset; +} + +int vb2_verify_packed_key2_inside(const void *parent, + uint32_t parent_size, + const struct vb2_packed_key2 *key) +{ + int rv; + + rv = vb2_verify_member_inside(parent, parent_size, + key, sizeof(*key), + key->key_offset, key->key_size); + if (rv) + return rv; + + return vb2_verify_common_header(parent, parent_size, &key->c); +} + +int vb2_unpack_key2(struct vb2_public_key *key, + const uint8_t *buf, + uint32_t size) +{ + const struct vb2_packed_key2 *pkey = + (const struct vb2_packed_key2 *)buf; + const uint32_t *buf32; + uint32_t expected_key_size; + uint32_t sig_size; + int rv; + + /* + * Check magic number. + * + * If it doesn't match, pass through to the old packed key format. + * + * TODO: remove passthru when signing scripts have switched over to + * use the new format. + */ + if (pkey->c.magic != VB2_MAGIC_PACKED_KEY2) + return vb2_unpack_key(key, buf, size); + + /* Make sure passed buffer is big enough for the packed key */ + rv = vb2_verify_packed_key2_inside(buf, size, pkey); + 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 (pkey->c.struct_version_major != VB2_PACKED_KEY2_VERSION_MAJOR) + return VB2_ERROR_UNPACK_KEY_STRUCT_VERSION; + + /* Copy key algorithms */ + key->sig_alg = pkey->sig_algorithm; + sig_size = vb2_rsa_sig_size(key->sig_alg); + if (!sig_size) + return VB2_ERROR_UNPACK_KEY_SIG_ALGORITHM; + + key->hash_alg = pkey->hash_algorithm; + if (!vb2_digest_size(key->hash_alg)) + return VB2_ERROR_UNPACK_KEY_HASH_ALGORITHM; + + expected_key_size = vb2_packed_key_size(key->sig_alg); + if (!expected_key_size || expected_key_size != pkey->key_size) { + VB2_DEBUG("Wrong key size for algorithm\n"); + return VB2_ERROR_UNPACK_KEY_SIZE; + } + + /* Make sure source buffer is 32-bit aligned */ + buf32 = (const uint32_t *)vb2_packed_key2_data(pkey); + if (!vb2_aligned(buf32, sizeof(uint32_t))) + return VB2_ERROR_UNPACK_KEY_ALIGN; + + /* Sanity check key array size */ + key->arrsize = buf32[0]; + if (key->arrsize * sizeof(uint32_t) != sig_size) + return VB2_ERROR_UNPACK_KEY_ARRAY_SIZE; + + key->n0inv = buf32[1]; + + /* Arrays point inside the key data */ + key->n = buf32 + 2; + key->rr = buf32 + 2 + key->arrsize; + + /* Key description */ + if (pkey->c.desc_size) + key->desc = (const char *)&(pkey->c) + pkey->c.desc_offset; + else + key->desc = ""; + + key->version = pkey->key_version; + key->guid = &pkey->key_guid; + + return VB2_SUCCESS; +} diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h index 8a00dd71..5ab145cf 100644 --- a/firmware/2lib/include/2common.h +++ b/firmware/2lib/include/2common.h @@ -103,7 +103,7 @@ void *vb2_workbuf_realloc(struct vb2_workbuf *wb, void vb2_workbuf_free(struct vb2_workbuf *wb, uint32_t size); /* Check if a pointer is aligned on an align-byte boundary */ -#define vb_aligned(ptr, align) (!(((uintptr_t)(ptr)) & ((align) - 1))) +#define vb2_aligned(ptr, align) (!(((uintptr_t)(ptr)) & ((align) - 1))) /** * Safer memcmp() for use in crypto. @@ -233,6 +233,21 @@ int vb2_unpack_key(struct vb2_public_key *key, const uint8_t *buf, uint32_t size); +/** + * Unpack a key for use in verification + * + * The elements of the unpacked key will point into the source buffer, so don't + * free the source buffer until you're done with the key. + * + * @param key Destintion for unpacked key + * @param buf Source buffer containing packed key + * @param size Size of buffer in bytes + * @return VB2_SUCCESS, or non-zero error code if error. + */ +int vb2_unpack_key2(struct vb2_public_key *key, + const uint8_t *buf, + 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 333c29c1..e75f4222 100644 --- a/firmware/2lib/include/2return_codes.h +++ b/firmware/2lib/include/2return_codes.h @@ -176,6 +176,9 @@ enum vb2_return_code { /* Member data overlaps member header */ VB2_ERROR_INSIDE_DATA_OVERLAP, + /* Unsupported packed key struct version */ + VB2_ERROR_UNPACK_KEY_STRUCT_VERSION, + /********************************************************************** * Keyblock verification errors (all in vb2_verify_keyblock()) */ diff --git a/firmware/2lib/include/2rsa.h b/firmware/2lib/include/2rsa.h index 8e21cd4d..3d591a5a 100644 --- a/firmware/2lib/include/2rsa.h +++ b/firmware/2lib/include/2rsa.h @@ -19,6 +19,9 @@ struct vb2_public_key { const uint32_t *rr; /* R^2 as little endian array */ enum vb2_signature_algorithm sig_alg; /* Signature algorithm */ enum vb2_hash_algorithm hash_alg; /* Hash algorithm */ + const char *desc; /* Description */ + uint32_t version; /* Key version */ + const struct vb2_guid *guid; /* Key GUID */ }; /** diff --git a/tests/vb2_common2_tests.c b/tests/vb2_common2_tests.c index 4b3a34e6..f58d2a35 100644 --- a/tests/vb2_common2_tests.c +++ b/tests/vb2_common2_tests.c @@ -11,6 +11,7 @@ #include "file_keys.h" #include "host_common.h" +#include "vb2_convert_structs.h" #include "vboot_common.h" #include "test_common.h" @@ -75,6 +76,113 @@ static void test_unpack_key(const VbPublicKey *orig_key) free(key); } +static void test_unpack_key2(const VbPublicKey *orig_key) +{ + /* vb2_packed_key and VbPublicKey are bit-identical */ + const struct vb2_packed_key *key1 = + (const struct vb2_packed_key *)orig_key; + + struct vb2_public_key pubk; + struct vb2_packed_key2 *key2; + uint32_t size; + + /* Should be able to handle a vboot1-style key binary as well */ + TEST_SUCC(vb2_unpack_key2(&pubk, (uint8_t *)key1, + key1->key_offset + key1->key_size), + "vb2_unpack_key2() passthru"); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + TEST_SUCC(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + "vb2_unpack_key2() ok"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->key_offset += 4; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_INSIDE_DATA_OUTSIDE, + "vb2_unpack_key2() buffer too small"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->c.desc_offset += size; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_INSIDE_DATA_OUTSIDE, + "vb2_unpack_key2() buffer too small for desc"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->c.desc_size = 0; + key2->c.desc_offset = 0; + TEST_SUCC(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + "vb2_unpack_key2() no desc"); + TEST_EQ(strcmp(pubk.desc, ""), 0, " empty desc string"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->c.magic++; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_INSIDE_DATA_OUTSIDE, + "vb2_unpack_key2() bad magic"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->c.struct_version_major++; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_UNPACK_KEY_STRUCT_VERSION, + "vb2_unpack_key2() bad major version"); + free(key2); + + /* + * Minor version changes are ok. Note that this test assumes that the + * source key struct version is the highest actually known to the + * reader. If the reader does know about minor version + 1 and that + * adds fields, this test will likely fail. But at that point, we + * should have already added a test for minor version compatibility to + * handle both old and new struct versions, so someone will have + * noticed this comment. + */ + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->c.struct_version_minor++; + TEST_SUCC(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + "vb2_unpack_key2() minor version change ok"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->sig_algorithm = VB2_SIG_INVALID; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_UNPACK_KEY_SIG_ALGORITHM, + "vb2_unpack_key2() bad sig algorithm"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->hash_algorithm = VB2_HASH_INVALID; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_UNPACK_KEY_HASH_ALGORITHM, + "vb2_unpack_key2() bad hash algorithm"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->key_size--; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_UNPACK_KEY_SIZE, + "vb2_unpack_key2() invalid size"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + key2->key_offset--; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_UNPACK_KEY_ALIGN, + "vb2_unpack_key2() unaligned data"); + free(key2); + + key2 = vb2_convert_packed_key2(key1, "Test key", &size); + *(uint32_t *)((uint8_t *)key2 + key2->key_offset) /= 2; + TEST_EQ(vb2_unpack_key2(&pubk, (uint8_t *)key2, size), + VB2_ERROR_UNPACK_KEY_ARRAY_SIZE, + "vb2_unpack_key2() invalid key array size"); + free(key2); +} + static void test_verify_data(const VbPublicKey *public_key, const VbPrivateKey *private_key) { @@ -173,6 +281,7 @@ int test_algorithm(int key_algorithm, const char *keys_dir) } test_unpack_key(public_key); + test_unpack_key2(public_key); test_verify_data(public_key, private_key); if (public_key) diff --git a/tests/vb2_convert_structs.c b/tests/vb2_convert_structs.c new file mode 100644 index 00000000..fe74f85f --- /dev/null +++ b/tests/vb2_convert_structs.c @@ -0,0 +1,57 @@ +/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + * Convert structs from vboot1 data format to new vboot2 structs + */ + +#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" + +struct vb2_packed_key2 *vb2_convert_packed_key2( + const struct vb2_packed_key *key, + const char *desc, uint32_t *out_size) +{ + struct vb2_packed_key2 k2 = { + .c.magic = VB2_MAGIC_PACKED_KEY2, + .c.struct_version_major = VB2_PACKED_KEY2_VERSION_MAJOR, + .c.struct_version_minor = VB2_PACKED_KEY2_VERSION_MINOR, + }; + uint8_t *kbuf; + + /* Calculate description size */ + k2.c.desc_offset = sizeof(k2); + k2.c.desc_size = roundup32(strlen(desc) + 1); + + /* Copy/initialize fields */ + k2.key_offset = k2.c.desc_offset + k2.c.desc_size; + k2.key_size = key->key_size; + k2.key_version = key->key_version; + k2.sig_algorithm = vb2_crypto_to_signature(key->algorithm); + k2.hash_algorithm = vb2_crypto_to_hash(key->algorithm); + /* TODO: fill in a non-zero GUID */ + + /* Allocate the new buffer */ + *out_size = k2.key_offset + k2.key_size; + kbuf = malloc(*out_size); + memset(kbuf, 0, *out_size); + + /* Copy data into the buffer */ + memcpy(kbuf, &k2, sizeof(k2)); + + /* strcpy() is safe because we allocated above based on strlen() */ + strcpy((char *)(kbuf + k2.c.desc_offset), desc); + kbuf[k2.c.desc_offset + k2.c.desc_size - 1] = 0; + + memcpy(kbuf + k2.key_offset, + (const uint8_t *)key + key->key_offset, + key->key_size); + + /* Return the newly allocated buffer */ + return (struct vb2_packed_key2 *)kbuf; +} diff --git a/tests/vb2_convert_structs.h b/tests/vb2_convert_structs.h new file mode 100644 index 00000000..dcf15831 --- /dev/null +++ b/tests/vb2_convert_structs.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + * + */ + +#ifndef VBOOT_REFERENCE_VB2_CONVERT_STRUCTS_H_ +#define VBOOT_REFERENCE_VB2_CONVERT_STRUCTS_H_ + +#include "2struct.h" + +/** + * Round up a size to a multiple of 32 bits (4 bytes). + */ +static __inline const uint32_t roundup32(uint32_t v) +{ + return (v + 3) & ~3; +} + +/** + * Convert a packed key 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 key Packed key in vboot1 format + * @param desc Description of packed key + * @param out_size Size of the newly allocated buffer + * @return a newly allocated buffer with the converted key. Caller is + * responsible for freeing this buffer. + */ +struct vb2_packed_key2 *vb2_convert_packed_key2( + const struct vb2_packed_key *key, + const char *desc, uint32_t *out_size); + +#endif /* VBOOT_REFERENCE_VB2_CONVERT_STRUCTS_H_ */ |