blob: 92a65449005a6da55fd5ef19a45389dcf060019d [file] [log] [blame]
/* Copyright 2014 The ChromiumOS Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#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 "2api.h"
#include "2common.h"
#include "2sha.h"
#include "2sysincludes.h"
#include "cbfstool.h"
#include "file_type_bios.h"
#include "file_type.h"
#include "fmap.h"
#include "futility.h"
#include "futility_options.h"
#include "host_common.h"
#include "host_key21.h"
#include "host_misc.h"
#include "util_misc.h"
#include "vb1_helper.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]
__attribute__((aligned(VB2_WORKBUF_ALIGN)));
static struct vb2_workbuf wb;
void show_pubkey(const struct vb2_packed_key *pubkey, const char *sp)
{
// Clear out formatting if we are in parseable mode.
if (show_option.parseable)
sp = "\0";
FT_PRINT("%sVboot API: 1.0\n", "%sapi::1.0\n", sp);
FT_PRINT("%sAlgorithm: %d %s\n",
"%salgorithm::%d::%s\n",
sp, pubkey->algorithm,
vb2_get_crypto_algorithm_name(pubkey->algorithm));
FT_PRINT("%sKey Version: %d\n", "%sversion::%d\n",
sp, pubkey->key_version);
FT_PRINT("%sKey sha1sum: %s\n", "%ssha1_sum::%s\n",
sp, packed_key_sha1_string(pubkey));
}
static void show_keyblock(struct vb2_keyblock *keyblock, const char *print_name,
int sign_key, int good_sig)
{
if (print_name)
FT_READABLE_PRINT("Keyblock: %s\n", print_name);
else
FT_READABLE_PRINT("Keyblock:\n");
FT_PRINT(" Signature: %s\n", "signature::%s\n",
sign_key ? (good_sig ? "valid" : "invalid") : "ignored");
FT_PRINT(" Size: %#x\n",
"size::%d\n", keyblock->keyblock_size);
FT_PRINT(" Flags: %d ",
"flags::%d:", keyblock->keyblock_flags);
if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_DEVELOPER_0)
FT_PRINT_RAW(" !DEV", ":!DEV");
if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_DEVELOPER_1)
FT_PRINT_RAW(" DEV", ":DEV");
if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_RECOVERY_0)
FT_PRINT_RAW(" !REC", ":!REC");
if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_RECOVERY_1)
FT_PRINT_RAW(" REC", ":REC");
if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_MINIOS_0)
FT_PRINT_RAW(" !MINIOS", ":!MINIOS");
if (keyblock->keyblock_flags & VB2_KEYBLOCK_FLAG_MINIOS_1)
FT_PRINT_RAW(" MINIOS", ":MINIOS");
printf("\n");
struct vb2_packed_key *data_key = &keyblock->data_key;
FT_PRINT(" Data key algorithm: %d %s\n",
"data_key::algorithm::%d::%s\n", data_key->algorithm,
vb2_get_crypto_algorithm_name(data_key->algorithm));
FT_PRINT(" Data key version: %d\n", "data_key::version::%d\n",
data_key->key_version);
FT_PRINT(" Data key sha1sum: %s\n", "data_key::sha1_sum::%s\n",
packed_key_sha1_string(data_key));
}
int ft_show_pubkey(const char *fname)
{
int fd = -1;
struct vb2_packed_key *pubkey;
uint32_t len;
int rv = 0;
if (futil_open_and_map_file(fname, &fd, FILE_RO, (uint8_t **)&pubkey,
&len))
return 1;
if (vb2_packed_key_looks_ok(pubkey, len)) {
ERROR("Invalid public key: %s\n", fname);
rv = 1;
goto done;
}
FT_READABLE_PRINT("Public Key file: %s\n", fname);
ft_print_header = "pubkey";
show_pubkey(pubkey, " ");
done:
futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)pubkey, len);
return rv;
}
int ft_show_privkey(const char *fname)
{
int fd = -1;
int rv = 0;
struct vb2_packed_private_key *pkey = NULL;
uint32_t len;
struct vb2_private_key key;
const unsigned char *start;
if (futil_open_and_map_file(fname, &fd, FILE_RO, (uint8_t **)&pkey,
&len))
return 1;
start = pkey->key_data;
if (len <= sizeof(*pkey)) {
ERROR("Invalid private key: %s\n", fname);
rv = 1;
goto done;
}
len -= sizeof(*pkey);
key.rsa_private_key = d2i_RSAPrivateKey(NULL, &start, len);
ft_print_header = "prikey";
FT_READABLE_PRINT("Private Key file: %s\n", fname);
FT_PRINT(" Vboot API: 1.0\n", "api::1.0\n");
FT_PRINT(" Algorithm: %u %s\n",
"algorithm::%d::%s\n", pkey->algorithm,
vb2_get_crypto_algorithm_name(pkey->algorithm));
FT_PRINT(" Key sha1sum: %s\n", "sha1_sum::%s\n",
private_key_sha1_string(&key));
done:
futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)pkey, len);
return rv;
}
int ft_show_keyblock(const char *fname)
{
struct vb2_keyblock *block;
struct vb2_public_key *sign_key = show_option.k;
int good_sig = 0;
int retval = 0;
int fd = -1;
uint32_t len;
if (futil_open_and_map_file(fname, &fd, FILE_RO, (uint8_t **)&block, &len))
return 1;
/* Check the hash only first */
if (vb2_verify_keyblock_hash(block, len, &wb)) {
ERROR("%s is invalid\n", fname);
FT_PARSEABLE_PRINT("keyblock::invalid\n");
retval = 1;
goto done;
}
/* 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;
ft_print_header = "keyblock";
show_keyblock(block, fname, !!sign_key, good_sig);
done:
futil_unmap_and_close_file(fd, FILE_RO, (uint8_t *)block, len);
return retval;
}
static int fw_show_metadata_hash(const char *fname, enum bios_component body_c,
struct vb2_fw_preamble *pre)
{
struct vb2_hash real_hash;
struct vb2_hash *body_hash =
(struct vb2_hash *)vb2_signature_data(&pre->body_signature);
const uint32_t bhsize = vb2_digest_size(body_hash->algo);
if (!bhsize || pre->body_signature.sig_size <
offsetof(struct vb2_hash, raw) + bhsize) {
ERROR("Body signature data is too small to fit metadata hash.\n");
return 1;
}
FT_READABLE_PRINT(" Body metadata hash: %s ",
vb2_get_hash_algorithm_name(body_hash->algo));
FT_PARSEABLE_PRINT("body::metatadata_hash::algorithm::%d::%s\n",
body_hash->algo,
vb2_get_hash_algorithm_name(body_hash->algo));
if (vb2_digest_size(body_hash->algo)) {
FT_PARSEABLE_PRINT("body::metatadata_hash::hex::");
print_bytes((uint8_t *)body_hash->raw,
vb2_digest_size(body_hash->algo));
putchar('\n');
}
if (cbfstool_get_metadata_hash(fname, fmap_name[body_c], &real_hash) !=
VB2_SUCCESS ||
real_hash.algo == VB2_HASH_INVALID) {
ERROR("Failed to get metadata hash. Firmware body is"
" corrupted or is not a valid CBFS.\n");
FT_PARSEABLE_PRINT("body::metadata_hash::invalid\n");
FT_PARSEABLE_PRINT("body::signature::invalid\n");
return 1;
}
if (body_hash->algo != real_hash.algo ||
!vb2_digest_size(body_hash->algo) ||
memcmp(body_hash->raw, real_hash.raw,
vb2_digest_size(body_hash->algo))) {
FT_READABLE_PRINT(" MISMATCH! Real hash: %s:",
vb2_get_hash_algorithm_name(real_hash.algo));
FT_PARSEABLE_PRINT("body::metadata_hash::invalid\n");
FT_PARSEABLE_PRINT(
"body::metadata_hash::expected::algorithm::%d::%s\n",
real_hash.algo,
vb2_get_hash_algorithm_name(real_hash.algo));
FT_PARSEABLE_PRINT("body::metadata_hash::expected::hex::");
print_bytes(&real_hash.raw, vb2_digest_size(real_hash.algo));
putchar('\n');
ERROR("Signature hash does not match with"
" real metadata hash.\n");
/* To balance out signature::valid otherwise printed by caller. */
FT_PARSEABLE_PRINT("body::signature::invalid\n");
return 1;
} else {
FT_PRINT(" Body metadata hash valid!\n",
"body::metadata_hash::valid\n");
}
return 0;
}
int show_fw_preamble_buf(const char *fname, uint8_t *buf, uint32_t len,
struct bios_state_s *state)
{
const char *print_name = state ? fmap_name[state->c] : fname;
struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf;
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;
enum bios_component body_c = BIOS_FMAP_FW_MAIN_A;
int good_sig = 0;
int retval = 0;
ft_print_header2 = "keyblock";
/* Check the hash... */
if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) {
ERROR("%s keyblock component is invalid\n", print_name);
FT_PARSEABLE_PRINT("invalid\n");
return 1;
} else {
FT_PARSEABLE_PRINT("valid\n");
}
/*
* 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 */
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, print_name, !!sign_key, good_sig);
ft_print_header2 = NULL;
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)) {
ERROR("Parsing data key in %s\n", print_name);
FT_PARSEABLE_PRINT("data_key::invalid\n");
return 1;
}
ft_print_header2 = "preamble";
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)) {
ERROR("%s is invalid\n", print_name);
FT_PARSEABLE_PRINT("invalid\n");
return 1;
} else {
FT_PARSEABLE_PRINT("valid\n");
}
uint32_t flags = pre2->flags;
if (pre2->header_version_minor < 1)
flags = 0; /* Old 2.0 structure didn't have flags */
FT_READABLE_PRINT("Firmware Preamble:\n");
FT_PRINT(" Size: %d\n", "size::%d\n",
pre2->preamble_size);
FT_PRINT(" Header version: %d.%d\n",
"header_version::%d.%d\n",
pre2->header_version_major,
pre2->header_version_minor);
FT_PRINT(" Firmware version: %d\n", "firmware_version::%d\n",
pre2->firmware_version);
struct vb2_packed_key *kernel_subkey = &pre2->kernel_subkey;
FT_PRINT(" Kernel key algorithm: %d %s\n",
"kernel_subkey::algorithm::%d::%s\n",
kernel_subkey->algorithm,
vb2_get_crypto_algorithm_name(kernel_subkey->algorithm));
if (kernel_subkey->algorithm >= VB2_ALG_COUNT)
retval = 1;
FT_PRINT(" Kernel key version: %d\n",
"kernel_subkey::version::%d\n",
kernel_subkey->key_version);
FT_PRINT(" Kernel key sha1sum: %s\n",
"kernel_subkey::sha1_sum::%s\n",
packed_key_sha1_string(kernel_subkey));
FT_READABLE_PRINT(" Firmware body size: %d\n",
pre2->body_signature.data_size);
FT_PRINT(" Preamble flags: %d\n",
"flags::%d\n", flags);
ft_print_header2 = NULL;
FT_PARSEABLE_PRINT("body::size::%d\n", pre2->body_signature.data_size);
if (flags & VB2_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
FT_PRINT("Preamble requests USE_RO_NORMAL;"
" skipping body verification.\n",
"body::signature::ignored\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) {
FT_PRINT("No firmware body available to verify.\n",
"body::signature::ignored\n");
if (show_option.strict)
return 1;
return 0;
}
if (pre2->body_signature.data_size) {
if (vb2_verify_data(fv_data, fv_size, &pre2->body_signature,
&data_key, &wb) != VB2_SUCCESS) {
ERROR("Verifying firmware body.\n");
FT_PARSEABLE_PRINT("body::signature::invalid\n");
return 1;
}
} else if (state) { /* Only works for images with at least FW_MAIN_A */
if (fw_show_metadata_hash(fname, body_c, pre2))
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))
FT_PRINT("Body verification succeeded.\n",
"body::signature::valid\n");
if (state)
state->area[state->c].is_valid = 1;
} else {
FT_PRINT("Seems legit, but the signature is unverified.\n",
"body::signature::ignored\n");
if (show_option.strict)
retval = 1;
}
return retval;
}
int ft_show_fw_preamble(const char *fname)
{
int rv = 0;
int fd = -1;
uint8_t *buf;
uint32_t len;
if (futil_open_and_map_file(fname, &fd, FILE_RO, &buf, &len))
return 1;
ft_print_header = "fw_pre";
rv = show_fw_preamble_buf(fname, buf, len, NULL);
futil_unmap_and_close_file(fd, FILE_RO, buf, len);
return rv;
}
int ft_show_kernel_preamble(const char *fname)
{
struct vb2_keyblock *keyblock;
struct vb2_public_key *sign_key = show_option.k;
int retval = 1;
int fd = -1;
uint8_t *buf;
uint32_t len;
if (futil_open_and_map_file(fname, &fd, FILE_RO, &buf, &len))
return 1;
keyblock = (struct vb2_keyblock *)buf;
ft_print_header = "kernel";
ft_print_header2 = "keyblock";
/* Check the hash... */
if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) {
ERROR("%s keyblock component is invalid\n", fname);
FT_PARSEABLE_PRINT("invalid\n");
goto done;
} else {
FT_PARSEABLE_PRINT("valid\n");
}
/* 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;
FT_READABLE_PRINT("Kernel partition: %s\n", fname);
show_keyblock(keyblock, NULL, !!sign_key, good_sig);
struct vb2_public_key data_key;
if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) {
ERROR("Parsing data key in %s\n", fname);
goto done;
}
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)) {
ERROR("%s is invalid\n", fname);
FT_PARSEABLE_PRINT("kernel_preamble::signature::invalid\n");
goto done;
}
ft_print_header2 = NULL;
FT_PRINT("Kernel Preamble:\n", "preamble::signature::valid\n");
FT_PRINT(" Size: %#x\n",
"preamble::size::%d\n", pre2->preamble_size);
FT_PRINT(" Header version: %d.%d\n",
"preamble::header_version::%d.%d\n",
pre2->header_version_major,
pre2->header_version_minor);
FT_PRINT(" Kernel version: %u\n",
"preamble::kernel_version::%u\n",
pre2->kernel_version);
FT_PRINT(" Body load address: 0x%" PRIx64 "\n",
"body::address::%" PRIu64 "\n",
pre2->body_load_address);
FT_PRINT(" Body size: %#x\n",
"body::size::%d\n",
pre2->body_signature.data_size);
FT_PRINT(" Bootloader address: 0x%" PRIx64 "\n",
"bootloader::address::%" PRIu64 "\n",
pre2->bootloader_address);
FT_PRINT(" Bootloader size: %#x\n",
"bootloader::size::%d\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) {
FT_PRINT(" Vmlinuz_header address: 0x%" PRIx64 "\n",
"vmlinuz_header::address::%" PRIu64 "\n",
vmlinuz_header_address);
FT_PRINT(" Vmlinuz header size: %#x\n",
"vmlinuz_header::size::%d\n",
vmlinuz_header_size);
}
FT_PRINT(" Flags: %#x\n",
"flags::%d\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. */
ERROR("No kernel blob available to verify.\n");
goto done;
}
if (VB2_SUCCESS !=
vb2_verify_data(kernel_blob, kernel_size, &pre2->body_signature,
&data_key, &wb)) {
ERROR("Verifying kernel body.\n");
FT_PARSEABLE_PRINT("body::signature::invalid\n");
goto done;
}
FT_PRINT("Body verification succeeded.\n",
"body::signature::valid\n");
FT_READABLE_PRINT("Config:\n%s\n",
kernel_blob + kernel_cmd_line_offset(pre2));
if (!show_option.strict || (sign_key && good_sig))
retval = 0;
done:
futil_unmap_and_close_file(fd, FILE_RO, buf, len);
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 (image.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"
" -P|--parseable Machine friendly output format\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},
{"parseable", 0, NULL, 'P'},
{"help", 0, NULL, OPT_HELP},
{NULL, 0, NULL, 0},
};
static const char *short_opts = ":f:k:Pt";
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 i;
int errorcnt = 0;
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) {
ERROR("Reading %s: %s\n",
optarg, strerror(errno));
errorcnt++;
}
break;
case 'k':
if (VB2_SUCCESS !=
vb2_read_file(optarg, &pubkbuf, &len)) {
ERROR("Reading %s\n", optarg);
errorcnt++;
break;
}
if (VB2_SUCCESS !=
vb2_unpack_key_buffer(&pubk2, pubkbuf, len)) {
ERROR("Unpacking %s\n", optarg);
errorcnt++;
break;
}
show_option.k = &pubk2;
break;
case 't':
show_option.t_flag = 1;
break;
case 'P':
show_option.parseable = true;
break;
case OPT_PADDING:
show_option.padding = strtoul(optarg, &e, 0);
if (!*optarg || (e && *e)) {
ERROR("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);
ERROR("Invalid --type \"%s\"\n", optarg);
errorcnt++;
}
type_override = 1;
break;
case OPT_PUBKEY:
if (vb21_packed_key_read(&show_option.pkey, optarg)) {
ERROR("Reading %s\n", optarg);
errorcnt++;
}
break;
case OPT_HELP:
print_help(argc, argv);
return !!errorcnt;
case '?':
if (optopt)
ERROR("Unrecognized option: -%c\n",
optopt);
else
ERROR("Unrecognized option\n");
errorcnt++;
break;
case ':':
ERROR("Missing argument to -%c\n", optopt);
errorcnt++;
break;
case 0: /* handled option */
break;
default:
FATAL("Unrecognized getopt output: %d\n", i);
}
}
if (errorcnt) {
print_help(argc, argv);
return 1;
}
if (argc - optind < 1) {
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];
/* Allow the user to override the type */
if (type_override)
type = show_option.type;
else
futil_file_type(infile, &type);
errorcnt += futil_file_type_show(type, infile);
}
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. "
"This does not verify GSCVD contents.");