123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- /*
- * 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.
- */
- #define OPENSSL_NO_SHA
- #include <openssl/rsa.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <getopt.h>
- #include <inttypes.h>
- #include <stddef.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include "2sysincludes.h"
- #include "2api.h"
- #include "2common.h"
- #include "2sha.h"
- #include "file_type.h"
- #include "file_type_bios.h"
- #include "fmap.h"
- #include "futility.h"
- #include "futility_options.h"
- #include "host_common.h"
- #include "host_key2.h"
- #include "util_misc.h"
- #include "vb1_helper.h"
- #include "vb2_common.h"
- /* Options */
- struct show_option_s show_option = {
- .padding = 65536,
- .type = FILE_TYPE_UNKNOWN,
- };
- /* Shared work buffer */
- static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE];
- static struct vb2_workbuf wb;
- void show_pubkey(const struct vb2_packed_key *pubkey, const char *sp)
- {
- printf("%sVboot API: 1.0\n", sp);
- printf("%sAlgorithm: %d %s\n", sp, pubkey->algorithm,
- vb2_get_crypto_algorithm_name(pubkey->algorithm));
- printf("%sKey Version: %d\n", sp, pubkey->key_version);
- printf("%sKey sha1sum: %s\n",
- sp, packed_key_sha1_string(pubkey));
- }
- static void show_keyblock(struct vb2_keyblock *keyblock, const char *name,
- int sign_key, int good_sig)
- {
- if (name)
- printf("Key block: %s\n", name);
- else
- printf("Key block:\n");
- printf(" Signature: %s\n",
- sign_key ? (good_sig ? "valid" : "invalid") : "ignored");
- printf(" Size: 0x%x\n", keyblock->keyblock_size);
- printf(" Flags: %d ", keyblock->keyblock_flags);
- if (keyblock->keyblock_flags & VB2_KEY_BLOCK_FLAG_DEVELOPER_0)
- printf(" !DEV");
- if (keyblock->keyblock_flags & VB2_KEY_BLOCK_FLAG_DEVELOPER_1)
- printf(" DEV");
- if (keyblock->keyblock_flags & VB2_KEY_BLOCK_FLAG_RECOVERY_0)
- printf(" !REC");
- if (keyblock->keyblock_flags & VB2_KEY_BLOCK_FLAG_RECOVERY_1)
- printf(" REC");
- printf("\n");
- struct vb2_packed_key *data_key = &keyblock->data_key;
- printf(" Data key algorithm: %d %s\n", data_key->algorithm,
- vb2_get_crypto_algorithm_name(data_key->algorithm));
- printf(" Data key version: %d\n", data_key->key_version);
- printf(" Data key sha1sum: %s\n",
- packed_key_sha1_string(data_key));
- }
- int ft_show_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
- {
- struct vb2_packed_key *pubkey = (struct vb2_packed_key *)buf;
- if (!packed_key_looks_ok(pubkey, len)) {
- printf("%s looks bogus\n", name);
- return 1;
- }
- printf("Public Key file: %s\n", name);
- show_pubkey(pubkey, " ");
- return 0;
- }
- int ft_show_privkey(const char *name, uint8_t *buf, uint32_t len, void *data)
- {
- struct vb2_packed_private_key *pkey =
- (struct vb2_packed_private_key *)buf;
- struct vb2_private_key key;
- const unsigned char *start = pkey->key_data;
- if (len <= sizeof(*pkey)) {
- printf("%s looks bogus\n", name);
- return 1;
- }
- len -= sizeof(*pkey);
- key.rsa_private_key = d2i_RSAPrivateKey(NULL, &start, len);
- printf("Private Key file: %s\n", name);
- printf(" Vboot API: 1.0\n");
- printf(" Algorithm: %u %s\n", pkey->algorithm,
- vb2_get_crypto_algorithm_name(pkey->algorithm));
- printf(" Key sha1sum: %s\n",
- private_key_sha1_string(&key));
- return 0;
- }
- int ft_show_keyblock(const char *name, uint8_t *buf, uint32_t len, void *data)
- {
- struct vb2_keyblock *block = (struct vb2_keyblock *)buf;
- struct vb2_public_key *sign_key = show_option.k;
- int good_sig = 0;
- int retval = 0;
- /* Check the hash only first */
- if (0 != vb2_verify_keyblock_hash(block, len, &wb)) {
- printf("%s is invalid\n", name);
- return 1;
- }
- /* Check the signature if we have one */
- if (sign_key &&
- VB2_SUCCESS == vb2_verify_keyblock(block, len, sign_key, &wb))
- good_sig = 1;
- if (show_option.strict && (!sign_key || !good_sig))
- retval = 1;
- show_keyblock(block, name, !!sign_key, good_sig);
- return retval;
- }
- int ft_show_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
- void *data)
- {
- struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf;
- struct bios_state_s *state = (struct bios_state_s *)data;
- struct vb2_public_key *sign_key = show_option.k;
- uint8_t *fv_data = show_option.fv;
- uint64_t fv_size = show_option.fv_size;
- struct bios_area_s *fw_body_area = 0;
- int good_sig = 0;
- int retval = 0;
- /* Check the hash... */
- if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) {
- printf("%s keyblock component is invalid\n", name);
- return 1;
- }
- /*
- * 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.
- */
- struct vb2_public_key root_key;
- if (state) {
- if (!sign_key &&
- state->rootkey.is_valid &&
- VB2_SUCCESS == vb2_unpack_key_buffer(&root_key,
- state->rootkey.buf,
- state->rootkey.len)) {
- /* BIOS should have a rootkey in the GBB */
- sign_key = &root_key;
- }
- /* 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 */
- if (sign_key && VB2_SUCCESS ==
- vb2_verify_keyblock(keyblock, len, sign_key, &wb))
- good_sig = 1;
- show_keyblock(keyblock, name, !!sign_key, good_sig);
- if (show_option.strict && (!sign_key || !good_sig))
- retval = 1;
- struct vb2_public_key data_key;
- if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) {
- fprintf(stderr, "Error parsing data key in %s\n", name);
- return 1;
- }
- uint32_t more = keyblock->keyblock_size;
- struct vb2_fw_preamble *pre2 = (struct vb2_fw_preamble *)(buf + more);
- if (VB2_SUCCESS != vb2_verify_fw_preamble(pre2, len - more,
- &data_key, &wb)) {
- printf("%s is invalid\n", name);
- return 1;
- }
- uint32_t flags = pre2->flags;
- if (pre2->header_version_minor < 1)
- flags = 0; /* Old 2.0 structure didn't have flags */
- printf("Firmware Preamble:\n");
- printf(" Size: %d\n", pre2->preamble_size);
- printf(" Header version: %d.%d\n",
- pre2->header_version_major, pre2->header_version_minor);
- printf(" Firmware version: %d\n", pre2->firmware_version);
- struct vb2_packed_key *kernel_subkey = &pre2->kernel_subkey;
- printf(" Kernel key algorithm: %d %s\n",
- kernel_subkey->algorithm,
- vb2_get_crypto_algorithm_name(kernel_subkey->algorithm));
- if (kernel_subkey->algorithm >= VB2_ALG_COUNT)
- retval = 1;
- printf(" Kernel key version: %d\n", kernel_subkey->key_version);
- printf(" Kernel key sha1sum: %s\n",
- packed_key_sha1_string(kernel_subkey));
- printf(" Firmware body size: %d\n", pre2->body_signature.data_size);
- printf(" Preamble flags: %d\n", flags);
- if (flags & VB2_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
- printf("Preamble requests USE_RO_NORMAL;"
- " skipping body verification.\n");
- goto done;
- }
- /* We'll need to get the firmware body from somewhere... */
- if (fw_body_area && fw_body_area->is_valid) {
- fv_data = fw_body_area->buf;
- fv_size = fw_body_area->len;
- }
- if (!fv_data) {
- printf("No firmware body available to verify.\n");
- if (show_option.strict)
- return 1;
- return 0;
- }
- if (VB2_SUCCESS !=
- vb2_verify_data(fv_data, fv_size, &pre2->body_signature,
- &data_key, &wb)) {
- fprintf(stderr, "Error verifying firmware body.\n");
- return 1;
- }
- done:
- /* 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 & VB2_FIRMWARE_PREAMBLE_USE_RO_NORMAL))
- printf("Body verification succeeded.\n");
- if (state)
- state->area[state->c].is_valid = 1;
- } else {
- printf("Seems legit, but the signature is unverified.\n");
- if (show_option.strict)
- retval = 1;
- }
- return retval;
- }
- int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len,
- void *data)
- {
- struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf;
- struct vb2_public_key *sign_key = show_option.k;
- int retval = 0;
- /* Check the hash... */
- if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) {
- printf("%s keyblock component is invalid\n", name);
- return 1;
- }
- /* If we have a key, check the signature too */
- int good_sig = 0;
- if (sign_key && VB2_SUCCESS ==
- vb2_verify_keyblock(keyblock, len, sign_key, &wb))
- good_sig = 1;
- printf("Kernel partition: %s\n", name);
- show_keyblock(keyblock, NULL, !!sign_key, good_sig);
- if (show_option.strict && (!sign_key || !good_sig))
- retval = 1;
- struct vb2_public_key data_key;
- if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) {
- fprintf(stderr, "Error parsing data key in %s\n", name);
- return 1;
- }
- uint32_t more = keyblock->keyblock_size;
- struct vb2_kernel_preamble *pre2 =
- (struct vb2_kernel_preamble *)(buf + more);
- if (VB2_SUCCESS != vb2_verify_kernel_preamble(pre2, len - more,
- &data_key, &wb)) {
- printf("%s is invalid\n", name);
- return 1;
- }
- printf("Kernel Preamble:\n");
- printf(" Size: 0x%x\n", pre2->preamble_size);
- printf(" Header version: %u.%u\n",
- pre2->header_version_major,
- pre2->header_version_minor);
- printf(" Kernel version: %u\n", pre2->kernel_version);
- printf(" Body load address: 0x%" PRIx64 "\n",
- pre2->body_load_address);
- printf(" Body size: 0x%x\n",
- pre2->body_signature.data_size);
- printf(" Bootloader address: 0x%" PRIx64 "\n",
- pre2->bootloader_address);
- printf(" Bootloader size: 0x%x\n", pre2->bootloader_size);
- uint64_t vmlinuz_header_address = 0;
- uint32_t vmlinuz_header_size = 0;
- vb2_kernel_get_vmlinuz_header(pre2,
- &vmlinuz_header_address,
- &vmlinuz_header_size);
- if (vmlinuz_header_size) {
- printf(" Vmlinuz_header address: 0x%" PRIx64 "\n",
- vmlinuz_header_address);
- printf(" Vmlinuz header size: 0x%x\n",
- vmlinuz_header_size);
- }
- printf(" Flags: 0x%x\n", vb2_kernel_get_flags(pre2));
- /* Verify kernel body */
- uint8_t *kernel_blob = 0;
- uint64_t kernel_size = 0;
- if (show_option.fv) {
- /* It's in a separate file, which we've already read in */
- kernel_blob = show_option.fv;
- kernel_size = show_option.fv_size;
- } else if (len > show_option.padding) {
- /* It should be at an offset within the input file. */
- kernel_blob = buf + show_option.padding;
- kernel_size = len - show_option.padding;
- }
- if (!kernel_blob) {
- /* TODO: Is this always a failure? The preamble is okay. */
- fprintf(stderr, "No kernel blob available to verify.\n");
- return 1;
- }
- if (VB2_SUCCESS !=
- vb2_verify_data(kernel_blob, kernel_size, &pre2->body_signature,
- &data_key, &wb)) {
- fprintf(stderr, "Error verifying kernel body.\n");
- return 1;
- }
- printf("Body verification succeeded.\n");
- printf("Config:\n%s\n", kernel_blob + kernel_cmd_line_offset(pre2));
- return retval;
- }
- enum no_short_opts {
- OPT_PADDING = 1000,
- OPT_TYPE,
- OPT_PUBKEY,
- OPT_HELP,
- };
- static const char usage[] = "\n"
- "Usage: " MYNAME " %s [OPTIONS] FILE [...]\n"
- "\n"
- "Where FILE could be\n"
- "\n"
- " a boot descriptor block (BDB)\n"
- " a keyblock (.keyblock)\n"
- " a firmware preamble signature (VBLOCK_A/B)\n"
- " a firmware image (bios.bin)\n"
- " a kernel partition (/dev/sda2, /dev/mmcblk0p2)\n"
- " keys in various formats (.vbpubk, .vbprivk, .pem)\n"
- " several other file types related to verified boot\n"
- "\n"
- "Options:\n"
- " -t Just show the type of each file\n"
- " --type TYPE Override the detected file type\n"
- " Use \"--type help\" for a list\n"
- "Type-specific options:\n"
- " -k|--publickey FILE.vbpubk Public key in vb1 format\n"
- " --pubkey FILE.vpubk2 Public key in vb2 format\n"
- " -f|--fv FILE Verify this payload (FW_MAIN_A/B)\n"
- " --pad NUM Kernel vblock padding size\n"
- " --strict "
- "Fail unless all signatures are valid\n"
- "\n";
- static void print_help(int argc, char *argv[])
- {
- if (!strcmp(argv[0], "verify"))
- printf("\nUsage: " MYNAME " %s [OPTIONS] FILE [...]\n\n"
- "This is just an alias for\n\n"
- " " MYNAME " show --strict\n\n",
- argv[0]);
- printf(usage, "show");
- }
- static const struct option long_opts[] = {
- /* name hasarg *flag val */
- {"publickey", 1, 0, 'k'},
- {"fv", 1, 0, 'f'},
- {"pad", 1, NULL, OPT_PADDING},
- {"type", 1, NULL, OPT_TYPE},
- {"strict", 0, &show_option.strict, 1},
- {"pubkey", 1, NULL, OPT_PUBKEY},
- {"help", 0, NULL, OPT_HELP},
- {NULL, 0, NULL, 0},
- };
- static char *short_opts = ":f:k:t";
- static int show_type(char *filename)
- {
- enum futil_file_err err;
- enum futil_file_type type;
- err = futil_file_type(filename, &type);
- switch (err) {
- case FILE_ERR_NONE:
- printf("%s:\t%s\n", filename, futil_file_type_name(type));
- /* Only our recognized types return success */
- return 0;
- case FILE_ERR_DIR:
- printf("%s:\t%s\n", filename, "directory");
- break;
- case FILE_ERR_CHR:
- printf("%s:\t%s\n", filename, "character special");
- break;
- case FILE_ERR_FIFO:
- printf("%s:\t%s\n", filename, "FIFO");
- break;
- case FILE_ERR_SOCK:
- printf("%s:\t%s\n", filename, "socket");
- break;
- default:
- break;
- }
- /* Everything else is an error */
- return 1;
- }
- static int do_show(int argc, char *argv[])
- {
- uint8_t *pubkbuf = NULL;
- struct vb2_public_key pubk2;
- char *infile = 0;
- int ifd, i;
- int errorcnt = 0;
- uint8_t *buf;
- uint32_t len;
- char *e = 0;
- int type_override = 0;
- enum futil_file_type type;
- vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
- opterr = 0; /* quiet, you */
- while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
- switch (i) {
- case 'f':
- show_option.fv = ReadFile(optarg,
- &show_option.fv_size);
- if (!show_option.fv) {
- fprintf(stderr, "Error reading %s: %s\n",
- optarg, strerror(errno));
- errorcnt++;
- }
- break;
- case 'k':
- if (VB2_SUCCESS !=
- vb2_read_file(optarg, &pubkbuf, &len)) {
- fprintf(stderr, "Error reading %s\n", optarg);
- errorcnt++;
- break;
- }
- if (VB2_SUCCESS !=
- vb2_unpack_key_buffer(&pubk2, pubkbuf, len)) {
- fprintf(stderr, "Error unpacking %s\n", optarg);
- errorcnt++;
- break;
- }
- show_option.k = &pubk2;
- break;
- case 't':
- show_option.t_flag = 1;
- break;
- case OPT_PADDING:
- show_option.padding = strtoul(optarg, &e, 0);
- if (!*optarg || (e && *e)) {
- fprintf(stderr,
- "Invalid --padding \"%s\"\n", optarg);
- errorcnt++;
- }
- break;
- case OPT_TYPE:
- if (!futil_str_to_file_type(optarg,
- &show_option.type)) {
- if (!strcasecmp("help", optarg))
- print_file_types_and_exit(errorcnt);
- fprintf(stderr,
- "Invalid --type \"%s\"\n", optarg);
- errorcnt++;
- }
- type_override = 1;
- break;
- case OPT_PUBKEY:
- if (vb21_packed_key_read(&show_option.pkey, optarg)) {
- fprintf(stderr, "Error reading %s\n", optarg);
- errorcnt++;
- }
- break;
- case OPT_HELP:
- print_help(argc, argv);
- return !!errorcnt;
- case '?':
- if (optopt)
- fprintf(stderr, "Unrecognized option: -%c\n",
- optopt);
- else
- fprintf(stderr, "Unrecognized option\n");
- errorcnt++;
- break;
- case ':':
- fprintf(stderr, "Missing argument to -%c\n", optopt);
- errorcnt++;
- break;
- case 0: /* handled option */
- break;
- default:
- DIE;
- }
- }
- if (errorcnt) {
- print_help(argc, argv);
- return 1;
- }
- if (argc - optind < 1) {
- fprintf(stderr, "ERROR: missing input filename\n");
- print_help(argc, argv);
- return 1;
- }
- if (show_option.t_flag) {
- for (i = optind; i < argc; i++)
- errorcnt += show_type(argv[i]);
- goto done;
- }
- for (i = optind; i < argc; i++) {
- infile = argv[i];
- ifd = open(infile, O_RDONLY);
- if (ifd < 0) {
- errorcnt++;
- fprintf(stderr, "Can't open %s: %s\n",
- infile, strerror(errno));
- continue;
- }
- if (0 != futil_map_file(ifd, MAP_RO, &buf, &len)) {
- errorcnt++;
- goto boo;
- }
- /* Allow the user to override the type */
- if (type_override)
- type = show_option.type;
- else
- type = futil_file_type_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++;
- fprintf(stderr, "Error when closing %s: %s\n",
- infile, strerror(errno));
- }
- }
- done:
- if (pubkbuf)
- free(pubkbuf);
- if (show_option.fv)
- free(show_option.fv);
- return !!errorcnt;
- }
- DECLARE_FUTIL_COMMAND(show, do_show, VBOOT_VERSION_ALL,
- "Display the content of various binary components");
- static int do_verify(int argc, char *argv[])
- {
- show_option.strict = 1;
- return do_show(argc, argv);
- }
- DECLARE_FUTIL_COMMAND(verify, do_verify,
- VBOOT_VERSION_ALL,
- "Verify the signatures of various binary components");
|