mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-08 16:41:55 +00:00
futility: refactor to handle each file type individually
Instead of calling futil_traverse() to iterate through a preset list of functions, this establishes a separate show() and sign() function for each type of file. The only significant change is that walking through the FMAP areas within BIOS images is done in BIOS-specific functions instead of that being the "normal" case with every other type of file skipping that traversal. This is a refactoring only. There is no externally visible change. BUG=chromium:231574 BRANCH=none TEST=make runtests Signed-off-by: Bill Richardson <wfrichar@chromium.org> Change-Id: I7080afb43e35308c8bb618793c8382c2efb3d6a1 Reviewed-on: https://chromium-review.googlesource.com/262894 Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
committed by
ChromeOS Commit Bot
parent
35c69cc159
commit
6ea2f72d03
@@ -31,11 +31,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 {
|
||||
VbPublicKey *k;
|
||||
@@ -48,6 +43,41 @@ static struct local_data_s {
|
||||
.padding = 65536,
|
||||
};
|
||||
|
||||
/* 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)
|
||||
{
|
||||
printf("%sVboot API: 1.0\n", sp);
|
||||
@@ -94,34 +124,37 @@ static void show_keyblock(VbKeyBlockHeader *key_block, const char *name,
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int futil_cb_show_pubkey(struct futil_traverse_state_s *state)
|
||||
int ft_show_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
|
||||
{
|
||||
VbPublicKey *pubkey = (VbPublicKey *)state->my_area->buf;
|
||||
VbPublicKey *pubkey = (VbPublicKey *)buf;
|
||||
|
||||
if (!PublicKeyLooksOkay(pubkey, state->my_area->len)) {
|
||||
printf("%s looks bogus\n", state->name);
|
||||
if (!PublicKeyLooksOkay(pubkey, len)) {
|
||||
printf("%s looks bogus\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Public Key file: %s\n", state->in_filename);
|
||||
printf("Public Key file: %s\n", name);
|
||||
show_key(pubkey, " ");
|
||||
|
||||
state->my_area->_flags |= AREA_IS_VALID;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int futil_cb_show_privkey(struct futil_traverse_state_s *state)
|
||||
int ft_show_privkey(const char *name, uint8_t *buf, uint32_t len, void *data)
|
||||
{
|
||||
VbPrivateKey key;
|
||||
const unsigned char *start;
|
||||
int len, alg_okay;
|
||||
int alg_okay;
|
||||
|
||||
key.algorithm = *(typeof(key.algorithm) *)state->my_area->buf;
|
||||
start = state->my_area->buf + sizeof(key.algorithm);
|
||||
len = state->my_area->len - sizeof(key.algorithm);
|
||||
key.algorithm = *(typeof(key.algorithm) *)buf;
|
||||
start = buf + sizeof(key.algorithm);
|
||||
if (len <= sizeof(key.algorithm)) {
|
||||
printf("%s looks bogus\n", name);
|
||||
return 1;
|
||||
}
|
||||
len -= sizeof(key.algorithm);
|
||||
key.rsa_private_key = d2i_RSAPrivateKey(NULL, &start, len);
|
||||
|
||||
printf("Private Key file: %s\n", state->in_filename);
|
||||
printf("Private Key file: %s\n", name);
|
||||
printf(" Vboot API: 1.0\n");
|
||||
alg_okay = key.algorithm < kNumAlgorithms;
|
||||
printf(" Algorithm: %" PRIu64 " %s\n", key.algorithm,
|
||||
@@ -135,26 +168,20 @@ int futil_cb_show_privkey(struct futil_traverse_state_s *state)
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (alg_okay)
|
||||
state->my_area->_flags |= AREA_IS_VALID;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int futil_cb_show_gbb(struct futil_traverse_state_s *state)
|
||||
int ft_show_gbb(const char *name, uint8_t *buf, uint32_t len, void *data)
|
||||
{
|
||||
uint8_t *buf = state->my_area->buf;
|
||||
uint32_t len = state->my_area->len;
|
||||
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",
|
||||
state->component == CB_GBB ?
|
||||
state->in_filename : state->name);
|
||||
printf("GBB header: %s <invalid>\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -162,8 +189,7 @@ int futil_cb_show_gbb(struct futil_traverse_state_s *state)
|
||||
if (!futil_valid_gbb_header(gbb, len, &maxlen))
|
||||
retval = 1;
|
||||
|
||||
printf("GBB header: %s\n",
|
||||
state->component == CB_GBB ? state->in_filename : state->name);
|
||||
printf("GBB header: %s\n", name);
|
||||
printf(" Version: %d.%d\n",
|
||||
gbb->major_version, gbb->minor_version);
|
||||
printf(" Flags: 0x%08x\n", gbb->flags);
|
||||
@@ -191,11 +217,14 @@ int futil_cb_show_gbb(struct futil_traverse_state_s *state)
|
||||
|
||||
pubkey = (VbPublicKey *)(buf + gbb->rootkey_offset);
|
||||
if (PublicKeyLooksOkay(pubkey, gbb->rootkey_size)) {
|
||||
state->rootkey.offset = state->my_area->offset +
|
||||
gbb->rootkey_offset;
|
||||
state->rootkey.buf = buf + gbb->rootkey_offset;
|
||||
state->rootkey.len = gbb->rootkey_size;
|
||||
state->rootkey._flags |= AREA_IS_VALID;
|
||||
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 {
|
||||
@@ -205,11 +234,15 @@ int futil_cb_show_gbb(struct futil_traverse_state_s *state)
|
||||
|
||||
pubkey = (VbPublicKey *)(buf + gbb->recovery_key_offset);
|
||||
if (PublicKeyLooksOkay(pubkey, gbb->recovery_key_size)) {
|
||||
state->recovery_key.offset = state->my_area->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._flags |= AREA_IS_VALID;
|
||||
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 {
|
||||
@@ -234,36 +267,34 @@ int futil_cb_show_gbb(struct futil_traverse_state_s *state)
|
||||
bmp->number_of_imageinfos);
|
||||
}
|
||||
|
||||
if (!retval)
|
||||
state->my_area->_flags |= AREA_IS_VALID;
|
||||
if (!retval && state)
|
||||
state->area[BIOS_FMAP_GBB].is_valid = 1;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int futil_cb_show_keyblock(struct futil_traverse_state_s *state)
|
||||
int ft_show_keyblock(const char *name, uint8_t *buf, uint32_t len, void *data)
|
||||
{
|
||||
VbKeyBlockHeader *block = (VbKeyBlockHeader *)state->my_area->buf;
|
||||
VbKeyBlockHeader *block = (VbKeyBlockHeader *)buf;
|
||||
VbPublicKey *sign_key = option.k;
|
||||
int good_sig = 0;
|
||||
int retval = 0;
|
||||
|
||||
/* Check the hash only first */
|
||||
if (0 != KeyBlockVerify(block, state->my_area->len, NULL, 1)) {
|
||||
printf("%s is invalid\n", state->name);
|
||||
if (0 != KeyBlockVerify(block, len, NULL, 1)) {
|
||||
printf("%s is invalid\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check the signature if we have one */
|
||||
if (sign_key && VBOOT_SUCCESS ==
|
||||
KeyBlockVerify(block, state->my_area->len, sign_key, 0))
|
||||
KeyBlockVerify(block, len, sign_key, 0))
|
||||
good_sig = 1;
|
||||
|
||||
if (option.strict && (!sign_key || !good_sig))
|
||||
retval = 1;
|
||||
|
||||
show_keyblock(block, state->in_filename, !!sign_key, good_sig);
|
||||
|
||||
state->my_area->_flags |= AREA_IS_VALID;
|
||||
show_keyblock(block, name, !!sign_key, good_sig);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@@ -271,63 +302,64 @@ int futil_cb_show_keyblock(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.
|
||||
* 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.
|
||||
*/
|
||||
int futil_cb_show_fw_main(struct futil_traverse_state_s *state)
|
||||
static int fmap_fw_main(const char *name, uint8_t *buf, uint32_t len,
|
||||
void *data)
|
||||
{
|
||||
if (!state->my_area->len) {
|
||||
printf("Firmware body: %s <invalid>\n", state->name);
|
||||
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", state->name);
|
||||
printf(" Offset: 0x%08x\n", state->my_area->offset);
|
||||
printf(" Size: 0x%08x\n", state->my_area->len);
|
||||
printf("Firmware body: %s\n", name);
|
||||
printf(" Offset: 0x%08x\n",
|
||||
state->area[state->c].offset);
|
||||
printf(" Size: 0x%08x\n", len);
|
||||
|
||||
state->my_area->_flags |= AREA_IS_VALID;
|
||||
state->area[state->c].is_valid = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state)
|
||||
int ft_show_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 show_state_s *state = (struct show_state_s *)data;
|
||||
VbPublicKey *sign_key = option.k;
|
||||
uint8_t *fv_data = option.fv;
|
||||
uint64_t fv_size = option.fv_size;
|
||||
struct cb_area_s *fw_body_area = 0;
|
||||
struct bios_area_s *fw_body_area = 0;
|
||||
int good_sig = 0;
|
||||
int retval = 0;
|
||||
|
||||
/* Check the hash... */
|
||||
if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
|
||||
printf("%s keyblock component is invalid\n", state->name);
|
||||
printf("%s keyblock component is invalid\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (state->component) {
|
||||
case CB_FMAP_VBLOCK_A:
|
||||
if (!sign_key && (state->rootkey._flags & AREA_IS_VALID))
|
||||
/*
|
||||
* If we're being invoked while poking through a BIOS, we should
|
||||
* be given the keys and data to verify as part of the state. If we
|
||||
* have no state, then we're just looking at a standalone fw_preamble,
|
||||
* 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;
|
||||
/* And we should have already seen the firmware body */
|
||||
fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
|
||||
break;
|
||||
case CB_FMAP_VBLOCK_B:
|
||||
if (!sign_key && (state->rootkey._flags & AREA_IS_VALID))
|
||||
/* BIOS should have a rootkey in the GBB */
|
||||
sign_key = (VbPublicKey *)state->rootkey.buf;
|
||||
/* And we should have already seen the firmware body */
|
||||
fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
|
||||
break;
|
||||
case CB_FW_PREAMBLE:
|
||||
/* We have to provide a signature and body in the options. */
|
||||
break;
|
||||
default:
|
||||
DIE;
|
||||
/* Identify the firmware body for this VBLOCK */
|
||||
enum bios_component body_c = state->c == BIOS_FMAP_VBLOCK_A
|
||||
? BIOS_FMAP_FW_MAIN_A
|
||||
: BIOS_FMAP_FW_MAIN_B;
|
||||
fw_body_area = &state->area[body_c];
|
||||
}
|
||||
|
||||
/* If we have a key, check the signature too */
|
||||
@@ -335,26 +367,23 @@ int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state)
|
||||
KeyBlockVerify(key_block, len, sign_key, 0))
|
||||
good_sig = 1;
|
||||
|
||||
show_keyblock(key_block,
|
||||
state->component == CB_FW_PREAMBLE
|
||||
? state->in_filename : state->name,
|
||||
!!sign_key, good_sig);
|
||||
show_keyblock(key_block, name, !!sign_key, good_sig);
|
||||
|
||||
if (option.strict && (!sign_key || !good_sig))
|
||||
retval = 1;
|
||||
|
||||
RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
|
||||
if (!rsa) {
|
||||
fprintf(stderr, "Error parsing data key in %s\n", state->name);
|
||||
fprintf(stderr, "Error parsing data key in %s\n", name);
|
||||
return 1;
|
||||
}
|
||||
uint32_t more = key_block->key_block_size;
|
||||
VbFirmwarePreambleHeader *preamble =
|
||||
(VbFirmwarePreambleHeader *)(state->my_area->buf + more);
|
||||
(VbFirmwarePreambleHeader *)(buf + more);
|
||||
|
||||
if (VBOOT_SUCCESS != VerifyFirmwarePreamble(preamble,
|
||||
len - more, rsa)) {
|
||||
printf("%s is invalid\n", state->name);
|
||||
printf("%s is invalid\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -390,7 +419,7 @@ int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state)
|
||||
}
|
||||
|
||||
/* We'll need to get the firmware body from somewhere... */
|
||||
if (fw_body_area && (fw_body_area->_flags & AREA_IS_VALID)) {
|
||||
if (fw_body_area && fw_body_area->is_valid) {
|
||||
fv_data = fw_body_area->buf;
|
||||
fv_size = fw_body_area->len;
|
||||
}
|
||||
@@ -409,13 +438,13 @@ int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state)
|
||||
}
|
||||
|
||||
done:
|
||||
/* Can't trust the BIOS unless everything is signed,
|
||||
* but standalone files are okay. */
|
||||
if ((state->component == CB_FW_PREAMBLE) ||
|
||||
(sign_key && good_sig)) {
|
||||
/* Can't trust the BIOS unless everything is signed (in which case
|
||||
* we've already returned), but standalone files are okay. */
|
||||
if (state || (sign_key && good_sig)) {
|
||||
if (!(flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL))
|
||||
printf("Body verification succeeded.\n");
|
||||
state->my_area->_flags |= AREA_IS_VALID;
|
||||
if (state)
|
||||
state->area[state->c].is_valid = 1;
|
||||
} else {
|
||||
printf("Seems legit, but the signature is unverified.\n");
|
||||
if (option.strict)
|
||||
@@ -425,11 +454,59 @@ done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
|
||||
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;
|
||||
|
||||
VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
|
||||
uint32_t len = state->my_area->len;
|
||||
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)
|
||||
{
|
||||
VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)buf;
|
||||
VbPublicKey *sign_key = option.k;
|
||||
uint8_t *kernel_blob = 0;
|
||||
uint64_t kernel_size = 0;
|
||||
@@ -441,7 +518,7 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
|
||||
|
||||
/* Check the hash... */
|
||||
if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
|
||||
printf("%s keyblock component is invalid\n", state->name);
|
||||
printf("%s keyblock component is invalid\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -450,7 +527,7 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
|
||||
KeyBlockVerify(key_block, len, sign_key, 0))
|
||||
good_sig = 1;
|
||||
|
||||
printf("Kernel partition: %s\n", state->in_filename);
|
||||
printf("Kernel partition: %s\n", name);
|
||||
show_keyblock(key_block, NULL, !!sign_key, good_sig);
|
||||
|
||||
if (option.strict && (!sign_key || !good_sig))
|
||||
@@ -458,16 +535,16 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
|
||||
|
||||
RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
|
||||
if (!rsa) {
|
||||
fprintf(stderr, "Error parsing data key in %s\n", state->name);
|
||||
fprintf(stderr, "Error parsing data key in %s\n", name);
|
||||
return 1;
|
||||
}
|
||||
uint32_t more = key_block->key_block_size;
|
||||
VbKernelPreambleHeader *preamble =
|
||||
(VbKernelPreambleHeader *)(state->my_area->buf + more);
|
||||
(VbKernelPreambleHeader *)(buf + more);
|
||||
|
||||
if (VBOOT_SUCCESS != VerifyKernelPreamble(preamble,
|
||||
len - more, rsa)) {
|
||||
printf("%s is invalid\n", state->name);
|
||||
printf("%s is invalid\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -511,10 +588,10 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
|
||||
/* It's in a separate file, which we've already read in */
|
||||
kernel_blob = option.fv;
|
||||
kernel_size = option.fv_size;
|
||||
} else if (state->my_area->len > option.padding) {
|
||||
} else if (len > option.padding) {
|
||||
/* It should be at an offset within the input file. */
|
||||
kernel_blob = state->my_area->buf + option.padding;
|
||||
kernel_size = state->my_area->len - option.padding;
|
||||
kernel_blob = buf + option.padding;
|
||||
kernel_size = len - option.padding;
|
||||
}
|
||||
|
||||
if (!kernel_blob) {
|
||||
@@ -536,25 +613,6 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int futil_cb_show_begin(struct futil_traverse_state_s *state)
|
||||
{
|
||||
switch (state->in_type) {
|
||||
case FILE_TYPE_UNKNOWN:
|
||||
fprintf(stderr, "Unable to determine type of %s\n",
|
||||
state->in_filename);
|
||||
return 1;
|
||||
|
||||
case FILE_TYPE_BIOS_IMAGE:
|
||||
case FILE_TYPE_OLD_BIOS_IMAGE:
|
||||
printf("BIOS: %s\n", state->in_filename);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum no_short_opts {
|
||||
OPT_PADDING = 1000,
|
||||
OPT_HELP,
|
||||
@@ -597,7 +655,7 @@ static const struct option long_opts[] = {
|
||||
{"publickey", 1, 0, 'k'},
|
||||
{"fv", 1, 0, 'f'},
|
||||
{"pad", 1, NULL, OPT_PADDING},
|
||||
{"verify", 0, &option.strict, 1},
|
||||
{"strict", 0, &option.strict, 1},
|
||||
{"help", 0, NULL, OPT_HELP},
|
||||
{NULL, 0, NULL, 0},
|
||||
};
|
||||
@@ -635,9 +693,9 @@ static int do_show(int argc, char *argv[])
|
||||
char *infile = 0;
|
||||
int ifd, i;
|
||||
int errorcnt = 0;
|
||||
struct futil_traverse_state_s state;
|
||||
enum futil_file_type type;
|
||||
uint8_t *buf;
|
||||
uint32_t buf_len;
|
||||
uint32_t len;
|
||||
char *e = 0;
|
||||
|
||||
opterr = 0; /* quiet, you */
|
||||
@@ -719,21 +777,16 @@ static int do_show(int argc, char *argv[])
|
||||
continue;
|
||||
}
|
||||
|
||||
if (0 != futil_map_file(ifd, MAP_RO, &buf, &buf_len)) {
|
||||
if (0 != futil_map_file(ifd, MAP_RO, &buf, &len)) {
|
||||
errorcnt++;
|
||||
goto boo;
|
||||
}
|
||||
|
||||
memset(&state, 0, sizeof(state));
|
||||
state.in_filename = infile ? infile : "<none>";
|
||||
state.op = FUTIL_OP_SHOW;
|
||||
type = futil_file_type_buf(buf, len);
|
||||
|
||||
errorcnt += futil_traverse(buf, buf_len, &state,
|
||||
FILE_TYPE_UNKNOWN);
|
||||
|
||||
|
||||
errorcnt += futil_unmap_file(ifd, MAP_RO, buf, buf_len);
|
||||
errorcnt += futil_file_type_show(type, infile, buf, len);
|
||||
|
||||
errorcnt += futil_unmap_file(ifd, MAP_RO, buf, len);
|
||||
boo:
|
||||
if (close(ifd)) {
|
||||
errorcnt++;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
switch (state->in_type) {
|
||||
case FILE_TYPE_BIOS_IMAGE:
|
||||
case FILE_TYPE_OLD_BIOS_IMAGE:
|
||||
return sign_bios_at_end(state);
|
||||
|
||||
default:
|
||||
/* Any other cleanup needed? */
|
||||
break;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
|
||||
@@ -154,3 +154,28 @@ enum futil_file_err futil_file_type(const char *filename,
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int futil_file_type_show(enum futil_file_type type,
|
||||
const char *filename,
|
||||
uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (futil_file_types[type].show)
|
||||
return futil_file_types[type].show(filename, buf, len, 0);
|
||||
|
||||
fprintf(stderr, "Don't know how to show %s (type %s)\n",
|
||||
filename, futil_file_type_name(type));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int futil_file_type_sign(enum futil_file_type type,
|
||||
const char *filename,
|
||||
uint8_t *buf, uint32_t len)
|
||||
{
|
||||
if (futil_file_types[type].sign)
|
||||
return futil_file_types[type].sign(filename, buf, len, 0);
|
||||
|
||||
fprintf(stderr, "Don't know how to sign %s (type %s)\n",
|
||||
filename, futil_file_type_name(type));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,24 @@ enum futil_file_type futil_file_type_buf(uint8_t *buf, uint32_t len);
|
||||
enum futil_file_err futil_file_type(const char *filename,
|
||||
enum futil_file_type *type);
|
||||
|
||||
/*
|
||||
* Call the show() method on a buffer containing a specific file type.
|
||||
* Returns zero on success. It's up to the caller to ensure that only valid
|
||||
* file types are invoked.
|
||||
*/
|
||||
int futil_file_type_show(enum futil_file_type type,
|
||||
const char *filename,
|
||||
uint8_t *buf, uint32_t len);
|
||||
|
||||
/*
|
||||
* Call the sign() method on a buffer containing a specific file type.
|
||||
* Returns zero on success. It's up to the caller to ensure that only valid
|
||||
* file types are invoked.
|
||||
*/
|
||||
int futil_file_type_sign(enum futil_file_type type,
|
||||
const char *filename,
|
||||
uint8_t *buf, uint32_t len);
|
||||
|
||||
/* Declare the file_type functions. */
|
||||
#define R_(FOO) \
|
||||
enum futil_file_type FOO(uint8_t *buf, uint32_t len);
|
||||
|
||||
@@ -15,59 +15,59 @@
|
||||
* show function
|
||||
* sign function
|
||||
*/
|
||||
FILE_TYPE(PUBKEY, "pubkey", "VbPublicKey (.vbpubk)",
|
||||
R_(ft_recognize_vb1_key),
|
||||
NONE,
|
||||
NONE)
|
||||
FILE_TYPE(KEYBLOCK, "keyblock", "VbKeyBlock",
|
||||
R_(ft_recognize_vblock1),
|
||||
NONE,
|
||||
FILE_TYPE(BIOS_IMAGE, "bios", "Chrome OS BIOS image",
|
||||
R_(ft_recognize_bios_image),
|
||||
S_(ft_show_bios),
|
||||
S_(ft_sign_bios))
|
||||
FILE_TYPE(OLD_BIOS_IMAGE, "oldbios", "Cr-48 Chrome OS BIOS image",
|
||||
R_(ft_recognize_bios_image),
|
||||
S_(ft_show_bios),
|
||||
S_(ft_sign_bios))
|
||||
FILE_TYPE(GBB, "gbb", "GBB",
|
||||
R_(ft_recognize_gbb),
|
||||
S_(ft_show_gbb),
|
||||
NONE)
|
||||
FILE_TYPE(FW_PREAMBLE, "fw_pre", "VbFirmwarePreamble (VBLOCK_A/B)",
|
||||
R_(ft_recognize_vblock1),
|
||||
NONE,
|
||||
NONE)
|
||||
FILE_TYPE(GBB, "gbb", "GBB",
|
||||
R_(ft_recognize_gbb),
|
||||
NONE,
|
||||
NONE)
|
||||
FILE_TYPE(BIOS_IMAGE, "bios", "Chrome OS BIOS image",
|
||||
R_(ft_recognize_bios_image),
|
||||
NONE,
|
||||
NONE)
|
||||
FILE_TYPE(OLD_BIOS_IMAGE, "oldbios", "Cr-48 Chrome OS BIOS image",
|
||||
R_(ft_recognize_bios_image),
|
||||
NONE,
|
||||
S_(ft_show_fw_preamble),
|
||||
NONE)
|
||||
FILE_TYPE(KERN_PREAMBLE, "kernel", "kernel preamble/partition",
|
||||
R_(ft_recognize_vblock1),
|
||||
NONE,
|
||||
S_(ft_show_kernel_preamble),
|
||||
S_(ft_sign_kern_preamble))
|
||||
FILE_TYPE(KEYBLOCK, "keyblock", "VbKeyBlock",
|
||||
R_(ft_recognize_vblock1),
|
||||
S_(ft_show_keyblock),
|
||||
NONE)
|
||||
FILE_TYPE(PUBKEY, "pubkey", "VbPublicKey (.vbpubk)",
|
||||
R_(ft_recognize_vb1_key),
|
||||
S_(ft_show_pubkey),
|
||||
S_(ft_sign_pubkey))
|
||||
FILE_TYPE(PRIVKEY, "prikey", "VbPrivateKey (.vbprivk)",
|
||||
R_(ft_recognize_vb1_key),
|
||||
S_(ft_show_privkey),
|
||||
NONE)
|
||||
FILE_TYPE(VB2_PUBKEY, "pubkey21", "vb21 public key (.vbpubk2)",
|
||||
R_(ft_recognize_vb2_key),
|
||||
S_(ft_show_vb2_pubkey),
|
||||
NONE)
|
||||
FILE_TYPE(VB2_PRIVKEY, "prikey21", "vb21 private key (.vbprik2)",
|
||||
R_(ft_recognize_vb2_key),
|
||||
S_(ft_show_vb2_privkey),
|
||||
NONE)
|
||||
FILE_TYPE(PEM, "pem", "RSA private key (.pem)",
|
||||
R_(ft_recognize_pem),
|
||||
S_(ft_show_pem),
|
||||
NONE)
|
||||
FILE_TYPE(RAW_FIRMWARE, "fwblob", "raw firmware blob (FW_MAIN_A/B)",
|
||||
NONE,
|
||||
NONE,
|
||||
NONE)
|
||||
S_(ft_sign_raw_firmware))
|
||||
FILE_TYPE(RAW_KERNEL, "vmlinuz", "raw linux kernel",
|
||||
NONE,
|
||||
NONE,
|
||||
NONE)
|
||||
S_(ft_sign_raw_kernel))
|
||||
FILE_TYPE(CHROMIUMOS_DISK, "disk_img", "chromiumos disk image",
|
||||
NONE,
|
||||
NONE,
|
||||
NONE)
|
||||
FILE_TYPE(PRIVKEY, "prikey", "VbPrivateKey (.vbprivk)",
|
||||
R_(ft_recognize_vb1_key),
|
||||
NONE,
|
||||
NONE)
|
||||
FILE_TYPE(VB2_PUBKEY, "pubkey21", "vb21 public key (.vbpubk2)",
|
||||
R_(ft_recognize_vb2_key),
|
||||
NONE,
|
||||
NONE)
|
||||
FILE_TYPE(VB2_PRIVKEY, "prikey21", "vb21 private key (.vbprik2)",
|
||||
R_(ft_recognize_vb2_key),
|
||||
NONE,
|
||||
NONE)
|
||||
FILE_TYPE(PEM, "pem", "RSA private key (.pem)",
|
||||
R_(ft_recognize_pem),
|
||||
NONE,
|
||||
NONE)
|
||||
|
||||
@@ -1,200 +1,20 @@
|
||||
/*
|
||||
* 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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "file_type.h"
|
||||
#include "fmap.h"
|
||||
#include "file_type.h"
|
||||
#include "futility.h"
|
||||
#include "traversal.h"
|
||||
|
||||
/* What functions do we invoke for a particular operation and component? */
|
||||
|
||||
/* FUTIL_OP_SHOW */
|
||||
static int (* const cb_show_funcs[])(struct futil_traverse_state_s *state) = {
|
||||
futil_cb_show_begin, /* CB_BEGIN_TRAVERSAL */
|
||||
NULL, /* CB_END_TRAVERSAL */
|
||||
futil_cb_show_gbb, /* CB_FMAP_GBB */
|
||||
futil_cb_show_fw_preamble, /* CB_FMAP_VBLOCK_A */
|
||||
futil_cb_show_fw_preamble, /* CB_FMAP_VBLOCK_B */
|
||||
futil_cb_show_fw_main, /* CB_FMAP_FW_MAIN_A */
|
||||
futil_cb_show_fw_main, /* CB_FMAP_FW_MAIN_B */
|
||||
futil_cb_show_pubkey, /* CB_PUBKEY */
|
||||
futil_cb_show_keyblock, /* CB_KEYBLOCK */
|
||||
futil_cb_show_gbb, /* CB_GBB */
|
||||
futil_cb_show_fw_preamble, /* CB_FW_PREAMBLE */
|
||||
futil_cb_show_kernel_preamble, /* CB_KERN_PREAMBLE */
|
||||
NULL, /* CB_RAW_FIRMWARE */
|
||||
NULL, /* CB_RAW_KERNEL */
|
||||
futil_cb_show_privkey, /* CB_PRIVKEY */
|
||||
futil_cb_show_vb2_pubkey, /* CB_VB2_PUBKEY */
|
||||
futil_cb_show_vb2_privkey, /* CB_VB2_PRIVKEY */
|
||||
futil_cb_show_pem, /* CB_PEM */
|
||||
/* 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(cb_show_funcs) == NUM_CB_COMPONENTS);
|
||||
BUILD_ASSERT(ARRAY_SIZE(bios_area) == NUM_BIOS_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_vblock, /* CB_FMAP_VBLOCK_A */
|
||||
futil_cb_sign_fw_vblock, /* 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_pubkey, /* CB_PUBKEY */
|
||||
NULL, /* CB_KEYBLOCK */
|
||||
NULL, /* CB_GBB */
|
||||
NULL, /* CB_FW_PREAMBLE */
|
||||
futil_cb_resign_kernel_part, /* CB_KERN_PREAMBLE */
|
||||
futil_cb_sign_raw_firmware, /* CB_RAW_FIRMWARE */
|
||||
futil_cb_create_kernel_part, /* CB_RAW_KERNEL */
|
||||
NULL, /* CB_PRIVKEY */
|
||||
NULL, /* CB_VB2_PUBKEY */
|
||||
NULL, /* CB_VB2_PRIVKEY */
|
||||
NULL, /* CB_PEM */
|
||||
};
|
||||
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);
|
||||
|
||||
/*
|
||||
* File types that don't need iterating can use a lookup table to determine the
|
||||
* callback component and name. The index is the file type.
|
||||
*/
|
||||
static const struct {
|
||||
enum futil_cb_component component;
|
||||
const char * const name;
|
||||
} direct_callback[] = {
|
||||
{0, NULL}, /* FILE_TYPE_UNKNOWN */
|
||||
{CB_PUBKEY, "VbPublicKey"}, /* FILE_TYPE_PUBKEY */
|
||||
{CB_KEYBLOCK, "VbKeyBlock"}, /* FILE_TYPE_KEYBLOCK */
|
||||
{CB_FW_PREAMBLE, "FW Preamble"}, /* FILE_TYPE_FW_PREAMBLE */
|
||||
{CB_GBB, "GBB"}, /* FILE_TYPE_GBB */
|
||||
{0, NULL}, /* FILE_TYPE_BIOS_IMAGE */
|
||||
{0, NULL}, /* FILE_TYPE_OLD_BIOS_IMAGE */
|
||||
{CB_KERN_PREAMBLE, "Kernel Preamble"}, /* FILE_TYPE_KERN_PREAMBLE */
|
||||
{CB_RAW_FIRMWARE, "raw firmware"}, /* FILE_TYPE_RAW_FIRMWARE */
|
||||
{CB_RAW_KERNEL, "raw kernel"}, /* FILE_TYPE_RAW_KERNEL */
|
||||
{0, "chromiumos disk"}, /* FILE_TYPE_CHROMIUMOS_DISK */
|
||||
{CB_PRIVKEY, "VbPrivateKey"}, /* FILE_TYPE_PRIVKEY */
|
||||
{CB_VB2_PUBKEY, "vb21 public key"}, /* FILE_TYPE_VB2_PUBKEY */
|
||||
{CB_VB2_PRIVKEY, "vb21 private key"}, /* FILE_TYPE_VB2_PRIVKEY */
|
||||
{CB_PEM, "RSA private key"}, /* FILE_TYPE_PEM */
|
||||
};
|
||||
BUILD_ASSERT(ARRAY_SIZE(direct_callback) == NUM_FILE_TYPES);
|
||||
|
||||
/*
|
||||
* The Chrome OS BIOS must contain specific FMAP areas, and we generally want
|
||||
* to look at each one in a certain order.
|
||||
*/
|
||||
struct bios_area_s {
|
||||
const char * const name;
|
||||
enum futil_cb_component component;
|
||||
};
|
||||
|
||||
/* This are the expected areas, in order of traversal. */
|
||||
static const struct bios_area_s bios_area[] = {
|
||||
{"GBB", CB_FMAP_GBB},
|
||||
{"FW_MAIN_A", CB_FMAP_FW_MAIN_A},
|
||||
{"FW_MAIN_B", CB_FMAP_FW_MAIN_B},
|
||||
{"VBLOCK_A", CB_FMAP_VBLOCK_A},
|
||||
{"VBLOCK_B", CB_FMAP_VBLOCK_B},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
/* Really old BIOS images had different names, but worked the same. */
|
||||
static const struct bios_area_s old_bios_area[] = {
|
||||
{"GBB Area", CB_FMAP_GBB},
|
||||
{"Firmware A Data", CB_FMAP_FW_MAIN_A},
|
||||
{"Firmware B Data", CB_FMAP_FW_MAIN_B},
|
||||
{"Firmware A Key", CB_FMAP_VBLOCK_A},
|
||||
{"Firmware B Key", CB_FMAP_VBLOCK_B},
|
||||
{0, 0}
|
||||
};
|
||||
|
||||
static int has_all_areas(uint8_t *buf, uint32_t len, FmapHeader *fmap,
|
||||
const struct bios_area_s *area)
|
||||
{
|
||||
/* We must have all the expected areas */
|
||||
for (; area->name; area++)
|
||||
if (!fmap_find_by_name(buf, len, fmap, area->name, 0))
|
||||
return 0;
|
||||
|
||||
/* Found 'em all */
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum futil_file_type ft_recognize_bios_image(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
FmapHeader *fmap = fmap_find(buf, len);
|
||||
if (fmap) {
|
||||
if (has_all_areas(buf, len, fmap, bios_area))
|
||||
return FILE_TYPE_BIOS_IMAGE;
|
||||
if (has_all_areas(buf, len, fmap, old_bios_area))
|
||||
return FILE_TYPE_OLD_BIOS_IMAGE;
|
||||
}
|
||||
return FILE_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
static const char * const futil_cb_component_str[] = {
|
||||
"CB_BEGIN_TRAVERSAL",
|
||||
"CB_END_TRAVERSAL",
|
||||
"CB_FMAP_GBB",
|
||||
"CB_FMAP_VBLOCK_A",
|
||||
"CB_FMAP_VBLOCK_B",
|
||||
"CB_FMAP_FW_MAIN_A",
|
||||
"CB_FMAP_FW_MAIN_B",
|
||||
"CB_PUBKEY",
|
||||
"CB_KEYBLOCK",
|
||||
"CB_GBB",
|
||||
"CB_FW_PREAMBLE",
|
||||
"CB_KERN_PREAMBLE",
|
||||
"CB_RAW_FIRMWARE",
|
||||
"CB_RAW_KERNEL",
|
||||
"CB_PRIVKEY",
|
||||
"CB_VB2_PUBKEY",
|
||||
"CB_VB2_PRIVKEY",
|
||||
"CB_PEM",
|
||||
};
|
||||
BUILD_ASSERT(ARRAY_SIZE(futil_cb_component_str) == NUM_CB_COMPONENTS);
|
||||
|
||||
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)
|
||||
{
|
||||
Debug("%s: name \"%s\" op %d component %s"
|
||||
" offset=0x%08x len=0x%08x, buf=%p\n",
|
||||
__func__, name, state->op, futil_cb_component_str[c],
|
||||
offset, len, buf);
|
||||
|
||||
if ((int) c < 0 || c >= NUM_CB_COMPONENTS) {
|
||||
fprintf(stderr, "Invalid component %d\n", c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
state->component = c;
|
||||
state->name = name;
|
||||
state->cb_area[c].offset = offset;
|
||||
state->cb_area[c].buf = buf;
|
||||
state->cb_area[c].len = len;
|
||||
state->my_area = &state->cb_area[c];
|
||||
|
||||
if (cb_func[state->op][c])
|
||||
return cb_func[state->op][c](state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fmap_limit_area(FmapAreaHeader *ah, uint32_t len)
|
||||
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) {
|
||||
@@ -206,82 +26,28 @@ static void fmap_limit_area(FmapAreaHeader *ah, uint32_t len)
|
||||
}
|
||||
}
|
||||
|
||||
int futil_traverse(uint8_t *buf, uint32_t len,
|
||||
struct futil_traverse_state_s *state,
|
||||
enum futil_file_type type)
|
||||
enum futil_file_type ft_recognize_bios_image(uint8_t *buf, uint32_t len)
|
||||
{
|
||||
FmapHeader *fmap;
|
||||
FmapAreaHeader *ah = 0;
|
||||
const struct bios_area_s *area;
|
||||
int retval = 0;
|
||||
int i;
|
||||
|
||||
if ((int) state->op < 0 || state->op >= NUM_FUTIL_OPS) {
|
||||
fprintf(stderr, "Invalid op %d\n", state->op);
|
||||
return 1;
|
||||
}
|
||||
fmap = fmap_find(buf, len);
|
||||
if (!fmap)
|
||||
return FILE_TYPE_UNKNOWN;
|
||||
|
||||
if (type == FILE_TYPE_UNKNOWN)
|
||||
type = futil_file_type_buf(buf, len);
|
||||
state->in_type = type;
|
||||
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;
|
||||
|
||||
state->errors = retval;
|
||||
retval |= invoke_callback(state, CB_BEGIN_TRAVERSAL, "<begin>",
|
||||
0, buf, len);
|
||||
state->errors = retval;
|
||||
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;
|
||||
|
||||
switch (type) {
|
||||
case FILE_TYPE_BIOS_IMAGE:
|
||||
/* We've already checked, so we know this will work. */
|
||||
fmap = fmap_find(buf, len);
|
||||
for (area = bios_area; area->name; area++) {
|
||||
/* We know this will work, too */
|
||||
fmap_find_by_name(buf, len, fmap, area->name, &ah);
|
||||
/* But the file might be truncated */
|
||||
fmap_limit_area(ah, len);
|
||||
retval |= invoke_callback(state,
|
||||
area->component,
|
||||
area->name,
|
||||
ah->area_offset,
|
||||
buf + ah->area_offset,
|
||||
ah->area_size);
|
||||
state->errors = retval;
|
||||
}
|
||||
break;
|
||||
|
||||
case FILE_TYPE_OLD_BIOS_IMAGE:
|
||||
/* We've already checked, so we know this will work. */
|
||||
fmap = fmap_find(buf, len);
|
||||
for (area = old_bios_area; area->name; area++) {
|
||||
/* We know this will work, too */
|
||||
fmap_find_by_name(buf, len, fmap, area->name, &ah);
|
||||
/* But the file might be truncated */
|
||||
fmap_limit_area(ah, len);
|
||||
retval |= invoke_callback(state,
|
||||
area->component,
|
||||
area->name,
|
||||
ah->area_offset,
|
||||
buf + ah->area_offset,
|
||||
ah->area_size);
|
||||
state->errors = retval;
|
||||
}
|
||||
break;
|
||||
|
||||
case FILE_TYPE_UNKNOWN:
|
||||
case FILE_TYPE_CHROMIUMOS_DISK:
|
||||
/* Nothing to do for these file types (yet) */
|
||||
break;
|
||||
|
||||
default:
|
||||
/* All other file types have their own callbacks */
|
||||
retval |= invoke_callback(state,
|
||||
direct_callback[type].component,
|
||||
direct_callback[type].name,
|
||||
0, buf, len);
|
||||
state->errors = retval;
|
||||
break;
|
||||
}
|
||||
|
||||
retval |= invoke_callback(state, CB_END_TRAVERSAL, "<end>",
|
||||
0, buf, len);
|
||||
return retval;
|
||||
return FILE_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -6,98 +6,33 @@
|
||||
#ifndef VBOOT_REFERENCE_FUTILITY_TRAVERSAL_H_
|
||||
#define VBOOT_REFERENCE_FUTILITY_TRAVERSAL_H_
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* What are we trying to accomplish? */
|
||||
enum futil_op_type {
|
||||
FUTIL_OP_SHOW,
|
||||
FUTIL_OP_SIGN,
|
||||
|
||||
NUM_FUTIL_OPS
|
||||
};
|
||||
|
||||
/* What component are we currently handling in the callback routine? */
|
||||
enum futil_cb_component {
|
||||
/* entire input buffer */
|
||||
CB_BEGIN_TRAVERSAL,
|
||||
CB_END_TRAVERSAL,
|
||||
/* fmap areas within a bios image */
|
||||
CB_FMAP_GBB,
|
||||
CB_FMAP_VBLOCK_A,
|
||||
CB_FMAP_VBLOCK_B,
|
||||
CB_FMAP_FW_MAIN_A,
|
||||
CB_FMAP_FW_MAIN_B,
|
||||
/* individual files (extracted from a bios, for example) */
|
||||
CB_PUBKEY,
|
||||
CB_KEYBLOCK,
|
||||
CB_GBB,
|
||||
CB_FW_PREAMBLE,
|
||||
CB_KERN_PREAMBLE,
|
||||
CB_RAW_FIRMWARE,
|
||||
CB_RAW_KERNEL,
|
||||
CB_PRIVKEY,
|
||||
CB_VB2_PUBKEY,
|
||||
CB_VB2_PRIVKEY,
|
||||
CB_PEM,
|
||||
|
||||
NUM_CB_COMPONENTS
|
||||
};
|
||||
|
||||
/* Where is the component we're poking at? */
|
||||
struct cb_area_s {
|
||||
uint32_t offset; /* to avoid pointer math */
|
||||
uint8_t *buf;
|
||||
uint32_t len;
|
||||
uint32_t _flags; /* for callback use */
|
||||
};
|
||||
|
||||
/* What do we know at this point in time? */
|
||||
struct futil_traverse_state_s {
|
||||
/* These two should be initialized by the caller as needed */
|
||||
const char *in_filename;
|
||||
enum futil_op_type op;
|
||||
/* Current activity during traversal */
|
||||
enum futil_cb_component component;
|
||||
struct cb_area_s *my_area;
|
||||
const char *name;
|
||||
/* Other activites, possibly before or after the current one */
|
||||
struct cb_area_s cb_area[NUM_CB_COMPONENTS];
|
||||
struct cb_area_s recovery_key;
|
||||
struct cb_area_s rootkey;
|
||||
enum futil_file_type in_type;
|
||||
int errors;
|
||||
};
|
||||
|
||||
#include "fmap.h"
|
||||
|
||||
/*
|
||||
* Traverse the buffer using the provided state, which should be initialized
|
||||
* before calling. Returns nonzero (but no details) if there were any errors.
|
||||
* The Chrome OS BIOS must contain specific FMAP areas, and we generally want
|
||||
* to look at each one in a certain order.
|
||||
*/
|
||||
int futil_traverse(uint8_t *buf, uint32_t len,
|
||||
struct futil_traverse_state_s *state,
|
||||
enum futil_file_type type_hint);
|
||||
enum bios_component {
|
||||
BIOS_FMAP_GBB,
|
||||
BIOS_FMAP_FW_MAIN_A,
|
||||
BIOS_FMAP_FW_MAIN_B,
|
||||
BIOS_FMAP_VBLOCK_A,
|
||||
BIOS_FMAP_VBLOCK_B,
|
||||
|
||||
/* These are invoked by the traversal. They also return nonzero on error. */
|
||||
int futil_cb_show_begin(struct futil_traverse_state_s *state);
|
||||
int futil_cb_show_pubkey(struct futil_traverse_state_s *state);
|
||||
int futil_cb_show_gbb(struct futil_traverse_state_s *state);
|
||||
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_show_kernel_preamble(struct futil_traverse_state_s *state);
|
||||
int futil_cb_show_privkey(struct futil_traverse_state_s *state);
|
||||
int futil_cb_show_vb2_pubkey(struct futil_traverse_state_s *state);
|
||||
int futil_cb_show_vb2_privkey(struct futil_traverse_state_s *state);
|
||||
int futil_cb_show_pem(struct futil_traverse_state_s *state);
|
||||
NUM_BIOS_COMPONENTS
|
||||
};
|
||||
|
||||
int futil_cb_sign_pubkey(struct futil_traverse_state_s *state);
|
||||
int futil_cb_sign_fw_main(struct futil_traverse_state_s *state);
|
||||
int futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state);
|
||||
int futil_cb_sign_raw_firmware(struct futil_traverse_state_s *state);
|
||||
int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state);
|
||||
int futil_cb_create_kernel_part(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);
|
||||
/* 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[];
|
||||
|
||||
|
||||
#endif /* VBOOT_REFERENCE_FUTILITY_TRAVERSAL_H_ */
|
||||
void fmap_limit_area(FmapAreaHeader *ah, uint32_t len);
|
||||
|
||||
|
||||
#endif /* VBOOT_REFERENCE_FUTILITY_TRAVERSAL_H_ */
|
||||
|
||||
@@ -64,7 +64,7 @@ static uint8_t *vb2_public_key_sha1sum(struct vb2_public_key *key)
|
||||
return digest;
|
||||
}
|
||||
|
||||
int futil_cb_show_vb2_pubkey(struct futil_traverse_state_s *state)
|
||||
int ft_show_vb2_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
|
||||
{
|
||||
struct vb2_public_key key;
|
||||
const struct vb2_text_vs_enum *entry;
|
||||
@@ -72,13 +72,12 @@ int futil_cb_show_vb2_pubkey(struct futil_traverse_state_s *state)
|
||||
|
||||
/* The key's members will point into the state buffer after this. Don't
|
||||
* free anything. */
|
||||
if (VB2_SUCCESS != vb2_unpack_key(&key, state->my_area->buf,
|
||||
state->my_area->len))
|
||||
if (VB2_SUCCESS != vb2_unpack_key(&key, buf, len))
|
||||
return 1;
|
||||
|
||||
sha1sum = vb2_public_key_sha1sum(&key);
|
||||
|
||||
printf("Public Key file: %s\n", state->in_filename);
|
||||
printf("Public Key file: %s\n", name);
|
||||
printf(" Vboot API: 2.1\n");
|
||||
printf(" Desc: \"%s\"\n", key.desc);
|
||||
entry = vb2_lookup_by_num(vb2_text_vs_sig, key.sig_alg);
|
||||
@@ -114,19 +113,19 @@ static uint8_t *vb2_private_key_sha1sum(struct vb2_private_key *key)
|
||||
return digest;
|
||||
}
|
||||
|
||||
int futil_cb_show_vb2_privkey(struct futil_traverse_state_s *state)
|
||||
int ft_show_vb2_privkey(const char *name, uint8_t *buf, uint32_t len,
|
||||
void *data)
|
||||
{
|
||||
struct vb2_private_key *key = 0;
|
||||
const struct vb2_text_vs_enum *entry;
|
||||
uint8_t *sha1sum;
|
||||
|
||||
if (VB2_SUCCESS != vb2_private_key_unpack(&key, state->my_area->buf,
|
||||
state->my_area->len))
|
||||
if (VB2_SUCCESS != vb2_private_key_unpack(&key, buf, len))
|
||||
return 1;
|
||||
|
||||
sha1sum = vb2_private_key_sha1sum(key);
|
||||
|
||||
printf("Private key file: %s\n", state->in_filename);
|
||||
printf("Private key file: %s\n", name);
|
||||
printf(" Vboot API: 2.1\n");
|
||||
printf(" Desc: \"%s\"\n", key->desc ? key->desc : "");
|
||||
entry = vb2_lookup_by_num(vb2_text_vs_sig, key->sig_alg);
|
||||
@@ -180,17 +179,17 @@ enum futil_file_type ft_recognize_pem(uint8_t *buf, uint32_t len)
|
||||
return FILE_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
int futil_cb_show_pem(struct futil_traverse_state_s *state)
|
||||
int ft_show_pem(const char *name, uint8_t *buf, uint32_t len, void *data)
|
||||
{
|
||||
RSA *rsa_key;
|
||||
uint8_t *keyb, *digest;
|
||||
uint32_t keyb_len;
|
||||
int i, bits;
|
||||
|
||||
printf("Private Key file: %s\n", state->in_filename);
|
||||
printf("Private Key file: %s\n", name);
|
||||
|
||||
/* We're called only after ft_recognize_pem, so this should work. */
|
||||
rsa_key = rsa_from_buffer(state->my_area->buf, state->my_area->len);
|
||||
rsa_key = rsa_from_buffer(buf, len);
|
||||
if (!rsa_key)
|
||||
DIE;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user