summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--firmware/2lib/2misc.c2
-rw-r--r--firmware/2lib/2packed_key.c2
-rw-r--r--firmware/2lib/2packed_key2.c109
-rw-r--r--firmware/2lib/include/2common.h17
-rw-r--r--firmware/2lib/include/2return_codes.h3
-rw-r--r--firmware/2lib/include/2rsa.h3
-rw-r--r--tests/vb2_common2_tests.c109
-rw-r--r--tests/vb2_convert_structs.c57
-rw-r--r--tests/vb2_convert_structs.h36
10 files changed, 341 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index c344b08f..2a3585ce 100644
--- a/Makefile
+++ b/Makefile
@@ -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_ */