summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-11-21 11:04:36 -0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-11-27 06:35:09 +0000
commitc644a8c0f2df024798ac0e60c6028261ed389a16 (patch)
treee9d4e91959ffd0a22025f34515b6a3996b94c863
parentfb9a216dd677d97f3d6963f668a9b84d349ef339 (diff)
downloadvboot-c644a8c0f2df024798ac0e60c6028261ed389a16.tar.gz
vboot2: Add host library functions for signing to new struct format
Including signing with bare hashes, and signing an object with more than one signature. With unit tests, even. BUG=chromium:423882 BRANCH=none TEST=VBOOT2=1 make runtests Change-Id: Iad0b9f9f6cca7129071aebf0cbc60c0daa94d382 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/231452 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r--Makefile5
-rw-r--r--firmware/2lib/include/2return_codes.h41
-rw-r--r--host/lib/host_misc2.c9
-rw-r--r--host/lib/host_signature2.c273
-rw-r--r--host/lib/include/host_misc.h12
-rw-r--r--host/lib/include/host_signature2.h88
-rw-r--r--tests/vb2_api2_tests.c2
-rw-r--r--tests/vb2_common_tests.c1
-rw-r--r--tests/vb2_convert_structs.c39
-rw-r--r--tests/vb2_host_misc_tests.c5
-rw-r--r--tests/vb2_host_sig_tests.c199
11 files changed, 642 insertions, 32 deletions
diff --git a/Makefile b/Makefile
index 08eaa5bf..e18679f5 100644
--- a/Makefile
+++ b/Makefile
@@ -378,6 +378,7 @@ ifneq (${VBOOT2},)
UTILLIB_SRCS += \
host/lib/host_key2.c \
host/lib/host_misc2.c \
+ host/lib/host_signature2.c \
endif
@@ -635,6 +636,7 @@ TEST_NAMES += \
tests/vb2_common3_tests \
tests/vb2_host_key_tests \
tests/vb2_host_misc_tests \
+ tests/vb2_host_sig_tests \
tests/vb2_misc_tests \
tests/vb2_misc2_tests \
tests/vb2_misc3_tests \
@@ -988,10 +990,12 @@ ${BUILD}/utility/pad_digest_utility: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/utility/signature_digest_utility: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/host/linktest/main: LDLIBS += ${CRYPTO_LIBS}
+${BUILD}/tests/vb2_api2_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vb2_common_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vb2_common2_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vb2_common3_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vb2_host_key_tests: LDLIBS += ${CRYPTO_LIBS}
+${BUILD}/tests/vb2_host_sig_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vboot_common2_tests: LDLIBS += ${CRYPTO_LIBS}
${BUILD}/tests/vboot_common3_tests: LDLIBS += ${CRYPTO_LIBS}
@@ -1173,6 +1177,7 @@ run2tests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vb2_common3_tests ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/vb2_host_key_tests ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/vb2_host_misc_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vb2_host_sig_tests ${TEST_KEYS}
${RUNTEST} ${BUILD_RUN}/tests/vb2_misc_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_misc2_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_misc3_tests
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index f12f2c12..8f5a5c51 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -559,6 +559,47 @@ enum vb2_return_code {
VB2_ERROR_PUBLIC_KEY_HASH,
/**********************************************************************
+ * Errors generated by host library signature functions
+ */
+ VB2_ERROR_HOST_SIG = VB2_ERROR_HOST_BASE + 0x030000,
+
+ /* Bad hash algorithm in vb2_digest_info() */
+ VB2_ERROR_DIGEST_INFO,
+
+ /*
+ * Unable to determine signature size for key algorithm in
+ * vb2_sig_size_for_key().
+ */
+ VB2_ERROR_SIG_SIZE_FOR_KEY,
+
+ /* Bad signature size in vb2_sign_data() */
+ VB2_SIGN_DATA_SIG_SIZE,
+
+ /* Unable to get digest info in vb2_sign_data() */
+ VB2_SIGN_DATA_DIGEST_INFO,
+
+ /* Unable to get digest size in vb2_sign_data() */
+ VB2_SIGN_DATA_DIGEST_SIZE,
+
+ /* Unable to allocate digest buffer in vb2_sign_data() */
+ VB2_SIGN_DATA_DIGEST_ALLOC,
+
+ /* Unable to initialize digest in vb2_sign_data() */
+ VB2_SIGN_DATA_DIGEST_INIT,
+
+ /* Unable to extend digest in vb2_sign_data() */
+ VB2_SIGN_DATA_DIGEST_EXTEND,
+
+ /* Unable to finalize digest in vb2_sign_data() */
+ VB2_SIGN_DATA_DIGEST_FINALIZE,
+
+ /* RSA encrypt failed in vb2_sign_data() */
+ VB2_SIGN_DATA_RSA_ENCRYPT,
+
+ /* Not enough buffer space to hold signature in vb2_sign_object() */
+ VB2_SIGN_OBJECT_OVERFLOW,
+
+ /**********************************************************************
* Highest non-zero error generated inside vboot library. Note that
* error codes passed through vboot when it calls external APIs may
* still be outside this range.
diff --git a/host/lib/host_misc2.c b/host/lib/host_misc2.c
index 71a20673..a78a7132 100644
--- a/host/lib/host_misc2.c
+++ b/host/lib/host_misc2.c
@@ -83,3 +83,12 @@ int vb2_write_object(const char *filename, const void *buf)
return vb2_write_file(filename, buf, cptr->total_size);
}
+
+uint32_t vb2_desc_size(const char *desc)
+{
+ if (!desc || !*desc)
+ return 0;
+
+ return roundup32(strlen(desc) + 1);
+}
+
diff --git a/host/lib/host_signature2.c b/host/lib/host_signature2.c
new file mode 100644
index 00000000..c5b2c466
--- /dev/null
+++ b/host/lib/host_signature2.c
@@ -0,0 +1,273 @@
+/* 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.
+ *
+ * Host functions for signatures.
+ */
+
+#define OPENSSL_NO_SHA
+#include <openssl/engine.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2rsa.h"
+#include "2sha.h"
+#include "host_common.h"
+#include "host_key2.h"
+#include "host_signature2.h"
+#include "host_misc.h"
+
+/**
+ * Get the digest info for a hash algorithm
+ *
+ * @param hash_alg Hash algorithm
+ * @param buf_ptr On success, points to the digest info
+ * @param size_ptr On success, contains the info size in bytes
+ * @return VB2_SUCCESS, or non-zero error code on failure.
+ */
+static int vb2_digest_info(enum vb2_hash_algorithm hash_alg,
+ const uint8_t **buf_ptr,
+ uint32_t *size_ptr)
+{
+ *buf_ptr = NULL;
+ *size_ptr = 0;
+
+ switch (hash_alg) {
+#if VB2_SUPPORT_SHA1
+ case VB2_HASH_SHA1:
+ {
+ static const uint8_t info[] = {
+ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
+ 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
+ };
+ *buf_ptr = info;
+ *size_ptr = sizeof(info);
+ return VB2_SUCCESS;
+ }
+#endif
+#if VB2_SUPPORT_SHA256
+ case VB2_HASH_SHA256:
+ {
+ static const uint8_t info[] = {
+ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
+ 0x00, 0x04, 0x20
+ };
+ *buf_ptr = info;
+ *size_ptr = sizeof(info);
+ return VB2_SUCCESS;
+ }
+#endif
+#if VB2_SUPPORT_SHA512
+ case VB2_HASH_SHA512:
+ {
+ static const uint8_t info[] = {
+ 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
+ 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
+ 0x00, 0x04, 0x40
+ };
+ *buf_ptr = info;
+ *size_ptr = sizeof(info);
+ return VB2_SUCCESS;
+ }
+#endif
+ default:
+ return VB2_ERROR_DIGEST_INFO;
+ }
+}
+
+int vb2_sign_data(struct vb2_signature2 **sig_ptr,
+ const uint8_t *data,
+ uint32_t size,
+ const struct vb2_private_key *key,
+ const char *desc)
+{
+ 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),
+ .sig_alg = key->sig_alg,
+ .hash_alg = key->hash_alg,
+ .data_size = size,
+ .guid = key->guid,
+ };
+
+ struct vb2_digest_context dc;
+ uint32_t digest_size;
+ const uint8_t *info = NULL;
+ uint32_t info_size = 0;
+ uint32_t sig_digest_size;
+ uint8_t *sig_digest;
+ uint8_t *buf;
+
+ *sig_ptr = NULL;
+
+ /* Use key description if no description supplied */
+ if (!desc)
+ desc = key->desc;
+
+ s.c.desc_size = vb2_desc_size(desc);
+
+ s.sig_offset = s.c.fixed_size + s.c.desc_size;
+ s.sig_size = vb2_sig_size(key->sig_alg, key->hash_alg);
+ if (!s.sig_size)
+ return VB2_SIGN_DATA_SIG_SIZE;
+
+ s.c.total_size = s.sig_offset + s.sig_size;
+
+ /* Determine digest size and allocate buffer */
+ if (s.sig_alg != VB2_SIG_NONE) {
+ if (vb2_digest_info(s.hash_alg, &info, &info_size))
+ return VB2_SIGN_DATA_DIGEST_INFO;
+ }
+
+ digest_size = vb2_digest_size(key->hash_alg);
+ if (!digest_size)
+ return VB2_SIGN_DATA_DIGEST_SIZE;
+
+ sig_digest_size = info_size + digest_size;
+ sig_digest = malloc(sig_digest_size);
+ if (!sig_digest)
+ return VB2_SIGN_DATA_DIGEST_ALLOC;
+
+ /* Prepend digest info, if any */
+ if (info_size)
+ memcpy(sig_digest, info, info_size);
+
+ /* Calculate hash digest */
+ if (vb2_digest_init(&dc, s.hash_alg)) {
+ free(sig_digest);
+ return VB2_SIGN_DATA_DIGEST_INIT;
+ }
+
+ if (vb2_digest_extend(&dc, data, size)) {
+ free(sig_digest);
+ return VB2_SIGN_DATA_DIGEST_EXTEND;
+ }
+
+ if (vb2_digest_finalize(&dc, sig_digest + info_size, digest_size)) {
+ free(sig_digest);
+ return VB2_SIGN_DATA_DIGEST_FINALIZE;
+ }
+
+ /* Allocate signature buffer and copy header */
+ buf = malloc(s.c.total_size);
+ memset(buf, 0, s.c.total_size);
+ memcpy(buf, &s, sizeof(s));
+
+ /* strcpy() is ok because we allocated buffer based on desc length */
+ if (desc)
+ strcpy((char *)buf + s.c.fixed_size, desc);
+
+ if (s.sig_alg == VB2_SIG_NONE) {
+ /* Bare hash signature is just the digest */
+ memcpy(buf + s.sig_offset, sig_digest, sig_digest_size);
+ } else {
+ /* RSA-encrypt the signature */
+ if (RSA_private_encrypt(sig_digest_size,
+ sig_digest,
+ buf + s.sig_offset,
+ key->rsa_private_key,
+ RSA_PKCS1_PADDING) == -1) {
+ free(sig_digest);
+ free(buf);
+ return VB2_SIGN_DATA_RSA_ENCRYPT;
+ }
+ }
+
+ free(sig_digest);
+ *sig_ptr = (struct vb2_signature2 *)buf;
+ return VB2_SUCCESS;
+}
+
+int vb2_sig_size_for_key(uint32_t *size_ptr,
+ const struct vb2_private_key *key,
+ const char *desc)
+{
+ uint32_t size = vb2_sig_size(key->sig_alg, key->hash_alg);
+
+ if (!size)
+ return VB2_ERROR_SIG_SIZE_FOR_KEY;
+
+ size += sizeof(struct vb2_signature2);
+ size += vb2_desc_size(desc ? desc : key->desc);
+
+ *size_ptr = size;
+ return VB2_SUCCESS;
+}
+
+int vb2_sig_size_for_keys(uint32_t *size_ptr,
+ const struct vb2_private_key **key_list,
+ uint32_t key_count)
+{
+ uint32_t total = 0, size = 0;
+ int rv, i;
+
+ *size_ptr = 0;
+
+ for (i = 0; i < key_count; i++) {
+ rv = vb2_sig_size_for_key(&size, key_list[i], NULL);
+ if (rv)
+ return rv;
+ total += size;
+ }
+
+ *size_ptr = total;
+ return VB2_SUCCESS;
+}
+
+int vb2_sign_object(uint8_t *buf,
+ uint32_t sig_offset,
+ const struct vb2_private_key *key,
+ const char *desc)
+{
+ struct vb2_struct_common *c = (struct vb2_struct_common *)buf;
+ struct vb2_signature2 *sig = NULL;
+ int rv;
+
+ rv = vb2_sign_data(&sig, buf, sig_offset, key, desc);
+ if (rv)
+ return rv;
+
+ if (sig_offset + sig->c.total_size > c->total_size) {
+ free(sig);
+ return VB2_SIGN_OBJECT_OVERFLOW;
+ }
+
+ memcpy(buf + sig_offset, sig, sig->c.total_size);
+ free(sig);
+
+ return VB2_SUCCESS;
+}
+
+int vb2_sign_object_multiple(uint8_t *buf,
+ uint32_t sig_offset,
+ const struct vb2_private_key **key_list,
+ uint32_t key_count)
+{
+ struct vb2_struct_common *c = (struct vb2_struct_common *)buf;
+ uint32_t sig_next = sig_offset;
+ int rv, i;
+
+ for (i = 0; i < key_count; i++) {
+ struct vb2_signature2 *sig = NULL;
+
+ rv = vb2_sign_data(&sig, buf, sig_offset, key_list[i], NULL);
+ if (rv)
+ return rv;
+
+ if (sig_next + sig->c.total_size > c->total_size) {
+ free(sig);
+ return VB2_SIGN_OBJECT_OVERFLOW;
+ }
+
+ memcpy(buf + sig_next, sig, sig->c.total_size);
+ sig_next += sig->c.total_size;
+ free(sig);
+ }
+
+ return VB2_SUCCESS;
+}
diff --git a/host/lib/include/host_misc.h b/host/lib/include/host_misc.h
index 2e18d90b..6dc225c1 100644
--- a/host/lib/include/host_misc.h
+++ b/host/lib/include/host_misc.h
@@ -84,4 +84,16 @@ static __inline const uint32_t roundup32(uint32_t v)
return (v + 3) & ~3;
}
+/**
+ * Return the buffer size required to hold a description string.
+ *
+ * If the string is NULL or empty, the size is zero. Otherwise, it is the
+ * size of a buffer which can hold the string and its null terminator,
+ * rounded up to the nerest multiple of 32 bits.
+ *
+ * @param desc Description string
+ * @return The buffer size in bytes.
+ */
+uint32_t vb2_desc_size(const char *desc);
+
#endif /* VBOOT_REFERENCE_HOST_MISC_H_ */
diff --git a/host/lib/include/host_signature2.h b/host/lib/include/host_signature2.h
new file mode 100644
index 00000000..2e5718b7
--- /dev/null
+++ b/host/lib/include/host_signature2.h
@@ -0,0 +1,88 @@
+/* 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.
+ *
+ * Host-side functions for verified boot key structures
+ */
+
+#ifndef VBOOT_REFERENCE_HOST_SIGNATURE2_H_
+#define VBOOT_REFERENCE_HOST_SIGNATURE2_H_
+
+#include "2struct.h"
+
+struct vb2_private_key;
+
+/**
+ * Sign data buffer
+ *
+ * @param sig_ptr On success, points to a newly allocated signature.
+ * Caller is responsible for calling free() on this.
+ * @param data Pointer to data to sign
+ * @param size Size of data to sign in bytes
+ * @param key Private key to use to sign data
+ * @param desc Optional description for signature. If NULL, the
+ * key description will be used.
+ * @return VB2_SUCCESS, or non-zero error code on failure.
+ */
+int vb2_sign_data(struct vb2_signature2 **sig_ptr,
+ const uint8_t *data,
+ uint32_t size,
+ const struct vb2_private_key *key,
+ const char *desc);
+
+/**
+ * Calculate the signature size for a private key.
+ *
+ * @param size_ptr On success, contains the signature size in bytes.
+ * @param key Key to calculate signature length from.
+ * @param desc Optional description for signature. If NULL, the
+ * key description will be used.
+ * @return VB2_SUCCESS, or non-zero error code on failure.
+ */
+int vb2_sig_size_for_key(uint32_t *size_ptr,
+ const struct vb2_private_key *key,
+ const char *desc);
+
+/**
+ * Calculate the total signature size for a list of keys.
+ *
+ * @param size_ptr On success, contains the signature size in bytes.
+ * @param key_list List of keys to calculate signature length from.
+ * @param key_count Number of keys.
+ * @return VB2_SUCCESS, or non-zero error code on failure.
+ */
+int vb2_sig_size_for_keys(uint32_t *size_ptr,
+ const struct vb2_private_key **key_list,
+ uint32_t key_count);
+
+/**
+ * Sign object with a key.
+ *
+ * @param buf Buffer containing object to sign, starting with
+ * common header
+ * @param sig_offset Offset in buffer at which to store signature. All
+ * data before this in the buffer will be signed.
+ * @param key Key to sign object with
+ * @param desc If non-null, description to use for signature
+ */
+int vb2_sign_object(uint8_t *buf,
+ uint32_t sig_offset,
+ const struct vb2_private_key *key,
+ const char *desc);
+
+/**
+ * Sign object with list of keys.
+ *
+ * @param buf Buffer containing object to sign, starting with
+ * common header
+ * @param sig_offset Offset to start signatures. All data before this
+ * in the buffer will be signed.
+ * @param key_list List of keys to sign object with
+ * @param key_count Number of keys in list
+ */
+int vb2_sign_object_multiple(uint8_t *buf,
+ uint32_t sig_offset,
+ const struct vb2_private_key **key_list,
+ uint32_t key_count);
+
+#endif /* VBOOT_REFERENCE_HOST_SIGNATURE2_H_ */
diff --git a/tests/vb2_api2_tests.c b/tests/vb2_api2_tests.c
index 17fc3b96..b6db1850 100644
--- a/tests/vb2_api2_tests.c
+++ b/tests/vb2_api2_tests.c
@@ -15,6 +15,8 @@
#include "2rsa.h"
#include "2secdata.h"
+#include "host_signature2.h"
+
#include "test_common.h"
#include "vb2_convert_structs.h"
diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c
index 37996ae3..29adfe84 100644
--- a/tests/vb2_common_tests.c
+++ b/tests/vb2_common_tests.c
@@ -9,6 +9,7 @@
#include "2common.h"
#include "2rsa.h"
#include "host_key2.h"
+#include "host_signature2.h"
#include "vb2_convert_structs.h"
#include "vboot_struct.h" /* For old struct sizes */
diff --git a/tests/vb2_convert_structs.c b/tests/vb2_convert_structs.c
index d30b337f..68cb326d 100644
--- a/tests/vb2_convert_structs.c
+++ b/tests/vb2_convert_structs.c
@@ -9,7 +9,9 @@
#include "2common.h"
#include "2rsa.h"
#include "host_common.h"
+#include "host_key2.h"
#include "host_misc.h"
+#include "host_signature2.h"
#include "vb2_convert_structs.h"
#include "vboot_struct.h" /* For old struct sizes */
@@ -117,41 +119,14 @@ 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;
+ const struct vb2_private_key *key;
+ struct vb2_signature2 *sig;
- /* Make sure hash algorithm was supported */
- if (!hash_guid || !s.sig_size)
+ if (vb2_private_key_hash(&key, hash_alg))
return NULL;
- memcpy(&s.guid, hash_guid, sizeof(s.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);
+ if (vb2_sign_data(&sig, data, size, key, NULL))
return NULL;
- }
- return (struct vb2_signature2 *)buf;
+ return sig;
}
diff --git a/tests/vb2_host_misc_tests.c b/tests/vb2_host_misc_tests.c
index e8c2a588..a78c7450 100644
--- a/tests/vb2_host_misc_tests.c
+++ b/tests/vb2_host_misc_tests.c
@@ -19,6 +19,11 @@ static void misc_tests(void)
TEST_EQ(roundup32(0), 0, "roundup32(0)");
TEST_EQ(roundup32(15), 16, "roundup32(15)");
TEST_EQ(roundup32(16), 16, "roundup32(16)");
+
+ TEST_EQ(vb2_desc_size(NULL), 0, "desc size null");
+ TEST_EQ(vb2_desc_size(""), 0, "desc size empty");
+ TEST_EQ(vb2_desc_size("foo"), 4, "desc size 'foo'");
+ TEST_EQ(vb2_desc_size("foob"), 8, "desc size 'foob'");
}
static void file_tests(void)
diff --git a/tests/vb2_host_sig_tests.c b/tests/vb2_host_sig_tests.c
new file mode 100644
index 00000000..a2793bc9
--- /dev/null
+++ b/tests/vb2_host_sig_tests.c
@@ -0,0 +1,199 @@
+/* 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.
+ *
+ * Tests for host library vboot2 key functions
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "2sysincludes.h"
+#include "2common.h"
+#include "2rsa.h"
+#include "host_common.h"
+#include "host_key2.h"
+#include "host_signature2.h"
+#include "test_common.h"
+
+/* Test only the algorithms we use */
+struct alg_combo {
+ const char *name;
+ enum vb2_signature_algorithm sig_alg;
+ enum vb2_hash_algorithm hash_alg;
+};
+
+static const struct alg_combo test_algs[] = {
+ {"RSA2048/SHA-256", VB2_SIG_RSA2048, VB2_HASH_SHA256},
+ {"RSA4096/SHA-256", VB2_SIG_RSA4096, VB2_HASH_SHA256},
+ {"RSA8192/SHA-512", VB2_SIG_RSA8192, VB2_HASH_SHA512},
+};
+
+const struct vb2_guid test_guid = {.raw = {0xaa}};
+const char *test_desc = "The test key";
+const char *test_sig_desc = "The test signature";
+const uint8_t test_data[] = "Some test data";
+const uint32_t test_size = sizeof(test_data);
+
+static void sig_tests(const struct alg_combo *combo,
+ const char *pemfile,
+ const char *keybfile)
+{
+ struct vb2_private_key *prik, prik2;
+ const struct vb2_private_key *prihash, *priks[2];
+ struct vb2_public_key *pubk, pubhash;
+ struct vb2_signature2 *sig, *sig2;
+ uint32_t size;
+
+ uint8_t workbuf[VB2_VERIFY_DATA_WORKBUF_BYTES];
+ struct vb2_workbuf wb;
+
+ uint8_t *buf;
+ uint32_t bufsize;
+ struct vb2_struct_common *c;
+ uint32_t c_sig_offs;
+
+ vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
+
+ /* Create test keys */
+ /* TODO: should read these from .vbprik2, .vbpubk2 files */
+ TEST_SUCC(vb2_private_key_read_pem(&prik, pemfile), "Read private key");
+ prik->guid = test_guid;
+ prik->hash_alg = combo->hash_alg;
+ prik->sig_alg = combo->sig_alg;
+ vb2_private_key_set_desc(prik, test_desc);
+
+ TEST_SUCC(vb2_public_key_read_keyb(&pubk, keybfile), "Read pub key");
+ pubk->guid = &test_guid;
+ pubk->hash_alg = combo->hash_alg;
+ vb2_public_key_set_desc(pubk, test_desc);
+
+ TEST_SUCC(vb2_private_key_hash(&prihash, combo->hash_alg),
+ "Private hash key");
+ TEST_SUCC(vb2_public_key_hash(&pubhash, combo->hash_alg),
+ "Public hash key");
+
+ priks[0] = prik;
+ priks[1] = prihash;
+
+ /* Sign test data */
+ TEST_SUCC(vb2_sign_data(&sig, test_data, test_size, prik, NULL),
+ "Sign good");
+ TEST_PTR_NEQ(sig, NULL, " sig_ptr");
+ TEST_EQ(0, strcmp((char *)sig + sig->c.fixed_size, test_desc),
+ " desc");
+ TEST_EQ(0, memcmp(&sig->guid, &test_guid, sizeof(test_guid)), " guid");
+ TEST_EQ(sig->data_size, test_size, " data_size");
+ TEST_SUCC(vb2_sig_size_for_key(&size, prik, NULL), "Sig size");
+ TEST_EQ(size, sig->c.total_size, " size");
+ TEST_SUCC(vb2_verify_data2(test_data, test_size, sig, pubk, &wb),
+ "Verify good");
+ free(sig);
+
+ TEST_SUCC(vb2_sign_data(&sig, test_data, test_size, prik,
+ test_sig_desc),
+ "Sign with desc");
+ TEST_EQ(0, strcmp((char *)sig + sig->c.fixed_size, test_sig_desc),
+ " desc");
+ free(sig);
+
+ TEST_SUCC(vb2_sign_data(&sig, test_data, test_size, prik, ""),
+ "Sign with no desc");
+ TEST_EQ(sig->c.desc_size, 0, " desc");
+ TEST_SUCC(vb2_sig_size_for_key(&size, prik, ""), "Sig size");
+ TEST_EQ(size, sig->c.total_size, " size");
+ free(sig);
+
+ TEST_SUCC(vb2_sign_data(&sig, test_data, test_size, prihash, NULL),
+ "Sign with hash");
+ TEST_SUCC(vb2_verify_data2(test_data, test_size, sig, &pubhash, &wb),
+ "Verify with hash");
+ free(sig);
+
+ prik2 = *prik;
+ prik2.sig_alg = VB2_SIG_INVALID;
+ TEST_EQ(vb2_sign_data(&sig, test_data, test_size, &prik2, NULL),
+ VB2_SIGN_DATA_SIG_SIZE, "Sign bad sig alg");
+
+ /* Sign an object with a little (24 bytes) data */
+ c_sig_offs = sizeof(*c) + 24;
+ TEST_SUCC(vb2_sig_size_for_key(&size, prik, NULL), "Sig size");
+ bufsize = c_sig_offs + size;
+ buf = malloc(bufsize);
+ memset(buf, 0, bufsize);
+ memset(buf + sizeof(*c), 0x12, 24);
+ c = (struct vb2_struct_common *)buf;
+ c->total_size = bufsize;
+
+ TEST_SUCC(vb2_sign_object(buf, c_sig_offs, prik, NULL), "Sign object");
+ sig = (struct vb2_signature2 *)(buf + c_sig_offs);
+ TEST_SUCC(vb2_verify_data2(buf, c_sig_offs, sig, pubk, &wb),
+ "Verify object");
+
+ TEST_EQ(vb2_sign_object(buf, c_sig_offs + 4, prik, NULL),
+ VB2_SIGN_OBJECT_OVERFLOW, "Sign object overflow");
+ free(buf);
+
+ /* Multiply sign an object */
+ TEST_SUCC(vb2_sig_size_for_keys(&size, priks, 2), "Sigs size");
+ bufsize = c_sig_offs + size;
+ buf = malloc(bufsize);
+ memset(buf, 0, bufsize);
+ memset(buf + sizeof(*c), 0x12, 24);
+ c = (struct vb2_struct_common *)buf;
+ c->total_size = bufsize;
+
+ TEST_SUCC(vb2_sign_object_multiple(buf, c_sig_offs, priks, 2),
+ "Sign multiple");
+ sig = (struct vb2_signature2 *)(buf + c_sig_offs);
+ TEST_SUCC(vb2_verify_data2(buf, c_sig_offs, sig, pubk, &wb),
+ "Verify object with sig 1");
+ sig2 = (struct vb2_signature2 *)(buf + c_sig_offs + sig->c.total_size);
+ TEST_SUCC(vb2_verify_data2(buf, c_sig_offs, sig2, &pubhash, &wb),
+ "Verify object with sig 2");
+
+ c->total_size -= 4;
+ TEST_EQ(vb2_sign_object_multiple(buf, c_sig_offs, priks, 2),
+ VB2_SIGN_OBJECT_OVERFLOW, "Sign multple overflow");
+
+ TEST_EQ(size, sig->c.total_size + sig2->c.total_size,
+ "Sigs size total");
+
+ free(buf);
+
+ vb2_private_key_free(prik);
+ vb2_public_key_free(pubk);
+}
+
+static int test_algorithm(const struct alg_combo *combo, const char *keys_dir)
+{
+ int rsa_bits = vb2_rsa_sig_size(combo->sig_alg) * 8;
+ char pemfile[1024];
+ char keybfile[1024];
+
+ printf("***Testing algorithm: %s\n", combo->name);
+
+ sprintf(pemfile, "%s/key_rsa%d.pem", keys_dir, rsa_bits);
+ sprintf(keybfile, "%s/key_rsa%d.keyb", keys_dir, rsa_bits);
+
+ sig_tests(combo, pemfile, keybfile);
+
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+
+ if (argc == 2) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_algs); i++) {
+ if (test_algorithm(test_algs + i, argv[1]))
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "Usage: %s <keys_dir>", argv[0]);
+ return -1;
+ }
+
+ return gTestSuccess ? 0 : 255;
+}