From e051975c900caf43046a97cda682629915c62c7e Mon Sep 17 00:00:00 2001 From: Bill Richardson Date: Wed, 3 Sep 2014 14:20:10 -0700 Subject: futility: sign command works on unsigned images This allows the sign command to work on BIOS images with invalid VBLOCK areas. When re-signing an existing image, the length of the firmware body is part of the firmware preamble in the VBLOCK areas. If those are invalid, the BIOS can still be signed, but it will have to sign the entire FW_MAIN area. That's a little slower to verify, so we'd prefer not to do that, but it works. BUG=chromium:224734 BRANCH=ToT TEST=make runtests Signed-off-by: Bill Richardson Change-Id: If58b5c86c5df12f004eabff72c22bfb1e84de7fd Reviewed-on: https://chromium-review.googlesource.com/216229 Reviewed-by: Randall Spangler --- futility/cmd_sign.c | 25 ++++++++++++++--- .../data_bios_peppy_mp_no_vblock.bin_expect.txt | 6 +++++ tests/futility/test_resign_firmware.sh | 31 +++++++++++++++++++++- 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 tests/futility/data_bios_peppy_mp_no_vblock.bin_expect.txt diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c index 41f3d9f7..3a65b22e 100644 --- a/futility/cmd_sign.c +++ b/futility/cmd_sign.c @@ -76,21 +76,37 @@ int futil_cb_sign_fw_main(struct futil_traverse_state_s *state) 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; + uint32_t len = state->my_area->len; /* 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. + * If we have a valid keyblock and fw_preamble, then we can use them to + * determine the size of the firmware body. Otherwise, we'll have to + * just sign the whole region. */ + if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) { + fprintf(stderr, "Warning: %s keyblock is invalid. " + "Signing the entire FW FMAP region...\n", + state->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); + goto whatever; + } 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; + struct cb_area_s *fw_body_area = 0; switch (state->component) { case CB_FMAP_VBLOCK_A: @@ -111,8 +127,11 @@ int futil_cb_sign_fw_preamble(struct futil_traverse_state_s *state) } /* Update the firmware size */ + fprintf(stderr, "HEY: set FW size from %d to %d\n", + fw_body_area->len, fw_size); fw_body_area->len = fw_size; +whatever: state->my_area->_flags |= AREA_IS_VALID; return 0; diff --git a/tests/futility/data_bios_peppy_mp_no_vblock.bin_expect.txt b/tests/futility/data_bios_peppy_mp_no_vblock.bin_expect.txt new file mode 100644 index 00000000..616530c5 --- /dev/null +++ b/tests/futility/data_bios_peppy_mp_no_vblock.bin_expect.txt @@ -0,0 +1,6 @@ +fc68bcb88bf9af1907289a9f377d658b3b9fe5b0 +bf39d0d3e30cbf6a121416d04df4603ad5310779 +e2c1c92d7d7aa7dfed5e8375edd30b7ae52b7450 +5d2b220899c4403d564092ada3f12d3cc4483223 +e2c1c92d7d7aa7dfed5e8375edd30b7ae52b7450 +5d2b220899c4403d564092ada3f12d3cc4483223 diff --git a/tests/futility/test_resign_firmware.sh b/tests/futility/test_resign_firmware.sh index d72ea05b..b1e397a3 100755 --- a/tests/futility/test_resign_firmware.sh +++ b/tests/futility/test_resign_firmware.sh @@ -21,6 +21,15 @@ ${SCRIPTDIR}/data/bios_peppy_mp.bin ${SCRIPTDIR}/data/bios_zgb_mp.bin " +# We also want to test that we can sign an image without any valid firmware +# preambles. That one won't be able to tell how much of the FW_MAIN region is +# the valid firmware, so it'll have to sign the entire region. +GOOD_VBLOCKS=${SCRIPTDIR}/data/bios_peppy_mp.bin +ONEMORE=bios_peppy_mp_no_vblock.bin +cp ${GOOD_VBLOCKS} ${ONEMORE} +${FUTILITY} load_fmap ${ONEMORE} VBLOCK_A:/dev/urandom VBLOCK_B:/dev/zero +INFILES="${INFILES} ${ONEMORE}" + count=0 for infile in $INFILES; do @@ -97,6 +106,26 @@ for infile in $INFILES; do done +# Make sure that the BIOS with the good vblocks signed the right size. +GOOD_OUT=${TMP}.${GOOD_VBLOCKS##*/}.new +MORE_OUT=${TMP}.${ONEMORE##*/}.new + +${FUTILITY} show ${GOOD_OUT} \ + | awk '/Firmware body size:/ {print $4}' > ${TMP}.good.body +${FUTILITY} dump_fmap -p ${GOOD_OUT} \ + | awk '/FW_MAIN_/ {print $3}' > ${TMP}.good.fw_main +# This should fail because they're different +if cmp ${TMP}.good.body ${TMP}.good.fw_main; then false; fi + +# Make sure that the BIOS with the bad vblocks signed the whole fw body +${FUTILITY} show ${MORE_OUT} \ + | awk '/Firmware body size:/ {print $4}' > ${TMP}.onemore.body +${FUTILITY} dump_fmap -p ${MORE_OUT} \ + | awk '/FW_MAIN_/ {print $3}' > ${TMP}.onemore.fw_main +# These should match +cmp ${TMP}.onemore.body ${TMP}.onemore.fw_main +cmp ${TMP}.onemore.body ${TMP}.good.fw_main + # cleanup -rm -rf ${TMP}* +rm -rf ${TMP}* ${ONEMORE} exit 0 -- cgit v1.2.1