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>
This commit is contained in:
Randall Spangler
2014-11-01 17:56:46 -07:00
committed by chrome-internal-fetch
parent c0ce70b468
commit b885c3bd3d
6 changed files with 325 additions and 2 deletions

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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_ */