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 */
no_opt_if(int expr,const char * optname)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. */
futil_cb_sign_pubkey(struct futil_traverse_state_s * state)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 */
futil_cb_sign_fw_main(struct futil_traverse_state_s * state)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 */
futil_cb_sign_fw_vblock(struct futil_traverse_state_s * state)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
futil_cb_create_kernel_part(struct futil_traverse_state_s * state)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
futil_cb_resign_kernel_part(struct futil_traverse_state_s * state)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
futil_cb_sign_raw_firmware(struct futil_traverse_state_s * state)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
futil_cb_sign_begin(struct futil_traverse_state_s * state)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
write_new_preamble(struct cb_area_s * vblock,struct cb_area_s * fw_body,VbPrivateKey * signkey,VbKeyBlockHeader * keyblock)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
write_loem(const char * ab,struct cb_area_s * vblock)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. */
sign_bios_at_end(struct futil_traverse_state_s * state)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
futil_cb_sign_end(struct futil_traverse_state_s * state)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
print_help(const char * prog)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
do_sign(int argc,char * argv[])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