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 */ 33enum callback_flags { 34 AREA_IS_VALID = 0x00000001, 35}; 36 37/* Local structure for args, etc. */ 38static 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 */ 74static 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. */ 84int 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 */ 127int 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 */ 138int 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 192whatever: 193 state->my_area->_flags |= AREA_IS_VALID; 194 195 return 0; 196} 197 198int 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 249int 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 334int 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 369int 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 380static 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 417static 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. */ 452static 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 503int 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 518static 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 529static 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 552static 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 570static 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 597static 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 624static 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 647static 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 657enum 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 671static 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}; 699static char *short_opts = ":s:b:k:S:B:v:f:d:l:"; 700 701static 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 1061done: 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 1081DECLARE_FUTIL_COMMAND(sign, do_sign, 1082 VBOOT_VERSION_ALL, 1083 "Sign / resign various binary components", 1084 print_help); 1085