Files
OpenCellular/host/lib21/host_signature.c
Adam Langley 9978e0aa00 vboot: fix name-collision with OpenSSL.
vboot currently uses the |SHA256_CTX| name, which is claimed by OpenSSL.
To work around this, it defines OPENSSL_NO_SHA, but that can't be done
at compile time:

The OPENSSL_NO_* defines are set by OpenSSL to reflect the configuration
that it was built with so that users of OpenSSL can disable features as
needed. They can affect the contents of structures any thus the ABI of
the library.

If these defines are set outside of OpenSSL, then the library and the
code that uses it will have incompatible ABIs. At that point it's only
functioning by blind luck.

This change renames the name-collisions so that this hack isn't needed.
This is the same change as was made internally in cl/85758149.

BUG=none
BRANCH=none
TEST=emerge-samus coreboot; make runtests

Change-Id: I709da2507f341896d89d50129ce30ffb111a20d1
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/263506
Reviewed-by: Randall Spangler <rspangler@chromium.org>
2015-04-02 00:54:07 +00:00

271 lines
6.1 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.
*/
#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,
.id = key->id,
};
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;
}