123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- /* Copyright 2011 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- *
- * Verified boot firmware utility
- */
- #include <getopt.h>
- #include <inttypes.h> /* For PRIu64 */
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include "2sysincludes.h"
- #include "2api.h"
- #include "2common.h"
- #include "2rsa.h"
- #include "futility.h"
- #include "host_common.h"
- #include "host_key2.h"
- #include "kernel_blob.h"
- #include "util_misc.h"
- #include "vboot_common.h"
- #include "vb1_helper.h"
- #include "vb2_common.h"
- /* Command line options */
- enum {
- OPT_MODE_VBLOCK = 1000,
- OPT_MODE_VERIFY,
- OPT_KEYBLOCK,
- OPT_SIGNPUBKEY,
- OPT_SIGNPRIVATE,
- OPT_VERSION,
- OPT_FV,
- OPT_KERNELKEY,
- OPT_FLAGS,
- OPT_HELP,
- };
- static const struct option long_opts[] = {
- {"vblock", 1, 0, OPT_MODE_VBLOCK},
- {"verify", 1, 0, OPT_MODE_VERIFY},
- {"keyblock", 1, 0, OPT_KEYBLOCK},
- {"signpubkey", 1, 0, OPT_SIGNPUBKEY},
- {"signprivate", 1, 0, OPT_SIGNPRIVATE},
- {"version", 1, 0, OPT_VERSION},
- {"fv", 1, 0, OPT_FV},
- {"kernelkey", 1, 0, OPT_KERNELKEY},
- {"flags", 1, 0, OPT_FLAGS},
- {"help", 0, 0, OPT_HELP},
- {NULL, 0, 0, 0}
- };
- /* Print help and return error */
- static void print_help(int argc, char *argv[])
- {
- printf("\nUsage: " MYNAME " %s <--vblock|--verify> <file> [OPTIONS]\n"
- "\n"
- "For '--vblock <file>', required OPTIONS are:\n"
- "\n"
- " --keyblock <file> Key block in .keyblock format\n"
- " --signprivate <file>"
- " Signing private key in .vbprivk format\n"
- " --version <number> Firmware version\n"
- " --fv <file> Firmware volume to sign\n"
- " --kernelkey <file> Kernel subkey in .vbpubk format\n"
- "\n"
- "optional OPTIONS are:\n"
- " --flags <number> Preamble flags (defaults to 0)\n"
- "\n"
- "For '--verify <file>', required OPTIONS are:\n"
- "\n"
- " --signpubkey <file>"
- " Signing public key in .vbpubk format\n"
- " --fv <file> Firmware volume to verify\n"
- "\n"
- "For '--verify <file>', optional OPTIONS are:\n"
- " --kernelkey <file>"
- " Write the kernel subkey to this file\n\n",
- argv[0]);
- }
- /* Create a firmware .vblock */
- static int do_vblock(const char *outfile, const char *keyblock_file,
- const char *signprivate, uint32_t version,
- const char *fv_file, const char *kernelkey_file,
- uint32_t preamble_flags)
- {
- struct vb2_keyblock *keyblock = NULL;
- struct vb2_private_key *signing_key = NULL;
- struct vb2_packed_key *kernel_subkey = NULL;
- struct vb2_signature *body_sig = NULL;
- struct vb2_fw_preamble *preamble = NULL;
- uint8_t *fv_data = NULL;
- int retval = 1;
- if (!outfile) {
- VbExError("Must specify output filename\n");
- goto vblock_cleanup;
- }
- if (!keyblock_file || !signprivate || !kernelkey_file) {
- VbExError("Must specify all keys\n");
- goto vblock_cleanup;
- }
- if (!fv_file) {
- VbExError("Must specify firmware volume\n");
- goto vblock_cleanup;
- }
- /* Read the key block and keys */
- keyblock = vb2_read_keyblock(keyblock_file);
- if (!keyblock) {
- VbExError("Error reading key block.\n");
- goto vblock_cleanup;
- }
- signing_key = vb2_read_private_key(signprivate);
- if (!signing_key) {
- VbExError("Error reading signing key.\n");
- goto vblock_cleanup;
- }
- kernel_subkey = vb2_read_packed_key(kernelkey_file);
- if (!kernel_subkey) {
- VbExError("Error reading kernel subkey.\n");
- goto vblock_cleanup;
- }
- /* Read and sign the firmware volume */
- uint32_t fv_size;
- if (VB2_SUCCESS != vb2_read_file(fv_file, &fv_data, &fv_size))
- goto vblock_cleanup;
- if (!fv_size) {
- VbExError("Empty firmware volume file\n");
- goto vblock_cleanup;
- }
- body_sig = vb2_calculate_signature(fv_data, fv_size, signing_key);
- if (!body_sig) {
- VbExError("Error calculating body signature\n");
- goto vblock_cleanup;
- }
- /* Create preamble */
- preamble = vb2_create_fw_preamble(version, kernel_subkey, body_sig,
- signing_key, preamble_flags);
- if (!preamble) {
- VbExError("Error creating preamble.\n");
- goto vblock_cleanup;
- }
- /* Write the output file */
- FILE *f = fopen(outfile, "wb");
- if (!f) {
- VbExError("Can't open output file %s\n", outfile);
- goto vblock_cleanup;
- }
- int i = ((1 != fwrite(keyblock, keyblock->keyblock_size, 1, f)) ||
- (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
- fclose(f);
- if (i) {
- VbExError("Can't write output file %s\n", outfile);
- unlink(outfile);
- goto vblock_cleanup;
- }
- /* Success */
- retval = 0;
- vblock_cleanup:
- if (keyblock)
- free(keyblock);
- if (signing_key)
- free(signing_key);
- if (kernel_subkey)
- free(kernel_subkey);
- if (fv_data)
- free(fv_data);
- if (body_sig)
- free(body_sig);
- if (preamble)
- free(preamble);
- return retval;
- }
- static int do_verify(const char *infile, const char *signpubkey,
- const char *fv_file, const char *kernelkey_file)
- {
- uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE];
- struct vb2_workbuf wb;
- vb2_workbuf_init(&wb, workbuf, sizeof(workbuf));
- uint32_t now = 0;
- uint8_t *pubkbuf = NULL;
- uint8_t *blob = NULL;
- uint8_t *fv_data = NULL;
- int retval = 1;
- if (!infile || !signpubkey || !fv_file) {
- VbExError("Must specify filename, signpubkey, and fv\n");
- goto verify_cleanup;
- }
- /* Read public signing key */
- uint32_t pubklen;
- struct vb2_public_key sign_key;
- if (VB2_SUCCESS != vb2_read_file(signpubkey, &pubkbuf, &pubklen)) {
- fprintf(stderr, "Error reading signpubkey.\n");
- goto verify_cleanup;
- }
- if (VB2_SUCCESS != vb2_unpack_key_buffer(&sign_key, pubkbuf, pubklen)) {
- fprintf(stderr, "Error unpacking signpubkey.\n");
- goto verify_cleanup;
- }
- /* Read blob */
- uint32_t blob_size;
- if (VB2_SUCCESS != vb2_read_file(infile, &blob, &blob_size)) {
- VbExError("Error reading input file\n");
- goto verify_cleanup;
- }
- /* Read firmware volume */
- uint32_t fv_size;
- if (VB2_SUCCESS != vb2_read_file(fv_file, &fv_data, &fv_size)) {
- VbExError("Error reading firmware volume\n");
- goto verify_cleanup;
- }
- /* Verify key block */
- struct vb2_keyblock *keyblock = (struct vb2_keyblock *)blob;
- if (VB2_SUCCESS !=
- vb2_verify_keyblock(keyblock, blob_size, &sign_key, &wb)) {
- VbExError("Error verifying key block.\n");
- goto verify_cleanup;
- }
- now += keyblock->keyblock_size;
- printf("Key block:\n");
- printf(" Size: %d\n", keyblock->keyblock_size);
- printf(" Flags: %d (ignored)\n",
- keyblock->keyblock_flags);
- struct vb2_packed_key *packed_key = &keyblock->data_key;
- printf(" Data key algorithm: %d %s\n", packed_key->algorithm,
- vb2_get_crypto_algorithm_name(packed_key->algorithm));
- printf(" Data key version: %d\n", packed_key->key_version);
- printf(" Data key sha1sum: %s\n",
- packed_key_sha1_string(packed_key));
- struct vb2_public_key data_key;
- if (VB2_SUCCESS !=
- vb2_unpack_key(&data_key, &keyblock->data_key)) {
- fprintf(stderr, "Error parsing data key.\n");
- goto verify_cleanup;
- }
- /* Verify preamble */
- struct vb2_fw_preamble *pre2 = (struct vb2_fw_preamble *)(blob + now);
- if (VB2_SUCCESS !=
- vb2_verify_fw_preamble(pre2, blob_size - now, &data_key, &wb)) {
- VbExError("Error2 verifying preamble.\n");
- goto verify_cleanup;
- }
- now += pre2->preamble_size;
- uint32_t flags = pre2->flags;
- if (pre2->header_version_minor < 1)
- flags = 0; /* Old 2.0 structure didn't have flags */
- printf("Preamble:\n");
- printf(" Size: %d\n", pre2->preamble_size);
- printf(" Header version: %d.%d\n",
- pre2->header_version_major, pre2->header_version_minor);
- printf(" Firmware version: %d\n", pre2->firmware_version);
- struct vb2_packed_key *kernel_subkey = &pre2->kernel_subkey;
- printf(" Kernel key algorithm: %d %s\n", kernel_subkey->algorithm,
- vb2_get_crypto_algorithm_name(kernel_subkey->algorithm));
- printf(" Kernel key version: %d\n", kernel_subkey->key_version);
- printf(" Kernel key sha1sum: %s\n",
- packed_key_sha1_string(kernel_subkey));
- printf(" Firmware body size: %d\n", pre2->body_signature.data_size);
- printf(" Preamble flags: %d\n", flags);
- /* TODO: verify body size same as signature size */
- /* Verify body */
- if (flags & VB2_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
- printf("Preamble requests USE_RO_NORMAL;"
- " skipping body verification.\n");
- } else if (VB2_SUCCESS ==
- vb2_verify_data(fv_data, fv_size, &pre2->body_signature,
- &data_key, &wb)) {
- printf("Body verification succeeded.\n");
- } else {
- VbExError("Error verifying firmware body.\n");
- goto verify_cleanup;
- }
- if (kernelkey_file &&
- VB2_SUCCESS != vb2_write_packed_key(kernelkey_file,
- kernel_subkey)) {
- VbExError("Unable to write kernel subkey\n");
- goto verify_cleanup;
- }
- /* Success */
- retval = 0;
- verify_cleanup:
- if (pubkbuf)
- free(pubkbuf);
- if (blob)
- free(blob);
- if (fv_data)
- free(fv_data);
- return retval;
- }
- static int do_vbutil_firmware(int argc, char *argv[])
- {
- char *filename = NULL;
- char *key_block_file = NULL;
- char *signpubkey = NULL;
- char *signprivate = NULL;
- uint32_t version = 0;
- char *fv_file = NULL;
- char *kernelkey_file = NULL;
- uint32_t preamble_flags = 0;
- int mode = 0;
- int parse_error = 0;
- char *e;
- int i;
- while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
- switch (i) {
- case '?':
- /* Unhandled option */
- printf("Unknown option\n");
- parse_error = 1;
- break;
- case OPT_HELP:
- print_help(argc, argv);
- return !!parse_error;
- case OPT_MODE_VBLOCK:
- case OPT_MODE_VERIFY:
- mode = i;
- filename = optarg;
- break;
- case OPT_KEYBLOCK:
- key_block_file = optarg;
- break;
- case OPT_SIGNPUBKEY:
- signpubkey = optarg;
- break;
- case OPT_SIGNPRIVATE:
- signprivate = optarg;
- break;
- case OPT_FV:
- fv_file = optarg;
- break;
- case OPT_KERNELKEY:
- kernelkey_file = optarg;
- break;
- case OPT_VERSION:
- version = strtoul(optarg, &e, 0);
- if (!*optarg || (e && *e)) {
- printf("Invalid --version\n");
- parse_error = 1;
- }
- break;
- case OPT_FLAGS:
- preamble_flags = strtoul(optarg, &e, 0);
- if (!*optarg || (e && *e)) {
- printf("Invalid --flags\n");
- parse_error = 1;
- }
- break;
- }
- }
- if (parse_error) {
- print_help(argc, argv);
- return 1;
- }
- switch (mode) {
- case OPT_MODE_VBLOCK:
- return do_vblock(filename, key_block_file, signprivate, version,
- fv_file, kernelkey_file, preamble_flags);
- case OPT_MODE_VERIFY:
- return do_verify(filename, signpubkey, fv_file, kernelkey_file);
- default:
- fprintf(stderr, "Must specify a mode.\n");
- print_help(argc, argv);
- return 1;
- }
- }
- DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware, VBOOT_VERSION_1_0,
- "Verified boot firmware utility");
|