diff options
author | Bill Richardson <wfrichar@chromium.org> | 2014-09-02 14:45:44 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-09-05 09:58:35 +0000 |
commit | 15dc6fc5eabc1b1756aca1dbed38cb9d26259bf2 (patch) | |
tree | a57df2077761907ad87e7c369f8d5b2605963059 /futility | |
parent | 64ddad77e58b9892c72f49977f479a585dce095c (diff) | |
download | vboot-15dc6fc5eabc1b1756aca1dbed38cb9d26259bf2.tar.gz |
futility: add "sign" command to resign firmware images
The "sign" command can perform the same operation as the old
resign_firmwarefd.sh script, only about 20 times faster. The
test for that will use the new command instead.
BUG=chromium:224734
BRANCH=ToT
TEST=make runtests
Change-Id: Ie7f7a0ab6fc00d7e06cb263733bf6e7246fdb023
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/216227
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'futility')
-rw-r--r-- | futility/cmd_show.c | 4 | ||||
-rw-r--r-- | futility/cmd_sign.c | 457 | ||||
-rw-r--r-- | futility/futility.h | 7 | ||||
-rw-r--r-- | futility/misc.c | 125 | ||||
-rw-r--r-- | futility/traversal.c | 67 | ||||
-rw-r--r-- | futility/traversal.h | 12 |
6 files changed, 633 insertions, 39 deletions
diff --git a/futility/cmd_show.c b/futility/cmd_show.c index 24d41fde..ac43bbf8 100644 --- a/futility/cmd_show.c +++ b/futility/cmd_show.c @@ -166,7 +166,7 @@ int futil_cb_show_gbb(struct futil_traverse_state_s *state) bmp = (BmpBlockHeader *)(buf + gbb->bmpfv_offset); if (0 != memcmp(bmp, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE)) { - retval = 1; + /* We don't support old formats, so it's not always an error */ printf(" BmpBlock: <invalid>\n"); } else { printf(" BmpBlock:\n"); @@ -461,7 +461,7 @@ static int do_show(int argc, char *argv[]) state.in_filename = infile ? infile : "<none>"; state.op = FUTIL_OP_SHOW; - errorcnt += futil_traverse(ifd, &state); + errorcnt += futil_traverse(ifd, &state, 0); if (close(ifd)) { errorcnt++; diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c new file mode 100644 index 00000000..41f3d9f7 --- /dev/null +++ b/futility/cmd_sign.c @@ -0,0 +1,457 @@ +/* + * 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 <fcntl.h> +#include <getopt.h> +#include <inttypes.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include "bmpblk_header.h" +#include "fmap.h" +#include "futility.h" +#include "gbb_header.h" +#include "host_common.h" +#include "traversal.h" +#include "util_misc.h" +#include "vboot_common.h" + +/* Local values for cb_area_s._flags */ +enum callback_flags { + AREA_IS_VALID = 0x00000001, +}; + +/* Local structure for args, etc. */ +struct local_data_s { + VbPrivateKey *signprivate; + VbKeyBlockHeader *keyblock; + VbPublicKey *kernel_subkey; + VbPrivateKey *devsignprivate; + VbKeyBlockHeader *devkeyblock; + uint32_t version; + uint32_t flags; + char *loemdir; + char *loemid; +} option = { + .version = 1, +}; + + +int futil_cb_sign_bogus(struct futil_traverse_state_s *state) +{ + fprintf(stderr, "Don't know how to sign %s\n", state->name); + return 1; +} + +int futil_cb_sign_notyet(struct futil_traverse_state_s *state) +{ + fprintf(stderr, "Signing %s is not yet implemented\n", state->name); + return 1; +} + +/* + * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image. + * + * The data in state->my_area 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. + */ +int futil_cb_sign_fw_main(struct futil_traverse_state_s *state) +{ + state->my_area->_flags |= AREA_IS_VALID; + return 0; +} + + +int futil_cb_sign_fw_preamble(struct futil_traverse_state_s *state) +{ + VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf; + struct cb_area_s *fw_body_area = 0; + + /* We don't (yet) handle standalone VBLOCKs */ + if (state->component == CB_FW_PREAMBLE) + return futil_cb_sign_notyet(state); + + /* + * We've already checked the Keyblock hash and taken a look at the + * preamble or we wouldn't be here. + */ + + uint32_t more = key_block->key_block_size; + VbFirmwarePreambleHeader *preamble = + (VbFirmwarePreambleHeader *)(state->my_area->buf + more); + uint32_t fw_size = preamble->body_signature.data_size; + + switch (state->component) { + case CB_FMAP_VBLOCK_A: + fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A]; + break; + case CB_FMAP_VBLOCK_B: + fw_body_area = &state->cb_area[CB_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", + state->name); + return 1; + } + + /* Update the firmware size */ + fw_body_area->len = fw_size; + + state->my_area->_flags |= AREA_IS_VALID; + + return 0; +} + +int futil_cb_sign_begin(struct futil_traverse_state_s *state) +{ + if (state->in_type == FILE_TYPE_UNKNOWN) { + fprintf(stderr, "Unable to determine type of %s\n", + state->in_filename); + return 1; + } + + return 0; +} + +static int write_new_preamble(struct cb_area_s *vblock, + struct cb_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(option.version, + option.kernel_subkey, + body_sig, + signkey, + 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 cb_area_s *vblock) +{ + char filename[PATH_MAX]; + int n; + n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s", + option.loemdir ? option.loemdir : ".", + ab, 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; +} + +int futil_cb_sign_end(struct futil_traverse_state_s *state) +{ + struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A]; + struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B]; + struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A]; + struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B]; + int retval = 0; + + if (state->errors || + !(vblock_a->_flags & AREA_IS_VALID) || + !(vblock_b->_flags & AREA_IS_VALID) || + !(fw_a->_flags & AREA_IS_VALID) || + !(fw_b->_flags & AREA_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 (!option.devsignprivate || !option.devkeyblock) { + fprintf(stderr, + "FW A & B differ. DEV keys are required.\n"); + return 1; + } + retval |= write_new_preamble(vblock_a, fw_a, + option.devsignprivate, + option.devkeyblock); + } else { + retval |= write_new_preamble(vblock_a, fw_a, + option.signprivate, + option.keyblock); + } + + /* FW B is always normal keys */ + retval |= write_new_preamble(vblock_b, fw_b, + option.signprivate, + option.keyblock); + + + + + if (option.loemid) { + retval |= write_loem("A", vblock_a); + retval |= write_loem("B", vblock_b); + } + + return retval; +} + +static const char usage[] = "\n" + "Usage: " MYNAME " %s [OPTIONS] FILE [OUTFILE]\n" + "\n" + "[Re]Sign the specified BIOS image\n" + "\n" + "Required OPTIONS:\n" + " -s|--signprivate FILE.vbprivk The private firmware data key\n" + " -b|--keyblock FILE.keyblock The keyblock containing the\n" + " public firmware data key\n" + " -k|--kernelkey FILE.vbpubk The public kernel subkey\n" + "\n" + "These are required if the A and B firmware differ:\n" + " -S|--devsign FILE.vbprivk The DEV private firmware data key\n" + " -B|--devkeyblock FILE.keyblock The keyblock containing the\n" + " DEV public firmware data key\n" + "\n" + "Optional OPTIONS:\n" + " -v|--version NUM The firmware version number (%d)\n" + " -f|--flags NUM The preamble flags value (%d)\n" + " -d|--loemdir DIR Local OEM output vblock directory\n" + " -l|--loemid STRING Local OEM vblock suffix\n" + "\n"; + +static void help_and_quit(const char *prog) +{ + fprintf(stderr, usage, prog, option.version, option.flags); + exit(1); +} + +static const struct option long_opts[] = { + /* name hasarg *flag val */ + {"signprivate", 1, NULL, 's'}, + {"keyblock", 1, NULL, 'b'}, + {"kernelkey", 1, NULL, 'k'}, + {"devsign", 1, NULL, 'S'}, + {"devkeyblock", 1, NULL, 'B'}, + {"version", 1, NULL, 'v'}, + {"flags", 1, NULL, 'f'}, + {"loemdir", 1, NULL, 'd'}, + {"loemid", 1, NULL, 'l'}, + {NULL, 0, NULL, 0}, +}; +static char *short_opts = ":s:b:k:S:B:v:f:d:l:"; + +static int do_sign(int argc, char *argv[]) +{ + char *infile = 0; + char *outfile = 0; + int fd, i; + int errorcnt = 0; + struct futil_traverse_state_s state; + char *e = 0; + + opterr = 0; /* quiet, you */ + while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) { + switch (i) { + case 's': + option.signprivate = PrivateKeyRead(optarg); + if (!option.signprivate) { + fprintf(stderr, "Error reading %s\n", optarg); + errorcnt++; + } + break; + case 'b': + option.keyblock = KeyBlockRead(optarg); + if (!option.keyblock) { + fprintf(stderr, "Error reading %s\n", optarg); + errorcnt++; + } + break; + case 'k': + option.kernel_subkey = PublicKeyRead(optarg); + if (!option.kernel_subkey) { + fprintf(stderr, "Error reading %s\n", optarg); + errorcnt++; + } + break; + case 'S': + option.devsignprivate = PrivateKeyRead(optarg); + if (!option.devsignprivate) { + fprintf(stderr, "Error reading %s\n", optarg); + errorcnt++; + } + break; + case 'B': + option.devkeyblock = KeyBlockRead(optarg); + if (!option.devkeyblock) { + fprintf(stderr, "Error reading %s\n", optarg); + errorcnt++; + } + break; + case 'v': + option.version = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, + "Invalid --version \"%s\"\n", optarg); + errorcnt++; + } + break; + + case 'f': + option.flags = strtoul(optarg, &e, 0); + if (!*optarg || (e && *e)) { + fprintf(stderr, + "Invalid --flags \"%s\"\n", optarg); + errorcnt++; + } + case 'd': + option.loemdir = optarg; + break; + case 'l': + option.loemid = optarg; + break; + + case '?': + if (optopt) + fprintf(stderr, "Unrecognized option: -%c\n", + optopt); + else + fprintf(stderr, "Unrecognized option\n"); + errorcnt++; + break; + case ':': + fprintf(stderr, "Missing argument to -%c\n", optopt); + errorcnt++; + break; + default: + DIE; + } + } + + if (!option.signprivate) { + fprintf(stderr, + "Missing required private firmware data key\n"); + errorcnt++; + } + + if (!option.keyblock) { + fprintf(stderr, + "Missing required keyblock\n"); + errorcnt++; + } + + if (!option.kernel_subkey) { + fprintf(stderr, + "Missing required kernel subkey\n"); + errorcnt++; + } + + if (errorcnt) + help_and_quit(argv[0]); + + switch (argc - optind) { + case 2: + infile = argv[optind++]; + outfile = argv[optind++]; + copy_file_or_die(infile, outfile); + break; + case 1: + /* Stomping right on it. Errors will leave it garbled. */ + /* TODO: Use a tempfile (mkstemp) for normal files. */ + infile = argv[optind++]; + outfile = infile; + break; + case 0: + fprintf(stderr, "ERROR: missing input filename\n"); + help_and_quit(argv[0]); + break; + default: + fprintf(stderr, "ERROR: too many arguments left over\n"); + help_and_quit(argv[0]); + } + + + fd = open(outfile, O_RDWR); + if (fd < 0) { + fprintf(stderr, "Can't open %s: %s\n", + outfile, strerror(errno)); + return 1; + } + + memset(&state, 0, sizeof(state)); + state.in_filename = outfile ? outfile : "<none>"; + state.op = FUTIL_OP_SIGN; + + errorcnt += futil_traverse(fd, &state, 1); + + if (close(fd)) { + errorcnt++; + fprintf(stderr, "Error when closing %s: %s\n", + outfile, strerror(errno)); + } + + if (option.signprivate) + free(option.signprivate); + if (option.keyblock) + free(option.keyblock); + if (option.kernel_subkey) + free(option.kernel_subkey); + + return !!errorcnt; +} + +DECLARE_FUTIL_COMMAND(sign, do_sign, "[Re]Sign a BIOS image"); diff --git a/futility/futility.h b/futility/futility.h index 8c2b809b..03b4cb57 100644 --- a/futility/futility.h +++ b/futility/futility.h @@ -71,4 +71,11 @@ int futil_looks_like_gbb(GoogleBinaryBlockHeader *gbb, uint32_t len); int futil_valid_gbb_header(GoogleBinaryBlockHeader *gbb, uint32_t len, uint32_t *maxlen); +/* Copies a file or dies with an error message */ +void copy_file_or_die(const char *infile, const char *outfile); + +/* Wrapper for mmap/munmap. Returns 0 on success. Skips stupidly large files. */ +int map_it(int fd, int writeable, void **buf, uint32_t *len); +int unmap_it(int fd, int writeable, void *buf, uint32_t len); + #endif /* VBOOT_REFERENCE_FUTILITY_H_ */ diff --git a/futility/misc.c b/futility/misc.c index 91962cbd..22e45165 100644 --- a/futility/misc.c +++ b/futility/misc.c @@ -4,8 +4,16 @@ * found in the LICENSE file. */ +#include <errno.h> #include <stdint.h> +#include <stdio.h> +#include <stdlib.h> #include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> #include "gbb_header.h" @@ -88,3 +96,120 @@ int futil_valid_gbb_header(GoogleBinaryBlockHeader *gbb, uint32_t len, /* Seems legit... */ return 1; } + + +/* + * TODO: All sorts of race conditions likely here, and everywhere this is used. + * Do we care? If so, fix it. + */ +void copy_file_or_die(const char *infile, const char *outfile) +{ + pid_t pid; + int status; + + pid = fork(); + + if (pid < 0) { + fprintf(stderr, "Couldn't fork /bin/cp process: %s\n", + strerror(errno)); + exit(1); + } + + /* child */ + if (!pid) { + execl("/bin/cp", "/bin/cp", infile, outfile, NULL); + fprintf(stderr, "Child couldn't exec /bin/cp: %s\n", + strerror(errno)); + exit(1); + } + + /* parent - wait for child to finish */ + if (wait(&status) == -1) { + fprintf(stderr, + "Couldn't wait for /bin/cp process to exit: %s\n", + strerror(errno)); + exit(1); + } + + if (WIFEXITED(status)) { + status = WEXITSTATUS(status); + /* zero is normal exit */ + if (!status) + return; + fprintf(stderr, "/bin/cp exited with status %d\n", status); + exit(1); + } + + if (WIFSIGNALED(status)) + { + status = WTERMSIG(status); + fprintf(stderr, "/bin/cp was killed with signal %d\n", status); + exit(1); + } + + fprintf(stderr, "I have no idea what just happened\n"); + exit(1); +} + + +int map_it(int fd, int writeable, void **buf, uint32_t *len) +{ + struct stat sb; + void *mmap_ptr; + uint32_t reasonable_len; + + if (0 != fstat(fd, &sb)) { + fprintf(stderr, "Can't stat input file: %s\n", + strerror(errno)); + return 1; + } + + if (!S_ISREG(sb.st_mode)) { + fprintf(stderr, "Block devices are not yet supported\n"); + return 1; + } + + /* If the image is larger than 2^32 bytes, it's wrong. */ + if (sb.st_size < 0 || sb.st_size > UINT32_MAX) { + fprintf(stderr, "Image size is unreasonable\n"); + return 1; + } + reasonable_len = (uint32_t)sb.st_size; + + if (writeable) + mmap_ptr = mmap(0, sb.st_size, + PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + else + mmap_ptr = mmap(0, sb.st_size, + PROT_READ, MAP_PRIVATE, fd, 0); + + if (mmap_ptr == (void *)-1) { + fprintf(stderr, "Can't mmap %s file: %s\n", + writeable ? "output" : "input", + strerror(errno)); + return 1; + } + + *buf = mmap_ptr; + *len = reasonable_len; + return 0; +} + +int unmap_it(int fd, int writeable, void *buf, uint32_t len) +{ + int errorcnt = 0; + + if (writeable && + (0 != msync(buf, len, MS_SYNC|MS_INVALIDATE))) { + fprintf(stderr, "msync failed: %s\n", strerror(errno)); + errorcnt++; + } + + if (0 != munmap(buf, len)) { + fprintf(stderr, "Can't munmap pointer: %s\n", + strerror(errno)); + errorcnt++; + } + + return errorcnt; +} diff --git a/futility/traversal.c b/futility/traversal.c index 81303d9d..7f58b74f 100644 --- a/futility/traversal.c +++ b/futility/traversal.c @@ -8,14 +8,12 @@ #include <stdint.h> #include <stdio.h> #include <string.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> #include <unistd.h> #include "fmap.h" #include "futility.h" #include "gbb_header.h" +#include "host_common.h" #include "host_key.h" #include "traversal.h" @@ -38,9 +36,27 @@ static int (* const cb_show_funcs[])(struct futil_traverse_state_s *state) = }; BUILD_ASSERT(ARRAY_SIZE(cb_show_funcs) == NUM_CB_COMPONENTS); +/* FUTIL_OP_SIGN */ +static int (* const cb_sign_funcs[])(struct futil_traverse_state_s *state) = +{ + futil_cb_sign_begin, /* CB_BEGIN_TRAVERSAL */ + futil_cb_sign_end, /* CB_END_TRAVERSAL */ + NULL, /* CB_FMAP_GBB */ + futil_cb_sign_fw_preamble, /* CB_FMAP_VBLOCK_A */ + futil_cb_sign_fw_preamble, /* CB_FMAP_VBLOCK_B */ + futil_cb_sign_fw_main, /* CB_FMAP_FW_MAIN_A */ + futil_cb_sign_fw_main, /* CB_FMAP_FW_MAIN_B */ + futil_cb_sign_bogus, /* CB_PUBKEY */ + futil_cb_sign_notyet, /* CB_KEYBLOCK */ + futil_cb_sign_bogus, /* CB_GBB */ + futil_cb_sign_fw_preamble, /* CB_FW_PREAMBLE */ +}; +BUILD_ASSERT(ARRAY_SIZE(cb_sign_funcs) == NUM_CB_COMPONENTS); + static int (* const * const cb_func[])(struct futil_traverse_state_s *state) = { cb_show_funcs, + cb_sign_funcs, }; BUILD_ASSERT(ARRAY_SIZE(cb_func) == NUM_FUTIL_OPS); @@ -49,6 +65,11 @@ static int invoke_callback(struct futil_traverse_state_s *state, enum futil_cb_component c, const char *name, uint32_t offset, uint8_t *buf, uint32_t len) { + + VBDEBUG(("%s: name \"%s\" op %d component %d" + " offset=0x%08x len=0x%08x, buf=%p\n", + __func__, name, state->op, c, offset, len, buf)); + if (c < 0 || c >= NUM_CB_COMPONENTS) { fprintf(stderr, "Invalid component %d\n", c); return 1; @@ -242,11 +263,11 @@ static int traverse_buffer(uint8_t *buf, uint32_t len, return retval; } -int futil_traverse(int ifd, struct futil_traverse_state_s *state) +int futil_traverse(int ifd, struct futil_traverse_state_s *state, + int writeable) { - struct stat sb; - void *mmap_ptr; - uint32_t reasonable_len; + void *mmap_ptr = 0; + uint32_t len; int errorcnt = 0; if (state->op < 0 || state->op >= NUM_FUTIL_OPS) { @@ -254,38 +275,12 @@ int futil_traverse(int ifd, struct futil_traverse_state_s *state) return 1; } - if (0 != fstat(ifd, &sb)) { - fprintf(stderr, "Can't stat input file: %s\n", - strerror(errno)); - return 1; - } - - if (!S_ISREG(sb.st_mode)) { - fprintf(stderr, "Block devices are not yet supported\n"); + if (0 != map_it(ifd, writeable, &mmap_ptr, &len)) return 1; - } - - /* If the image is larger than 2^32 bytes, it's wrong. */ - if (sb.st_size < 0 || sb.st_size > UINT32_MAX) { - fprintf(stderr, "Image size is unreasonable\n"); - return 1; - } - reasonable_len = (uint32_t)sb.st_size; - mmap_ptr = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, ifd, 0); - if (mmap_ptr == (void *)-1) { - fprintf(stderr, "Can't mmap input file: %s\n", - strerror(errno)); - return 1; - } + errorcnt |= traverse_buffer(mmap_ptr, len, state); - errorcnt += traverse_buffer(mmap_ptr, reasonable_len, state); - - if (0 != munmap(mmap_ptr, sb.st_size)) { - fprintf(stderr, "Can't munmap pointer: %s\n", - strerror(errno)); - errorcnt++; - } + errorcnt |= unmap_it(ifd, writeable, mmap_ptr, len); return errorcnt; } diff --git a/futility/traversal.h b/futility/traversal.h index ca31978a..48bc3b6a 100644 --- a/futility/traversal.h +++ b/futility/traversal.h @@ -24,6 +24,7 @@ enum futil_file_type { /* What are we trying to accomplish? */ enum futil_op_type { FUTIL_OP_SHOW, + FUTIL_OP_SIGN, NUM_FUTIL_OPS }; @@ -77,7 +78,8 @@ struct futil_traverse_state_s { * Traverse the input file using the provided state * Return nonzero (but no details) if there were any errors. */ -int futil_traverse(int ifd, struct futil_traverse_state_s *state); +int futil_traverse(int ifd, struct futil_traverse_state_s *state, + int writeable); /* These are invoked by the traversal. They also return nonzero on error. */ int futil_cb_show_begin(struct futil_traverse_state_s *state); @@ -87,4 +89,12 @@ int futil_cb_show_keyblock(struct futil_traverse_state_s *state); int futil_cb_show_fw_main(struct futil_traverse_state_s *state); int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state); +int futil_cb_sign_bogus(struct futil_traverse_state_s *state); +int futil_cb_sign_notyet(struct futil_traverse_state_s *state); +int futil_cb_sign_fw_main(struct futil_traverse_state_s *state); +int futil_cb_sign_fw_preamble(struct futil_traverse_state_s *state); +int futil_cb_sign_begin(struct futil_traverse_state_s *state); +int futil_cb_sign_end(struct futil_traverse_state_s *state); + + #endif /* VBOOT_REFERENCE_FUTILITY_TRAVERSAL_H_ */ |