summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Czapiga <jacz@semihalf.com>2022-07-04 12:34:28 +0200
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2022-07-22 07:46:32 +0000
commit64dd01225f64d6745a008d91fba3fcac2f1920bd (patch)
tree6d1bb9a194c763284a8d2655853b212ade295cd7
parent499b1814a76303b332c49dd5efb2c84e30b973ba (diff)
downloadvboot-factory-foobar-15000.B.tar.gz
futility: Add --keyset option to sign command for BIOS and kernelstabilize-14998.Bfactory-foobar-15000.B
This patch adds --keyset option for sign command for BIOS_IMAGE, RAW_FIRMWARE, RAW_KERNEL and KERN_PREAMBLE file types. The default value of this option is '/usr/share/vboot/devkeys'. It allows futility to load public and private keys, and keyblocks from under this path, when they were not provided manually using their respective options. Files loaded by default for BIOS_IMAGE and RAW_FIRMWARE: - ${keysetdir}/firmware_data_key.vbprivk - ${keysetdir}/firmware.keyblock - ${keysetdir}/kernel_subkey.vbpubk Files loaded by default for RAW_KERNEL: - ${keysetdir}/kernel_data_key.vbprivk - ${keysetdir}/kernel.keyblock File loaded by default for KERN_PREAMBLE: - ${keysetdir}/kernel_data_key.vbprivk BUG=none BRANCH=none TEST=make runfutiltests Signed-off-by: Jakub Czapiga <jacz@semihalf.com> Change-Id: Ic4026d501d88e0de7d2c6f52c7494c639d08bd15 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/3740601 Auto-Submit: Jakub Czapiga <czapiga@google.com> Reviewed-by: Julius Werner <jwerner@chromium.org> Commit-Queue: Julius Werner <jwerner@chromium.org> Tested-by: Jakub Czapiga <czapiga@google.com>
-rw-r--r--futility/cmd_sign.c167
-rw-r--r--futility/futility_options.h1
-rwxr-xr-xtests/futility/test_sign_firmware.sh43
-rwxr-xr-xtests/futility/test_sign_fw_main.sh4
-rwxr-xr-xtests/futility/test_sign_kernel.sh5
5 files changed, 165 insertions, 55 deletions
diff --git a/futility/cmd_sign.c b/futility/cmd_sign.c
index b35712a3..2f9a0179 100644
--- a/futility/cmd_sign.c
+++ b/futility/cmd_sign.c
@@ -29,8 +29,11 @@
#include "util_misc.h"
#include "vb1_helper.h"
+#define DEFAULT_KEYSETDIR "/usr/share/vboot/devkeys"
+
/* Options */
struct sign_option_s sign_option = {
+ .keysetdir = DEFAULT_KEYSETDIR,
.version = 1,
.arch = ARCH_UNSPECIFIED,
.kloadaddr = CROS_32BIT_ENTRY_ADDR,
@@ -306,6 +309,86 @@ done:
return rv;
}
+static int load_keyset(void)
+{
+ char *buf = NULL;
+ int errorcnt = 0;
+ const char *s = NULL;
+ const char *b = NULL;
+ const char *k = NULL;
+ const char *format;
+ struct stat sb;
+
+ if (!sign_option.keysetdir)
+ FATAL("Keyset should never be NULL. Aborting\n");
+
+ /* Failure means this is not a directory */
+ if (stat(sign_option.keysetdir, &sb) == -1 ||
+ (sb.st_mode & S_IFMT) != S_IFDIR)
+ format = "%s%s.%s";
+ else
+ format = "%s/%s.%s";
+
+ switch (sign_option.type) {
+ case FILE_TYPE_BIOS_IMAGE:
+ case FILE_TYPE_RAW_FIRMWARE:
+ s = "firmware_data_key";
+ b = "firmware";
+ k = "kernel_subkey";
+ break;
+ case FILE_TYPE_RAW_KERNEL:
+ s = "kernel_data_key";
+ b = "kernel";
+ break;
+ case FILE_TYPE_KERN_PREAMBLE:
+ s = "kernel_data_key";
+ break;
+ default:
+ return 0;
+ }
+
+ if (s && !sign_option.signprivate) {
+ if (asprintf(&buf, format, sign_option.keysetdir, s,
+ "vbprivk") <= 0)
+ FATAL("Failed to allocate string\n");
+ INFO("Loading private data key from default keyset: %s\n", buf);
+ sign_option.signprivate = vb2_read_private_key(buf);
+ if (!sign_option.signprivate) {
+ ERROR("Error reading %s\n", buf);
+ errorcnt++;
+ }
+ free(buf);
+ }
+
+ if (b && !sign_option.keyblock) {
+ if (asprintf(&buf, format, sign_option.keysetdir, b,
+ "keyblock") <= 0)
+ FATAL("Failed to allocate string\n");
+ INFO("Loading keyblock from default keyset: %s\n", buf);
+ sign_option.keyblock = vb2_read_keyblock(buf);
+ if (!sign_option.keyblock) {
+ ERROR("Error reading %s\n", buf);
+ errorcnt++;
+ }
+ free(buf);
+ }
+
+ if (k && !sign_option.kernel_subkey) {
+ if (asprintf(&buf, format, sign_option.keysetdir, k,
+ "vbpubk") <= 0)
+ FATAL("Failed to allocate string\n");
+ INFO("Loading kernel subkey from default keyset: %s\n", buf);
+ sign_option.kernel_subkey = vb2_read_packed_key(buf);
+ if (!sign_option.kernel_subkey) {
+ ERROR("Error reading %s\n", buf);
+ errorcnt++;
+ }
+ free(buf);
+ }
+
+ return errorcnt;
+}
+
static const char usage_pubkey[] = "\n"
"To sign a public key / create a new keyblock:\n"
"\n"
@@ -338,36 +421,46 @@ static const char usage_fw_main[] = "\n"
"To sign a raw firmware blob (FW_MAIN_A/B):\n"
"\n"
"Required PARAMS:\n"
- " -s|--signprivate FILE.vbprivk The private firmware data key\n"
- " -b|--keyblock FILE.keyblock The keyblock containing the\n"
- " public firmware data key\n"
- " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
" -v|--version NUM The firmware version number\n"
" [--fv] INFILE"
" The raw firmware blob (FW_MAIN_A/B)\n"
" [--outfile] OUTFILE Output VBLOCK_A/B\n"
"\n"
"Optional PARAMS:\n"
+ " -s|--signprivate FILE.vbprivk The private firmware data key\n"
+ " -b|--keyblock FILE.keyblock The keyblock containing the\n"
+ " public firmware data key\n"
+ " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
" -f|--flags NUM The preamble flags value"
" (default is 0)\n"
+ " -K|--keyset PATH Prefix of private firmware data"
+ " key,\n"
+ " keyblock and public kernel"
+ " subkey.\n"
+ " Prefix must be valid path with\n"
+ " optional file name prefix.\n"
+ " Used as defaults for -s, -b and"
+ " -k,\n"
+ " if not passed expliticly\n"
+ " (default is '%s')\n"
"\n";
static void print_help_raw_firmware(int argc, char *argv[])
{
- puts(usage_fw_main);
+ printf(usage_fw_main, DEFAULT_KEYSETDIR);
}
static const char usage_bios[] = "\n"
"To sign a complete firmware image (bios.bin):\n"
"\n"
"Required PARAMS:\n"
- " -s|--signprivate FILE.vbprivk The private firmware data key\n"
- " -b|--keyblock FILE.keyblock The keyblock containing the\n"
- " public firmware data key\n"
- " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
" [--infile] INFILE Input firmware image (modified\n"
" in place if no OUTFILE given)\n"
"\n"
"Optional PARAMS:\n"
+ " -s|--signprivate FILE.vbprivk The private firmware data key\n"
+ " -b|--keyblock FILE.keyblock The keyblock containing the\n"
+ " public firmware data key\n"
+ " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
" -v|--version NUM The firmware version number"
" (default %d)\n"
" -f|--flags NUM The preamble flags value"
@@ -375,21 +468,27 @@ static const char usage_bios[] = "\n"
" unchanged, or 0 if unknown)\n"
" -d|--loemdir DIR Local OEM output vblock directory\n"
" -l|--loemid STRING Local OEM vblock suffix\n"
+ " -K|--keyset PATH Prefix of private firmware data"
+ " key,\n"
+ " keyblock and public kernel"
+ " subkey.\n"
+ " Prefix must be valid path with\n"
+ " optional file name prefix.\n"
+ " Used as defaults for -s, -b and"
+ " -k,\n"
+ " if not passed expliticly\n"
+ " (default is '%s')\n"
" [--outfile] OUTFILE Output firmware image\n"
"\n";
static void print_help_bios_image(int argc, char *argv[])
{
- printf(usage_bios, sign_option.version);
+ printf(usage_bios, sign_option.version, DEFAULT_KEYSETDIR);
}
static const char usage_new_kpart[] = "\n"
"To create a new kernel partition image (/dev/sda2, /dev/mmcblk0p2):\n"
"\n"
"Required PARAMS:\n"
- " -s|--signprivate FILE.vbprivk"
- " The private key to sign the kernel blob\n"
- " -b|--keyblock FILE.keyblock Keyblock containing the public\n"
- " key to verify the kernel blob\n"
" -v|--version NUM The kernel version number\n"
" --bootloader FILE Bootloader stub\n"
" --config FILE The kernel commandline file\n"
@@ -399,6 +498,10 @@ static const char usage_new_kpart[] = "\n"
" [--outfile] OUTFILE Output kernel partition or vblock\n"
"\n"
"Optional PARAMS:\n"
+ " -s|--signprivate FILE.vbprivk"
+ " The private key to sign the kernel blob\n"
+ " -b|--keyblock FILE.keyblock Keyblock containing the public\n"
+ " key to verify the kernel blob\n"
" --kloadaddr NUM"
" RAM address to load the kernel body\n"
" (default %#x)\n"
@@ -407,22 +510,33 @@ static const char usage_new_kpart[] = "\n"
" --vblockonly Emit just the vblock (requires a\n"
" distinct outfile)\n"
" -f|--flags NUM The preamble flags value\n"
+ " -K|--keyset DIR Path to directory containing"
+ " private\n"
+ " kernel data key, and keyblock\n"
+ " -K|--keyset PATH Prefix of private kernel data key\n"
+ " and keyblock.\n"
+ " Prefix must be valid path with\n"
+ " optional file name prefix.\n"
+ " Used as defaults for -s and -b,\n"
+ " if not passed expliticly\n"
+ " (default is '%s')\n"
"\n";
static void print_help_raw_kernel(int argc, char *argv[])
{
- printf(usage_new_kpart, sign_option.kloadaddr, sign_option.padding);
+ printf(usage_new_kpart, sign_option.kloadaddr, sign_option.padding,
+ DEFAULT_KEYSETDIR);
}
static const char usage_old_kpart[] = "\n"
"To resign an existing kernel partition (/dev/sda2, /dev/mmcblk0p2):\n"
"\n"
"Required PARAMS:\n"
- " -s|--signprivate FILE.vbprivk"
- " The private key to sign the kernel blob\n"
" [--infile] INFILE Input kernel partition (modified\n"
" in place if no OUTFILE given)\n"
"\n"
"Optional PARAMS:\n"
+ " -s|--signprivate FILE.vbprivk"
+ " The private key to sign the kernel blob\n"
" -b|--keyblock FILE.keyblock Keyblock containing the public\n"
" key to verify the kernel blob\n"
" -v|--version NUM The kernel version number\n"
@@ -433,10 +547,17 @@ static const char usage_old_kpart[] = "\n"
" --vblockonly Emit just the vblock (requires a\n"
" distinct OUTFILE)\n"
" -f|--flags NUM The preamble flags value\n"
+ " -K|--keyset PATH Prefix of private kernel data"
+ " key.\n"
+ " Prefix must be valid path with\n"
+ " optional file name prefix.\n"
+ " Used as default for -s,\n"
+ " if not passed expliticly\n"
+ " (default is '%s')\n"
"\n";
static void print_help_kern_preamble(int argc, char *argv[])
{
- printf(usage_old_kpart, sign_option.padding);
+ printf(usage_old_kpart, sign_option.padding, DEFAULT_KEYSETDIR);
}
static void print_help_usbpd1(int argc, char *argv[])
@@ -619,6 +740,7 @@ static const struct option long_opts[] = {
{"flags", 1, NULL, 'f'},
{"loemdir", 1, NULL, 'd'},
{"loemid", 1, NULL, 'l'},
+ {"keyset", 1, NULL, 'K'},
{"fv", 1, NULL, OPT_FV},
{"infile", 1, NULL, OPT_INFILE},
{"datapubkey", 1, NULL, OPT_INFILE}, /* alias */
@@ -647,7 +769,7 @@ static const struct option long_opts[] = {
{"help", 0, NULL, OPT_HELP},
{NULL, 0, NULL, 0},
};
-static const char *short_opts = ":s:b:k:S:B:v:f:d:l:";
+static const char *short_opts = ":s:b:k:v:f:d:l:K:";
/* Return zero on success */
static int parse_number_opt(const char *arg, const char *name, uint32_t *dest)
@@ -717,6 +839,9 @@ static int do_sign(int argc, char *argv[])
case 'l':
sign_option.loemid = optarg;
break;
+ case 'K':
+ sign_option.keysetdir = optarg;
+ break;
case OPT_FV:
sign_option.fv_specified = 1;
VBOOT_FALLTHROUGH;
@@ -908,6 +1033,10 @@ static int do_sign(int argc, char *argv[])
sign_option.type = FILE_TYPE_RAW_FIRMWARE;
}
+ /* Load keys and keyblocks from keyset path, if they were not provided
+ earlier. */
+ errorcnt += load_keyset();
+
VB2_DEBUG("type=%s\n", futil_file_type_name(sign_option.type));
/* Check the arguments for the type of thing we want to sign */
diff --git a/futility/futility_options.h b/futility/futility_options.h
index da839586..32f240a5 100644
--- a/futility/futility_options.h
+++ b/futility/futility_options.h
@@ -34,6 +34,7 @@ struct sign_option_s {
struct vb2_private_key *signprivate;
struct vb2_keyblock *keyblock;
struct vb2_packed_key *kernel_subkey;
+ const char *keysetdir;
uint32_t version;
int version_specified;
uint32_t flags;
diff --git a/tests/futility/test_sign_firmware.sh b/tests/futility/test_sign_firmware.sh
index c373803f..fe8462c8 100755
--- a/tests/futility/test_sign_firmware.sh
+++ b/tests/futility/test_sign_firmware.sh
@@ -111,9 +111,7 @@ for infile in $INFILES; do
mkdir -p "${loemdir}"
"${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
-v 14 \
-f 8 \
-d "${loemdir}" \
@@ -193,8 +191,7 @@ cbfstool "${GOOD_CBFS_OUT}.1" add \
"${FUTILITY}" sign \
-s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${GOOD_CBFS_OUT}.1"
"${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \
@@ -222,9 +219,8 @@ cbfstool "${GOOD_CBFS_OUT}.1" add \
echo -n "${count} " 1>&3
"${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
-b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${MORE_OUT}" "${MORE_OUT}.2"
m=$("${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \
@@ -238,9 +234,8 @@ echo -n "${count} " 1>&3
"${FUTILITY}" load_fmap "${MORE_OUT}" VBLOCK_A:/dev/urandom VBLOCK_B:/dev/zero
"${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
-k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${MORE_OUT}" "${MORE_OUT}.3"
m=$("${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" \
@@ -256,7 +251,7 @@ echo -n "${count} " 1>&3
"${FUTILITY}" sign \
-s "${KEYDIR}/firmware_data_key.vbprivk" \
-b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${CLEAN_B}" "${CLEAN_B}.1"
"${FUTILITY}" verify --publickey "${KEYDIR}/root_key.vbpubk" "${CLEAN_B}.1" \
@@ -291,8 +286,8 @@ apply_xxd_patch "${NO_B_SLOT_PATCH}" "${NO_B_SLOT}"
"${FUTILITY}" sign \
-s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
-k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
-v 1 \
"${NO_B_SLOT}" "${NO_B_SLOT_SIGNED_IMG}"
@@ -321,9 +316,9 @@ echo -en 'echo "0xFFEEDD0"; exit 0;' > "${CBFSTOOL_STUB}"
chmod +x "${CBFSTOOL_STUB}"
if CBFSTOOL="${CBFSTOOL_STUB}" "${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
-b "${KEYDIR}/firmware.keyblock" \
-k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
-v 1 \
"${GOOD_CBFS}" "${TMP}.1.${GOOD_CBFS##*/}"
then
@@ -351,9 +346,7 @@ exit 0;
EOF
if CBFSTOOL="${CBFSTOOL_STUB}" "${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
-v 1 \
"${GOOD_CBFS}" "${TMP}.2.${GOOD_CBFS##*/}"
then
@@ -379,9 +372,7 @@ for keyblock_patch in "${BAD_KEYBLOCK_PATCHES[@]}"; do
grep -q 'VBLOCK_A keyblock component is invalid' <<< "${FUTIL_OUTPUT}"
FUTIL_OUTPUT="$("${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${BAD_IN}" "${BAD_OUT}" 2>&1)"
grep -q 'VBLOCK_A keyblock is invalid' <<< "${FUTIL_OUTPUT}"
@@ -410,9 +401,7 @@ for vblock_patch in "${BAD_PREAMBLE_PATCHES[@]}"; do
grep -q 'VBLOCK_A is invalid' <<< "${FUTIL_OUTPUT}"
FUTIL_OUTPUT="$("${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${BAD_IN}" "${BAD_OUT}" 2>&1)"
grep -q 'VBLOCK_A preamble is invalid' <<< "${FUTIL_OUTPUT}"
@@ -441,9 +430,7 @@ for vblock_patch in "${BAD_FMAP_KEYBLOCK_PATCHES[@]}"; do
grep -q 'VBLOCK_A keyblock component is invalid' <<< "${FUTIL_OUTPUT}"
FUTIL_OUTPUT="$(if "${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${BAD_IN}" "${BAD_OUT}" 2>&1; \
then false; fi)"
m="$(grep -c -E \
@@ -466,9 +453,7 @@ FUTIL_OUTPUT="$(if "${FUTILITY}" verify \
grep -q 'VBLOCK_A is invalid' <<< "${FUTIL_OUTPUT}"
FUTIL_OUTPUT="$(if "${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${BAD_IN}" "${BAD_OUT}" 2>&1; \
then false; fi)"
m="$(grep -c -E \
@@ -490,9 +475,7 @@ FUTIL_OUTPUT="$(if "${FUTILITY}" verify \
grep -q 'VBLOCK_A is invalid' <<< "${FUTIL_OUTPUT}"
FUTIL_OUTPUT="$(if "${FUTILITY}" sign \
- -s "${KEYDIR}/firmware_data_key.vbprivk" \
- -b "${KEYDIR}/firmware.keyblock" \
- -k "${KEYDIR}/kernel_subkey.vbpubk" \
+ -K "${KEYDIR}" \
"${BAD_IN}" "${BAD_OUT}" 2>&1; \
then false; fi)"
m="$(grep -c -E \
diff --git a/tests/futility/test_sign_fw_main.sh b/tests/futility/test_sign_fw_main.sh
index 6ab2083b..e22f9072 100755
--- a/tests/futility/test_sign_fw_main.sh
+++ b/tests/futility/test_sign_fw_main.sh
@@ -30,9 +30,7 @@ dd bs=1024 count=16 if=/dev/urandom of="${TMP}.fw_main"
# and the new way
"${FUTILITY}" --debug sign \
- --signprivate "${KEYDIR}/firmware_data_key.vbprivk" \
- --keyblock "${KEYDIR}/firmware.keyblock" \
- --kernelkey "${KEYDIR}/kernel_subkey.vbpubk" \
+ --keyset "${KEYDIR}" \
--version 12 \
--fv "${TMP}.fw_main" \
--flags 42 \
diff --git a/tests/futility/test_sign_kernel.sh b/tests/futility/test_sign_kernel.sh
index 61b1c5aa..bba1164f 100755
--- a/tests/futility/test_sign_kernel.sh
+++ b/tests/futility/test_sign_kernel.sh
@@ -45,8 +45,7 @@ try_arch () {
# pack it up the new way
"${FUTILITY}" --debug sign \
- --keyblock "${DEVKEYS}/recovery_kernel.keyblock" \
- --signprivate "${DEVKEYS}/recovery_kernel_data_key.vbprivk" \
+ --keyset "${DEVKEYS}/recovery_" \
--version 1 \
--config "${TMP}.config.txt" \
--bootloader "${TMP}.bootloader.bin" \
@@ -84,7 +83,7 @@ try_arch () {
# repack it the new way
"${FUTILITY}" --debug sign \
- --signprivate "${DEVKEYS}/kernel_data_key.vbprivk" \
+ --keyset "${DEVKEYS}" \
--keyblock "${DEVKEYS}/kernel.keyblock" \
--version 2 \
--pad "${padding}" \