Files
OpenCellular/host/lib21/host_signature.c
Randall Spangler 308d254092 vboot2: Get rid of extra '2' at end of new struct names
Now that lib20 and lib21 are distinct, they can have overlapping
struct names.  This will be cleaner in the long run, since vboot 2.0
(lib20) is just a temporary stepping stone to vboot 2.1 (lib21).  It
would be a shame to need to carry around the overhead of that extra
digit forever.

No functional changes, just a lot of renaming.

BUG=chromium:423882
BRANCH=none
TEST=make runtests && VBOOT2=1 make runtests (works with/withoug VBOOT2 flag)
     And compile firmware for veyron_pinky

Change-Id: I25f348fd31e32d08ca576836dfdd1278828765a1
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/233183
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
2014-12-05 00:02:00 +00:00

274 lines
6.2 KiB
C

/* 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 "vb2_common.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_signature **sig_ptr,
const uint8_t *data,
uint32_t size,
const struct vb2_private_key *key,
const char *desc)
{
struct vb2_signature s = {
.c.magic = VB2_MAGIC_SIGNATURE,
.c.struct_version_major = VB2_SIGNATURE_VERSION_MAJOR,
.c.struct_version_minor = VB2_SIGNATURE_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 = calloc(1, 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_signature *)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_signature);
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_signature *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_signature *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;
}