diff options
-rw-r--r-- | futility/cmd_sign.c | 167 | ||||
-rw-r--r-- | futility/futility_options.h | 1 | ||||
-rwxr-xr-x | tests/futility/test_sign_firmware.sh | 43 | ||||
-rwxr-xr-x | tests/futility/test_sign_fw_main.sh | 4 | ||||
-rwxr-xr-x | tests/futility/test_sign_kernel.sh | 5 |
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}" \ |