Home | History | Annotate | Download | only in futility
      1 /* Copyright 2011 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  *
      5  * Verified boot firmware utility
      6  */
      7 
      8 #include <getopt.h>
      9 #include <inttypes.h>		/* For PRIu64 */
     10 #include <stddef.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <unistd.h>
     14 
     15 #include "cryptolib.h"
     16 #include "futility.h"
     17 #include "host_common.h"
     18 #include "kernel_blob.h"
     19 #include "util_misc.h"
     20 #include "vboot_common.h"
     21 
     22 /* Command line options */
     23 enum {
     24 	OPT_MODE_VBLOCK = 1000,
     25 	OPT_MODE_VERIFY,
     26 	OPT_KEYBLOCK,
     27 	OPT_SIGNPUBKEY,
     28 	OPT_SIGNPRIVATE,
     29 	OPT_VERSION,
     30 	OPT_FV,
     31 	OPT_KERNELKEY,
     32 	OPT_FLAGS,
     33 };
     34 
     35 static const struct option long_opts[] = {
     36 	{"vblock", 1, 0, OPT_MODE_VBLOCK},
     37 	{"verify", 1, 0, OPT_MODE_VERIFY},
     38 	{"keyblock", 1, 0, OPT_KEYBLOCK},
     39 	{"signpubkey", 1, 0, OPT_SIGNPUBKEY},
     40 	{"signprivate", 1, 0, OPT_SIGNPRIVATE},
     41 	{"version", 1, 0, OPT_VERSION},
     42 	{"fv", 1, 0, OPT_FV},
     43 	{"kernelkey", 1, 0, OPT_KERNELKEY},
     44 	{"flags", 1, 0, OPT_FLAGS},
     45 	{NULL, 0, 0, 0}
     46 };
     47 
     48 /* Print help and return error */
     49 static void print_help(const char *prog)
     50 {
     51 	printf("\nUsage:  " MYNAME " %s <--vblock|--verify> <file> [OPTIONS]\n"
     52 	       "\n"
     53 	       "For '--vblock <file>', required OPTIONS are:\n"
     54 	       "\n"
     55 	       "  --keyblock <file>           Key block in .keyblock format\n"
     56 	       "  --signprivate <file>"
     57 	       "        Signing private key in .vbprivk format\n"
     58 	       "  --version <number>          Firmware version\n"
     59 	       "  --fv <file>                 Firmware volume to sign\n"
     60 	       "  --kernelkey <file>          Kernel subkey in .vbpubk format\n"
     61 	       "\n"
     62 	       "optional OPTIONS are:\n"
     63 	       "  --flags <number>            Preamble flags (defaults to 0)\n"
     64 	       "\n"
     65 	       "For '--verify <file>', required OPTIONS are:\n"
     66 	       "\n"
     67 	       "  --signpubkey <file>"
     68 	       "         Signing public key in .vbpubk format\n"
     69 	       "  --fv <file>                 Firmware volume to verify\n"
     70 	       "\n"
     71 	       "For '--verify <file>', optional OPTIONS are:\n"
     72 	       "  --kernelkey <file>"
     73 	       "          Write the kernel subkey to this file\n\n",
     74 	       prog);
     75 }
     76 
     77 /* Create a firmware .vblock */
     78 static int Vblock(const char *outfile, const char *keyblock_file,
     79 		  const char *signprivate, uint64_t version,
     80 		  const char *fv_file, const char *kernelkey_file,
     81 		  uint32_t preamble_flags)
     82 {
     83 
     84 	VbPrivateKey *signing_key;
     85 	VbPublicKey *kernel_subkey;
     86 	VbSignature *body_sig;
     87 	VbFirmwarePreambleHeader *preamble;
     88 	VbKeyBlockHeader *key_block;
     89 	uint64_t key_block_size;
     90 	uint8_t *fv_data;
     91 	uint64_t fv_size;
     92 	FILE *f;
     93 	uint64_t i;
     94 
     95 	if (!outfile) {
     96 		VbExError("Must specify output filename\n");
     97 		return 1;
     98 	}
     99 	if (!keyblock_file || !signprivate || !kernelkey_file) {
    100 		VbExError("Must specify all keys\n");
    101 		return 1;
    102 	}
    103 	if (!fv_file) {
    104 		VbExError("Must specify firmware volume\n");
    105 		return 1;
    106 	}
    107 
    108 	/* Read the key block and keys */
    109 	key_block =
    110 	    (VbKeyBlockHeader *) ReadFile(keyblock_file, &key_block_size);
    111 	if (!key_block) {
    112 		VbExError("Error reading key block.\n");
    113 		return 1;
    114 	}
    115 
    116 	signing_key = PrivateKeyRead(signprivate);
    117 	if (!signing_key) {
    118 		VbExError("Error reading signing key.\n");
    119 		return 1;
    120 	}
    121 
    122 	kernel_subkey = PublicKeyRead(kernelkey_file);
    123 	if (!kernel_subkey) {
    124 		VbExError("Error reading kernel subkey.\n");
    125 		return 1;
    126 	}
    127 
    128 	/* Read and sign the firmware volume */
    129 	fv_data = ReadFile(fv_file, &fv_size);
    130 	if (!fv_data)
    131 		return 1;
    132 	if (!fv_size) {
    133 		VbExError("Empty firmware volume file\n");
    134 		return 1;
    135 	}
    136 	body_sig = CalculateSignature(fv_data, fv_size, signing_key);
    137 	if (!body_sig) {
    138 		VbExError("Error calculating body signature\n");
    139 		return 1;
    140 	}
    141 	free(fv_data);
    142 
    143 	/* Create preamble */
    144 	preamble = CreateFirmwarePreamble(version,
    145 					  kernel_subkey,
    146 					  body_sig,
    147 					  signing_key, preamble_flags);
    148 	if (!preamble) {
    149 		VbExError("Error creating preamble.\n");
    150 		return 1;
    151 	}
    152 
    153 	/* Write the output file */
    154 	f = fopen(outfile, "wb");
    155 	if (!f) {
    156 		VbExError("Can't open output file %s\n", outfile);
    157 		return 1;
    158 	}
    159 	i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
    160 	     (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
    161 	fclose(f);
    162 	if (i) {
    163 		VbExError("Can't write output file %s\n", outfile);
    164 		unlink(outfile);
    165 		return 1;
    166 	}
    167 
    168 	/* Success */
    169 	return 0;
    170 }
    171 
    172 static int Verify(const char *infile, const char *signpubkey,
    173 		  const char *fv_file, const char *kernelkey_file)
    174 {
    175 
    176 	VbKeyBlockHeader *key_block;
    177 	VbFirmwarePreambleHeader *preamble;
    178 	VbPublicKey *data_key;
    179 	VbPublicKey *sign_key;
    180 	VbPublicKey *kernel_subkey;
    181 	RSAPublicKey *rsa;
    182 	uint8_t *blob;
    183 	uint64_t blob_size;
    184 	uint8_t *fv_data;
    185 	uint64_t fv_size;
    186 	uint64_t now = 0;
    187 	uint32_t flags;
    188 
    189 	if (!infile || !signpubkey || !fv_file) {
    190 		VbExError("Must specify filename, signpubkey, and fv\n");
    191 		return 1;
    192 	}
    193 
    194 	/* Read public signing key */
    195 	sign_key = PublicKeyRead(signpubkey);
    196 	if (!sign_key) {
    197 		VbExError("Error reading signpubkey.\n");
    198 		return 1;
    199 	}
    200 
    201 	/* Read blob */
    202 	blob = ReadFile(infile, &blob_size);
    203 	if (!blob) {
    204 		VbExError("Error reading input file\n");
    205 		return 1;
    206 	}
    207 
    208 	/* Read firmware volume */
    209 	fv_data = ReadFile(fv_file, &fv_size);
    210 	if (!fv_data) {
    211 		VbExError("Error reading firmware volume\n");
    212 		return 1;
    213 	}
    214 
    215 	/* Verify key block */
    216 	key_block = (VbKeyBlockHeader *) blob;
    217 	if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) {
    218 		VbExError("Error verifying key block.\n");
    219 		return 1;
    220 	}
    221 	free(sign_key);
    222 	now += key_block->key_block_size;
    223 
    224 	printf("Key block:\n");
    225 	data_key = &key_block->data_key;
    226 	printf("  Size:                %" PRIu64 "\n",
    227 	       key_block->key_block_size);
    228 	printf("  Flags:               %" PRIu64 " (ignored)\n",
    229 	       key_block->key_block_flags);
    230 	printf("  Data key algorithm:  %" PRIu64 " %s\n", data_key->algorithm,
    231 	       (data_key->algorithm <
    232 		kNumAlgorithms ? algo_strings[data_key->
    233 					      algorithm] : "(invalid)"));
    234 	printf("  Data key version:    %" PRIu64 "\n", data_key->key_version);
    235 	printf("  Data key sha1sum:    ");
    236 	PrintPubKeySha1Sum(data_key);
    237 	printf("\n");
    238 
    239 	rsa = PublicKeyToRSA(&key_block->data_key);
    240 	if (!rsa) {
    241 		VbExError("Error parsing data key.\n");
    242 		return 1;
    243 	}
    244 
    245 	/* Verify preamble */
    246 	preamble = (VbFirmwarePreambleHeader *) (blob + now);
    247 	if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) {
    248 		VbExError("Error verifying preamble.\n");
    249 		return 1;
    250 	}
    251 	now += preamble->preamble_size;
    252 
    253 	flags = VbGetFirmwarePreambleFlags(preamble);
    254 	printf("Preamble:\n");
    255 	printf("  Size:                  %" PRIu64 "\n",
    256 	       preamble->preamble_size);
    257 	printf("  Header version:        %" PRIu32 ".%" PRIu32 "\n",
    258 	       preamble->header_version_major, preamble->header_version_minor);
    259 	printf("  Firmware version:      %" PRIu64 "\n",
    260 	       preamble->firmware_version);
    261 	kernel_subkey = &preamble->kernel_subkey;
    262 	printf("  Kernel key algorithm:  %" PRIu64 " %s\n",
    263 	       kernel_subkey->algorithm,
    264 	       (kernel_subkey->algorithm < kNumAlgorithms ?
    265 		algo_strings[kernel_subkey->algorithm] : "(invalid)"));
    266 	printf("  Kernel key version:    %" PRIu64 "\n",
    267 	       kernel_subkey->key_version);
    268 	printf("  Kernel key sha1sum:    ");
    269 	PrintPubKeySha1Sum(kernel_subkey);
    270 	printf("\n");
    271 	printf("  Firmware body size:    %" PRIu64 "\n",
    272 	       preamble->body_signature.data_size);
    273 	printf("  Preamble flags:        %" PRIu32 "\n", flags);
    274 
    275 	/* TODO: verify body size same as signature size */
    276 
    277 	/* Verify body */
    278 	if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
    279 		printf
    280 		    ("Preamble requests USE_RO_NORMAL;"
    281 		     " skipping body verification.\n");
    282 	} else {
    283 		if (0 !=
    284 		    VerifyData(fv_data, fv_size, &preamble->body_signature,
    285 			       rsa)) {
    286 			VbExError("Error verifying firmware body.\n");
    287 			return 1;
    288 		}
    289 		printf("Body verification succeeded.\n");
    290 	}
    291 
    292 	if (kernelkey_file) {
    293 		if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) {
    294 			VbExError("Unable to write kernel subkey\n");
    295 			return 1;
    296 		}
    297 	}
    298 
    299 	return 0;
    300 }
    301 
    302 static int do_vbutil_firmware(int argc, char *argv[])
    303 {
    304 
    305 	char *filename = NULL;
    306 	char *key_block_file = NULL;
    307 	char *signpubkey = NULL;
    308 	char *signprivate = NULL;
    309 	uint64_t version = 0;
    310 	char *fv_file = NULL;
    311 	char *kernelkey_file = NULL;
    312 	uint32_t preamble_flags = 0;
    313 	int mode = 0;
    314 	int parse_error = 0;
    315 	char *e;
    316 	int i;
    317 
    318 	while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
    319 		switch (i) {
    320 		case '?':
    321 			/* Unhandled option */
    322 			printf("Unknown option\n");
    323 			parse_error = 1;
    324 			break;
    325 
    326 		case OPT_MODE_VBLOCK:
    327 		case OPT_MODE_VERIFY:
    328 			mode = i;
    329 			filename = optarg;
    330 			break;
    331 
    332 		case OPT_KEYBLOCK:
    333 			key_block_file = optarg;
    334 			break;
    335 
    336 		case OPT_SIGNPUBKEY:
    337 			signpubkey = optarg;
    338 			break;
    339 
    340 		case OPT_SIGNPRIVATE:
    341 			signprivate = optarg;
    342 			break;
    343 
    344 		case OPT_FV:
    345 			fv_file = optarg;
    346 			break;
    347 
    348 		case OPT_KERNELKEY:
    349 			kernelkey_file = optarg;
    350 			break;
    351 
    352 		case OPT_VERSION:
    353 			version = strtoul(optarg, &e, 0);
    354 			if (!*optarg || (e && *e)) {
    355 				printf("Invalid --version\n");
    356 				parse_error = 1;
    357 			}
    358 			break;
    359 
    360 		case OPT_FLAGS:
    361 			preamble_flags = strtoul(optarg, &e, 0);
    362 			if (!*optarg || (e && *e)) {
    363 				printf("Invalid --flags\n");
    364 				parse_error = 1;
    365 			}
    366 			break;
    367 		}
    368 	}
    369 
    370 	if (parse_error) {
    371 		print_help(argv[0]);
    372 		return 1;
    373 	}
    374 
    375 	switch (mode) {
    376 	case OPT_MODE_VBLOCK:
    377 		return Vblock(filename, key_block_file, signprivate, version,
    378 			      fv_file, kernelkey_file, preamble_flags);
    379 	case OPT_MODE_VERIFY:
    380 		return Verify(filename, signpubkey, fv_file, kernelkey_file);
    381 	default:
    382 		fprintf(stderr, "Must specify a mode.\n");
    383 		print_help(argv[0]);
    384 		return 1;
    385 	}
    386 }
    387 
    388 DECLARE_FUTIL_COMMAND(vbutil_firmware, do_vbutil_firmware,
    389 		      VBOOT_VERSION_1_0,
    390 		      "Verified boot firmware utility",
    391 		      print_help);
    392