summaryrefslogtreecommitdiff
path: root/futility/cmd_vb2_verify_fw.c
diff options
context:
space:
mode:
Diffstat (limited to 'futility/cmd_vb2_verify_fw.c')
-rw-r--r--futility/cmd_vb2_verify_fw.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/futility/cmd_vb2_verify_fw.c b/futility/cmd_vb2_verify_fw.c
new file mode 100644
index 00000000..7343d7a4
--- /dev/null
+++ b/futility/cmd_vb2_verify_fw.c
@@ -0,0 +1,219 @@
+/* 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 "2sysincludes.h"
+#include "2api.h"
+#include "futility.h"
+
+const char *progname = "vb2_verify_fw";
+
+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.
+ */
+int vb2ex_read_resource(struct vb2_context *ctx,
+ 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;
+}
+
+int vb2ex_tpm_clear_owner(struct vb2_context *ctx)
+{
+ // TODO: implement
+ return VB2_SUCCESS;
+}
+
+/**
+ * Save non-volatile and/or secure data if needed.
+ */
+void save_if_needed(struct vb2_context *ctx)
+{
+
+ if (ctx->flags & VB2_CONTEXT_NVDATA_CHANGED) {
+ // TODO: implement
+ ctx->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
+ }
+
+ if (ctx->flags & VB2_CONTEXT_SECDATA_CHANGED) {
+ // TODO: implement
+ ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED;
+ }
+}
+
+/**
+ * Verify firmware body
+ */
+int hash_body(struct vb2_context *ctx)
+{
+ uint32_t expect_size;
+ uint8_t block[8192];
+ uint32_t size;
+ FILE *f;
+ int rv;
+
+ /* Open the body data */
+ f = fopen(body_fname, "rb");
+
+ /* Start the body hash */
+ rv = vb2api_init_hash(ctx, VB2_HASH_TAG_FW_BODY, &expect_size);
+ if (rv)
+ return rv;
+
+ printf("Expect %d bytes of body...\n", expect_size);
+
+ /* Extend over the body */
+ while (expect_size) {
+ size = sizeof(block);
+ if (size > expect_size)
+ size = expect_size;
+
+ /* Read next body block */
+ size = fread(block, 1, size, f);
+ if (size <= 0)
+ break;
+
+ /* Hash it */
+ rv = vb2api_extend_hash(ctx, block, size);
+ if (rv)
+ return rv;
+
+ expect_size -= size;
+ }
+
+ /* Check the result */
+ rv = vb2api_check_hash(ctx);
+ if (rv)
+ return rv;
+
+ return VB2_SUCCESS;
+}
+
+int do_vb2_verify_fw(int argc, char *argv[])
+{
+ struct vb2_context ctx;
+ uint8_t workbuf[16384];
+ int rv;
+
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ progname++;
+ else
+ progname = argv[0];
+
+ if (argc < 4) {
+ fprintf(stderr,
+ "usage: %s <gbb> <vblock> <body>\n", progname);
+ return 1;
+ }
+
+ /* Save filenames */
+ gbb_fname = argv[1];
+ vblock_fname = argv[2];
+ body_fname = argv[3];
+
+ /* Set up context */
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.workbuf = workbuf;
+ ctx.workbuf_size = sizeof(workbuf);
+
+ /* Initialize secure context */
+ rv = vb2api_secdata_create(&ctx);
+ if (rv) {
+ fprintf(stderr,
+ "error: vb2api_secdata_create() failed (%d)\n", rv);
+ return 1;
+ }
+
+ // 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");
+
+ printf("Workbuf used = %d bytes\n", ctx.workbuf_used);
+
+ return 0;
+}
+
+DECLARE_FUTIL_COMMAND(vb2_verify_fw, do_vb2_verify_fw,
+ "Verifies firmware using vboot2 library");