cmd_show.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  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. #define OPENSSL_NO_SHA
  7. #include <openssl/rsa.h>
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <getopt.h>
  11. #include <inttypes.h>
  12. #include <stddef.h>
  13. #include <stdint.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <sys/stat.h>
  18. #include <sys/types.h>
  19. #include <unistd.h>
  20. #include "2sysincludes.h"
  21. #include "2api.h"
  22. #include "2common.h"
  23. #include "2sha.h"
  24. #include "file_type.h"
  25. #include "file_type_bios.h"
  26. #include "fmap.h"
  27. #include "futility.h"
  28. #include "futility_options.h"
  29. #include "host_common.h"
  30. #include "host_key2.h"
  31. #include "util_misc.h"
  32. #include "vb1_helper.h"
  33. #include "vb2_common.h"
  34. /* Options */
  35. struct show_option_s show_option = {
  36. .padding = 65536,
  37. .type = FILE_TYPE_UNKNOWN,
  38. };
  39. /* Shared work buffer */
  40. static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE];
  41. static struct vb2_workbuf wb;
  42. void show_pubkey(const struct vb2_packed_key *pubkey, const char *sp)
  43. {
  44. printf("%sVboot API: 1.0\n", sp);
  45. printf("%sAlgorithm: %d %s\n", sp, pubkey->algorithm,
  46. vb2_get_crypto_algorithm_name(pubkey->algorithm));
  47. printf("%sKey Version: %d\n", sp, pubkey->key_version);
  48. printf("%sKey sha1sum: %s\n",
  49. sp, packed_key_sha1_string(pubkey));
  50. }
  51. static void show_keyblock(struct vb2_keyblock *keyblock, const char *name,
  52. int sign_key, int good_sig)
  53. {
  54. if (name)
  55. printf("Key block: %s\n", name);
  56. else
  57. printf("Key block:\n");
  58. printf(" Signature: %s\n",
  59. sign_key ? (good_sig ? "valid" : "invalid") : "ignored");
  60. printf(" Size: 0x%x\n", keyblock->keyblock_size);
  61. printf(" Flags: %d ", keyblock->keyblock_flags);
  62. if (keyblock->keyblock_flags & VB2_KEY_BLOCK_FLAG_DEVELOPER_0)
  63. printf(" !DEV");
  64. if (keyblock->keyblock_flags & VB2_KEY_BLOCK_FLAG_DEVELOPER_1)
  65. printf(" DEV");
  66. if (keyblock->keyblock_flags & VB2_KEY_BLOCK_FLAG_RECOVERY_0)
  67. printf(" !REC");
  68. if (keyblock->keyblock_flags & VB2_KEY_BLOCK_FLAG_RECOVERY_1)
  69. printf(" REC");
  70. printf("\n");
  71. struct vb2_packed_key *data_key = &keyblock->data_key;
  72. printf(" Data key algorithm: %d %s\n", data_key->algorithm,
  73. vb2_get_crypto_algorithm_name(data_key->algorithm));
  74. printf(" Data key version: %d\n", data_key->key_version);
  75. printf(" Data key sha1sum: %s\n",
  76. packed_key_sha1_string(data_key));
  77. }
  78. int ft_show_pubkey(const char *name, uint8_t *buf, uint32_t len, void *data)
  79. {
  80. struct vb2_packed_key *pubkey = (struct vb2_packed_key *)buf;
  81. if (!packed_key_looks_ok(pubkey, len)) {
  82. printf("%s looks bogus\n", name);
  83. return 1;
  84. }
  85. printf("Public Key file: %s\n", name);
  86. show_pubkey(pubkey, " ");
  87. return 0;
  88. }
  89. int ft_show_privkey(const char *name, uint8_t *buf, uint32_t len, void *data)
  90. {
  91. struct vb2_packed_private_key *pkey =
  92. (struct vb2_packed_private_key *)buf;
  93. struct vb2_private_key key;
  94. const unsigned char *start = pkey->key_data;
  95. if (len <= sizeof(*pkey)) {
  96. printf("%s looks bogus\n", name);
  97. return 1;
  98. }
  99. len -= sizeof(*pkey);
  100. key.rsa_private_key = d2i_RSAPrivateKey(NULL, &start, len);
  101. printf("Private Key file: %s\n", name);
  102. printf(" Vboot API: 1.0\n");
  103. printf(" Algorithm: %u %s\n", pkey->algorithm,
  104. vb2_get_crypto_algorithm_name(pkey->algorithm));
  105. printf(" Key sha1sum: %s\n",
  106. private_key_sha1_string(&key));
  107. return 0;
  108. }
  109. int ft_show_keyblock(const char *name, uint8_t *buf, uint32_t len, void *data)
  110. {
  111. struct vb2_keyblock *block = (struct vb2_keyblock *)buf;
  112. struct vb2_public_key *sign_key = show_option.k;
  113. int good_sig = 0;
  114. int retval = 0;
  115. /* Check the hash only first */
  116. if (0 != vb2_verify_keyblock_hash(block, len, &wb)) {
  117. printf("%s is invalid\n", name);
  118. return 1;
  119. }
  120. /* Check the signature if we have one */
  121. if (sign_key &&
  122. VB2_SUCCESS == vb2_verify_keyblock(block, len, sign_key, &wb))
  123. good_sig = 1;
  124. if (show_option.strict && (!sign_key || !good_sig))
  125. retval = 1;
  126. show_keyblock(block, name, !!sign_key, good_sig);
  127. return retval;
  128. }
  129. int ft_show_fw_preamble(const char *name, uint8_t *buf, uint32_t len,
  130. void *data)
  131. {
  132. struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf;
  133. struct bios_state_s *state = (struct bios_state_s *)data;
  134. struct vb2_public_key *sign_key = show_option.k;
  135. uint8_t *fv_data = show_option.fv;
  136. uint64_t fv_size = show_option.fv_size;
  137. struct bios_area_s *fw_body_area = 0;
  138. int good_sig = 0;
  139. int retval = 0;
  140. /* Check the hash... */
  141. if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) {
  142. printf("%s keyblock component is invalid\n", name);
  143. return 1;
  144. }
  145. /*
  146. * If we're being invoked while poking through a BIOS, we should
  147. * be given the keys and data to verify as part of the state. If we
  148. * have no state, then we're just looking at a standalone fw_preamble,
  149. * so we'll have to get any keys or data from options.
  150. */
  151. struct vb2_public_key root_key;
  152. if (state) {
  153. if (!sign_key &&
  154. state->rootkey.is_valid &&
  155. VB2_SUCCESS == vb2_unpack_key_buffer(&root_key,
  156. state->rootkey.buf,
  157. state->rootkey.len)) {
  158. /* BIOS should have a rootkey in the GBB */
  159. sign_key = &root_key;
  160. }
  161. /* Identify the firmware body for this VBLOCK */
  162. enum bios_component body_c = state->c == BIOS_FMAP_VBLOCK_A
  163. ? BIOS_FMAP_FW_MAIN_A
  164. : BIOS_FMAP_FW_MAIN_B;
  165. fw_body_area = &state->area[body_c];
  166. }
  167. /* If we have a key, check the signature too */
  168. if (sign_key && VB2_SUCCESS ==
  169. vb2_verify_keyblock(keyblock, len, sign_key, &wb))
  170. good_sig = 1;
  171. show_keyblock(keyblock, name, !!sign_key, good_sig);
  172. if (show_option.strict && (!sign_key || !good_sig))
  173. retval = 1;
  174. struct vb2_public_key data_key;
  175. if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) {
  176. fprintf(stderr, "Error parsing data key in %s\n", name);
  177. return 1;
  178. }
  179. uint32_t more = keyblock->keyblock_size;
  180. struct vb2_fw_preamble *pre2 = (struct vb2_fw_preamble *)(buf + more);
  181. if (VB2_SUCCESS != vb2_verify_fw_preamble(pre2, len - more,
  182. &data_key, &wb)) {
  183. printf("%s is invalid\n", name);
  184. return 1;
  185. }
  186. uint32_t flags = pre2->flags;
  187. if (pre2->header_version_minor < 1)
  188. flags = 0; /* Old 2.0 structure didn't have flags */
  189. printf("Firmware Preamble:\n");
  190. printf(" Size: %d\n", pre2->preamble_size);
  191. printf(" Header version: %d.%d\n",
  192. pre2->header_version_major, pre2->header_version_minor);
  193. printf(" Firmware version: %d\n", pre2->firmware_version);
  194. struct vb2_packed_key *kernel_subkey = &pre2->kernel_subkey;
  195. printf(" Kernel key algorithm: %d %s\n",
  196. kernel_subkey->algorithm,
  197. vb2_get_crypto_algorithm_name(kernel_subkey->algorithm));
  198. if (kernel_subkey->algorithm >= VB2_ALG_COUNT)
  199. retval = 1;
  200. printf(" Kernel key version: %d\n", kernel_subkey->key_version);
  201. printf(" Kernel key sha1sum: %s\n",
  202. packed_key_sha1_string(kernel_subkey));
  203. printf(" Firmware body size: %d\n", pre2->body_signature.data_size);
  204. printf(" Preamble flags: %d\n", flags);
  205. if (flags & VB2_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
  206. printf("Preamble requests USE_RO_NORMAL;"
  207. " skipping body verification.\n");
  208. goto done;
  209. }
  210. /* We'll need to get the firmware body from somewhere... */
  211. if (fw_body_area && fw_body_area->is_valid) {
  212. fv_data = fw_body_area->buf;
  213. fv_size = fw_body_area->len;
  214. }
  215. if (!fv_data) {
  216. printf("No firmware body available to verify.\n");
  217. if (show_option.strict)
  218. return 1;
  219. return 0;
  220. }
  221. if (VB2_SUCCESS !=
  222. vb2_verify_data(fv_data, fv_size, &pre2->body_signature,
  223. &data_key, &wb)) {
  224. fprintf(stderr, "Error verifying firmware body.\n");
  225. return 1;
  226. }
  227. done:
  228. /* Can't trust the BIOS unless everything is signed (in which case
  229. * we've already returned), but standalone files are okay. */
  230. if (state || (sign_key && good_sig)) {
  231. if (!(flags & VB2_FIRMWARE_PREAMBLE_USE_RO_NORMAL))
  232. printf("Body verification succeeded.\n");
  233. if (state)
  234. state->area[state->c].is_valid = 1;
  235. } else {
  236. printf("Seems legit, but the signature is unverified.\n");
  237. if (show_option.strict)
  238. retval = 1;
  239. }
  240. return retval;
  241. }
  242. int ft_show_kernel_preamble(const char *name, uint8_t *buf, uint32_t len,
  243. void *data)
  244. {
  245. struct vb2_keyblock *keyblock = (struct vb2_keyblock *)buf;
  246. struct vb2_public_key *sign_key = show_option.k;
  247. int retval = 0;
  248. /* Check the hash... */
  249. if (VB2_SUCCESS != vb2_verify_keyblock_hash(keyblock, len, &wb)) {
  250. printf("%s keyblock component is invalid\n", name);
  251. return 1;
  252. }
  253. /* If we have a key, check the signature too */
  254. int good_sig = 0;
  255. if (sign_key && VB2_SUCCESS ==
  256. vb2_verify_keyblock(keyblock, len, sign_key, &wb))
  257. good_sig = 1;
  258. printf("Kernel partition: %s\n", name);
  259. show_keyblock(keyblock, NULL, !!sign_key, good_sig);
  260. if (show_option.strict && (!sign_key || !good_sig))
  261. retval = 1;
  262. struct vb2_public_key data_key;
  263. if (VB2_SUCCESS != vb2_unpack_key(&data_key, &keyblock->data_key)) {
  264. fprintf(stderr, "Error parsing data key in %s\n", name);
  265. return 1;
  266. }
  267. uint32_t more = keyblock->keyblock_size;
  268. struct vb2_kernel_preamble *pre2 =
  269. (struct vb2_kernel_preamble *)(buf + more);
  270. if (VB2_SUCCESS != vb2_verify_kernel_preamble(pre2, len - more,
  271. &data_key, &wb)) {
  272. printf("%s is invalid\n", name);
  273. return 1;
  274. }
  275. printf("Kernel Preamble:\n");
  276. printf(" Size: 0x%x\n", pre2->preamble_size);
  277. printf(" Header version: %u.%u\n",
  278. pre2->header_version_major,
  279. pre2->header_version_minor);
  280. printf(" Kernel version: %u\n", pre2->kernel_version);
  281. printf(" Body load address: 0x%" PRIx64 "\n",
  282. pre2->body_load_address);
  283. printf(" Body size: 0x%x\n",
  284. pre2->body_signature.data_size);
  285. printf(" Bootloader address: 0x%" PRIx64 "\n",
  286. pre2->bootloader_address);
  287. printf(" Bootloader size: 0x%x\n", pre2->bootloader_size);
  288. uint64_t vmlinuz_header_address = 0;
  289. uint32_t vmlinuz_header_size = 0;
  290. vb2_kernel_get_vmlinuz_header(pre2,
  291. &vmlinuz_header_address,
  292. &vmlinuz_header_size);
  293. if (vmlinuz_header_size) {
  294. printf(" Vmlinuz_header address: 0x%" PRIx64 "\n",
  295. vmlinuz_header_address);
  296. printf(" Vmlinuz header size: 0x%x\n",
  297. vmlinuz_header_size);
  298. }
  299. printf(" Flags: 0x%x\n", vb2_kernel_get_flags(pre2));
  300. /* Verify kernel body */
  301. uint8_t *kernel_blob = 0;
  302. uint64_t kernel_size = 0;
  303. if (show_option.fv) {
  304. /* It's in a separate file, which we've already read in */
  305. kernel_blob = show_option.fv;
  306. kernel_size = show_option.fv_size;
  307. } else if (len > show_option.padding) {
  308. /* It should be at an offset within the input file. */
  309. kernel_blob = buf + show_option.padding;
  310. kernel_size = len - show_option.padding;
  311. }
  312. if (!kernel_blob) {
  313. /* TODO: Is this always a failure? The preamble is okay. */
  314. fprintf(stderr, "No kernel blob available to verify.\n");
  315. return 1;
  316. }
  317. if (VB2_SUCCESS !=
  318. vb2_verify_data(kernel_blob, kernel_size, &pre2->body_signature,
  319. &data_key, &wb)) {
  320. fprintf(stderr, "Error verifying kernel body.\n");
  321. return 1;
  322. }
  323. printf("Body verification succeeded.\n");
  324. printf("Config:\n%s\n", kernel_blob + kernel_cmd_line_offset(pre2));
  325. return retval;
  326. }
  327. enum no_short_opts {
  328. OPT_PADDING = 1000,
  329. OPT_TYPE,
  330. OPT_PUBKEY,
  331. OPT_HELP,
  332. };
  333. static const char usage[] = "\n"
  334. "Usage: " MYNAME " %s [OPTIONS] FILE [...]\n"
  335. "\n"
  336. "Where FILE could be\n"
  337. "\n"
  338. " a boot descriptor block (BDB)\n"
  339. " a keyblock (.keyblock)\n"
  340. " a firmware preamble signature (VBLOCK_A/B)\n"
  341. " a firmware image (bios.bin)\n"
  342. " a kernel partition (/dev/sda2, /dev/mmcblk0p2)\n"
  343. " keys in various formats (.vbpubk, .vbprivk, .pem)\n"
  344. " several other file types related to verified boot\n"
  345. "\n"
  346. "Options:\n"
  347. " -t Just show the type of each file\n"
  348. " --type TYPE Override the detected file type\n"
  349. " Use \"--type help\" for a list\n"
  350. "Type-specific options:\n"
  351. " -k|--publickey FILE.vbpubk Public key in vb1 format\n"
  352. " --pubkey FILE.vpubk2 Public key in vb2 format\n"
  353. " -f|--fv FILE Verify this payload (FW_MAIN_A/B)\n"
  354. " --pad NUM Kernel vblock padding size\n"
  355. " --strict "
  356. "Fail unless all signatures are valid\n"
  357. "\n";
  358. static void print_help(int argc, char *argv[])
  359. {
  360. if (!strcmp(argv[0], "verify"))
  361. printf("\nUsage: " MYNAME " %s [OPTIONS] FILE [...]\n\n"
  362. "This is just an alias for\n\n"
  363. " " MYNAME " show --strict\n\n",
  364. argv[0]);
  365. printf(usage, "show");
  366. }
  367. static const struct option long_opts[] = {
  368. /* name hasarg *flag val */
  369. {"publickey", 1, 0, 'k'},
  370. {"fv", 1, 0, 'f'},
  371. {"pad", 1, NULL, OPT_PADDING},
  372. {"type", 1, NULL, OPT_TYPE},
  373. {"strict", 0, &show_option.strict, 1},
  374. {"pubkey", 1, NULL, OPT_PUBKEY},
  375. {"help", 0, NULL, OPT_HELP},
  376. {NULL, 0, NULL, 0},
  377. };
  378. static char *short_opts = ":f:k:t";
  379. static int show_type(char *filename)
  380. {
  381. enum futil_file_err err;
  382. enum futil_file_type type;
  383. err = futil_file_type(filename, &type);
  384. switch (err) {
  385. case FILE_ERR_NONE:
  386. printf("%s:\t%s\n", filename, futil_file_type_name(type));
  387. /* Only our recognized types return success */
  388. return 0;
  389. case FILE_ERR_DIR:
  390. printf("%s:\t%s\n", filename, "directory");
  391. break;
  392. case FILE_ERR_CHR:
  393. printf("%s:\t%s\n", filename, "character special");
  394. break;
  395. case FILE_ERR_FIFO:
  396. printf("%s:\t%s\n", filename, "FIFO");
  397. break;
  398. case FILE_ERR_SOCK:
  399. printf("%s:\t%s\n", filename, "socket");
  400. break;
  401. default:
  402. break;
  403. }
  404. /* Everything else is an error */
  405. return 1;
  406. }
  407. static int do_show(int argc, char *argv[])
  408. {
  409. uint8_t *pubkbuf = NULL;
  410. struct vb2_public_key pubk2;
  411. char *infile = 0;
  412. int ifd, i;
  413. int errorcnt = 0;
  414. uint8_t *buf;
  415. uint32_t len;
  416. char *e = 0;
  417. int type_override = 0;
  418. enum futil_file_type type;
  419. vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
  420. opterr = 0; /* quiet, you */
  421. while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
  422. switch (i) {
  423. case 'f':
  424. show_option.fv = ReadFile(optarg,
  425. &show_option.fv_size);
  426. if (!show_option.fv) {
  427. fprintf(stderr, "Error reading %s: %s\n",
  428. optarg, strerror(errno));
  429. errorcnt++;
  430. }
  431. break;
  432. case 'k':
  433. if (VB2_SUCCESS !=
  434. vb2_read_file(optarg, &pubkbuf, &len)) {
  435. fprintf(stderr, "Error reading %s\n", optarg);
  436. errorcnt++;
  437. break;
  438. }
  439. if (VB2_SUCCESS !=
  440. vb2_unpack_key_buffer(&pubk2, pubkbuf, len)) {
  441. fprintf(stderr, "Error unpacking %s\n", optarg);
  442. errorcnt++;
  443. break;
  444. }
  445. show_option.k = &pubk2;
  446. break;
  447. case 't':
  448. show_option.t_flag = 1;
  449. break;
  450. case OPT_PADDING:
  451. show_option.padding = strtoul(optarg, &e, 0);
  452. if (!*optarg || (e && *e)) {
  453. fprintf(stderr,
  454. "Invalid --padding \"%s\"\n", optarg);
  455. errorcnt++;
  456. }
  457. break;
  458. case OPT_TYPE:
  459. if (!futil_str_to_file_type(optarg,
  460. &show_option.type)) {
  461. if (!strcasecmp("help", optarg))
  462. print_file_types_and_exit(errorcnt);
  463. fprintf(stderr,
  464. "Invalid --type \"%s\"\n", optarg);
  465. errorcnt++;
  466. }
  467. type_override = 1;
  468. break;
  469. case OPT_PUBKEY:
  470. if (vb21_packed_key_read(&show_option.pkey, optarg)) {
  471. fprintf(stderr, "Error reading %s\n", optarg);
  472. errorcnt++;
  473. }
  474. break;
  475. case OPT_HELP:
  476. print_help(argc, argv);
  477. return !!errorcnt;
  478. case '?':
  479. if (optopt)
  480. fprintf(stderr, "Unrecognized option: -%c\n",
  481. optopt);
  482. else
  483. fprintf(stderr, "Unrecognized option\n");
  484. errorcnt++;
  485. break;
  486. case ':':
  487. fprintf(stderr, "Missing argument to -%c\n", optopt);
  488. errorcnt++;
  489. break;
  490. case 0: /* handled option */
  491. break;
  492. default:
  493. DIE;
  494. }
  495. }
  496. if (errorcnt) {
  497. print_help(argc, argv);
  498. return 1;
  499. }
  500. if (argc - optind < 1) {
  501. fprintf(stderr, "ERROR: missing input filename\n");
  502. print_help(argc, argv);
  503. return 1;
  504. }
  505. if (show_option.t_flag) {
  506. for (i = optind; i < argc; i++)
  507. errorcnt += show_type(argv[i]);
  508. goto done;
  509. }
  510. for (i = optind; i < argc; i++) {
  511. infile = argv[i];
  512. ifd = open(infile, O_RDONLY);
  513. if (ifd < 0) {
  514. errorcnt++;
  515. fprintf(stderr, "Can't open %s: %s\n",
  516. infile, strerror(errno));
  517. continue;
  518. }
  519. if (0 != futil_map_file(ifd, MAP_RO, &buf, &len)) {
  520. errorcnt++;
  521. goto boo;
  522. }
  523. /* Allow the user to override the type */
  524. if (type_override)
  525. type = show_option.type;
  526. else
  527. type = futil_file_type_buf(buf, len);
  528. errorcnt += futil_file_type_show(type, infile, buf, len);
  529. errorcnt += futil_unmap_file(ifd, MAP_RO, buf, len);
  530. boo:
  531. if (close(ifd)) {
  532. errorcnt++;
  533. fprintf(stderr, "Error when closing %s: %s\n",
  534. infile, strerror(errno));
  535. }
  536. }
  537. done:
  538. if (pubkbuf)
  539. free(pubkbuf);
  540. if (show_option.fv)
  541. free(show_option.fv);
  542. return !!errorcnt;
  543. }
  544. DECLARE_FUTIL_COMMAND(show, do_show, VBOOT_VERSION_ALL,
  545. "Display the content of various binary components");
  546. static int do_verify(int argc, char *argv[])
  547. {
  548. show_option.strict = 1;
  549. return do_show(argc, argv);
  550. }
  551. DECLARE_FUTIL_COMMAND(verify, do_verify,
  552. VBOOT_VERSION_ALL,
  553. "Verify the signatures of various binary components");