summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2015-03-26 16:58:49 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-03-31 06:28:25 +0000
commit091c7b17f09f287da115ca247d39e7128158a581 (patch)
tree32d0dc4ee097290c72946a25762a068825f25487
parent08d52b9bf52fb140b7c77c54bee500c3a59ff69b (diff)
downloadvboot-091c7b17f09f287da115ca247d39e7128158a581.tar.gz
futility: put all the BIOS stuff into a separate file
This moves the functions that handle BIOS file types into a separate set of source files. BIOSes are constructed from other components arranged in particular ways, so they shouldn't be mixed in with the code specifically for those components. BUG=chromium:231574 BRANCH=none TEST=make runtests Signed-off-by: Bill Richardson <wfrichar@chromium.org> Change-Id: I15c3fec61498925f9b8c672092fd97e7ea2d90e9 Reviewed-on: https://chromium-review.googlesource.com/262898 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--Makefile2
-rw-r--r--futility/cmd_show.c224
-rw-r--r--futility/cmd_sign.c287
-rw-r--r--futility/file_type_bios.c521
-rw-r--r--futility/file_type_bios.h42
-rw-r--r--futility/traversal.c53
-rw-r--r--futility/traversal.h38
-rw-r--r--futility/vb1_helper.h5
-rw-r--r--futility/vb2_helper.c1
9 files changed, 574 insertions, 599 deletions
diff --git a/Makefile b/Makefile
index 5f21f32d..108f92c3 100644
--- a/Makefile
+++ b/Makefile
@@ -625,7 +625,7 @@ FUTIL_SRCS = \
futility/cmd_vbutil_key.c \
futility/cmd_vbutil_keyblock.c \
futility/file_type.c \
- futility/traversal.c \
+ futility/file_type_bios.c \
futility/vb1_helper.c \
futility/vb2_helper.c
diff --git a/futility/cmd_show.c b/futility/cmd_show.c
index 714b0e58..44a3ab36 100644
--- a/futility/cmd_show.c
+++ b/futility/cmd_show.c
@@ -20,14 +20,12 @@
#include <sys/types.h>
#include <unistd.h>
-#include "bmpblk_header.h"
#include "file_type.h"
+#include "file_type_bios.h"
#include "fmap.h"
#include "futility.h"
#include "futility_options.h"
-#include "gbb_header.h"
#include "host_common.h"
-#include "traversal.h"
#include "util_misc.h"
#include "vb1_helper.h"
#include "vboot_common.h"
@@ -38,42 +36,7 @@ struct show_option_s show_option = {
.type = FILE_TYPE_UNKNOWN,
};
-/* Stuff for BIOS images. */
-
-/* Forward declarations */
-static int fmap_fw_main(const char *name, uint8_t *buf, uint32_t len,
- void *data);
-
-/* These are the functions we'll call for each FMAP area. */
-static int (*fmap_func[])(const char *name, uint8_t *buf, uint32_t len,
- void *data) = {
- ft_show_gbb,
- fmap_fw_main,
- fmap_fw_main,
- ft_show_fw_preamble,
- ft_show_fw_preamble,
-};
-BUILD_ASSERT(ARRAY_SIZE(fmap_func) == NUM_BIOS_COMPONENTS);
-
-/* Where is the component we're looking at? */
-struct bios_area_s {
- uint32_t offset; /* to avoid pointer math */
- uint8_t *buf;
- uint32_t len;
- uint32_t is_valid;
-};
-
-/* When looking at the FMAP areas, we need to gather some state for later. */
-struct show_state_s {
- /* Current component */
- enum bios_component c;
- /* Other activites, possibly before or after the current one */
- struct bios_area_s area[NUM_BIOS_COMPONENTS];
- struct bios_area_s recovery_key;
- struct bios_area_s rootkey;
-};
-
-static void show_key(VbPublicKey *pubkey, const char *sp)
+void show_pubkey(VbPublicKey *pubkey, const char *sp)
{
printf("%sVboot API: 1.0\n", sp);
printf("%sAlgorithm: %" PRIu64 " %s\n", sp, pubkey->algorithm,
@@ -129,7 +92,7 @@ int ft_show_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
}
printf("Public Key file: %s\n", name);
- show_key(pubkey, " ");
+ show_pubkey(pubkey, " ");
return 0;
}
@@ -166,108 +129,6 @@ int ft_show_privkey(const char *name, uint8_t *buf, uint32_t len, void *data)
return 0;
}
-int ft_show_gbb(const char *name, uint8_t *buf, uint32_t len, void *data)
-{
- GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)buf;
- struct show_state_s *state = (struct show_state_s *)data;
- VbPublicKey *pubkey;
- BmpBlockHeader *bmp;
- int retval = 0;
- uint32_t maxlen = 0;
-
- if (!len) {
- printf("GBB header: %s <invalid>\n", name);
- return 1;
- }
-
- /* It looks like a GBB or we wouldn't be called. */
- if (!futil_valid_gbb_header(gbb, len, &maxlen))
- retval = 1;
-
- printf("GBB header: %s\n", name);
- printf(" Version: %d.%d\n",
- gbb->major_version, gbb->minor_version);
- printf(" Flags: 0x%08x\n", gbb->flags);
- printf(" Regions: offset size\n");
- printf(" hwid 0x%08x 0x%08x\n",
- gbb->hwid_offset, gbb->hwid_size);
- printf(" bmpvf 0x%08x 0x%08x\n",
- gbb->bmpfv_offset, gbb->bmpfv_size);
- printf(" rootkey 0x%08x 0x%08x\n",
- gbb->rootkey_offset, gbb->rootkey_size);
- printf(" recovery_key 0x%08x 0x%08x\n",
- gbb->recovery_key_offset, gbb->recovery_key_size);
-
- printf(" Size: 0x%08x / 0x%08x%s\n",
- maxlen, len, maxlen > len ? " (not enough)" : "");
-
- if (retval) {
- printf("GBB header is invalid, ignoring content\n");
- return 1;
- }
-
- printf("GBB content:\n");
- printf(" HWID: %s\n", buf + gbb->hwid_offset);
- print_hwid_digest(gbb, " digest: ", "\n");
-
- pubkey = (VbPublicKey *)(buf + gbb->rootkey_offset);
- if (PublicKeyLooksOkay(pubkey, gbb->rootkey_size)) {
- if (state) {
- state->rootkey.offset =
- state->area[BIOS_FMAP_GBB].offset +
- gbb->rootkey_offset;
- state->rootkey.buf = buf + gbb->rootkey_offset;
- state->rootkey.len = gbb->rootkey_size;
- state->rootkey.is_valid = 1;
- }
- printf(" Root Key:\n");
- show_key(pubkey, " ");
- } else {
- retval = 1;
- printf(" Root Key: <invalid>\n");
- }
-
- pubkey = (VbPublicKey *)(buf + gbb->recovery_key_offset);
- if (PublicKeyLooksOkay(pubkey, gbb->recovery_key_size)) {
- if (state) {
- state->recovery_key.offset =
- state->area[BIOS_FMAP_GBB].offset +
- gbb->recovery_key_offset;
- state->recovery_key.buf = buf +
- gbb->recovery_key_offset;
- state->recovery_key.len = gbb->recovery_key_size;
- state->recovery_key.is_valid = 1;
- }
- printf(" Recovery Key:\n");
- show_key(pubkey, " ");
- } else {
- retval = 1;
- printf(" Recovery Key: <invalid>\n");
- }
-
- bmp = (BmpBlockHeader *)(buf + gbb->bmpfv_offset);
- if (0 != memcmp(bmp, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE)) {
- printf(" BmpBlock: <invalid>\n");
- /* We don't support older BmpBlock formats, so we can't
- * be strict about this. */
- } else {
- printf(" BmpBlock:\n");
- printf(" Version: %d.%d\n",
- bmp->major_version, bmp->minor_version);
- printf(" Localizations: %d\n",
- bmp->number_of_localizations);
- printf(" Screen layouts: %d\n",
- bmp->number_of_screenlayouts);
- printf(" Image infos: %d\n",
- bmp->number_of_imageinfos);
- }
-
- if (!retval && state)
- state->area[BIOS_FMAP_GBB].is_valid = 1;
-
- return retval;
-}
-
int ft_show_keyblock(const char *name, uint8_t *buf, uint32_t len, void *data)
{
VbKeyBlockHeader *block = (VbKeyBlockHeader *)buf;
@@ -294,38 +155,11 @@ int ft_show_keyblock(const char *name, uint8_t *buf, uint32_t len, void *data)
return retval;
}
-/*
- * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
- *
- * The data is just the RW firmware blob, so there's nothing useful to show
- * about it. We'll just mark it as present so when we encounter corresponding
- * VBLOCK area, we'll have this to verify.
- */
-static int fmap_fw_main(const char *name, uint8_t *buf, uint32_t len,
- void *data)
-{
- struct show_state_s *state = (struct show_state_s *)data;
-
- if (!len) {
- printf("Firmware body: %s <invalid>\n", name);
- return 1;
- }
-
- printf("Firmware body: %s\n", name);
- printf(" Offset: 0x%08x\n",
- state->area[state->c].offset);
- printf(" Size: 0x%08x\n", len);
-
- state->area[state->c].is_valid = 1;
-
- return 0;
-}
-
int ft_show_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
void *data)
{
VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)buf;
- struct show_state_s *state = (struct show_state_s *)data;
+ struct bios_state_s *state = (struct bios_state_s *)data;
VbPublicKey *sign_key = show_option.k;
uint8_t *fv_data = show_option.fv;
uint64_t fv_size = show_option.fv_size;
@@ -346,7 +180,6 @@ int ft_show_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
* so we'll have to get any keys or data from options.
*/
if (state) {
-
if (!sign_key && state->rootkey.is_valid)
/* BIOS should have a rootkey in the GBB */
sign_key = (VbPublicKey *)state->rootkey.buf;
@@ -449,55 +282,6 @@ done:
return retval;
}
-int ft_show_bios(const char *name, uint8_t *buf, uint32_t len, void *data)
-{
- FmapHeader *fmap;
- FmapAreaHeader *ah = 0;
- char ah_name[FMAP_NAMELEN + 1];
- int i;
- int retval = 0;
- struct show_state_s state;
-
- memset(&state, 0, sizeof(state));
-
- printf("BIOS: %s\n", name);
-
- /* We've already checked, so we know this will work. */
- fmap = fmap_find(buf, len);
- for (i = 0; i < NUM_BIOS_COMPONENTS; i++) {
- /* We know one of these will work, too */
- if (fmap_find_by_name(buf, len, fmap,
- bios_area[i].name, &ah) ||
- fmap_find_by_name(buf, len, fmap,
- bios_area[i].oldname, &ah)) {
- /* But the file might be truncated */
- fmap_limit_area(ah, len);
- /* The name is not necessarily null-terminated */
- snprintf(ah_name, sizeof(ah_name), "%s", ah->area_name);
-
- /* Update the state we're passing around */
- state.c = i;
- state.area[i].offset = ah->area_offset;
- state.area[i].buf = buf + ah->area_offset;
- state.area[i].len = ah->area_size;
-
- Debug("%s() showing FMAP area %d (%s),"
- " offset=0x%08x len=0x%08x\n",
- __func__, i, ah_name,
- ah->area_offset, ah->area_size);
-
- /* Go look at it. */
- if (fmap_func[i])
- retval += fmap_func[i](ah_name,
- state.area[i].buf,
- state.area[i].len,
- &state);
- }
- }
-
- return retval;
-}
-
int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len,
void *data)
{
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c
index 47d147f0..9ec99f6f 100644
--- a/futility/cmd_sign.c
+++ b/futility/cmd_sign.c
@@ -17,15 +17,14 @@
#include <sys/types.h>
#include <unistd.h>
-#include "bmpblk_header.h"
#include "file_type.h"
+#include "file_type_bios.h"
#include "fmap.h"
#include "futility.h"
#include "futility_options.h"
#include "gbb_header.h"
#include "host_common.h"
#include "kernel_blob.h"
-#include "traversal.h"
#include "util_misc.h"
#include "vb1_helper.h"
#include "vboot_common.h"
@@ -49,41 +48,6 @@ static int no_opt_if(int expr, const char *optname)
return 0;
}
-/* Stuff for BIOS images */
-
-/* Forward declarations */
-static int fmap_fw_main(const char *name, uint8_t *buf, uint32_t len,
- void *data);
-static int fmap_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
- void *data);
-
-/* These are the functions we'll call for each FMAP area. */
-static int (*fmap_func[])(const char *name, uint8_t *buf, uint32_t len,
- void *data) = {
- 0,
- fmap_fw_main,
- fmap_fw_main,
- fmap_fw_preamble,
- fmap_fw_preamble,
-};
-BUILD_ASSERT(ARRAY_SIZE(fmap_func) == NUM_BIOS_COMPONENTS);
-
-/* Where is the component we're looking at? */
-struct bios_area_s {
- uint8_t *buf;
- uint32_t len;
- uint32_t is_valid;
-};
-
-/* When looking at the FMAP areas, we need to gather some state for later. */
-struct sign_state_s {
- /* Current component */
- enum bios_component c;
- /* Other activites, possibly before or after the current one */
- struct bios_area_s area[NUM_BIOS_COMPONENTS];
-};
-
-
/* This wraps/signs a public key, producing a keyblock. */
int ft_sign_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
{
@@ -124,85 +88,6 @@ int ft_sign_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
NULL, 0);
}
-/*
- * This handles FW_MAIN_A and FW_MAIN_B while signing a BIOS image. The data is
- * just the RW firmware blob so there's nothing useful to do with it, but we'll
- * mark it as valid so that we'll know that this FMAP area exists and can
- * be signed.
- */
-static int fmap_fw_main(const char *name, uint8_t *buf, uint32_t len,
- void *data)
-{
- struct sign_state_s *state = (struct sign_state_s *)data;
- state->area[state->c].is_valid = 1;
- return 0;
-}
-
-/*
- * This handles VBLOCK_A and VBLOCK_B while processing a BIOS image. We don't
- * do any signing here. We just check to see if the existing FMAP area contains
- * a firmware preamble so we can preserve its contents. We do the signing once
- * we've looked over all the components.
- */
-static int fmap_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
- void *data)
-{
- VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)buf;
- struct sign_state_s *state = (struct sign_state_s *)data;
-
- /*
- * If we have a valid keyblock and fw_preamble, then we can use them to
- * determine the size of the firmware body. Otherwise, we'll have to
- * just sign the whole region.
- */
- if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
- fprintf(stderr, "Warning: %s keyblock is invalid. "
- "Signing the entire FW FMAP region...\n", name);
- goto whatever;
- }
-
- RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
- if (!rsa) {
- fprintf(stderr, "Warning: %s public key is invalid. "
- "Signing the entire FW FMAP region...\n", name);
- goto whatever;
- }
- uint32_t more = key_block->key_block_size;
- VbFirmwarePreambleHeader *preamble =
- (VbFirmwarePreambleHeader *)(buf + more);
- uint32_t fw_size = preamble->body_signature.data_size;
- struct bios_area_s *fw_body_area = 0;
-
- switch (state->c) {
- case BIOS_FMAP_VBLOCK_A:
- fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_A];
- /* Preserve the flags if they're not specified */
- if (!sign_option.flags_specified)
- sign_option.flags = preamble->flags;
- break;
- case BIOS_FMAP_VBLOCK_B:
- fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_B];
- break;
- default:
- DIE;
- }
-
- if (fw_size > fw_body_area->len) {
- fprintf(stderr,
- "%s says the firmware is larger than we have\n",
- name);
- return 1;
- }
-
- /* Update the firmware size */
- fw_body_area->len = fw_size;
-
-whatever:
- state->area[state->c].is_valid = 1;
-
- return 0;
-}
-
int ft_sign_raw_kernel(const char *name, uint8_t *buf, uint32_t len,
void *data)
{
@@ -383,176 +268,6 @@ int ft_sign_raw_firmware(const char *name, uint8_t *buf, uint32_t len,
return rv;
}
-
-static int write_new_preamble(struct bios_area_s *vblock,
- struct bios_area_s *fw_body,
- VbPrivateKey *signkey,
- VbKeyBlockHeader *keyblock)
-{
- VbSignature *body_sig;
- VbFirmwarePreambleHeader *preamble;
-
- body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
- if (!body_sig) {
- fprintf(stderr, "Error calculating body signature\n");
- return 1;
- }
-
- preamble = CreateFirmwarePreamble(sign_option.version,
- sign_option.kernel_subkey,
- body_sig,
- signkey,
- sign_option.flags);
- if (!preamble) {
- fprintf(stderr, "Error creating firmware preamble.\n");
- free(body_sig);
- return 1;
- }
-
- /* Write the new keyblock */
- uint32_t more = keyblock->key_block_size;
- memcpy(vblock->buf, keyblock, more);
- /* and the new preamble */
- memcpy(vblock->buf + more, preamble, preamble->preamble_size);
-
- free(preamble);
- free(body_sig);
-
- return 0;
-}
-
-static int write_loem(const char *ab, struct bios_area_s *vblock)
-{
- char filename[PATH_MAX];
- int n;
- n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
- sign_option.loemdir ? sign_option.loemdir : ".",
- ab, sign_option.loemid);
- if (n >= sizeof(filename)) {
- fprintf(stderr, "LOEM args produce bogus filename\n");
- return 1;
- }
-
- FILE *fp = fopen(filename, "w");
- if (!fp) {
- fprintf(stderr, "Can't open %s for writing: %s\n",
- filename, strerror(errno));
- return 1;
- }
-
- if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
- fprintf(stderr, "Can't write to %s: %s\n",
- filename, strerror(errno));
- fclose(fp);
- return 1;
- }
- if (fclose(fp)) {
- fprintf(stderr, "Failed closing loem output: %s\n",
- strerror(errno));
- return 1;
- }
-
- return 0;
-}
-
-/* This signs a full BIOS image after it's been traversed. */
-static int sign_bios_at_end(struct sign_state_s *state)
-{
- struct bios_area_s *vblock_a = &state->area[BIOS_FMAP_VBLOCK_A];
- struct bios_area_s *vblock_b = &state->area[BIOS_FMAP_VBLOCK_B];
- struct bios_area_s *fw_a = &state->area[BIOS_FMAP_FW_MAIN_A];
- struct bios_area_s *fw_b = &state->area[BIOS_FMAP_FW_MAIN_B];
- int retval = 0;
-
- if (!vblock_a->is_valid || !vblock_b->is_valid ||
- !fw_a->is_valid || !fw_b->is_valid) {
- fprintf(stderr, "Something's wrong. Not changing anything\n");
- return 1;
- }
-
- /* Do A & B differ ? */
- if (fw_a->len != fw_b->len ||
- memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
- /* Yes, must use DEV keys for A */
- if (!sign_option.devsignprivate || !sign_option.devkeyblock) {
- fprintf(stderr,
- "FW A & B differ. DEV keys are required.\n");
- return 1;
- }
- retval |= write_new_preamble(vblock_a, fw_a,
- sign_option.devsignprivate,
- sign_option.devkeyblock);
- } else {
- retval |= write_new_preamble(vblock_a, fw_a,
- sign_option.signprivate,
- sign_option.keyblock);
- }
-
- /* FW B is always normal keys */
- retval |= write_new_preamble(vblock_b, fw_b,
- sign_option.signprivate,
- sign_option.keyblock);
-
-
-
-
- if (sign_option.loemid) {
- retval |= write_loem("A", vblock_a);
- retval |= write_loem("B", vblock_b);
- }
-
- return retval;
-}
-
-
-int ft_sign_bios(const char *name, uint8_t *buf, uint32_t len, void *data)
-{
- FmapHeader *fmap;
- FmapAreaHeader *ah = 0;
- char ah_name[FMAP_NAMELEN + 1];
- int i;
- int retval = 0;
- struct sign_state_s state;
-
- memset(&state, 0, sizeof(state));
-
- /* We've already checked, so we know this will work. */
- fmap = fmap_find(buf, len);
- for (i = 0; i < NUM_BIOS_COMPONENTS; i++) {
- /* We know one of these will work, too */
- if (fmap_find_by_name(buf, len, fmap,
- bios_area[i].name, &ah) ||
- fmap_find_by_name(buf, len, fmap,
- bios_area[i].oldname, &ah)) {
- /* But the file might be truncated */
- fmap_limit_area(ah, len);
- /* The name is not necessarily null-terminated */
- snprintf(ah_name, sizeof(ah_name), "%s", ah->area_name);
-
- /* Update the state we're passing around */
- state.c = i;
- state.area[i].buf = buf + ah->area_offset;
- state.area[i].len = ah->area_size;
-
- Debug("%s() examining FMAP area %d (%s),"
- " offset=0x%08x len=0x%08x\n",
- __func__, i, ah_name,
- ah->area_offset, ah->area_size);
-
- /* Go look at it, but abort on error */
- if (fmap_func[i])
- retval += fmap_func[i](ah_name,
- state.area[i].buf,
- state.area[i].len,
- &state);
- }
- }
-
- retval += sign_bios_at_end(&state);
-
- return retval;
-}
-
static const char usage_pubkey[] = "\n"
"To sign a public key / create a new keyblock:\n"
"\n"
diff --git a/futility/file_type_bios.c b/futility/file_type_bios.c
new file mode 100644
index 00000000..247bb3f9
--- /dev/null
+++ b/futility/file_type_bios.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright 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.
+ */
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "bmpblk_header.h"
+#include "fmap.h"
+#include "file_type.h"
+#include "file_type_bios.h"
+#include "futility.h"
+#include "futility_options.h"
+#include "gbb_header.h"
+#include "host_common.h"
+#include "vb1_helper.h"
+
+static const char * const fmap_name[] = {
+ "GBB", /* BIOS_FMAP_GBB */
+ "FW_MAIN_A", /* BIOS_FMAP_FW_MAIN_A */
+ "FW_MAIN_B", /* BIOS_FMAP_FW_MAIN_B */
+ "VBLOCK_A", /* BIOS_FMAP_VBLOCK_A */
+ "VBLOCK_B", /* BIOS_FMAP_VBLOCK_B */
+};
+BUILD_ASSERT(ARRAY_SIZE(fmap_name) == NUM_BIOS_COMPONENTS);
+
+static const char * const fmap_oldname[] = {
+ "GBB Area", /* BIOS_FMAP_GBB */
+ "Firmware A Data", /* BIOS_FMAP_FW_MAIN_A */
+ "Firmware B Data", /* BIOS_FMAP_FW_MAIN_B */
+ "Firmware A Key", /* BIOS_FMAP_VBLOCK_A */
+ "Firmware B Key", /* BIOS_FMAP_VBLOCK_B */
+};
+BUILD_ASSERT(ARRAY_SIZE(fmap_oldname) == NUM_BIOS_COMPONENTS);
+
+static void fmap_limit_area(FmapAreaHeader *ah, uint32_t len)
+{
+ uint32_t sum = ah->area_offset + ah->area_size;
+ if (sum < ah->area_size || sum > len) {
+ Debug("%s(%s) 0x%x + 0x%x > 0x%x\n",
+ __func__, ah->area_name,
+ ah->area_offset, ah->area_size, len);
+ ah->area_offset = 0;
+ ah->area_size = 0;
+ }
+}
+
+/** Show functions **/
+
+int ft_show_gbb(const char *name, uint8_t *buf, uint32_t len, void *data)
+{
+ GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)buf;
+ struct bios_state_s *state = (struct bios_state_s *)data;
+ VbPublicKey *pubkey;
+ BmpBlockHeader *bmp;
+ int retval = 0;
+ uint32_t maxlen = 0;
+
+ if (!len) {
+ printf("GBB header: %s <invalid>\n", name);
+ return 1;
+ }
+
+ /* It looks like a GBB or we wouldn't be called. */
+ if (!futil_valid_gbb_header(gbb, len, &maxlen))
+ retval = 1;
+
+ printf("GBB header: %s\n", name);
+ printf(" Version: %d.%d\n",
+ gbb->major_version, gbb->minor_version);
+ printf(" Flags: 0x%08x\n", gbb->flags);
+ printf(" Regions: offset size\n");
+ printf(" hwid 0x%08x 0x%08x\n",
+ gbb->hwid_offset, gbb->hwid_size);
+ printf(" bmpvf 0x%08x 0x%08x\n",
+ gbb->bmpfv_offset, gbb->bmpfv_size);
+ printf(" rootkey 0x%08x 0x%08x\n",
+ gbb->rootkey_offset, gbb->rootkey_size);
+ printf(" recovery_key 0x%08x 0x%08x\n",
+ gbb->recovery_key_offset, gbb->recovery_key_size);
+
+ printf(" Size: 0x%08x / 0x%08x%s\n",
+ maxlen, len, maxlen > len ? " (not enough)" : "");
+
+ if (retval) {
+ printf("GBB header is invalid, ignoring content\n");
+ return 1;
+ }
+
+ printf("GBB content:\n");
+ printf(" HWID: %s\n", buf + gbb->hwid_offset);
+ print_hwid_digest(gbb, " digest: ", "\n");
+
+ pubkey = (VbPublicKey *)(buf + gbb->rootkey_offset);
+ if (PublicKeyLooksOkay(pubkey, gbb->rootkey_size)) {
+ if (state) {
+ state->rootkey.offset =
+ state->area[BIOS_FMAP_GBB].offset +
+ gbb->rootkey_offset;
+ state->rootkey.buf = buf + gbb->rootkey_offset;
+ state->rootkey.len = gbb->rootkey_size;
+ state->rootkey.is_valid = 1;
+ }
+ printf(" Root Key:\n");
+ show_pubkey(pubkey, " ");
+ } else {
+ retval = 1;
+ printf(" Root Key: <invalid>\n");
+ }
+
+ pubkey = (VbPublicKey *)(buf + gbb->recovery_key_offset);
+ if (PublicKeyLooksOkay(pubkey, gbb->recovery_key_size)) {
+ if (state) {
+ state->recovery_key.offset =
+ state->area[BIOS_FMAP_GBB].offset +
+ gbb->recovery_key_offset;
+ state->recovery_key.buf = buf +
+ gbb->recovery_key_offset;
+ state->recovery_key.len = gbb->recovery_key_size;
+ state->recovery_key.is_valid = 1;
+ }
+ printf(" Recovery Key:\n");
+ show_pubkey(pubkey, " ");
+ } else {
+ retval = 1;
+ printf(" Recovery Key: <invalid>\n");
+ }
+
+ bmp = (BmpBlockHeader *)(buf + gbb->bmpfv_offset);
+ if (0 != memcmp(bmp, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE)) {
+ printf(" BmpBlock: <invalid>\n");
+ /* We don't support older BmpBlock formats, so we can't
+ * be strict about this. */
+ } else {
+ printf(" BmpBlock:\n");
+ printf(" Version: %d.%d\n",
+ bmp->major_version, bmp->minor_version);
+ printf(" Localizations: %d\n",
+ bmp->number_of_localizations);
+ printf(" Screen layouts: %d\n",
+ bmp->number_of_screenlayouts);
+ printf(" Image infos: %d\n",
+ bmp->number_of_imageinfos);
+ }
+
+ if (!retval && state)
+ state->area[BIOS_FMAP_GBB].is_valid = 1;
+
+ return retval;
+}
+
+/*
+ * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
+ *
+ * The data is just the RW firmware blob, so there's nothing useful to show
+ * about it. We'll just mark it as present so when we encounter corresponding
+ * VBLOCK area, we'll have this to verify.
+ */
+static int fmap_show_fw_main(const char *name, uint8_t *buf, uint32_t len,
+ void *data)
+{
+ struct bios_state_s *state = (struct bios_state_s *)data;
+
+ if (!len) {
+ printf("Firmware body: %s <invalid>\n", name);
+ return 1;
+ }
+
+ printf("Firmware body: %s\n", name);
+ printf(" Offset: 0x%08x\n",
+ state->area[state->c].offset);
+ printf(" Size: 0x%08x\n", len);
+
+ state->area[state->c].is_valid = 1;
+
+ return 0;
+}
+
+/* Functions to call to show the bios components */
+static int (*fmap_show_fn[])(const char *name, uint8_t *buf, uint32_t len,
+ void *data) = {
+ ft_show_gbb,
+ fmap_show_fw_main,
+ fmap_show_fw_main,
+ ft_show_fw_preamble,
+ ft_show_fw_preamble,
+};
+BUILD_ASSERT(ARRAY_SIZE(fmap_show_fn) == NUM_BIOS_COMPONENTS);
+
+int ft_show_bios(const char *name, uint8_t *buf, uint32_t len, void *data)
+{
+ FmapHeader *fmap;
+ FmapAreaHeader *ah = 0;
+ char ah_name[FMAP_NAMELEN + 1];
+ enum bios_component c;
+ int retval = 0;
+ struct bios_state_s state;
+
+ memset(&state, 0, sizeof(state));
+
+ printf("BIOS: %s\n", name);
+
+ /* We've already checked, so we know this will work. */
+ fmap = fmap_find(buf, len);
+ for (c = 0; c < NUM_BIOS_COMPONENTS; c++) {
+ /* We know one of these will work, too */
+ if (fmap_find_by_name(buf, len, fmap, fmap_name[c], &ah) ||
+ fmap_find_by_name(buf, len, fmap, fmap_oldname[c], &ah)) {
+ /* But the file might be truncated */
+ fmap_limit_area(ah, len);
+ /* The name is not necessarily null-terminated */
+ snprintf(ah_name, sizeof(ah_name), "%s", ah->area_name);
+
+ /* Update the state we're passing around */
+ state.c = c;
+ state.area[c].offset = ah->area_offset;
+ state.area[c].buf = buf + ah->area_offset;
+ state.area[c].len = ah->area_size;
+
+ Debug("%s() showing FMAP area %d (%s),"
+ " offset=0x%08x len=0x%08x\n",
+ __func__, c, ah_name,
+ ah->area_offset, ah->area_size);
+
+ /* Go look at it. */
+ if (fmap_show_fn[c])
+ retval += fmap_show_fn[c](ah_name,
+ state.area[c].buf,
+ state.area[c].len,
+ &state);
+ }
+ }
+
+ return retval;
+}
+
+/** Sign functions **/
+
+/*
+ * This handles FW_MAIN_A and FW_MAIN_B while signing a BIOS image. The data is
+ * just the RW firmware blob so there's nothing useful to do with it, but we'll
+ * mark it as valid so that we'll know that this FMAP area exists and can
+ * be signed.
+ */
+static int fmap_sign_fw_main(const char *name, uint8_t *buf, uint32_t len,
+ void *data)
+{
+ struct bios_state_s *state = (struct bios_state_s *)data;
+ state->area[state->c].is_valid = 1;
+ return 0;
+}
+
+/*
+ * This handles VBLOCK_A and VBLOCK_B while processing a BIOS image. We don't
+ * do any signing here. We just check to see if the existing FMAP area contains
+ * a firmware preamble so we can preserve its contents. We do the signing once
+ * we've looked over all the components.
+ */
+static int fmap_sign_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
+ void *data)
+{
+ VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)buf;
+ struct bios_state_s *state = (struct bios_state_s *)data;
+
+ /*
+ * If we have a valid keyblock and fw_preamble, then we can use them to
+ * determine the size of the firmware body. Otherwise, we'll have to
+ * just sign the whole region.
+ */
+ if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
+ fprintf(stderr, "Warning: %s keyblock is invalid. "
+ "Signing the entire FW FMAP region...\n", name);
+ goto whatever;
+ }
+
+ RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
+ if (!rsa) {
+ fprintf(stderr, "Warning: %s public key is invalid. "
+ "Signing the entire FW FMAP region...\n", name);
+ goto whatever;
+ }
+ uint32_t more = key_block->key_block_size;
+ VbFirmwarePreambleHeader *preamble =
+ (VbFirmwarePreambleHeader *)(buf + more);
+ uint32_t fw_size = preamble->body_signature.data_size;
+ struct bios_area_s *fw_body_area = 0;
+
+ switch (state->c) {
+ case BIOS_FMAP_VBLOCK_A:
+ fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_A];
+ /* Preserve the flags if they're not specified */
+ if (!sign_option.flags_specified)
+ sign_option.flags = preamble->flags;
+ break;
+ case BIOS_FMAP_VBLOCK_B:
+ fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_B];
+ break;
+ default:
+ DIE;
+ }
+
+ if (fw_size > fw_body_area->len) {
+ fprintf(stderr,
+ "%s says the firmware is larger than we have\n",
+ name);
+ return 1;
+ }
+
+ /* Update the firmware size */
+ fw_body_area->len = fw_size;
+
+whatever:
+ state->area[state->c].is_valid = 1;
+
+ return 0;
+}
+
+static int write_new_preamble(struct bios_area_s *vblock,
+ struct bios_area_s *fw_body,
+ VbPrivateKey *signkey,
+ VbKeyBlockHeader *keyblock)
+{
+ VbSignature *body_sig;
+ VbFirmwarePreambleHeader *preamble;
+
+ body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
+ if (!body_sig) {
+ fprintf(stderr, "Error calculating body signature\n");
+ return 1;
+ }
+
+ preamble = CreateFirmwarePreamble(sign_option.version,
+ sign_option.kernel_subkey,
+ body_sig,
+ signkey,
+ sign_option.flags);
+ if (!preamble) {
+ fprintf(stderr, "Error creating firmware preamble.\n");
+ free(body_sig);
+ return 1;
+ }
+
+ /* Write the new keyblock */
+ uint32_t more = keyblock->key_block_size;
+ memcpy(vblock->buf, keyblock, more);
+ /* and the new preamble */
+ memcpy(vblock->buf + more, preamble, preamble->preamble_size);
+
+ free(preamble);
+ free(body_sig);
+
+ return 0;
+}
+
+static int write_loem(const char *ab, struct bios_area_s *vblock)
+{
+ char filename[PATH_MAX];
+ int n;
+ n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
+ sign_option.loemdir ? sign_option.loemdir : ".",
+ ab, sign_option.loemid);
+ if (n >= sizeof(filename)) {
+ fprintf(stderr, "LOEM args produce bogus filename\n");
+ return 1;
+ }
+
+ FILE *fp = fopen(filename, "w");
+ if (!fp) {
+ fprintf(stderr, "Can't open %s for writing: %s\n",
+ filename, strerror(errno));
+ return 1;
+ }
+
+ if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
+ fprintf(stderr, "Can't write to %s: %s\n",
+ filename, strerror(errno));
+ fclose(fp);
+ return 1;
+ }
+ if (fclose(fp)) {
+ fprintf(stderr, "Failed closing loem output: %s\n",
+ strerror(errno));
+ return 1;
+ }
+
+ return 0;
+}
+
+/* This signs a full BIOS image after it's been traversed. */
+static int sign_bios_at_end(struct bios_state_s *state)
+{
+ struct bios_area_s *vblock_a = &state->area[BIOS_FMAP_VBLOCK_A];
+ struct bios_area_s *vblock_b = &state->area[BIOS_FMAP_VBLOCK_B];
+ struct bios_area_s *fw_a = &state->area[BIOS_FMAP_FW_MAIN_A];
+ struct bios_area_s *fw_b = &state->area[BIOS_FMAP_FW_MAIN_B];
+ int retval = 0;
+
+ if (!vblock_a->is_valid || !vblock_b->is_valid ||
+ !fw_a->is_valid || !fw_b->is_valid) {
+ fprintf(stderr, "Something's wrong. Not changing anything\n");
+ return 1;
+ }
+
+ /* Do A & B differ ? */
+ if (fw_a->len != fw_b->len ||
+ memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
+ /* Yes, must use DEV keys for A */
+ if (!sign_option.devsignprivate || !sign_option.devkeyblock) {
+ fprintf(stderr,
+ "FW A & B differ. DEV keys are required.\n");
+ return 1;
+ }
+ retval |= write_new_preamble(vblock_a, fw_a,
+ sign_option.devsignprivate,
+ sign_option.devkeyblock);
+ } else {
+ retval |= write_new_preamble(vblock_a, fw_a,
+ sign_option.signprivate,
+ sign_option.keyblock);
+ }
+
+ /* FW B is always normal keys */
+ retval |= write_new_preamble(vblock_b, fw_b,
+ sign_option.signprivate,
+ sign_option.keyblock);
+
+
+
+
+ if (sign_option.loemid) {
+ retval |= write_loem("A", vblock_a);
+ retval |= write_loem("B", vblock_b);
+ }
+
+ return retval;
+}
+
+/* Functions to call while preparing to sign the bios */
+static int (*fmap_sign_fn[])(const char *name, uint8_t *buf, uint32_t len,
+ void *data) = {
+ 0,
+ fmap_sign_fw_main,
+ fmap_sign_fw_main,
+ fmap_sign_fw_preamble,
+ fmap_sign_fw_preamble,
+};
+BUILD_ASSERT(ARRAY_SIZE(fmap_sign_fn) == NUM_BIOS_COMPONENTS);
+
+int ft_sign_bios(const char *name, uint8_t *buf, uint32_t len, void *data)
+{
+ FmapHeader *fmap;
+ FmapAreaHeader *ah = 0;
+ char ah_name[FMAP_NAMELEN + 1];
+ enum bios_component c;
+ int retval = 0;
+ struct bios_state_s state;
+
+ memset(&state, 0, sizeof(state));
+
+ /* We've already checked, so we know this will work. */
+ fmap = fmap_find(buf, len);
+ for (c = 0; c < NUM_BIOS_COMPONENTS; c++) {
+ /* We know one of these will work, too */
+ if (fmap_find_by_name(buf, len, fmap, fmap_name[c], &ah) ||
+ fmap_find_by_name(buf, len, fmap, fmap_oldname[c], &ah)) {
+ /* But the file might be truncated */
+ fmap_limit_area(ah, len);
+ /* The name is not necessarily null-terminated */
+ snprintf(ah_name, sizeof(ah_name), "%s", ah->area_name);
+
+ /* Update the state we're passing around */
+ state.c = c;
+ state.area[c].buf = buf + ah->area_offset;
+ state.area[c].len = ah->area_size;
+
+ Debug("%s() examining FMAP area %d (%s),"
+ " offset=0x%08x len=0x%08x\n",
+ __func__, c, ah_name,
+ ah->area_offset, ah->area_size);
+
+ /* Go look at it, but abort on error */
+ if (fmap_sign_fn[c])
+ retval += fmap_sign_fn[c](ah_name,
+ state.area[c].buf,
+ state.area[c].len,
+ &state);
+ }
+ }
+
+ retval += sign_bios_at_end(&state);
+
+ return retval;
+}
+
+enum futil_file_type ft_recognize_bios_image(uint8_t *buf, uint32_t len)
+{
+ FmapHeader *fmap;
+ enum bios_component c;
+
+ fmap = fmap_find(buf, len);
+ if (!fmap)
+ return FILE_TYPE_UNKNOWN;
+
+ for (c = 0; c < NUM_BIOS_COMPONENTS; c++)
+ if (!fmap_find_by_name(buf, len, fmap, fmap_name[c], 0))
+ break;
+ if (c == NUM_BIOS_COMPONENTS)
+ return FILE_TYPE_BIOS_IMAGE;
+
+ for (c = 0; c < NUM_BIOS_COMPONENTS; c++)
+ if (!fmap_find_by_name(buf, len, fmap, fmap_oldname[c], 0))
+ break;
+ if (c == NUM_BIOS_COMPONENTS)
+ return FILE_TYPE_OLD_BIOS_IMAGE;
+
+ return FILE_TYPE_UNKNOWN;
+}
diff --git a/futility/file_type_bios.h b/futility/file_type_bios.h
new file mode 100644
index 00000000..3cd2e797
--- /dev/null
+++ b/futility/file_type_bios.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013 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.
+ */
+#ifndef VBOOT_REFERENCE_FUTILITY_FILE_TYPE_BIOS_H_
+#define VBOOT_REFERENCE_FUTILITY_FILE_TYPE_BIOS_H_
+#include <stdint.h>
+
+/*
+ * The Chrome OS BIOS must contain specific FMAP areas, which we want to look
+ * at in a certain order.
+ */
+enum bios_component {
+ BIOS_FMAP_GBB,
+ BIOS_FMAP_FW_MAIN_A,
+ BIOS_FMAP_FW_MAIN_B,
+ BIOS_FMAP_VBLOCK_A,
+ BIOS_FMAP_VBLOCK_B,
+
+ NUM_BIOS_COMPONENTS
+};
+
+/* Location information for each component */
+struct bios_area_s {
+ uint32_t offset; /* to avoid pointer math */
+ uint8_t *buf;
+ uint32_t len;
+ uint32_t is_valid;
+};
+
+/* State to track as we visit all components */
+struct bios_state_s {
+ /* Current component */
+ enum bios_component c;
+ /* Other activites, possibly before or after the current one */
+ struct bios_area_s area[NUM_BIOS_COMPONENTS];
+ struct bios_area_s recovery_key;
+ struct bios_area_s rootkey;
+};
+
+#endif /* VBOOT_REFERENCE_FUTILITY_FILE_TYPE_BIOS_H_ */
diff --git a/futility/traversal.c b/futility/traversal.c
deleted file mode 100644
index 99cc477c..00000000
--- a/futility/traversal.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "fmap.h"
-#include "file_type.h"
-#include "futility.h"
-#include "traversal.h"
-
-/* These are the expected areas, in order of traversal */
-struct bios_fmap_s bios_area[] = {
- {BIOS_FMAP_GBB, "GBB", "GBB Area"},
- {BIOS_FMAP_FW_MAIN_A, "FW_MAIN_A", "Firmware A Data"},
- {BIOS_FMAP_FW_MAIN_B, "FW_MAIN_B", "Firmware B Data"},
- {BIOS_FMAP_VBLOCK_A, "VBLOCK_A", "Firmware A Key"},
- {BIOS_FMAP_VBLOCK_B, "VBLOCK_B", "Firmware B Key"},
-};
-BUILD_ASSERT(ARRAY_SIZE(bios_area) == NUM_BIOS_COMPONENTS);
-
-
-void fmap_limit_area(FmapAreaHeader *ah, uint32_t len)
-{
- uint32_t sum = ah->area_offset + ah->area_size;
- if (sum < ah->area_size || sum > len) {
- Debug("%s(%s) 0x%x + 0x%x > 0x%x\n",
- __func__, ah->area_name,
- ah->area_offset, ah->area_size, len);
- ah->area_offset = 0;
- ah->area_size = 0;
- }
-}
-
-enum futil_file_type ft_recognize_bios_image(uint8_t *buf, uint32_t len)
-{
- FmapHeader *fmap;
- int i;
-
- fmap = fmap_find(buf, len);
- if (!fmap)
- return FILE_TYPE_UNKNOWN;
-
- for (i = 0; i < NUM_BIOS_COMPONENTS; i++)
- if (!fmap_find_by_name(buf, len, fmap,
- bios_area[i].name, 0))
- break;
- if (i == NUM_BIOS_COMPONENTS)
- return FILE_TYPE_BIOS_IMAGE;
-
- for (i = 0; i < NUM_BIOS_COMPONENTS; i++)
- if (!fmap_find_by_name(buf, len, fmap,
- bios_area[i].oldname, 0))
- break;
- if (i == NUM_BIOS_COMPONENTS)
- return FILE_TYPE_OLD_BIOS_IMAGE;
-
- return FILE_TYPE_UNKNOWN;
-}
diff --git a/futility/traversal.h b/futility/traversal.h
deleted file mode 100644
index cb2052d0..00000000
--- a/futility/traversal.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2013 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.
- */
-#ifndef VBOOT_REFERENCE_FUTILITY_TRAVERSAL_H_
-#define VBOOT_REFERENCE_FUTILITY_TRAVERSAL_H_
-#include <stdint.h>
-#include "fmap.h"
-
-/*
- * The Chrome OS BIOS must contain specific FMAP areas, and we generally want
- * to look at each one in a certain order.
- */
-enum bios_component {
- BIOS_FMAP_GBB,
- BIOS_FMAP_FW_MAIN_A,
- BIOS_FMAP_FW_MAIN_B,
- BIOS_FMAP_VBLOCK_A,
- BIOS_FMAP_VBLOCK_B,
-
- NUM_BIOS_COMPONENTS
-};
-
-/* These are the expected areas, in order of traversal */
-extern struct bios_fmap_s {
- enum bios_component component;
- const char * const name;
- /* The Cr-48 BIOS images have different FMAP names but work the same,
- * so we allow those too. */
- const char * const oldname;
-} bios_area[];
-
-
-void fmap_limit_area(FmapAreaHeader *ah, uint32_t len);
-
-
-#endif /* VBOOT_REFERENCE_FUTILITY_TRAVERSAL_H_ */
diff --git a/futility/vb1_helper.h b/futility/vb1_helper.h
index 2cf71f4e..59732e7a 100644
--- a/futility/vb1_helper.h
+++ b/futility/vb1_helper.h
@@ -6,6 +6,11 @@
#ifndef VBOOT_REFERENCE_FUTILITY_VB1_HELPER_H_
#define VBOOT_REFERENCE_FUTILITY_VB1_HELPER_H_
+/* Display a public key with variable indentation */
+void show_pubkey(VbPublicKey *pubkey, const char *sp);
+
+/* Other random functions needed for backward compatibility */
+
uint8_t *ReadConfigFile(const char *config_file, uint64_t *config_size);
uint8_t *CreateKernelBlob(uint8_t *vmlinuz_buf, uint64_t vmlinuz_size,
diff --git a/futility/vb2_helper.c b/futility/vb2_helper.c
index c6ffbb75..c10190ff 100644
--- a/futility/vb2_helper.c
+++ b/futility/vb2_helper.c
@@ -21,7 +21,6 @@
#include "file_type.h"
#include "futility.h"
-#include "traversal.h"
enum futil_file_type ft_recognize_vb2_key(uint8_t *buf, uint32_t len)
{