176 lines
5.2 KiB
C
176 lines
5.2 KiB
C
/* 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_key2.h"
|
|
#include "host_keyblock.h"
|
|
#include "host_key.h"
|
|
#include "vb2_common.h"
|
|
#include "vb2_struct.h"
|
|
#include "vboot_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];
|
|
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);
|
|
}
|