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 */
31enum callback_flags {
32	AREA_IS_VALID =     0x00000001,
33};
34
35/* Local structure for args, etc. */
36static 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
47static 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
58static 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
92int 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
108int 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
126int 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
225int 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 */
260int 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
276int 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
393done:
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
410int 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
521int 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
540enum no_short_opts {
541	OPT_PADDING = 1000,
542};
543
544static 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
564static 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
576static 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};
585static char *short_opts = ":f:k:t";
586
587
588static 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
614static 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
715boo:
716		if (close(ifd)) {
717			errorcnt++;
718			fprintf(stderr, "Error when closing %s: %s\n",
719				infile, strerror(errno));
720		}
721	}
722
723done:
724	if (option.k)
725		free(option.k);
726	if (option.fv)
727		free(option.fv);
728
729	return !!errorcnt;
730}
731
732DECLARE_FUTIL_COMMAND(show, do_show,
733		      VBOOT_VERSION_ALL,
734		      "Display the content of various binary components",
735		      print_help);
736
737static int do_verify(int argc, char *argv[])
738{
739	option.strict = 1;
740	return do_show(argc, argv);
741}
742
743DECLARE_FUTIL_COMMAND(verify, do_verify,
744		      VBOOT_VERSION_ALL,
745		      "Verify the signatures of various binary components",
746		      print_help);
747