| /* 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 "2common.h" |
| #include "2rsa.h" |
| #include "2sha.h" |
| #include "2sysincludes.h" |
| #include "host_common.h" |
| #include "host_common21.h" |
| #include "host_key21.h" |
| #include "host_misc.h" |
| #include "host_signature21.h" |
| |
| vb2_error_t 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; |
| } |
| } |
| |
| vb2_error_t vb21_sign_data(struct vb21_signature **sig_ptr, const uint8_t *data, |
| uint32_t size, const struct vb2_private_key *key, |
| const char *desc) |
| { |
| struct vb21_signature s = { |
| .c.magic = VB21_MAGIC_SIGNATURE, |
| .c.struct_version_major = VB21_SIGNATURE_VERSION_MAJOR, |
| .c.struct_version_minor = VB21_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 vb21_signature *)buf; |
| return VB2_SUCCESS; |
| } |
| |
| vb2_error_t vb21_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 vb21_signature); |
| size += vb2_desc_size(desc ? desc : key->desc); |
| |
| *size_ptr = size; |
| return VB2_SUCCESS; |
| } |
| |
| vb2_error_t vb21_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; |
| vb2_error_t rv, i; |
| |
| *size_ptr = 0; |
| |
| for (i = 0; i < key_count; i++) { |
| rv = vb21_sig_size_for_key(&size, key_list[i], NULL); |
| if (rv) |
| return rv; |
| total += size; |
| } |
| |
| *size_ptr = total; |
| return VB2_SUCCESS; |
| } |
| |
| vb2_error_t vb21_sign_object(uint8_t *buf, uint32_t sig_offset, |
| const struct vb2_private_key *key, |
| const char *desc) |
| { |
| struct vb21_struct_common *c = (struct vb21_struct_common *)buf; |
| struct vb21_signature *sig = NULL; |
| vb2_error_t rv; |
| |
| rv = vb21_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; |
| } |
| |
| vb2_error_t vb21_sign_object_multiple(uint8_t *buf, uint32_t sig_offset, |
| const struct vb2_private_key **key_list, |
| uint32_t key_count) |
| { |
| struct vb21_struct_common *c = (struct vb21_struct_common *)buf; |
| uint32_t sig_next = sig_offset; |
| vb2_error_t rv, i; |
| |
| for (i = 0; i < key_count; i++) { |
| struct vb21_signature *sig = NULL; |
| |
| rv = vb21_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; |
| } |