blob: f732b8b251f244ff02f34bb757f15d8d936e5543 [file] [log] [blame]
/* 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.
*
* Routines for verifying a firmware image's signature.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "2common.h"
#include "2misc.h"
#include "2sysincludes.h"
const char *gbb_fname;
const char *vblock_fname;
const char *body_fname;
/**
* Local implementation which reads resources from individual files. Could be
* more elegant and read from bios.bin, if we understood the fmap.
*/
vb2_error_t vb2ex_read_resource(struct vb2_context *c,
enum vb2_resource_index index, uint32_t offset,
void *buf, uint32_t size)
{
const char *fname;
FILE *f;
int got_size;
/* Get the filename for the resource */
switch (index) {
case VB2_RES_GBB:
fname = gbb_fname;
break;
case VB2_RES_FW_VBLOCK:
fname = vblock_fname;
break;
default:
return VB2_ERROR_UNKNOWN;
}
/* Open file and seek to the requested offset */
f = fopen(fname, "rb");
if (!f)
return VB2_ERROR_UNKNOWN;
if (fseek(f, offset, SEEK_SET)) {
fclose(f);
return VB2_ERROR_UNKNOWN;
}
/* Read data and close file */
got_size = fread(buf, 1, size, f);
fclose(f);
/* Return success if we read everything */
return got_size == size ? VB2_SUCCESS : VB2_ERROR_UNKNOWN;
}
vb2_error_t vb2ex_tpm_clear_owner(struct vb2_context *c)
{
// TODO: implement
return VB2_SUCCESS;
}
/**
* Save non-volatile and/or secure data if needed.
*/
static void save_if_needed(struct vb2_context *c)
{
if (c->flags & VB2_CONTEXT_NVDATA_CHANGED) {
// TODO: implement
c->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
}
if (c->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED) {
// TODO: implement
c->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
}
}
/**
* Verify firmware body
*/
static vb2_error_t hash_body(struct vb2_context *c)
{
uint32_t remaining;
uint8_t block[8192];
uint32_t size;
FILE *f;
vb2_error_t rv;
/* Open the body data */
f = fopen(body_fname, "rb");
if (!f)
return VB2_ERROR_TEST_INPUT_FILE;
/* Start the body hash */
rv = vb2api_init_hash(c, VB2_HASH_TAG_FW_BODY);
if (rv) {
fclose(f);
return rv;
}
remaining = vb2api_get_firmware_size(c);
printf("Expect %d bytes of body...\n", remaining);
/* Extend over the body */
while (remaining) {
size = sizeof(block);
if (size > remaining)
size = remaining;
/* Read next body block */
size = fread(block, 1, size, f);
if (size <= 0)
break;
/* Hash it */
rv = vb2api_extend_hash(c, block, size);
if (rv) {
fclose(f);
return rv;
}
remaining -= size;
}
fclose(f);
/* Check the result */
rv = vb2api_check_hash(c);
if (rv)
return rv;
return VB2_SUCCESS;
}
static void print_help(const char *progname)
{
printf("Usage: %s <gbb> <vblock> <body>\n", progname);
}
int main(int argc, char *argv[])
{
uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
__attribute__((aligned(VB2_WORKBUF_ALIGN)));
struct vb2_context *ctx;
struct vb2_shared_data *sd;
vb2_error_t rv;
if (argc < 4) {
print_help(argv[0]);
return 1;
}
/* Save filenames */
gbb_fname = argv[1];
vblock_fname = argv[2];
body_fname = argv[3];
/* Intialize workbuf with sentinel value to see how much we'll use. */
uint32_t *ptr = (uint32_t *)workbuf;
while ((uint8_t *)ptr + sizeof(*ptr) <= workbuf + sizeof(workbuf))
*ptr++ = 0xbeefdead;
/* Set up context */
if (vb2api_init(workbuf, sizeof(workbuf), &ctx)) {
printf("Failed to initialize workbuf.\n");
return 1;
}
sd = vb2_get_sd(ctx);
/* Initialize secure context */
vb2api_secdata_firmware_create(ctx);
vb2api_secdata_kernel_create(ctx);
// TODO: optional args to set contents for nvdata, secdata?
/* Do early init */
printf("Phase 1...\n");
rv = vb2api_fw_phase1(ctx);
if (rv) {
printf("Phase 1 wants recovery mode.\n");
save_if_needed(ctx);
return rv;
}
/* Determine which firmware slot to boot */
printf("Phase 2...\n");
rv = vb2api_fw_phase2(ctx);
if (rv) {
printf("Phase 2 wants reboot.\n");
save_if_needed(ctx);
return rv;
}
/* Try that slot */
printf("Phase 3...\n");
rv = vb2api_fw_phase3(ctx);
if (rv) {
printf("Phase 3 wants reboot.\n");
save_if_needed(ctx);
return rv;
}
/* Verify body */
printf("Hash body...\n");
rv = hash_body(ctx);
save_if_needed(ctx);
if (rv) {
printf("Phase 4 wants reboot.\n");
return rv;
}
printf("Yaay!\n");
while ((uint8_t *)ptr > workbuf && *--ptr == 0xbeefdead)
/* find last used workbuf offset */;
printf("Workbuf used = %d bytes, high watermark = %zu bytes\n",
sd->workbuf_used, (uint8_t *)ptr + sizeof(*ptr) - workbuf);
return 0;
}