summaryrefslogtreecommitdiff
path: root/futility/cmd_sign.c
diff options
context:
space:
mode:
Diffstat (limited to 'futility/cmd_sign.c')
-rw-r--r--futility/cmd_sign.c244
1 files changed, 135 insertions, 109 deletions
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c
index 2db53136..cae08b2e 100644
--- a/futility/cmd_sign.c
+++ b/futility/cmd_sign.c
@@ -29,11 +29,6 @@
#include "vb1_helper.h"
#include "vboot_common.h"
-/* Local values for cb_area_s._flags */
-enum callback_flags {
- AREA_IS_VALID = 0x00000001,
-};
-
/* Local structure for args, etc. */
static struct local_data_s {
VbPrivateKey *signprivate;
@@ -80,10 +75,45 @@ 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 futil_cb_sign_pubkey(struct futil_traverse_state_s *state)
+int ft_sign_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
{
- VbPublicKey *data_key = (VbPublicKey *)state->my_area->buf;
+ VbPublicKey *data_key = (VbPublicKey *)buf;
VbKeyBlockHeader *vblock;
if (option.pem_signpriv) {
@@ -119,26 +149,30 @@ int futil_cb_sign_pubkey(struct futil_traverse_state_s *state)
}
/*
- * 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.
+ * 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.
*/
-int futil_cb_sign_fw_main(struct futil_traverse_state_s *state)
+static int fmap_fw_main(const char *name, uint8_t *buf, uint32_t len,
+ void *data)
{
- state->my_area->_flags |= AREA_IS_VALID;
+ 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 VBLOCK
- * area contains a firmware preamble.
+ * 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.
*/
-int futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state)
+static int fmap_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
+ void *data)
{
- VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
- uint32_t len = state->my_area->len;
+ 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
@@ -147,33 +181,31 @@ int futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state)
*/
if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
fprintf(stderr, "Warning: %s keyblock is invalid. "
- "Signing the entire FW FMAP region...\n",
- state->name);
+ "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",
- state->name);
+ "Signing the entire FW FMAP region...\n", name);
goto whatever;
}
uint32_t more = key_block->key_block_size;
VbFirmwarePreambleHeader *preamble =
- (VbFirmwarePreambleHeader *)(state->my_area->buf + more);
+ (VbFirmwarePreambleHeader *)(buf + more);
uint32_t fw_size = preamble->body_signature.data_size;
- struct cb_area_s *fw_body_area = 0;
+ struct bios_area_s *fw_body_area = 0;
- switch (state->component) {
- case CB_FMAP_VBLOCK_A:
- fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
+ 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 (!option.flags_specified)
option.flags = preamble->flags;
break;
- case CB_FMAP_VBLOCK_B:
- fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
+ case BIOS_FMAP_VBLOCK_B:
+ fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_B];
break;
default:
DIE;
@@ -182,7 +214,7 @@ int futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state)
if (fw_size > fw_body_area->len) {
fprintf(stderr,
"%s says the firmware is larger than we have\n",
- state->name);
+ name);
return 1;
}
@@ -190,19 +222,20 @@ int futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state)
fw_body_area->len = fw_size;
whatever:
- state->my_area->_flags |= AREA_IS_VALID;
+ state->area[state->c].is_valid = 1;
return 0;
}
-int futil_cb_create_kernel_part(struct futil_traverse_state_s *state)
+int ft_sign_raw_kernel(const char *name, uint8_t *buf, uint32_t len,
+ void *data)
{
uint8_t *vmlinuz_data, *kblob_data, *vblock_data;
uint64_t vmlinuz_size, kblob_size, vblock_size;
int rv;
- vmlinuz_data = state->my_area->buf;
- vmlinuz_size = state->my_area->len;
+ vmlinuz_data = buf;
+ vmlinuz_size = len;
kblob_data = CreateKernelBlob(
vmlinuz_data, vmlinuz_size,
@@ -246,7 +279,8 @@ int futil_cb_create_kernel_part(struct futil_traverse_state_s *state)
return rv;
}
-int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
+int ft_sign_kern_preamble(const char *name, uint8_t *buf, uint32_t len,
+ void *data)
{
uint8_t *kpart_data, *kblob_data, *vblock_data;
uint64_t kpart_size, kblob_size, vblock_size;
@@ -254,8 +288,8 @@ int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
VbKernelPreambleHeader *preamble = NULL;
int rv = 0;
- kpart_data = state->my_area->buf;
- kpart_size = state->my_area->len;
+ kpart_data = buf;
+ kpart_size = len;
/* Note: This just sets some static pointers. It doesn't malloc. */
kblob_data = UnpackKPart(kpart_data, kpart_size, option.padding,
@@ -331,14 +365,14 @@ int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
}
-int futil_cb_sign_raw_firmware(struct futil_traverse_state_s *state)
+int ft_sign_raw_firmware(const char *name, uint8_t *buf, uint32_t len,
+ void *data)
{
VbSignature *body_sig;
VbFirmwarePreambleHeader *preamble;
int rv;
- body_sig = CalculateSignature(state->my_area->buf, state->my_area->len,
- option.signprivate);
+ body_sig = CalculateSignature(buf, len, option.signprivate);
if (!body_sig) {
fprintf(stderr, "Error calculating body signature\n");
return 1;
@@ -366,19 +400,8 @@ int futil_cb_sign_raw_firmware(struct futil_traverse_state_s *state)
}
-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,
+static int write_new_preamble(struct bios_area_s *vblock,
+ struct bios_area_s *fw_body,
VbPrivateKey *signkey,
VbKeyBlockHeader *keyblock)
{
@@ -414,7 +437,7 @@ static int write_new_preamble(struct cb_area_s *vblock,
return 0;
}
-static int write_loem(const char *ab, struct cb_area_s *vblock)
+static int write_loem(const char *ab, struct bios_area_s *vblock)
{
char filename[PATH_MAX];
int n;
@@ -449,19 +472,16 @@ static int write_loem(const char *ab, struct cb_area_s *vblock)
}
/* This signs a full BIOS image after it's been traversed. */
-static int sign_bios_at_end(struct futil_traverse_state_s *state)
+static int sign_bios_at_end(struct sign_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];
+ 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 (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)) {
+ 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;
}
@@ -500,19 +520,53 @@ static int sign_bios_at_end(struct futil_traverse_state_s *state)
return retval;
}
-int futil_cb_sign_end(struct futil_traverse_state_s *state)
+
+int ft_sign_bios(const char *name, uint8_t *buf, uint32_t len, void *data)
{
- switch (state->in_type) {
- case FILE_TYPE_BIOS_IMAGE:
- case FILE_TYPE_OLD_BIOS_IMAGE:
- return sign_bios_at_end(state);
+ FmapHeader *fmap;
+ FmapAreaHeader *ah = 0;
+ char ah_name[FMAP_NAMELEN + 1];
+ int i;
+ int retval = 0;
+ struct sign_state_s state;
- default:
- /* Any other cleanup needed? */
- break;
+ 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);
+ }
}
- return state->errors;
+ retval += sign_bios_at_end(&state);
+
+ return retval;
}
static const char usage_pubkey[] = "\n"
@@ -684,7 +738,7 @@ static void print_help(int argc, char *argv[])
enum no_short_opts {
OPT_FV = 1000,
- OPT_INFILE, /* aka "--vmlinuz" */
+ OPT_INFILE,
OPT_OUTFILE,
OPT_BOOTLOADER,
OPT_CONFIG,
@@ -733,7 +787,6 @@ static int do_sign(int argc, char *argv[])
int i;
int ifd = -1;
int errorcnt = 0;
- struct futil_traverse_state_s state;
uint8_t *buf;
uint32_t buf_len;
char *e = 0;
@@ -808,7 +861,7 @@ static int do_sign(int argc, char *argv[])
case OPT_FV:
option.fv_specified = 1;
/* fallthrough */
- case OPT_INFILE: /* aka "--vmlinuz" */
+ case OPT_INFILE:
inout_file_count++;
infile = optarg;
break;
@@ -959,11 +1012,6 @@ static int do_sign(int argc, char *argv[])
/* Check the arguments for the type of thing we want to sign */
switch (type) {
- case FILE_TYPE_UNKNOWN:
- fprintf(stderr,
- "Unable to determine the type of the input file\n");
- errorcnt++;
- goto done;
case FILE_TYPE_PUBKEY:
option.create_new_outfile = 1;
if (option.signprivate && option.pem_signpriv) {
@@ -986,20 +1034,6 @@ static int do_sign(int argc, char *argv[])
/* We'll wait to read the PEM file, since the external signer
* may want to read it instead. */
break;
- case FILE_TYPE_KEYBLOCK:
- fprintf(stderr, "Resigning a keyblock is kind of pointless.\n");
- fprintf(stderr, "Just create a new one.\n");
- errorcnt++;
- break;
- case FILE_TYPE_FW_PREAMBLE:
- fprintf(stderr,
- "%s IS a signature. Sign the firmware instead\n",
- infile);
- break;
- case FILE_TYPE_GBB:
- fprintf(stderr, "There's no way to sign a GBB\n");
- errorcnt++;
- break;
case FILE_TYPE_BIOS_IMAGE:
case FILE_TYPE_OLD_BIOS_IMAGE:
errorcnt += no_opt_if(!option.signprivate, "signprivate");
@@ -1027,13 +1061,10 @@ static int do_sign(int argc, char *argv[])
errorcnt += no_opt_if(!option.config_data, "config");
errorcnt += no_opt_if(option.arch == ARCH_UNSPECIFIED, "arch");
break;
- case FILE_TYPE_CHROMIUMOS_DISK:
- fprintf(stderr, "Signing a %s is not yet supported\n",
- futil_file_type_desc(type));
- errorcnt++;
- break;
default:
- DIE;
+ fprintf(stderr, "Unable to sign type %s\n",
+ futil_file_type_name(type));
+ errorcnt++;
}
Debug("infile=%s\n", infile);
@@ -1061,13 +1092,9 @@ static int do_sign(int argc, char *argv[])
if (errorcnt)
goto done;
- memset(&state, 0, sizeof(state));
- state.op = FUTIL_OP_SIGN;
-
if (option.create_new_outfile) {
/* The input is read-only, the output is write-only. */
mapping = MAP_RO;
- state.in_filename = infile;
Debug("open RO %s\n", infile);
ifd = open(infile, O_RDONLY);
if (ifd < 0) {
@@ -1079,10 +1106,10 @@ static int do_sign(int argc, char *argv[])
} else {
/* We'll read-modify-write the output file */
mapping = MAP_RW;
- state.in_filename = option.outfile;
if (inout_file_count > 1)
futil_copy_file_or_die(infile, option.outfile);
Debug("open RW %s\n", option.outfile);
+ infile = option.outfile;
ifd = open(option.outfile, O_RDWR);
if (ifd < 0) {
errorcnt++;
@@ -1097,7 +1124,7 @@ static int do_sign(int argc, char *argv[])
goto done;
}
- errorcnt += futil_traverse(buf, buf_len, &state, type);
+ errorcnt += futil_file_type_sign(type, infile, buf, buf_len);
errorcnt += futil_unmap_file(ifd, MAP_RW, buf, buf_len);
@@ -1123,4 +1150,3 @@ done:
DECLARE_FUTIL_COMMAND(sign, do_sign, VBOOT_VERSION_ALL,
"Sign / resign various binary components");
-