Home | History | Annotate | Download | only in futility
      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 <limits.h>
     11 #include <stddef.h>
     12 #include <stdint.h>
     13 #include <stdio.h>
     14 #include <stdlib.h>
     15 #include <string.h>
     16 #include <sys/stat.h>
     17 #include <sys/types.h>
     18 #include <unistd.h>
     19 
     20 #include "bmpblk_header.h"
     21 #include "file_type.h"
     22 #include "fmap.h"
     23 #include "futility.h"
     24 #include "gbb_header.h"
     25 #include "host_common.h"
     26 #include "kernel_blob.h"
     27 #include "traversal.h"
     28 #include "util_misc.h"
     29 #include "vb1_helper.h"
     30 #include "vboot_common.h"
     31 
     32 /* Local values for cb_area_s._flags */
     33 enum callback_flags {
     34 	AREA_IS_VALID =     0x00000001,
     35 };
     36 
     37 /* Local structure for args, etc. */
     38 static struct local_data_s {
     39 	VbPrivateKey *signprivate;
     40 	VbKeyBlockHeader *keyblock;
     41 	VbPublicKey *kernel_subkey;
     42 	VbPrivateKey *devsignprivate;
     43 	VbKeyBlockHeader *devkeyblock;
     44 	uint32_t version;
     45 	int version_specified;
     46 	uint32_t flags;
     47 	int flags_specified;
     48 	char *loemdir;
     49 	char *loemid;
     50 	uint8_t *bootloader_data;
     51 	uint64_t bootloader_size;
     52 	uint8_t *config_data;
     53 	uint64_t config_size;
     54 	enum arch_t arch;
     55 	int fv_specified;
     56 	uint32_t kloadaddr;
     57 	uint32_t padding;
     58 	int vblockonly;
     59 	char *outfile;
     60 	int create_new_outfile;
     61 	char *pem_signpriv;
     62 	int pem_algo_specified;
     63 	uint32_t pem_algo;
     64 	char *pem_external;
     65 } option = {
     66 	.version = 1,
     67 	.arch = ARCH_UNSPECIFIED,
     68 	.kloadaddr = CROS_32BIT_ENTRY_ADDR,
     69 	.padding = 65536,
     70 };
     71 
     72 
     73 /* Helper to complain about invalid args. Returns num errors discovered */
     74 static int no_opt_if(int expr, const char *optname)
     75 {
     76 	if (expr) {
     77 		fprintf(stderr, "Missing --%s option\n", optname);
     78 		return 1;
     79 	}
     80 	return 0;
     81 }
     82 
     83 /* This wraps/signs a public key, producing a keyblock. */
     84 int futil_cb_sign_pubkey(struct futil_traverse_state_s *state)
     85 {
     86 	VbPublicKey *data_key = (VbPublicKey *)state->my_area->buf;
     87 	VbKeyBlockHeader *vblock;
     88 
     89 	if (option.pem_signpriv) {
     90 		if (option.pem_external) {
     91 			/* External signing uses the PEM file directly. */
     92 			vblock = KeyBlockCreate_external(
     93 				data_key,
     94 				option.pem_signpriv,
     95 				option.pem_algo, option.flags,
     96 				option.pem_external);
     97 		} else {
     98 			option.signprivate = PrivateKeyReadPem(
     99 				option.pem_signpriv, option.pem_algo);
    100 			if (!option.signprivate) {
    101 				fprintf(stderr,
    102 					"Unable to read PEM signing key: %s\n",
    103 					strerror(errno));
    104 				return 1;
    105 			}
    106 			vblock = KeyBlockCreate(data_key, option.signprivate,
    107 						option.flags);
    108 		}
    109 	} else {
    110 		/* Not PEM. Should already have a signing key. */
    111 		vblock = KeyBlockCreate(data_key, option.signprivate,
    112 					option.flags);
    113 	}
    114 
    115 	/* Write it out */
    116 	return WriteSomeParts(option.outfile,
    117 			      vblock, vblock->key_block_size,
    118 			      NULL, 0);
    119 }
    120 
    121 /*
    122  * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
    123  * The data in state->my_area is just the RW firmware blob, so there's nothing
    124  * useful to show about it. We'll just mark it as present so when we encounter
    125  * corresponding VBLOCK area, we'll have this to verify.
    126  */
    127 int futil_cb_sign_fw_main(struct futil_traverse_state_s *state)
    128 {
    129 	state->my_area->_flags |= AREA_IS_VALID;
    130 	return 0;
    131 }
    132 
    133 /*
    134  * This handles VBLOCK_A and VBLOCK_B while processing a BIOS image.
    135  * We don't do any signing here. We just check to see if the VBLOCK
    136  * area contains a firmware preamble.
    137  */
    138 int futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state)
    139 {
    140 	VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
    141 	uint32_t len = state->my_area->len;
    142 
    143 	/*
    144 	 * If we have a valid keyblock and fw_preamble, then we can use them to
    145 	 * determine the size of the firmware body. Otherwise, we'll have to
    146 	 * just sign the whole region.
    147 	 */
    148 	if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
    149 		fprintf(stderr, "Warning: %s keyblock is invalid. "
    150 			"Signing the entire FW FMAP region...\n",
    151 			state->name);
    152 		goto whatever;
    153 	}
    154 
    155 	RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
    156 	if (!rsa) {
    157 		fprintf(stderr, "Warning: %s public key is invalid. "
    158 			"Signing the entire FW FMAP region...\n",
    159 			state->name);
    160 		goto whatever;
    161 	}
    162 	uint32_t more = key_block->key_block_size;
    163 	VbFirmwarePreambleHeader *preamble =
    164 		(VbFirmwarePreambleHeader *)(state->my_area->buf + more);
    165 	uint32_t fw_size = preamble->body_signature.data_size;
    166 	struct cb_area_s *fw_body_area = 0;
    167 
    168 	switch (state->component) {
    169 	case CB_FMAP_VBLOCK_A:
    170 		fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
    171 		/* Preserve the flags if they're not specified */
    172 		if (!option.flags_specified)
    173 			option.flags = preamble->flags;
    174 		break;
    175 	case CB_FMAP_VBLOCK_B:
    176 		fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
    177 		break;
    178 	default:
    179 		DIE;
    180 	}
    181 
    182 	if (fw_size > fw_body_area->len) {
    183 		fprintf(stderr,
    184 			"%s says the firmware is larger than we have\n",
    185 			state->name);
    186 		return 1;
    187 	}
    188 
    189 	/* Update the firmware size */
    190 	fw_body_area->len = fw_size;
    191 
    192 whatever:
    193 	state->my_area->_flags |= AREA_IS_VALID;
    194 
    195 	return 0;
    196 }
    197 
    198 int futil_cb_create_kernel_part(struct futil_traverse_state_s *state)
    199 {
    200 	uint8_t *vmlinuz_data, *kblob_data, *vblock_data;
    201 	uint64_t vmlinuz_size, kblob_size, vblock_size;
    202 	int rv;
    203 
    204 	vmlinuz_data = state->my_area->buf;
    205 	vmlinuz_size = state->my_area->len;
    206 
    207 	kblob_data = CreateKernelBlob(
    208 		vmlinuz_data, vmlinuz_size,
    209 		option.arch, option.kloadaddr,
    210 		option.config_data, option.config_size,
    211 		option.bootloader_data, option.bootloader_size,
    212 		&kblob_size);
    213 	if (!kblob_data) {
    214 		fprintf(stderr, "Unable to create kernel blob\n");
    215 		return 1;
    216 	}
    217 	Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
    218 
    219 	vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
    220 				     option.version, option.kloadaddr,
    221 				     option.keyblock, option.signprivate,
    222 				     option.flags, &vblock_size);
    223 	if (!vblock_data) {
    224 		fprintf(stderr, "Unable to sign kernel blob\n");
    225 		free(kblob_data);
    226 		return 1;
    227 	}
    228 	Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
    229 
    230 	/* We should be creating a completely new output file.
    231 	 * If not, something's wrong. */
    232 	if (!option.create_new_outfile)
    233 		DIE;
    234 
    235 	if (option.vblockonly)
    236 		rv = WriteSomeParts(option.outfile,
    237 				    vblock_data, vblock_size,
    238 				    NULL, 0);
    239 	else
    240 		rv = WriteSomeParts(option.outfile,
    241 				    vblock_data, vblock_size,
    242 				    kblob_data, kblob_size);
    243 
    244 	free(vblock_data);
    245 	free(kblob_data);
    246 	return rv;
    247 }
    248 
    249 int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
    250 {
    251 	uint8_t *kpart_data, *kblob_data, *vblock_data;
    252 	uint64_t kpart_size, kblob_size, vblock_size;
    253 	VbKeyBlockHeader *keyblock = NULL;
    254 	VbKernelPreambleHeader *preamble = NULL;
    255 	int rv = 0;
    256 
    257 	kpart_data = state->my_area->buf;
    258 	kpart_size = state->my_area->len;
    259 
    260 	/* Note: This just sets some static pointers. It doesn't malloc. */
    261 	kblob_data = UnpackKPart(kpart_data, kpart_size, option.padding,
    262 				 &keyblock, &preamble, &kblob_size);
    263 
    264 	if (!kblob_data) {
    265 		fprintf(stderr, "Unable to unpack kernel partition\n");
    266 		return 1;
    267 	}
    268 
    269 	/*
    270 	 * We don't let --kloadaddr change when resigning, because the original
    271 	 * vbutil_kernel program didn't do it right. Since obviously no one
    272 	 * ever noticed, we'll maintain bug-compatibility by just not allowing
    273 	 * it here either. To enable it, we'd need to update the zeropage
    274 	 * table's cmd_line_ptr as well as the preamble.
    275 	 */
    276 	option.kloadaddr = preamble->body_load_address;
    277 
    278 	/* Replace the config if asked */
    279 	if (option.config_data &&
    280 	    0 != UpdateKernelBlobConfig(kblob_data, kblob_size,
    281 					option.config_data,
    282 					option.config_size)) {
    283 		fprintf(stderr, "Unable to update config\n");
    284 		return 1;
    285 	}
    286 
    287 	/* Preserve the version unless a new one is given */
    288 	if (!option.version_specified)
    289 		option.version = preamble->kernel_version;
    290 
    291 	/* Preserve the flags if not specified */
    292 	if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) {
    293 		if (option.flags_specified == 0)
    294 			option.flags = preamble->flags;
    295 	}
    296 
    297 	/* Replace the keyblock if asked */
    298 	if (option.keyblock)
    299 		keyblock = option.keyblock;
    300 
    301 	/* Compute the new signature */
    302 	vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
    303 				     option.version, option.kloadaddr,
    304 				     keyblock, option.signprivate,
    305 				     option.flags, &vblock_size);
    306 	if (!vblock_data) {
    307 		fprintf(stderr, "Unable to sign kernel blob\n");
    308 		return 1;
    309 	}
    310 	Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
    311 
    312 	if (option.create_new_outfile) {
    313 		/* Write out what we've been asked for */
    314 		if (option.vblockonly)
    315 			rv = WriteSomeParts(option.outfile,
    316 					    vblock_data, vblock_size,
    317 					    NULL, 0);
    318 		else
    319 			rv = WriteSomeParts(option.outfile,
    320 					    vblock_data, vblock_size,
    321 					    kblob_data, kblob_size);
    322 	} else {
    323 		/* If we're modifying an existing file, it's mmap'ed so that
    324 		 * all our modifications to the buffer will get flushed to
    325 		 * disk when we close it. */
    326 		Memcpy(kpart_data, vblock_data, vblock_size);
    327 	}
    328 
    329 	free(vblock_data);
    330 	return rv;
    331 }
    332 
    333 
    334 int futil_cb_sign_raw_firmware(struct futil_traverse_state_s *state)
    335 {
    336 	VbSignature *body_sig;
    337 	VbFirmwarePreambleHeader *preamble;
    338 	int rv;
    339 
    340 	body_sig = CalculateSignature(state->my_area->buf, state->my_area->len,
    341 				      option.signprivate);
    342 	if (!body_sig) {
    343 		fprintf(stderr, "Error calculating body signature\n");
    344 		return 1;
    345 	}
    346 
    347 	preamble = CreateFirmwarePreamble(option.version,
    348 					  option.kernel_subkey,
    349 					  body_sig,
    350 					  option.signprivate,
    351 					  option.flags);
    352 	if (!preamble) {
    353 		fprintf(stderr, "Error creating firmware preamble.\n");
    354 		free(body_sig);
    355 		return 1;
    356 	}
    357 
    358 	rv = WriteSomeParts(option.outfile,
    359 			    option.keyblock, option.keyblock->key_block_size,
    360 			    preamble, preamble->preamble_size);
    361 
    362 	free(preamble);
    363 	free(body_sig);
    364 
    365 	return rv;
    366 }
    367 
    368 
    369 int futil_cb_sign_begin(struct futil_traverse_state_s *state)
    370 {
    371 	if (state->in_type == FILE_TYPE_UNKNOWN) {
    372 		fprintf(stderr, "Unable to determine type of %s\n",
    373 			state->in_filename);
    374 		return 1;
    375 	}
    376 
    377 	return 0;
    378 }
    379 
    380 static int write_new_preamble(struct cb_area_s *vblock,
    381 			      struct cb_area_s *fw_body,
    382 			      VbPrivateKey *signkey,
    383 			      VbKeyBlockHeader *keyblock)
    384 {
    385 	VbSignature *body_sig;
    386 	VbFirmwarePreambleHeader *preamble;
    387 
    388 	body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
    389 	if (!body_sig) {
    390 		fprintf(stderr, "Error calculating body signature\n");
    391 		return 1;
    392 	}
    393 
    394 	preamble = CreateFirmwarePreamble(option.version,
    395 					  option.kernel_subkey,
    396 					  body_sig,
    397 					  signkey,
    398 					  option.flags);
    399 	if (!preamble) {
    400 		fprintf(stderr, "Error creating firmware preamble.\n");
    401 		free(body_sig);
    402 		return 1;
    403 	}
    404 
    405 	/* Write the new keyblock */
    406 	uint32_t more = keyblock->key_block_size;
    407 	memcpy(vblock->buf, keyblock, more);
    408 	/* and the new preamble */
    409 	memcpy(vblock->buf + more, preamble, preamble->preamble_size);
    410 
    411 	free(preamble);
    412 	free(body_sig);
    413 
    414 	return 0;
    415 }
    416 
    417 static int write_loem(const char *ab, struct cb_area_s *vblock)
    418 {
    419 	char filename[PATH_MAX];
    420 	int n;
    421 	n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
    422 		     option.loemdir ? option.loemdir : ".",
    423 		     ab, option.loemid);
    424 	if (n >= sizeof(filename)) {
    425 		fprintf(stderr, "LOEM args produce bogus filename\n");
    426 		return 1;
    427 	}
    428 
    429 	FILE *fp = fopen(filename, "w");
    430 	if (!fp) {
    431 		fprintf(stderr, "Can't open %s for writing: %s\n",
    432 			filename, strerror(errno));
    433 		return 1;
    434 	}
    435 
    436 	if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
    437 		fprintf(stderr, "Can't write to %s: %s\n",
    438 			filename, strerror(errno));
    439 		fclose(fp);
    440 		return 1;
    441 	}
    442 	if (fclose(fp)) {
    443 		fprintf(stderr, "Failed closing loem output: %s\n",
    444 			strerror(errno));
    445 		return 1;
    446 	}
    447 
    448 	return 0;
    449 }
    450 
    451 /* This signs a full BIOS image after it's been traversed. */
    452 static int sign_bios_at_end(struct futil_traverse_state_s *state)
    453 {
    454 	struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A];
    455 	struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B];
    456 	struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A];
    457 	struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B];
    458 	int retval = 0;
    459 
    460 	if (state->errors ||
    461 	    !(vblock_a->_flags & AREA_IS_VALID) ||
    462 	    !(vblock_b->_flags & AREA_IS_VALID) ||
    463 	    !(fw_a->_flags & AREA_IS_VALID) ||
    464 	    !(fw_b->_flags & AREA_IS_VALID)) {
    465 		fprintf(stderr, "Something's wrong. Not changing anything\n");
    466 		return 1;
    467 	}
    468 
    469 	/* Do A & B differ ? */
    470 	if (fw_a->len != fw_b->len ||
    471 	    memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
    472 		/* Yes, must use DEV keys for A */
    473 		if (!option.devsignprivate || !option.devkeyblock) {
    474 			fprintf(stderr,
    475 				"FW A & B differ. DEV keys are required.\n");
    476 			return 1;
    477 		}
    478 		retval |= write_new_preamble(vblock_a, fw_a,
    479 					     option.devsignprivate,
    480 					     option.devkeyblock);
    481 	} else {
    482 		retval |= write_new_preamble(vblock_a, fw_a,
    483 					     option.signprivate,
    484 					     option.keyblock);
    485 	}
    486 
    487 	/* FW B is always normal keys */
    488 	retval |= write_new_preamble(vblock_b, fw_b,
    489 				     option.signprivate,
    490 				     option.keyblock);
    491 
    492 
    493 
    494 
    495 	if (option.loemid) {
    496 		retval |= write_loem("A", vblock_a);
    497 		retval |= write_loem("B", vblock_b);
    498 	}
    499 
    500 	return retval;
    501 }
    502 
    503 int futil_cb_sign_end(struct futil_traverse_state_s *state)
    504 {
    505 	switch (state->in_type) {
    506 	case FILE_TYPE_BIOS_IMAGE:
    507 	case FILE_TYPE_OLD_BIOS_IMAGE:
    508 		return sign_bios_at_end(state);
    509 
    510 	default:
    511 		/* Any other cleanup needed? */
    512 		break;
    513 	}
    514 
    515 	return state->errors;
    516 }
    517 
    518 static const char usage[] = "\n"
    519 	"Usage:  " MYNAME " %s [PARAMS] INFILE [OUTFILE]\n"
    520 	"\n"
    521 	"Where INFILE is a\n"
    522 	"\n"
    523 	"  public key (.vbpubk); OUTFILE is a keyblock\n"
    524 	"  raw firmware blob (FW_MAIN_A/B); OUTFILE is a VBLOCK_A/B\n"
    525 	"  complete firmware image (bios.bin)\n"
    526 	"  raw linux kernel; OUTFILE is a kernel partition image\n"
    527 	"  kernel partition image (/dev/sda2, /dev/mmcblk0p2)\n";
    528 
    529 static const char usage_pubkey[] = "\n"
    530 	"-----------------------------------------------------------------\n"
    531 	"To sign a public key / create a new keyblock:\n"
    532 	"\n"
    533 	"Required PARAMS:\n"
    534 	"  [--datapubkey]   INFILE          The public key to wrap\n"
    535 	"  [--outfile]      OUTFILE         The resulting keyblock\n"
    536 	"\n"
    537 	"Optional PARAMS:\n"
    538 	"  A private signing key, specified as either\n"
    539 	"    -s|--signprivate FILE.vbprivk  Signing key in .vbprivk format\n"
    540 	"  Or\n"
    541 	"    --pem_signpriv   FILE.pem      Signing key in PEM format...\n"
    542 	"    --pem_algo       NUM           AND the algorithm to use (0 - %d)\n"
    543 	"\n"
    544 	"  If a signing key is not given, the keyblock will not be signed (duh)."
    545 	"\n\n"
    546 	"And these, too:\n\n"
    547 	"  -f|--flags       NUM             Flags specifying use conditions\n"
    548 	"  --pem_external   PROGRAM"
    549 	"         External program to compute the signature\n"
    550 	"                                     (requires a PEM signing key)\n";
    551 
    552 static const char usage_fw_main[] = "\n"
    553 	"-----------------------------------------------------------------\n"
    554 	"To sign a raw firmware blob (FW_MAIN_A/B):\n"
    555 	"\n"
    556 	"Required PARAMS:\n"
    557 	"  -s|--signprivate FILE.vbprivk    The private firmware data key\n"
    558 	"  -b|--keyblock    FILE.keyblock   The keyblock containing the\n"
    559 	"                                     public firmware data key\n"
    560 	"  -k|--kernelkey   FILE.vbpubk     The public kernel subkey\n"
    561 	"  -v|--version     NUM             The firmware version number\n"
    562 	"  [--fv]           INFILE"
    563 	"          The raw firmware blob (FW_MAIN_A/B)\n"
    564 	"  [--outfile]      OUTFILE         Output VBLOCK_A/B\n"
    565 	"\n"
    566 	"Optional PARAMS:\n"
    567 	"  -f|--flags       NUM             The preamble flags value"
    568 	" (default is 0)\n";
    569 
    570 static const char usage_bios[] = "\n"
    571 	"-----------------------------------------------------------------\n"
    572 	"To sign a complete firmware image (bios.bin):\n"
    573 	"\n"
    574 	"Required PARAMS:\n"
    575 	"  -s|--signprivate FILE.vbprivk    The private firmware data key\n"
    576 	"  -b|--keyblock    FILE.keyblock   The keyblock containing the\n"
    577 	"                                     public firmware data key\n"
    578 	"  -k|--kernelkey   FILE.vbpubk     The public kernel subkey\n"
    579 	"  [--infile]       INFILE          Input firmware image (modified\n"
    580 	"                                     in place if no OUTFILE given)\n"
    581 	"\n"
    582 	"These are required if the A and B firmware differ:\n"
    583 	"  -S|--devsign     FILE.vbprivk    The DEV private firmware data key\n"
    584 	"  -B|--devkeyblock FILE.keyblock   The keyblock containing the\n"
    585 	"                                     DEV public firmware data key\n"
    586 	"\n"
    587 	"Optional PARAMS:\n"
    588 	"  -v|--version     NUM             The firmware version number"
    589 	" (default %d)\n"
    590 	"  -f|--flags       NUM             The preamble flags value"
    591 	" (default is\n"
    592 	"                                     unchanged, or 0 if unknown)\n"
    593 	"  -d|--loemdir     DIR             Local OEM output vblock directory\n"
    594 	"  -l|--loemid      STRING          Local OEM vblock suffix\n"
    595 	"  [--outfile]      OUTFILE         Output firmware image\n";
    596 
    597 static const char usage_new_kpart[] = "\n"
    598 	"-----------------------------------------------------------------\n"
    599 	"To create a new kernel parition image (/dev/sda2, /dev/mmcblk0p2):\n"
    600 	"\n"
    601 	"Required PARAMS:\n"
    602 	"  -s|--signprivate FILE.vbprivk"
    603 	"    The private key to sign the kernel blob\n"
    604 	"  -b|--keyblock    FILE.keyblock   The keyblock containing the public\n"
    605 	"                                     key to verify the kernel blob\n"
    606 	"  -v|--version     NUM             The kernel version number\n"
    607 	"  --bootloader     FILE            Bootloader stub\n"
    608 	"  --config         FILE            The kernel commandline file\n"
    609 	"  --arch           ARCH            The CPU architecture (one of\n"
    610 	"                                     x86|amd64, arm|aarch64, mips)\n"
    611 	"  [--vmlinuz]      INFILE          Linux kernel bzImage file\n"
    612 	"  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
    613 	"\n"
    614 	"Optional PARAMS:\n"
    615 	"  --kloadaddr      NUM"
    616 	"             RAM address to load the kernel body\n"
    617 	"                                     (default 0x%x)\n"
    618 	"  --pad            NUM             The vblock padding size in bytes\n"
    619 	"                                     (default 0x%x)\n"
    620 	" --vblockonly                      Emit just the vblock (requires a\n"
    621 	"                                     distinct outfile)\n"
    622 	"  -f|--flags       NUM             The preamble flags value\n";
    623 
    624 static const char usage_old_kpart[] = "\n"
    625 	"-----------------------------------------------------------------\n"
    626 	"To resign an existing kernel parition (/dev/sda2, /dev/mmcblk0p2):\n"
    627 	"\n"
    628 	"Required PARAMS:\n"
    629 	"  -s|--signprivate FILE.vbprivk"
    630 	"    The private key to sign the kernel blob\n"
    631 	"  [--infile]       INFILE          Input kernel partition (modified\n"
    632 	"                                     in place if no OUTFILE given)\n"
    633 	"\n"
    634 	"Optional PARAMS:\n"
    635 	"  -b|--keyblock    FILE.keyblock   The keyblock containing the public\n"
    636 	"                                     key to verify the kernel blob\n"
    637 	"  -v|--version     NUM             The kernel version number\n"
    638 	"  --config         FILE            The kernel commandline file\n"
    639 	"  --pad            NUM             The vblock padding size in bytes\n"
    640 	"                                     (default 0x%x)\n"
    641 	"  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
    642 	"  --vblockonly                     Emit just the vblock (requires a\n"
    643 	"                                     distinct OUTFILE)\n"
    644 	"  -f|--flags       NUM             The preamble flags value\n"
    645 	"\n";
    646 
    647 static void print_help(const char *prog)
    648 {
    649 	printf(usage, prog);
    650 	printf(usage_pubkey, kNumAlgorithms - 1);
    651 	puts(usage_fw_main);
    652 	printf(usage_bios, option.version);
    653 	printf(usage_new_kpart, option.kloadaddr, option.padding);
    654 	printf(usage_old_kpart, option.padding);
    655 }
    656 
    657 enum no_short_opts {
    658 	OPT_FV = 1000,
    659 	OPT_INFILE,			/* aka "--vmlinuz" */
    660 	OPT_OUTFILE,
    661 	OPT_BOOTLOADER,
    662 	OPT_CONFIG,
    663 	OPT_ARCH,
    664 	OPT_KLOADADDR,
    665 	OPT_PADDING,
    666 	OPT_PEM_SIGNPRIV,
    667 	OPT_PEM_ALGO,
    668 	OPT_PEM_EXTERNAL,
    669 };
    670 
    671 static const struct option long_opts[] = {
    672 	/* name    hasarg *flag  val */
    673 	{"signprivate",  1, NULL, 's'},
    674 	{"keyblock",     1, NULL, 'b'},
    675 	{"kernelkey",    1, NULL, 'k'},
    676 	{"devsign",      1, NULL, 'S'},
    677 	{"devkeyblock",  1, NULL, 'B'},
    678 	{"version",      1, NULL, 'v'},
    679 	{"flags",        1, NULL, 'f'},
    680 	{"loemdir",      1, NULL, 'd'},
    681 	{"loemid",       1, NULL, 'l'},
    682 	{"fv",           1, NULL, OPT_FV},
    683 	{"infile",       1, NULL, OPT_INFILE},
    684 	{"datapubkey",   1, NULL, OPT_INFILE},	/* alias */
    685 	{"vmlinuz",      1, NULL, OPT_INFILE},	/* alias */
    686 	{"outfile",      1, NULL, OPT_OUTFILE},
    687 	{"bootloader",   1, NULL, OPT_BOOTLOADER},
    688 	{"config",       1, NULL, OPT_CONFIG},
    689 	{"arch",         1, NULL, OPT_ARCH},
    690 	{"kloadaddr",    1, NULL, OPT_KLOADADDR},
    691 	{"pad",          1, NULL, OPT_PADDING},
    692 	{"pem_signpriv", 1, NULL, OPT_PEM_SIGNPRIV},
    693 	{"pem_algo",     1, NULL, OPT_PEM_ALGO},
    694 	{"pem_external", 1, NULL, OPT_PEM_EXTERNAL},
    695 	{"vblockonly",   0, &option.vblockonly, 1},
    696 	{"debug",        0, &debugging_enabled, 1},
    697 	{NULL,           0, NULL, 0},
    698 };
    699 static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
    700 
    701 static int do_sign(int argc, char *argv[])
    702 {
    703 	char *infile = 0;
    704 	int i;
    705 	int ifd = -1;
    706 	int errorcnt = 0;
    707 	struct futil_traverse_state_s state;
    708 	uint8_t *buf;
    709 	uint32_t buf_len;
    710 	char *e = 0;
    711 	enum futil_file_type type;
    712 	int inout_file_count = 0;
    713 	int mapping;
    714 
    715 	opterr = 0;		/* quiet, you */
    716 	while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
    717 		switch (i) {
    718 		case 's':
    719 			option.signprivate = PrivateKeyRead(optarg);
    720 			if (!option.signprivate) {
    721 				fprintf(stderr, "Error reading %s\n", optarg);
    722 				errorcnt++;
    723 			}
    724 			break;
    725 		case 'b':
    726 			option.keyblock = KeyBlockRead(optarg);
    727 			if (!option.keyblock) {
    728 				fprintf(stderr, "Error reading %s\n", optarg);
    729 				errorcnt++;
    730 			}
    731 			break;
    732 		case 'k':
    733 			option.kernel_subkey = PublicKeyRead(optarg);
    734 			if (!option.kernel_subkey) {
    735 				fprintf(stderr, "Error reading %s\n", optarg);
    736 				errorcnt++;
    737 			}
    738 			break;
    739 		case 'S':
    740 			option.devsignprivate = PrivateKeyRead(optarg);
    741 			if (!option.devsignprivate) {
    742 				fprintf(stderr, "Error reading %s\n", optarg);
    743 				errorcnt++;
    744 			}
    745 			break;
    746 		case 'B':
    747 			option.devkeyblock = KeyBlockRead(optarg);
    748 			if (!option.devkeyblock) {
    749 				fprintf(stderr, "Error reading %s\n", optarg);
    750 				errorcnt++;
    751 			}
    752 			break;
    753 		case 'v':
    754 			option.version_specified = 1;
    755 			option.version = strtoul(optarg, &e, 0);
    756 			if (!*optarg || (e && *e)) {
    757 				fprintf(stderr,
    758 					"Invalid --version \"%s\"\n", optarg);
    759 				errorcnt++;
    760 			}
    761 			break;
    762 
    763 		case 'f':
    764 			option.flags_specified = 1;
    765 			option.flags = strtoul(optarg, &e, 0);
    766 			if (!*optarg || (e && *e)) {
    767 				fprintf(stderr,
    768 					"Invalid --flags \"%s\"\n", optarg);
    769 				errorcnt++;
    770 			}
    771 			break;
    772 		case 'd':
    773 			option.loemdir = optarg;
    774 			break;
    775 		case 'l':
    776 			option.loemid = optarg;
    777 			break;
    778 		case OPT_FV:
    779 			option.fv_specified = 1;
    780 			/* fallthrough */
    781 		case OPT_INFILE:		/* aka "--vmlinuz" */
    782 			inout_file_count++;
    783 			infile = optarg;
    784 			break;
    785 		case OPT_OUTFILE:
    786 			inout_file_count++;
    787 			option.outfile = optarg;
    788 			break;
    789 		case OPT_BOOTLOADER:
    790 			option.bootloader_data = ReadFile(
    791 				optarg, &option.bootloader_size);
    792 			if (!option.bootloader_data) {
    793 				fprintf(stderr,
    794 					"Error reading bootloader file: %s\n",
    795 					strerror(errno));
    796 				errorcnt++;
    797 			}
    798 			Debug("bootloader file size=0x%" PRIx64 "\n",
    799 			      option.bootloader_size);
    800 			break;
    801 		case OPT_CONFIG:
    802 			option.config_data = ReadConfigFile(
    803 				optarg, &option.config_size);
    804 			if (!option.config_data) {
    805 				fprintf(stderr,
    806 					"Error reading config file: %s\n",
    807 					strerror(errno));
    808 				errorcnt++;
    809 			}
    810 			break;
    811 		case OPT_ARCH:
    812 			/* check the first 3 characters to also match x86_64 */
    813 			if ((!strncasecmp(optarg, "x86", 3)) ||
    814 			    (!strcasecmp(optarg, "amd64")))
    815 				option.arch = ARCH_X86;
    816 			else if ((!strcasecmp(optarg, "arm")) ||
    817 				 (!strcasecmp(optarg, "aarch64")))
    818 				option.arch = ARCH_ARM;
    819 			else if (!strcasecmp(optarg, "mips"))
    820 				option.arch = ARCH_MIPS;
    821 			else {
    822 				fprintf(stderr,
    823 					"Unknown architecture: \"%s\"\n",
    824 					optarg);
    825 				errorcnt++;
    826 			}
    827 			break;
    828 		case OPT_KLOADADDR:
    829 			option.kloadaddr = strtoul(optarg, &e, 0);
    830 			if (!*optarg || (e && *e)) {
    831 				fprintf(stderr,
    832 					"Invalid --kloadaddr \"%s\"\n", optarg);
    833 				errorcnt++;
    834 			}
    835 			break;
    836 		case OPT_PADDING:
    837 			option.padding = strtoul(optarg, &e, 0);
    838 			if (!*optarg || (e && *e)) {
    839 				fprintf(stderr,
    840 					"Invalid --padding \"%s\"\n", optarg);
    841 				errorcnt++;
    842 			}
    843 			break;
    844 		case OPT_PEM_SIGNPRIV:
    845 			option.pem_signpriv = optarg;
    846 			break;
    847 		case OPT_PEM_ALGO:
    848 			option.pem_algo_specified = 1;
    849 			option.pem_algo = strtoul(optarg, &e, 0);
    850 			if (!*optarg || (e && *e) ||
    851 			    (option.pem_algo >= kNumAlgorithms)) {
    852 				fprintf(stderr,
    853 					"Invalid --pem_algo \"%s\"\n", optarg);
    854 				errorcnt++;
    855 			}
    856 			break;
    857 		case OPT_PEM_EXTERNAL:
    858 			option.pem_external = optarg;
    859 			break;
    860 
    861 		case '?':
    862 			if (optopt)
    863 				fprintf(stderr, "Unrecognized option: -%c\n",
    864 					optopt);
    865 			else
    866 				fprintf(stderr, "Unrecognized option: %s\n",
    867 					argv[optind - 1]);
    868 			errorcnt++;
    869 			break;
    870 		case ':':
    871 			fprintf(stderr, "Missing argument to -%c\n", optopt);
    872 			errorcnt++;
    873 			break;
    874 		case 0:				/* handled option */
    875 			break;
    876 		default:
    877 			Debug("i=%d\n", i);
    878 			DIE;
    879 		}
    880 	}
    881 
    882 	/* If we don't have an input file already, we need one */
    883 	if (!infile) {
    884 		if (argc - optind <= 0) {
    885 			errorcnt++;
    886 			fprintf(stderr, "ERROR: missing input filename\n");
    887 			goto done;
    888 		} else {
    889 			inout_file_count++;
    890 			infile = argv[optind++];
    891 		}
    892 	}
    893 
    894 	/* Look for an output file if we don't have one, just in case. */
    895 	if (!option.outfile && argc - optind > 0) {
    896 		inout_file_count++;
    897 		option.outfile = argv[optind++];
    898 	}
    899 
    900 	/* What are we looking at? */
    901 	if (futil_file_type(infile, &type)) {
    902 		errorcnt++;
    903 		goto done;
    904 	}
    905 
    906 	/* We may be able to infer the type based on the other args */
    907 	if (type == FILE_TYPE_UNKNOWN) {
    908 		if (option.bootloader_data || option.config_data
    909 		    || option.arch != ARCH_UNSPECIFIED)
    910 			type = FILE_TYPE_RAW_KERNEL;
    911 		else if (option.kernel_subkey || option.fv_specified)
    912 			type = FILE_TYPE_RAW_FIRMWARE;
    913 	}
    914 
    915 	Debug("type=%s\n", futil_file_type_str(type));
    916 
    917 	/* Check the arguments for the type of thing we want to sign */
    918 	switch (type) {
    919 	case FILE_TYPE_UNKNOWN:
    920 		fprintf(stderr,
    921 			"Unable to determine the type of the input file\n");
    922 		errorcnt++;
    923 		goto done;
    924 	case FILE_TYPE_PUBKEY:
    925 		option.create_new_outfile = 1;
    926 		if (option.signprivate && option.pem_signpriv) {
    927 			fprintf(stderr,
    928 				"Only one of --signprivate and --pem_signpriv"
    929 				" can be specified\n");
    930 			errorcnt++;
    931 		}
    932 		if ((option.signprivate && option.pem_algo_specified) ||
    933 		    (option.pem_signpriv && !option.pem_algo_specified)) {
    934 			fprintf(stderr, "--pem_algo must be used with"
    935 				" --pem_signpriv\n");
    936 			errorcnt++;
    937 		}
    938 		if (option.pem_external && !option.pem_signpriv) {
    939 			fprintf(stderr, "--pem_external must be used with"
    940 				" --pem_signpriv\n");
    941 			errorcnt++;
    942 		}
    943 		/* We'll wait to read the PEM file, since the external signer
    944 		 * may want to read it instead. */
    945 		break;
    946 	case FILE_TYPE_KEYBLOCK:
    947 		fprintf(stderr, "Resigning a keyblock is kind of pointless.\n");
    948 		fprintf(stderr, "Just create a new one.\n");
    949 		errorcnt++;
    950 		break;
    951 	case FILE_TYPE_FW_PREAMBLE:
    952 		fprintf(stderr,
    953 			"%s IS a signature. Sign the firmware instead\n",
    954 			infile);
    955 		break;
    956 	case FILE_TYPE_GBB:
    957 		fprintf(stderr, "There's no way to sign a GBB\n");
    958 		errorcnt++;
    959 		break;
    960 	case FILE_TYPE_BIOS_IMAGE:
    961 	case FILE_TYPE_OLD_BIOS_IMAGE:
    962 		errorcnt += no_opt_if(!option.signprivate, "signprivate");
    963 		errorcnt += no_opt_if(!option.keyblock, "keyblock");
    964 		errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
    965 		break;
    966 	case FILE_TYPE_KERN_PREAMBLE:
    967 		errorcnt += no_opt_if(!option.signprivate, "signprivate");
    968 		if (option.vblockonly || inout_file_count > 1)
    969 			option.create_new_outfile = 1;
    970 		break;
    971 	case FILE_TYPE_RAW_FIRMWARE:
    972 		option.create_new_outfile = 1;
    973 		errorcnt += no_opt_if(!option.signprivate, "signprivate");
    974 		errorcnt += no_opt_if(!option.keyblock, "keyblock");
    975 		errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
    976 		errorcnt += no_opt_if(!option.version_specified, "version");
    977 		break;
    978 	case FILE_TYPE_RAW_KERNEL:
    979 		option.create_new_outfile = 1;
    980 		errorcnt += no_opt_if(!option.signprivate, "signprivate");
    981 		errorcnt += no_opt_if(!option.keyblock, "keyblock");
    982 		errorcnt += no_opt_if(!option.version_specified, "version");
    983 		errorcnt += no_opt_if(!option.bootloader_data, "bootloader");
    984 		errorcnt += no_opt_if(!option.config_data, "config");
    985 		errorcnt += no_opt_if(option.arch == ARCH_UNSPECIFIED, "arch");
    986 		break;
    987 	case FILE_TYPE_CHROMIUMOS_DISK:
    988 		fprintf(stderr, "Signing a %s is not yet supported\n",
    989 			futil_file_type_str(type));
    990 		errorcnt++;
    991 		break;
    992 	default:
    993 		DIE;
    994 	}
    995 
    996 	Debug("infile=%s\n", infile);
    997 	Debug("inout_file_count=%d\n", inout_file_count);
    998 	Debug("option.create_new_outfile=%d\n", option.create_new_outfile);
    999 
   1000 	/* Make sure we have an output file if one is needed */
   1001 	if (!option.outfile) {
   1002 		if (option.create_new_outfile) {
   1003 			errorcnt++;
   1004 			fprintf(stderr, "Missing output filename\n");
   1005 			goto done;
   1006 		} else {
   1007 			option.outfile = infile;
   1008 		}
   1009 	}
   1010 
   1011 	Debug("option.outfile=%s\n", option.outfile);
   1012 
   1013 	if (argc - optind > 0) {
   1014 		errorcnt++;
   1015 		fprintf(stderr, "ERROR: too many arguments left over\n");
   1016 	}
   1017 
   1018 	if (errorcnt)
   1019 		goto done;
   1020 
   1021 	memset(&state, 0, sizeof(state));
   1022 	state.op = FUTIL_OP_SIGN;
   1023 
   1024 	if (option.create_new_outfile) {
   1025 		/* The input is read-only, the output is write-only. */
   1026 		mapping = MAP_RO;
   1027 		state.in_filename = infile;
   1028 		Debug("open RO %s\n", infile);
   1029 		ifd = open(infile, O_RDONLY);
   1030 		if (ifd < 0) {
   1031 			errorcnt++;
   1032 			fprintf(stderr, "Can't open %s for reading: %s\n",
   1033 				infile, strerror(errno));
   1034 			goto done;
   1035 		}
   1036 	} else {
   1037 		/* We'll read-modify-write the output file */
   1038 		mapping = MAP_RW;
   1039 		state.in_filename = option.outfile;
   1040 		if (inout_file_count > 1)
   1041 			futil_copy_file_or_die(infile, option.outfile);
   1042 		Debug("open RW %s\n", option.outfile);
   1043 		ifd = open(option.outfile, O_RDWR);
   1044 		if (ifd < 0) {
   1045 			errorcnt++;
   1046 			fprintf(stderr, "Can't open %s for writing: %s\n",
   1047 				option.outfile, strerror(errno));
   1048 			goto done;
   1049 		}
   1050 	}
   1051 
   1052 	if (0 != futil_map_file(ifd, mapping, &buf, &buf_len)) {
   1053 		errorcnt++;
   1054 		goto done;
   1055 	}
   1056 
   1057 	errorcnt += futil_traverse(buf, buf_len, &state, type);
   1058 
   1059 	errorcnt += futil_unmap_file(ifd, MAP_RW, buf, buf_len);
   1060 
   1061 done:
   1062 	if (ifd >= 0 && close(ifd)) {
   1063 		errorcnt++;
   1064 		fprintf(stderr, "Error when closing ifd: %s\n",
   1065 			strerror(errno));
   1066 	}
   1067 
   1068 	if (option.signprivate)
   1069 		free(option.signprivate);
   1070 	if (option.keyblock)
   1071 		free(option.keyblock);
   1072 	if (option.kernel_subkey)
   1073 		free(option.kernel_subkey);
   1074 
   1075 	if (errorcnt)
   1076 		fprintf(stderr, "Use --help for usage instructions\n");
   1077 
   1078 	return !!errorcnt;
   1079 }
   1080 
   1081 DECLARE_FUTIL_COMMAND(sign, do_sign,
   1082 		      VBOOT_VERSION_ALL,
   1083 		      "Sign / resign various binary components",
   1084 		      print_help);
   1085