You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
271 lines
6.1 KiB
271 lines
6.1 KiB
/* 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,
|
|
.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;
|
|
}
|