diff options
author | Bill Richardson <wfrichar@chromium.org> | 2014-09-23 22:31:08 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-09-27 00:28:55 +0000 |
commit | 52a15f96ac009222ebf7d1299c7d17825e5a4ab5 (patch) | |
tree | bc91d1532fc7d1987b58e987911eae3c181951cf | |
parent | c540f59be047d69251b7f9ce0637a8a0c6fe150f (diff) | |
download | vboot-52a15f96ac009222ebf7d1299c7d17825e5a4ab5.tar.gz |
futility: show vs verify
This adds a --strict mode to the show command, which requires
that all signatures be valid in order to exit cleanly. It also
creates a "verify" command, which is really just an alias for
"show --strict".
BUG=none
BRANCH=ToT
TEST=make runtests
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Change-Id: I1fed7db7fe7128191bcab0c615706ef4fe2709f5
Reviewed-on: https://chromium-review.googlesource.com/219732
Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | futility/cmd_show.c | 48 | ||||
-rw-r--r-- | tests/futility/data/rec_kernel_part.bin | bin | 0 -> 4083712 bytes | |||
-rwxr-xr-x | tests/futility/run_test_scripts.sh | 1 | ||||
-rwxr-xr-x | tests/futility/test_show_vs_verify.sh | 75 | ||||
-rwxr-xr-x | tests/futility/test_sign_firmware.sh | 47 | ||||
-rwxr-xr-x | tests/futility/test_sign_kernel.sh | 15 |
6 files changed, 163 insertions, 23 deletions
diff --git a/futility/cmd_show.c b/futility/cmd_show.c index b8f06014..2873f60b 100644 --- a/futility/cmd_show.c +++ b/futility/cmd_show.c @@ -175,6 +175,8 @@ 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)) { printf(" BmpBlock: <invalid>\n"); + /* We don't support older BmpBlock formats, so we can't + * be strict about this. */ } else { printf(" BmpBlock:\n"); printf(" Version: %d.%d\n", @@ -198,6 +200,7 @@ int futil_cb_show_keyblock(struct futil_traverse_state_s *state) VbKeyBlockHeader *block = (VbKeyBlockHeader *)state->my_area->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)) { @@ -210,11 +213,14 @@ int futil_cb_show_keyblock(struct futil_traverse_state_s *state) KeyBlockVerify(block, state->my_area->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; - return 0; + return retval; } /* @@ -244,6 +250,7 @@ int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state) uint64_t fv_size = option.fv_size; struct cb_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)) { @@ -283,6 +290,9 @@ int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state) ? state->in_filename : state->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); @@ -311,6 +321,8 @@ int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state) kernel_subkey->algorithm, (kernel_subkey->algorithm < kNumAlgorithms ? algo_strings[kernel_subkey->algorithm] : "(invalid)")); + if (kernel_subkey->algorithm >= kNumAlgorithms) + retval = 1; printf(" Kernel key version: %" PRIu64 "\n", kernel_subkey->key_version); printf(" Kernel key sha1sum: "); @@ -335,6 +347,8 @@ int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state) if (!fv_data) { printf("No firmware body available to verify.\n"); + if (option.strict) + return 1; return 0; } @@ -354,9 +368,11 @@ done: state->my_area->_flags |= AREA_IS_VALID; } else { printf("Seems legit, but the signature is unverified.\n"); + if (option.strict) + retval = 1; } - return 0; + return retval; } int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state) @@ -368,6 +384,7 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state) uint8_t *kernel_blob = 0; uint64_t kernel_size; int good_sig = 0; + int retval = 0; /* Check the hash... */ if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) { @@ -383,6 +400,9 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state) printf("Kernel partition: %s\n", state->in_filename); show_keyblock(key_block, NULL, !!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); @@ -443,7 +463,7 @@ int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state) printf("Config:\n%s\n", kernel_blob + KernelCmdLineOffset(preamble)); - return 0; + return retval; } int futil_cb_show_begin(struct futil_traverse_state_s *state) @@ -474,6 +494,7 @@ static const char usage[] = "\n" "\n" "Where FILE could be a\n" "\n" + "%s" " keyblock (.keyblock)\n" " firmware preamble signature (VBLOCK_A/B)\n" " firmware image (bios.bin)\n" @@ -484,11 +505,19 @@ static const char usage[] = "\n" " Use this public key for validation\n" " -f|--fv FILE Verify this payload (FW_MAIN_A/B)\n" " --pad NUM Kernel vblock padding size\n" + "%s" "\n"; static void print_help(const char *prog) { - printf(usage, prog); + if (strcmp(prog, "verify")) + printf(usage, prog, + " public key (.vbpubk)\n", + " --strict " + "Fail unless all signatures are valid\n"); + else + printf(usage, prog, "", + "\nIt will fail unless all signatures are valid\n"); } static const struct option long_opts[] = { @@ -496,6 +525,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}, {"debug", 0, &debugging_enabled, 1}, {NULL, 0, NULL, 0}, }; @@ -612,3 +642,13 @@ boo: DECLARE_FUTIL_COMMAND(show, do_show, "Display the content of various binary components", print_help); + +static int do_verify(int argc, char *argv[]) +{ + option.strict = 1; + return do_show(argc, argv); +} + +DECLARE_FUTIL_COMMAND(verify, do_verify, + "Verify the signatures of various binary components", + print_help); diff --git a/tests/futility/data/rec_kernel_part.bin b/tests/futility/data/rec_kernel_part.bin Binary files differnew file mode 100644 index 00000000..54694bb6 --- /dev/null +++ b/tests/futility/data/rec_kernel_part.bin diff --git a/tests/futility/run_test_scripts.sh b/tests/futility/run_test_scripts.sh index f4508461..f6bbe885 100755 --- a/tests/futility/run_test_scripts.sh +++ b/tests/futility/run_test_scripts.sh @@ -45,6 +45,7 @@ ${SCRIPTDIR}/test_dump_fmap.sh ${SCRIPTDIR}/test_load_fmap.sh ${SCRIPTDIR}/test_gbb_utility.sh ${SCRIPTDIR}/test_show_kernel.sh +${SCRIPTDIR}/test_show_vs_verify.sh ${SCRIPTDIR}/test_sign_keyblocks.sh ${SCRIPTDIR}/test_sign_fw_main.sh ${SCRIPTDIR}/test_sign_firmware.sh diff --git a/tests/futility/test_show_vs_verify.sh b/tests/futility/test_show_vs_verify.sh new file mode 100755 index 00000000..6cccd0be --- /dev/null +++ b/tests/futility/test_show_vs_verify.sh @@ -0,0 +1,75 @@ +#!/bin/bash -eux +# 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. + +me=${0##*/} +TMP="$me.tmp" + +# Work in scratch directory +cd "$OUTDIR" + +# some stuff we'll need +DEVKEYS=${SRCDIR}/tests/devkeys + +# The show command exits with 0 if the data is consistent. +# The verify command exits with 0 only if all the data is verified. + +#### keyblock + +${FUTILITY} show ${DEVKEYS}/firmware.keyblock + +if ${FUTILITY} verify ${DEVKEYS}/firmware.keyblock ; then false; fi + +${FUTILITY} verify ${DEVKEYS}/firmware.keyblock \ + --publickey ${DEVKEYS}/root_key.vbpubk + + +#### firmware vblock + +# Get some bits to look at +${FUTILITY} dump_fmap -x ${SCRIPTDIR}/data/bios_peppy_mp.bin \ + GBB:${TMP}.gbb VBLOCK_A:${TMP}.vblock_a FW_MAIN_A:${TMP}.fw_main_a +${FUTILITY} gbb_utility -g -k ${TMP}.rootkey ${TMP}.gbb + + +${FUTILITY} show ${TMP}.vblock_a + +${FUTILITY} show ${TMP}.vblock_a --publickey ${TMP}.rootkey + +${FUTILITY} show ${TMP}.vblock_a \ + --publickey ${TMP}.rootkey \ + --fv ${TMP}.fw_main_a + +if ${FUTILITY} verify ${TMP}.vblock_a ; then false ; fi + +if ${FUTILITY} verify ${TMP}.vblock_a \ + --publickey ${TMP}.rootkey ; then false ; fi + +${FUTILITY} verify ${TMP}.vblock_a \ + --publickey ${TMP}.rootkey \ + --fv ${TMP}.fw_main_a + + +#### kernel partition + +${FUTILITY} show ${SCRIPTDIR}/data/rec_kernel_part.bin + +${FUTILITY} show ${SCRIPTDIR}/data/rec_kernel_part.bin \ + --publickey ${DEVKEYS}/kernel_subkey.vbpubk + +${FUTILITY} show ${SCRIPTDIR}/data/rec_kernel_part.bin \ + --publickey ${DEVKEYS}/recovery_key.vbpubk + +if ${FUTILITY} verify ${SCRIPTDIR}/data/rec_kernel_part.bin ; then false ; fi + +if ${FUTILITY} verify ${SCRIPTDIR}/data/rec_kernel_part.bin \ + --publickey ${DEVKEYS}/kernel_subkey.vbpubk ; then false ; fi + +${FUTILITY} verify ${SCRIPTDIR}/data/rec_kernel_part.bin \ + --publickey ${DEVKEYS}/recovery_key.vbpubk + + +# cleanup +rm -rf ${TMP}* +exit 0 diff --git a/tests/futility/test_sign_firmware.sh b/tests/futility/test_sign_firmware.sh index 649382d9..7ebedcca 100755 --- a/tests/futility/test_sign_firmware.sh +++ b/tests/futility/test_sign_firmware.sh @@ -30,6 +30,8 @@ cp ${GOOD_VBLOCKS} ${ONEMORE} ${FUTILITY} load_fmap ${ONEMORE} VBLOCK_A:/dev/urandom VBLOCK_B:/dev/zero INFILES="${INFILES} ${ONEMORE}" +set -o pipefail + count=0 for infile in $INFILES; do @@ -84,21 +86,32 @@ for infile in $INFILES; do ${infile} ${outfile} # check the firmware version and preamble flags - # TODO: verify - m=$(${FUTILITY} show ${outfile} | \ - egrep 'Firmware version: +14$|Preamble flags: +8$' | wc -l) + m=$(${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${outfile} \ + | egrep 'Firmware version: +14$|Preamble flags: +8$' | wc -l) [ "$m" = "4" ] # check the sha1sums - # TODO: verify - ${FUTILITY} show ${outfile} | grep sha1sum \ + ${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${outfile} \ + | grep sha1sum \ | sed -e 's/.*: \+//' > ${TMP}.${base}.sha.new cmp ${SCRIPTDIR}/data_${base}_expect.txt ${TMP}.${base}.sha.new - # and the LOEM stuff - # TODO: verify - ${FUTILITY} show ${loemdir}/*.${loemid} | grep sha1sum \ - | sed -e 's/.*: \+//' > ${loemdir}/loem.sha.new + # and the LOEM stuff + ${FUTILITY} dump_fmap -x ${outfile} \ + FW_MAIN_A:${loemdir}/fw_main_A FW_MAIN_B:${loemdir}/fw_main_B \ + "Firmware A Data":${loemdir}/fw_main_A \ + "Firmware B Data":${loemdir}/fw_main_B + + + ${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk \ + --fv ${loemdir}/fw_main_A \ + ${loemdir}/vblock_A.${loemid} | grep sha1sum \ + | sed -e 's/.*: \+//' > ${loemdir}/loem.sha.new + ${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk \ + --fv ${loemdir}/fw_main_B \ + ${loemdir}/vblock_B.${loemid} | grep sha1sum \ + | sed -e 's/.*: \+//' >> ${loemdir}/loem.sha.new + # the vblocks don't have root or recovery keys tail -4 ${SCRIPTDIR}/data_${base}_expect.txt > ${loemdir}/sha.expect cmp ${loemdir}/sha.expect ${loemdir}/loem.sha.new @@ -109,8 +122,7 @@ done GOOD_OUT=${TMP}.${GOOD_VBLOCKS##*/}.new MORE_OUT=${TMP}.${ONEMORE##*/}.new -# TODO: verify -${FUTILITY} show ${GOOD_OUT} \ +${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${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 @@ -118,8 +130,7 @@ ${FUTILITY} dump_fmap -p ${GOOD_OUT} \ 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 -# TODO: verify -${FUTILITY} show ${MORE_OUT} \ +${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${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 @@ -141,9 +152,8 @@ ${FUTILITY} sign \ -k ${KEYDIR}/kernel_subkey.vbpubk \ ${MORE_OUT} ${MORE_OUT}.2 -# TODO: verify -m=$(${FUTILITY} show ${MORE_OUT}.2 | \ - egrep 'Firmware version: +1$|Preamble flags: +8$' | wc -l) +m=$(${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${MORE_OUT}.2 \ + | egrep 'Firmware version: +1$|Preamble flags: +8$' | wc -l) [ "$m" = "4" ] @@ -160,9 +170,8 @@ ${FUTILITY} sign \ -k ${KEYDIR}/kernel_subkey.vbpubk \ ${MORE_OUT} ${MORE_OUT}.3 -# TODO: verify -m=$(${FUTILITY} show ${MORE_OUT}.3 | \ - egrep 'Firmware version: +1$|Preamble flags: +0$' | wc -l) +m=$(${FUTILITY} verify --publickey ${KEYDIR}/root_key.vbpubk ${MORE_OUT}.3 \ + | egrep 'Firmware version: +1$|Preamble flags: +0$' | wc -l) [ "$m" = "4" ] diff --git a/tests/futility/test_sign_kernel.sh b/tests/futility/test_sign_kernel.sh index 0fdb6259..2a8e8c13 100755 --- a/tests/futility/test_sign_kernel.sh +++ b/tests/futility/test_sign_kernel.sh @@ -147,6 +147,14 @@ try_arch () { cmp ${TMP}.blob2.${arch}.vb0 ${TMP}.blob2.${arch}.vb1 + # and verify it the new way + dd bs=${padding} skip=1 if=${TMP}.blob2.${arch} of=${TMP}.blob2.${arch}.kb1 + ${FUTILITY} verify --debug \ + --pad ${padding} \ + --publickey ${DEVKEYS}/recovery_key.vbpubk \ + --fv ${TMP}.blob2.${arch}.kb1 \ + ${TMP}.blob2.${arch}.vb1 + echo -n "5 " 1>&3 dd bs=${padding} count=1 if=${TMP}.blob3.${arch} of=${TMP}.blob3.${arch}.vb0 @@ -176,6 +184,13 @@ try_arch () { cmp ${TMP}.blob4.${arch}.vb0 ${TMP}.blob4.${arch}.vb1 + dd bs=${padding} skip=1 if=${TMP}.blob4.${arch} of=${TMP}.blob4.${arch}.kb1 + ${FUTILITY} verify --debug \ + --pad ${padding} \ + --publickey ${DEVKEYS}/kernel_subkey.vbpubk \ + --fv ${TMP}.blob4.${arch}.kb1 \ + ${TMP}.blob4.${arch}.vb1 + # Note: We specifically do not test repacking with a different --kloadaddr, # because the old way has a bug and does not update params->cmd_line_ptr to # point at the new on-disk location. Apparently (and not surprisingly), no |