• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
show_key(VbPublicKey * pubkey,const char * sp)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 
show_keyblock(VbKeyBlockHeader * key_block,const char * name,int sign_key,int good_sig)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 
futil_cb_show_pubkey(struct futil_traverse_state_s * state)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 
futil_cb_show_privkey(struct futil_traverse_state_s * state)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 
futil_cb_show_gbb(struct futil_traverse_state_s * state)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 
futil_cb_show_keyblock(struct futil_traverse_state_s * state)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  */
futil_cb_show_fw_main(struct futil_traverse_state_s * state)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 
futil_cb_show_fw_preamble(struct futil_traverse_state_s * state)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 
futil_cb_show_kernel_preamble(struct futil_traverse_state_s * state)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 
futil_cb_show_begin(struct futil_traverse_state_s * state)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 
print_help(const char * prog)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 
show_type(char * filename)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 
do_show(int argc,char * argv[])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 
do_verify(int argc,char * argv[])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