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