summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2014-11-01 17:56:46 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-11-05 06:05:19 +0000
commitb885c3bd3d35284af81a83c3f23be4f02ddfbf47 (patch)
tree2118bd4c032baefe36446ea59fa02f767ea28d4d
parentc0ce70b468cc469556d0f43c63a6d63ec8280c99 (diff)
downloadvboot-b885c3bd3d35284af81a83c3f23be4f02ddfbf47.tar.gz
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 <rspangler@chromium.org> Reviewed-by: Bill Richardson <wfrichar@chromium.org> Commit-Queue: Randall Spangler <rspangler@chromium.org>
-rw-r--r--firmware/2lib/2common2.c120
-rw-r--r--firmware/2lib/include/2common.h39
-rw-r--r--tests/vb2_common2_tests.c78
-rw-r--r--tests/vb2_common_tests.c35
-rw-r--r--tests/vb2_convert_structs.c43
-rw-r--r--tests/vb2_convert_structs.h12
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
@@ -292,6 +292,15 @@ 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
* @param size Size of buffer containing 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_ */