| /* Copyright (c) 2011 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 verified boot. |
| */ |
| |
| #include <stdio.h> |
| |
| #include "2sysincludes.h" |
| |
| #include "2api.h" |
| #include "2common.h" |
| #include "2rsa.h" |
| #include "2sha.h" |
| #include "host_common.h" |
| #include "host_key21.h" |
| #include "host_keyblock.h" |
| #include "host_key.h" |
| #include "vb2_common.h" |
| |
| struct vb2_keyblock *vb2_create_keyblock( |
| const struct vb2_packed_key *data_key, |
| const struct vb2_private_key *signing_key, |
| uint32_t flags) |
| { |
| /* Allocate keyblock */ |
| uint32_t signed_size = sizeof(struct vb2_keyblock) + data_key->key_size; |
| uint32_t sig_data_size = |
| (signing_key ? vb2_rsa_sig_size(signing_key->sig_alg) : 0); |
| uint32_t block_size = |
| signed_size + VB2_SHA512_DIGEST_SIZE + sig_data_size; |
| struct vb2_keyblock *h = (struct vb2_keyblock *)calloc(block_size, 1); |
| if (!h) |
| return NULL; |
| |
| uint8_t *data_key_dest = (uint8_t *)(h + 1); |
| uint8_t *block_chk_dest = data_key_dest + data_key->key_size; |
| uint8_t *block_sig_dest = block_chk_dest + VB2_SHA512_DIGEST_SIZE; |
| |
| memcpy(h->magic, VB2_KEYBLOCK_MAGIC, VB2_KEYBLOCK_MAGIC_SIZE); |
| h->header_version_major = VB2_KEYBLOCK_VERSION_MAJOR; |
| h->header_version_minor = VB2_KEYBLOCK_VERSION_MINOR; |
| h->keyblock_size = block_size; |
| h->keyblock_flags = flags; |
| |
| /* Copy data key */ |
| vb2_init_packed_key(&h->data_key, data_key_dest, data_key->key_size); |
| vb2_copy_packed_key(&h->data_key, data_key); |
| |
| /* Set up signature structs so we can calculate the signatures */ |
| vb2_init_signature(&h->keyblock_hash, block_chk_dest, |
| VB2_SHA512_DIGEST_SIZE, signed_size); |
| if (signing_key) { |
| vb2_init_signature(&h->keyblock_signature, block_sig_dest, |
| sig_data_size, signed_size); |
| } else { |
| memset(&h->keyblock_signature, 0, |
| sizeof(h->keyblock_signature)); |
| } |
| |
| /* Calculate hash */ |
| struct vb2_signature *chk = |
| vb2_sha512_signature((uint8_t*)h, signed_size); |
| vb2_copy_signature(&h->keyblock_hash, chk); |
| free(chk); |
| |
| /* Calculate signature */ |
| if (signing_key) { |
| struct vb2_signature *sigtmp = |
| vb2_calculate_signature((uint8_t*)h, |
| signed_size, |
| signing_key); |
| vb2_copy_signature(&h->keyblock_signature, sigtmp); |
| free(sigtmp); |
| } |
| |
| /* Return the header */ |
| return h; |
| } |
| |
| /* TODO(gauravsh): This could easily be integrated into the function above |
| * since the code is almost a mirror - I have kept it as such to avoid changing |
| * the existing interface. */ |
| struct vb2_keyblock *vb2_create_keyblock_external( |
| const struct vb2_packed_key *data_key, |
| const char *signing_key_pem_file, |
| uint32_t algorithm, |
| uint32_t flags, |
| const char *external_signer) |
| { |
| if (!signing_key_pem_file || !data_key || !external_signer) |
| return NULL; |
| |
| uint32_t signed_size = sizeof(struct vb2_keyblock) + data_key->key_size; |
| uint32_t sig_data_size = vb2_rsa_sig_size(vb2_crypto_to_signature(algorithm)); |
| uint32_t block_size = |
| signed_size + VB2_SHA512_DIGEST_SIZE + sig_data_size; |
| |
| /* Allocate keyblock */ |
| struct vb2_keyblock *h = (struct vb2_keyblock *)calloc(block_size, 1); |
| if (!h) |
| return NULL; |
| |
| uint8_t *data_key_dest = (uint8_t *)(h + 1); |
| uint8_t *block_chk_dest = data_key_dest + data_key->key_size; |
| uint8_t *block_sig_dest = block_chk_dest + VB2_SHA512_DIGEST_SIZE; |
| |
| memcpy(h->magic, VB2_KEYBLOCK_MAGIC, VB2_KEYBLOCK_MAGIC_SIZE); |
| h->header_version_major = VB2_KEYBLOCK_VERSION_MAJOR; |
| h->header_version_minor = VB2_KEYBLOCK_VERSION_MINOR; |
| h->keyblock_size = block_size; |
| h->keyblock_flags = flags; |
| |
| /* Copy data key */ |
| vb2_init_packed_key(&h->data_key, data_key_dest, data_key->key_size); |
| vb2_copy_packed_key(&h->data_key, data_key); |
| |
| /* Set up signature structs so we can calculate the signatures */ |
| vb2_init_signature(&h->keyblock_hash, block_chk_dest, |
| VB2_SHA512_DIGEST_SIZE, signed_size); |
| vb2_init_signature(&h->keyblock_signature, block_sig_dest, |
| sig_data_size, signed_size); |
| |
| /* Calculate checksum */ |
| struct vb2_signature *chk = |
| vb2_sha512_signature((uint8_t*)h, signed_size); |
| vb2_copy_signature(&h->keyblock_hash, chk); |
| free(chk); |
| |
| /* Calculate signature */ |
| struct vb2_signature *sigtmp = |
| vb2_external_signature((uint8_t*)h, signed_size, |
| signing_key_pem_file, algorithm, |
| external_signer); |
| vb2_copy_signature(&h->keyblock_signature, sigtmp); |
| free(sigtmp); |
| |
| /* Return the header */ |
| return h; |
| } |
| |
| struct vb2_keyblock *vb2_read_keyblock(const char *filename) |
| { |
| uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE] |
| __attribute__((aligned(VB2_WORKBUF_ALIGN))); |
| struct vb2_workbuf wb; |
| vb2_workbuf_init(&wb, workbuf, sizeof(workbuf)); |
| |
| struct vb2_keyblock *block; |
| uint32_t file_size; |
| if (VB2_SUCCESS != |
| vb2_read_file(filename, (uint8_t **)&block, &file_size)) { |
| fprintf(stderr, "Error reading keyblock file: %s\n", filename); |
| return NULL; |
| } |
| |
| /* Verify the hash of the keyblock, since we can do that without |
| * the public signing key. */ |
| if (VB2_SUCCESS != vb2_verify_keyblock_hash(block, file_size, &wb)) { |
| fprintf(stderr, "Invalid keyblock file: %s\n", filename); |
| free(block); |
| return NULL; |
| } |
| |
| return block; |
| } |
| |
| |
| int vb2_write_keyblock(const char *filename, |
| const struct vb2_keyblock *keyblock) |
| { |
| return vb2_write_file(filename, keyblock, keyblock->keyblock_size); |
| } |