mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-25 18:55:24 +00:00
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:
committed by
chrome-internal-fetch
parent
c0ce70b468
commit
b885c3bd3d
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
Reference in New Issue
Block a user