Home | History | Annotate | Download | only in futility
      1 /*
      2  * Copyright 2014 The Chromium OS Authors. All rights reserved.
      3  * Use of this source code is governed by a BSD-style license that can be
      4  * found in the LICENSE file.
      5  */
      6 #include <errno.h>
      7 #include <fcntl.h>
      8 #include <getopt.h>
      9 #include <inttypes.h>
     10 #include <stddef.h>
     11 #include <stdint.h>
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <string.h>
     15 #include <sys/stat.h>
     16 #include <sys/types.h>
     17 #include <unistd.h>
     18 
     19 #include "bmpblk_header.h"
     20 #include "file_type.h"
     21 #include "fmap.h"
     22 #include "futility.h"
     23 #include "gbb_header.h"
     24 #include "host_common.h"
     25 #include "traversal.h"
     26 #include "util_misc.h"
     27 #include "vb1_helper.h"
     28 #include "vboot_common.h"
     29 
     30 /* Local values for cb_area_s._flags */
     31 enum callback_flags {
     32 	AREA_IS_VALID =     0x00000001,
     33 };
     34 
     35 /* Local structure for args, etc. */
     36 static struct local_data_s {
     37 	VbPublicKey *k;
     38 	uint8_t *fv;
     39 	uint64_t fv_size;
     40 	uint32_t padding;
     41 	int strict;
     42 	int t_flag;
     43 } option = {
     44 	.padding = 65536,
     45 };
     46 
     47 static void show_key(VbPublicKey *pubkey, const char *sp)
     48 {
     49 	printf("%sAlgorithm:           %" PRIu64 " %s\n", sp, pubkey->algorithm,
     50 	       (pubkey->algorithm < kNumAlgorithms ?
     51 		algo_strings[pubkey->algorithm] : "(invalid)"));
     52 	printf("%sKey Version:         %" PRIu64 "\n", sp, pubkey->key_version);
     53 	printf("%sKey sha1sum:         ", sp);
     54 	PrintPubKeySha1Sum(pubkey);
     55 	printf("\n");
     56 }
     57 
     58 static void show_keyblock(VbKeyBlockHeader *key_block, const char *name,
     59 			  int sign_key, int good_sig)
     60 {
     61 	if (name)
     62 		printf("Key block:               %s\n", name);
     63 	else
     64 		printf("Key block:\n");
     65 	printf("  Signature:             %s\n",
     66 	       sign_key ? (good_sig ? "valid" : "invalid") : "ignored");
     67 	printf("  Size:                  0x%" PRIx64 "\n",
     68 	       key_block->key_block_size);
     69 	printf("  Flags:                 %" PRIu64 " ",
     70 	       key_block->key_block_flags);
     71 	if (key_block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
     72 		printf(" !DEV");
     73 	if (key_block->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
     74 		printf(" DEV");
     75 	if (key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
     76 		printf(" !REC");
     77 	if (key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
     78 		printf(" REC");
     79 	printf("\n");
     80 
     81 	VbPublicKey *data_key = &key_block->data_key;
     82 	printf("  Data key algorithm:    %" PRIu64 " %s\n", data_key->algorithm,
     83 	       (data_key->algorithm < kNumAlgorithms
     84 		? algo_strings[data_key->algorithm]
     85 		: "(invalid)"));
     86 	printf("  Data key version:      %" PRIu64 "\n", data_key->key_version);
     87 	printf("  Data key sha1sum:      ");
     88 	PrintPubKeySha1Sum(data_key);
     89 	printf("\n");
     90 }
     91 
     92 int futil_cb_show_pubkey(struct futil_traverse_state_s *state)
     93 {
     94 	VbPublicKey *pubkey = (VbPublicKey *)state->my_area->buf;
     95 
     96 	if (!PublicKeyLooksOkay(pubkey, state->my_area->len)) {
     97 		printf("%s looks bogus\n", state->name);
     98 		return 1;
     99 	}
    100 
    101 	printf("Public Key file:       %s\n", state->in_filename);
    102 	show_key(pubkey, "  ");
    103 
    104 	state->my_area->_flags |= AREA_IS_VALID;
    105 	return 0;
    106 }
    107 
    108 int futil_cb_show_privkey(struct futil_traverse_state_s *state)
    109 {
    110 	VbPrivateKey key;
    111 	int alg_okay;
    112 
    113 	key.algorithm = *(typeof(key.algorithm) *)state->my_area->buf;
    114 
    115 	printf("Private Key file:      %s\n", state->in_filename);
    116 	alg_okay = key.algorithm < kNumAlgorithms;
    117 	printf("  Algorithm:           %" PRIu64 " %s\n", key.algorithm,
    118 	       alg_okay ? algo_strings[key.algorithm] : "(unknown)");
    119 
    120 	if (alg_okay)
    121 		state->my_area->_flags |= AREA_IS_VALID;
    122 
    123 	return 0;
    124 }
    125 
    126 int futil_cb_show_gbb(struct futil_traverse_state_s *state)
    127 {
    128 	uint8_t *buf = state->my_area->buf;
    129 	uint32_t len = state->my_area->len;
    130 	GoogleBinaryBlockHeader *gbb = (GoogleBinaryBlockHeader *)buf;
    131 	VbPublicKey *pubkey;
    132 	BmpBlockHeader *bmp;
    133 	int retval = 0;
    134 	uint32_t maxlen = 0;
    135 
    136 	if (!len) {
    137 		printf("GBB header:              %s <invalid>\n",
    138 		       state->component == CB_GBB ?
    139 		       state->in_filename : state->name);
    140 		return 1;
    141 	}
    142 
    143 	/* It looks like a GBB or we wouldn't be called. */
    144 	if (!futil_valid_gbb_header(gbb, len, &maxlen))
    145 		retval = 1;
    146 
    147 	printf("GBB header:              %s\n",
    148 	       state->component == CB_GBB ? state->in_filename : state->name);
    149 	printf("  Version:               %d.%d\n",
    150 	       gbb->major_version, gbb->minor_version);
    151 	printf("  Flags:                 0x%08x\n", gbb->flags);
    152 	printf("  Regions:                 offset       size\n");
    153 	printf("    hwid                 0x%08x   0x%08x\n",
    154 	       gbb->hwid_offset, gbb->hwid_size);
    155 	printf("    bmpvf                0x%08x   0x%08x\n",
    156 	       gbb->bmpfv_offset, gbb->bmpfv_size);
    157 	printf("    rootkey              0x%08x   0x%08x\n",
    158 	       gbb->rootkey_offset, gbb->rootkey_size);
    159 	printf("    recovery_key         0x%08x   0x%08x\n",
    160 	       gbb->recovery_key_offset, gbb->recovery_key_size);
    161 
    162 	printf("  Size:                  0x%08x / 0x%08x%s\n",
    163 	       maxlen, len, maxlen > len ? "  (not enough)" : "");
    164 
    165 	if (retval) {
    166 		printf("GBB header is invalid, ignoring content\n");
    167 		return 1;
    168 	}
    169 
    170 	printf("GBB content:\n");
    171 	printf("  HWID:                  %s\n", buf + gbb->hwid_offset);
    172 	print_hwid_digest(gbb, "     digest:             ", "\n");
    173 
    174 	pubkey = (VbPublicKey *)(buf + gbb->rootkey_offset);
    175 	if (PublicKeyLooksOkay(pubkey, gbb->rootkey_size)) {
    176 		state->rootkey.offset = state->my_area->offset +
    177 			gbb->rootkey_offset;
    178 		state->rootkey.buf = buf + gbb->rootkey_offset;
    179 		state->rootkey.len = gbb->rootkey_size;
    180 		state->rootkey._flags |= AREA_IS_VALID;
    181 		printf("  Root Key:\n");
    182 		show_key(pubkey, "    ");
    183 	} else {
    184 		retval = 1;
    185 		printf("  Root Key:              <invalid>\n");
    186 	}
    187 
    188 	pubkey = (VbPublicKey *)(buf + gbb->recovery_key_offset);
    189 	if (PublicKeyLooksOkay(pubkey, gbb->recovery_key_size)) {
    190 		state->recovery_key.offset = state->my_area->offset +
    191 			gbb->recovery_key_offset;
    192 		state->recovery_key.buf = buf + gbb->recovery_key_offset;
    193 		state->recovery_key.len = gbb->recovery_key_size;
    194 		state->recovery_key._flags |= AREA_IS_VALID;
    195 		printf("  Recovery Key:\n");
    196 		show_key(pubkey, "    ");
    197 	} else {
    198 		retval = 1;
    199 		printf("  Recovery Key:          <invalid>\n");
    200 	}
    201 
    202 	bmp = (BmpBlockHeader *)(buf + gbb->bmpfv_offset);
    203 	if (0 != memcmp(bmp, BMPBLOCK_SIGNATURE, BMPBLOCK_SIGNATURE_SIZE)) {
    204 		printf("  BmpBlock:              <invalid>\n");
    205 		/* We don't support older BmpBlock formats, so we can't
    206 		 * be strict about this. */
    207 	} else {
    208 		printf("  BmpBlock:\n");
    209 		printf("    Version:             %d.%d\n",
    210 		       bmp->major_version, bmp->minor_version);
    211 		printf("    Localizations:       %d\n",
    212 		       bmp->number_of_localizations);
    213 		printf("    Screen layouts:      %d\n",
    214 		       bmp->number_of_screenlayouts);
    215 		printf("    Image infos:         %d\n",
    216 		       bmp->number_of_imageinfos);
    217 	}
    218 
    219 	if (!retval)
    220 		state->my_area->_flags |= AREA_IS_VALID;
    221 
    222 	return retval;
    223 }
    224 
    225 int futil_cb_show_keyblock(struct futil_traverse_state_s *state)
    226 {
    227 	VbKeyBlockHeader *block = (VbKeyBlockHeader *)state->my_area->buf;
    228 	VbPublicKey *sign_key = option.k;
    229 	int good_sig = 0;
    230 	int retval = 0;
    231 
    232 	/* Check the hash only first */
    233 	if (0 != KeyBlockVerify(block, state->my_area->len, NULL, 1)) {
    234 		printf("%s is invalid\n", state->name);
    235 		return 1;
    236 	}
    237 
    238 	/* Check the signature if we have one */
    239 	if (sign_key && VBOOT_SUCCESS ==
    240 	    KeyBlockVerify(block, state->my_area->len, sign_key, 0))
    241 		good_sig = 1;
    242 
    243 	if (option.strict && (!sign_key || !good_sig))
    244 		retval = 1;
    245 
    246 	show_keyblock(block, state->in_filename, !!sign_key, good_sig);
    247 
    248 	state->my_area->_flags |= AREA_IS_VALID;
    249 
    250 	return retval;
    251 }
    252 
    253 /*
    254  * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
    255  *
    256  * The data in state->my_area is just the RW firmware blob, so there's nothing
    257  * useful to show about it. We'll just mark it as present so when we encounter
    258  * corresponding VBLOCK area, we'll have this to verify.
    259  */
    260 int futil_cb_show_fw_main(struct futil_traverse_state_s *state)
    261 {
    262 	if (!state->my_area->len) {
    263 		printf("Firmware body:           %s <invalid>\n", state->name);
    264 		return 1;
    265 	}
    266 
    267 	printf("Firmware body:           %s\n", state->name);
    268 	printf("  Offset:                0x%08x\n", state->my_area->offset);
    269 	printf("  Size:                  0x%08x\n", state->my_area->len);
    270 
    271 	state->my_area->_flags |= AREA_IS_VALID;
    272 
    273 	return 0;
    274 }
    275 
    276 int futil_cb_show_fw_preamble(struct futil_traverse_state_s *state)
    277 {
    278 	VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
    279 	uint32_t len = state->my_area->len;
    280 	VbPublicKey *sign_key = option.k;
    281 	uint8_t *fv_data = option.fv;
    282 	uint64_t fv_size = option.fv_size;
    283 	struct cb_area_s *fw_body_area = 0;
    284 	int good_sig = 0;
    285 	int retval = 0;
    286 
    287 	/* Check the hash... */
    288 	if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
    289 		printf("%s keyblock component is invalid\n", state->name);
    290 		return 1;
    291 	}
    292 
    293 	switch (state->component) {
    294 	case CB_FMAP_VBLOCK_A:
    295 		if (!sign_key && (state->rootkey._flags & AREA_IS_VALID))
    296 			/* BIOS should have a rootkey in the GBB */
    297 			sign_key = (VbPublicKey *)state->rootkey.buf;
    298 		/* And we should have already seen the firmware body */
    299 		fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
    300 		break;
    301 	case CB_FMAP_VBLOCK_B:
    302 		if (!sign_key && (state->rootkey._flags & AREA_IS_VALID))
    303 			/* BIOS should have a rootkey in the GBB */
    304 			sign_key = (VbPublicKey *)state->rootkey.buf;
    305 		/* And we should have already seen the firmware body */
    306 		fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
    307 		break;
    308 	case CB_FW_PREAMBLE:
    309 		/* We have to provide a signature and body in the options. */
    310 		break;
    311 	default:
    312 		DIE;
    313 	}
    314 
    315 	/* If we have a key, check the signature too */
    316 	if (sign_key && VBOOT_SUCCESS ==
    317 	    KeyBlockVerify(key_block, len, sign_key, 0))
    318 		good_sig = 1;
    319 
    320 	show_keyblock(key_block,
    321 		      state->component == CB_FW_PREAMBLE
    322 		      ? state->in_filename : state->name,
    323 		      !!sign_key, good_sig);
    324 
    325 	if (option.strict && (!sign_key || !good_sig))
    326 		retval = 1;
    327 
    328 	RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
    329 	if (!rsa) {
    330 		fprintf(stderr, "Error parsing data key in %s\n", state->name);
    331 		return 1;
    332 	}
    333 	uint32_t more = key_block->key_block_size;
    334 	VbFirmwarePreambleHeader *preamble =
    335 		(VbFirmwarePreambleHeader *)(state->my_area->buf + more);
    336 
    337 	if (VBOOT_SUCCESS != VerifyFirmwarePreamble(preamble,
    338 						    len - more, rsa)) {
    339 		printf("%s is invalid\n", state->name);
    340 		return 1;
    341 	}
    342 
    343 	uint32_t flags = VbGetFirmwarePreambleFlags(preamble);
    344 	printf("Firmware Preamble:\n");
    345 	printf("  Size:                  %" PRIu64 "\n",
    346 	       preamble->preamble_size);
    347 	printf("  Header version:        %" PRIu32 ".%" PRIu32 "\n",
    348 	       preamble->header_version_major, preamble->header_version_minor);
    349 	printf("  Firmware version:      %" PRIu64 "\n",
    350 	       preamble->firmware_version);
    351 	VbPublicKey *kernel_subkey = &preamble->kernel_subkey;
    352 	printf("  Kernel key algorithm:  %" PRIu64 " %s\n",
    353 	       kernel_subkey->algorithm,
    354 	       (kernel_subkey->algorithm < kNumAlgorithms ?
    355 		algo_strings[kernel_subkey->algorithm] : "(invalid)"));
    356 	if (kernel_subkey->algorithm >= kNumAlgorithms)
    357 		retval = 1;
    358 	printf("  Kernel key version:    %" PRIu64 "\n",
    359 	       kernel_subkey->key_version);
    360 	printf("  Kernel key sha1sum:    ");
    361 	PrintPubKeySha1Sum(kernel_subkey);
    362 	printf("\n");
    363 	printf("  Firmware body size:    %" PRIu64 "\n",
    364 	       preamble->body_signature.data_size);
    365 	printf("  Preamble flags:        %" PRIu32 "\n", flags);
    366 
    367 
    368 	if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
    369 		printf("Preamble requests USE_RO_NORMAL;"
    370 		       " skipping body verification.\n");
    371 		goto done;
    372 	}
    373 
    374 	/* We'll need to get the firmware body from somewhere... */
    375 	if (fw_body_area && (fw_body_area->_flags & AREA_IS_VALID)) {
    376 		fv_data = fw_body_area->buf;
    377 		fv_size = fw_body_area->len;
    378 	}
    379 
    380 	if (!fv_data) {
    381 		printf("No firmware body available to verify.\n");
    382 		if (option.strict)
    383 			return 1;
    384 		return 0;
    385 	}
    386 
    387 	if (VBOOT_SUCCESS !=
    388 	    VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) {
    389 		fprintf(stderr, "Error verifying firmware body.\n");
    390 		return 1;
    391 	}
    392 
    393 done:
    394 	/* Can't trust the BIOS unless everything is signed,
    395 	 * but standalone files are okay. */
    396 	if ((state->component == CB_FW_PREAMBLE) ||
    397 	    (sign_key && good_sig)) {
    398 		if (!(flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL))
    399 			printf("Body verification succeeded.\n");
    400 		state->my_area->_flags |= AREA_IS_VALID;
    401 	} else {
    402 		printf("Seems legit, but the signature is unverified.\n");
    403 		if (option.strict)
    404 			retval = 1;
    405 	}
    406 
    407 	return retval;
    408 }
    409 
    410 int futil_cb_show_kernel_preamble(struct futil_traverse_state_s *state)
    411 {
    412 
    413 	VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
    414 	uint32_t len = state->my_area->len;
    415 	VbPublicKey *sign_key = option.k;
    416 	uint8_t *kernel_blob = 0;
    417 	uint64_t kernel_size = 0;
    418 	int good_sig = 0;
    419 	int retval = 0;
    420 	uint64_t vmlinuz_header_size = 0;
    421 	uint64_t vmlinuz_header_address = 0;
    422 	uint32_t flags = 0;
    423 
    424 	/* Check the hash... */
    425 	if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
    426 		printf("%s keyblock component is invalid\n", state->name);
    427 		return 1;
    428 	}
    429 
    430 	/* If we have a key, check the signature too */
    431 	if (sign_key && VBOOT_SUCCESS ==
    432 	    KeyBlockVerify(key_block, len, sign_key, 0))
    433 		good_sig = 1;
    434 
    435 	printf("Kernel partition:        %s\n", state->in_filename);
    436 	show_keyblock(key_block, NULL, !!sign_key, good_sig);
    437 
    438 	if (option.strict && (!sign_key || !good_sig))
    439 		retval = 1;
    440 
    441 	RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
    442 	if (!rsa) {
    443 		fprintf(stderr, "Error parsing data key in %s\n", state->name);
    444 		return 1;
    445 	}
    446 	uint32_t more = key_block->key_block_size;
    447 	VbKernelPreambleHeader *preamble =
    448 		(VbKernelPreambleHeader *)(state->my_area->buf + more);
    449 
    450 	if (VBOOT_SUCCESS != VerifyKernelPreamble(preamble,
    451 						    len - more, rsa)) {
    452 		printf("%s is invalid\n", state->name);
    453 		return 1;
    454 	}
    455 
    456 	printf("Kernel Preamble:\n");
    457 	printf("  Size:                  0x%" PRIx64 "\n",
    458 	       preamble->preamble_size);
    459 	printf("  Header version:        %" PRIu32 ".%" PRIu32 "\n",
    460 	       preamble->header_version_major,
    461 	       preamble->header_version_minor);
    462 	printf("  Kernel version:        %" PRIu64 "\n",
    463 	       preamble->kernel_version);
    464 	printf("  Body load address:     0x%" PRIx64 "\n",
    465 	       preamble->body_load_address);
    466 	printf("  Body size:             0x%" PRIx64 "\n",
    467 	       preamble->body_signature.data_size);
    468 	printf("  Bootloader address:    0x%" PRIx64 "\n",
    469 	       preamble->bootloader_address);
    470 	printf("  Bootloader size:       0x%" PRIx64 "\n",
    471 	       preamble->bootloader_size);
    472 
    473 	if (VbGetKernelVmlinuzHeader(preamble,
    474 				     &vmlinuz_header_address,
    475 				     &vmlinuz_header_size)
    476 	    != VBOOT_SUCCESS) {
    477 		fprintf(stderr, "Unable to retrieve Vmlinuz Header!");
    478 		return 1;
    479 	}
    480 	if (vmlinuz_header_size) {
    481 		printf("  Vmlinuz_header address:    0x%" PRIx64 "\n",
    482 		       vmlinuz_header_address);
    483 		printf("  Vmlinuz header size:       0x%" PRIx64 "\n",
    484 		       vmlinuz_header_size);
    485 	}
    486 
    487 	if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS)
    488 		flags = preamble->flags;
    489 	printf("  Flags:                 0x%" PRIx32 "\n", flags);
    490 
    491 	/* Verify kernel body */
    492 	if (option.fv) {
    493 		/* It's in a separate file, which we've already read in */
    494 		kernel_blob = option.fv;
    495 		kernel_size = option.fv_size;
    496 	} else if (state->my_area->len > option.padding) {
    497 		/* It should be at an offset within the input file. */
    498 		kernel_blob = state->my_area->buf + option.padding;
    499 		kernel_size = state->my_area->len - option.padding;
    500 	}
    501 
    502 	if (!kernel_blob) {
    503 		/* TODO: Is this always a failure? The preamble is okay. */
    504 		fprintf(stderr, "No kernel blob available to verify.\n");
    505 		return 1;
    506 	}
    507 
    508 	if (0 != VerifyData(kernel_blob, kernel_size,
    509 			    &preamble->body_signature, rsa)) {
    510 		fprintf(stderr, "Error verifying kernel body.\n");
    511 		return 1;
    512 	}
    513 
    514 	printf("Body verification succeeded.\n");
    515 
    516 	printf("Config:\n%s\n", kernel_blob + KernelCmdLineOffset(preamble));
    517 
    518 	return retval;
    519 }
    520 
    521 int futil_cb_show_begin(struct futil_traverse_state_s *state)
    522 {
    523 	switch (state->in_type) {
    524 	case FILE_TYPE_UNKNOWN:
    525 		fprintf(stderr, "Unable to determine type of %s\n",
    526 			state->in_filename);
    527 		return 1;
    528 
    529 	case FILE_TYPE_BIOS_IMAGE:
    530 	case FILE_TYPE_OLD_BIOS_IMAGE:
    531 		printf("BIOS:                    %s\n", state->in_filename);
    532 		break;
    533 
    534 	default:
    535 		break;
    536 	}
    537 	return 0;
    538 }
    539 
    540 enum no_short_opts {
    541 	OPT_PADDING = 1000,
    542 };
    543 
    544 static const char usage[] = "\n"
    545 	"Usage:  " MYNAME " %s [OPTIONS] FILE [...]\n"
    546 	"\n"
    547 	"Where FILE could be a\n"
    548 	"\n"
    549 	"%s"
    550 	"  keyblock (.keyblock)\n"
    551 	"  firmware preamble signature (VBLOCK_A/B)\n"
    552 	"  firmware image (bios.bin)\n"
    553 	"  kernel partition (/dev/sda2, /dev/mmcblk0p2)\n"
    554 	"\n"
    555 	"Options:\n"
    556 	"  -t                               Just show the type of each file\n"
    557 	"  -k|--publickey   FILE"
    558 	"            Use this public key for validation\n"
    559 	"  -f|--fv          FILE            Verify this payload (FW_MAIN_A/B)\n"
    560 	"  --pad            NUM             Kernel vblock padding size\n"
    561 	"%s"
    562 	"\n";
    563 
    564 static void print_help(const char *prog)
    565 {
    566 	if (strcmp(prog, "verify"))
    567 		printf(usage, prog,
    568 		       "  public key (.vbpubk)\n",
    569 		       "  --strict                         "
    570 		       "Fail unless all signatures are valid\n");
    571 	else
    572 		printf(usage, prog, "",
    573 		       "\nIt will fail unless all signatures are valid\n");
    574 }
    575 
    576 static const struct option long_opts[] = {
    577 	/* name    hasarg *flag val */
    578 	{"publickey",   1, 0, 'k'},
    579 	{"fv",          1, 0, 'f'},
    580 	{"pad",         1, NULL, OPT_PADDING},
    581 	{"verify",      0, &option.strict, 1},
    582 	{"debug",       0, &debugging_enabled, 1},
    583 	{NULL, 0, NULL, 0},
    584 };
    585 static char *short_opts = ":f:k:t";
    586 
    587 
    588 static void show_type(char *filename)
    589 {
    590 	enum futil_file_err err;
    591 	enum futil_file_type type;
    592 	err = futil_file_type(filename, &type);
    593 	switch (err) {
    594 	case FILE_ERR_NONE:
    595 		printf("%s:\t%s\n", filename, futil_file_type_str(type));
    596 		break;
    597 	case FILE_ERR_DIR:
    598 		printf("%s:\t%s\n", filename, "directory");
    599 		break;
    600 	case FILE_ERR_CHR:
    601 		printf("%s:\t%s\n", filename, "character special");
    602 		break;
    603 	case FILE_ERR_FIFO:
    604 		printf("%s:\t%s\n", filename, "FIFO");
    605 		break;
    606 	case FILE_ERR_SOCK:
    607 		printf("%s:\t%s\n", filename, "socket");
    608 		break;
    609 	default:
    610 		break;
    611 	}
    612 }
    613 
    614 static int do_show(int argc, char *argv[])
    615 {
    616 	char *infile = 0;
    617 	int ifd, i;
    618 	int errorcnt = 0;
    619 	struct futil_traverse_state_s state;
    620 	uint8_t *buf;
    621 	uint32_t buf_len;
    622 	char *e = 0;
    623 
    624 	opterr = 0;		/* quiet, you */
    625 	while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
    626 		switch (i) {
    627 		case 'f':
    628 			option.fv = ReadFile(optarg, &option.fv_size);
    629 			if (!option.fv) {
    630 				fprintf(stderr, "Error reading %s: %s\n",
    631 					optarg, strerror(errno));
    632 				errorcnt++;
    633 			}
    634 			break;
    635 		case 'k':
    636 			option.k = PublicKeyRead(optarg);
    637 			if (!option.k) {
    638 				fprintf(stderr, "Error reading %s\n", optarg);
    639 				errorcnt++;
    640 			}
    641 			break;
    642 		case 't':
    643 			option.t_flag = 1;
    644 			break;
    645 		case OPT_PADDING:
    646 			option.padding = strtoul(optarg, &e, 0);
    647 			if (!*optarg || (e && *e)) {
    648 				fprintf(stderr,
    649 					"Invalid --padding \"%s\"\n", optarg);
    650 				errorcnt++;
    651 			}
    652 			break;
    653 
    654 		case '?':
    655 			if (optopt)
    656 				fprintf(stderr, "Unrecognized option: -%c\n",
    657 					optopt);
    658 			else
    659 				fprintf(stderr, "Unrecognized option\n");
    660 			errorcnt++;
    661 			break;
    662 		case ':':
    663 			fprintf(stderr, "Missing argument to -%c\n", optopt);
    664 			errorcnt++;
    665 			break;
    666 		case 0:				/* handled option */
    667 			break;
    668 		default:
    669 			DIE;
    670 		}
    671 	}
    672 
    673 	if (errorcnt) {
    674 		print_help(argv[0]);
    675 		return 1;
    676 	}
    677 
    678 	if (argc - optind < 1) {
    679 		fprintf(stderr, "ERROR: missing input filename\n");
    680 		print_help(argv[0]);
    681 		return 1;
    682 	}
    683 
    684 	if (option.t_flag) {
    685 		for (i = optind; i < argc; i++)
    686 			show_type(argv[i]);
    687 		goto done;
    688 	}
    689 
    690 	for (i = optind; i < argc; i++) {
    691 		infile = argv[i];
    692 		ifd = open(infile, O_RDONLY);
    693 		if (ifd < 0) {
    694 			errorcnt++;
    695 			fprintf(stderr, "Can't open %s: %s\n",
    696 				infile, strerror(errno));
    697 			continue;
    698 		}
    699 
    700 		if (0 != futil_map_file(ifd, MAP_RO, &buf, &buf_len)) {
    701 			errorcnt++;
    702 			goto boo;
    703 		}
    704 
    705 		memset(&state, 0, sizeof(state));
    706 		state.in_filename = infile ? infile : "<none>";
    707 		state.op = FUTIL_OP_SHOW;
    708 
    709 		errorcnt += futil_traverse(buf, buf_len, &state,
    710 					   FILE_TYPE_UNKNOWN);
    711 
    712 
    713 		errorcnt += futil_unmap_file(ifd, MAP_RO, buf, buf_len);
    714 
    715 boo:
    716 		if (close(ifd)) {
    717 			errorcnt++;
    718 			fprintf(stderr, "Error when closing %s: %s\n",
    719 				infile, strerror(errno));
    720 		}
    721 	}
    722 
    723 done:
    724 	if (option.k)
    725 		free(option.k);
    726 	if (option.fv)
    727 		free(option.fv);
    728 
    729 	return !!errorcnt;
    730 }
    731 
    732 DECLARE_FUTIL_COMMAND(show, do_show,
    733 		      VBOOT_VERSION_ALL,
    734 		      "Display the content of various binary components",
    735 		      print_help);
    736 
    737 static int do_verify(int argc, char *argv[])
    738 {
    739 	option.strict = 1;
    740 	return do_show(argc, argv);
    741 }
    742 
    743 DECLARE_FUTIL_COMMAND(verify, do_verify,
    744 		      VBOOT_VERSION_ALL,
    745 		      "Verify the signatures of various binary components",
    746 		      print_help);
    747