1 /* Copyright 2014 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
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 "2common.h"
21 #include "file_type.h"
22 #include "file_type_bios.h"
23 #include "futility.h"
24 #include "futility_options.h"
25 #include "host_common.h"
26 #include "host_common21.h"
27 #include "host_key21.h"
28 #include "kernel_blob.h"
29 #include "util_misc.h"
30 #include "vb1_helper.h"
31
32 #define DEFAULT_KEYSETDIR "/usr/share/vboot/devkeys"
33
34 /* Options */
35 struct sign_option_s sign_option = {
36 .keysetdir = DEFAULT_KEYSETDIR,
37 .version = 1,
38 .arch = ARCH_UNSPECIFIED,
39 .kloadaddr = CROS_32BIT_ENTRY_ADDR,
40 .padding = 65536,
41 .type = FILE_TYPE_UNKNOWN,
42 .hash_alg = VB2_HASH_SHA256, /* default */
43 .ro_size = 0xffffffff,
44 .rw_size = 0xffffffff,
45 .ro_offset = 0xffffffff,
46 .rw_offset = 0xffffffff,
47 .sig_size = 1024,
48 };
49
50 /* Helper to complain about invalid args. Returns num errors discovered */
no_opt_if(bool expr,const char * optname)51 static int no_opt_if(bool expr, const char *optname)
52 {
53 if (expr) {
54 ERROR("Missing --%s option\n", optname);
55 return 1;
56 }
57 return 0;
58 }
59
bad_opt_if(bool expr,const char * optname)60 static int bad_opt_if(bool expr, const char *optname)
61 {
62 if (expr) {
63 ERROR("Option --%s is not supported for file type %s\n",
64 optname, futil_file_type_name(sign_option.type));
65 return 1;
66 }
67 return 0;
68 }
69
70 /* This wraps/signs a public key, producing a keyblock. */
ft_sign_pubkey(const char * fname)71 int ft_sign_pubkey(const char *fname)
72 {
73 struct vb2_packed_key *data_key;
74 uint32_t data_len;
75 struct vb2_keyblock *block;
76 int rv = 1;
77 int fd = -1;
78
79 if (futil_open_and_map_file(fname, &fd, FILE_MODE_SIGN(sign_option),
80 (uint8_t **)&data_key, &data_len))
81 return 1;
82
83 if (vb2_packed_key_looks_ok(data_key, data_len)) {
84 ERROR("Public key looks bad.\n");
85 goto done;
86 }
87
88 if (sign_option.pem_signpriv) {
89 if (sign_option.pem_external) {
90 /* External signing uses the PEM file directly. */
91 block = vb2_create_keyblock_external(
92 data_key,
93 sign_option.pem_signpriv,
94 sign_option.pem_algo,
95 sign_option.flags,
96 sign_option.pem_external);
97 } else {
98 sign_option.signprivate = vb2_read_private_key_pem(
99 sign_option.pem_signpriv,
100 sign_option.pem_algo);
101 if (!sign_option.signprivate) {
102 ERROR(
103 "Unable to read PEM signing key: %s\n",
104 strerror(errno));
105 goto done;
106 }
107 block = vb2_create_keyblock(data_key,
108 sign_option.signprivate,
109 sign_option.flags);
110 }
111 } else {
112 /* Not PEM. Should already have a signing key. */
113 block = vb2_create_keyblock(data_key, sign_option.signprivate,
114 sign_option.flags);
115 }
116
117 /* Write it out */
118 rv = WriteSomeParts(sign_option.outfile, block, block->keyblock_size,
119 NULL, 0);
120 done:
121 futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option),
122 (uint8_t *)data_key, data_len);
123 return rv;
124 }
125
ft_sign_raw_kernel(const char * fname)126 int ft_sign_raw_kernel(const char *fname)
127 {
128 uint8_t *vmlinuz_data = NULL, *kblob_data = NULL, *vblock_data = NULL;
129 uint32_t vmlinuz_size, kblob_size, vblock_size;
130 int rv = 1;
131 int fd = -1;
132
133 if (futil_open_and_map_file(fname, &fd, FILE_MODE_SIGN(sign_option),
134 &vmlinuz_data, &vmlinuz_size))
135 return 1;
136
137 kblob_data = CreateKernelBlob(
138 vmlinuz_data, vmlinuz_size,
139 sign_option.arch, sign_option.kloadaddr,
140 sign_option.config_data, sign_option.config_size,
141 sign_option.bootloader_data, sign_option.bootloader_size,
142 &kblob_size);
143 if (!kblob_data) {
144 ERROR("Unable to create kernel blob\n");
145 goto done;
146 }
147 VB2_DEBUG("kblob_size = %#x\n", kblob_size);
148
149 vblock_data = SignKernelBlob(kblob_data, kblob_size,
150 sign_option.padding,
151 sign_option.version,
152 sign_option.kloadaddr,
153 sign_option.keyblock,
154 sign_option.signprivate,
155 sign_option.flags, &vblock_size);
156 if (!vblock_data) {
157 ERROR("Unable to sign kernel blob\n");
158 goto done;
159 }
160 VB2_DEBUG("vblock_size = %#x\n", vblock_size);
161
162 /* We should be creating a completely new output file.
163 * If not, something's wrong. */
164 if (!sign_option.create_new_outfile)
165 FATAL("create_new_outfile should be selected\n");
166
167 if (sign_option.vblockonly)
168 rv = WriteSomeParts(sign_option.outfile,
169 vblock_data, vblock_size,
170 NULL, 0);
171 else
172 rv = WriteSomeParts(sign_option.outfile,
173 vblock_data, vblock_size,
174 kblob_data, kblob_size);
175
176 done:
177 futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option),
178 vmlinuz_data, vmlinuz_size);
179 free(vblock_data);
180 free(kblob_data);
181 return rv;
182 }
183
ft_sign_kern_preamble(const char * fname)184 int ft_sign_kern_preamble(const char *fname)
185 {
186 uint8_t *kpart_data = NULL, *kblob_data = NULL, *vblock_data = NULL;
187 uint32_t kpart_size, kblob_size, vblock_size;
188 struct vb2_keyblock *keyblock = NULL;
189 struct vb2_kernel_preamble *preamble = NULL;
190 int rv = 1;
191 int fd = -1;
192
193 if (futil_open_and_map_file(fname, &fd, FILE_MODE_SIGN(sign_option),
194 &kpart_data, &kpart_size))
195 return 1;
196
197 /* Note: This just sets some static pointers. It doesn't malloc. */
198 kblob_data = unpack_kernel_partition(kpart_data, kpart_size,
199 &keyblock, &preamble, &kblob_size);
200
201 if (!kblob_data) {
202 ERROR("Unable to unpack kernel partition\n");
203 goto done;
204 }
205
206 /*
207 * We don't let --kloadaddr change when resigning, because the original
208 * vbutil_kernel program didn't do it right. Since obviously no one
209 * ever noticed, we'll maintain bug-compatibility by just not allowing
210 * it here either. To enable it, we'd need to update the zeropage
211 * table's cmd_line_ptr as well as the preamble.
212 */
213 sign_option.kloadaddr = preamble->body_load_address;
214
215 /* Replace the config if asked */
216 if (sign_option.config_data &&
217 0 != UpdateKernelBlobConfig(kblob_data, kblob_size,
218 sign_option.config_data,
219 sign_option.config_size)) {
220 ERROR("Unable to update config\n");
221 goto done;
222 }
223
224 /* Preserve the version unless a new one is given */
225 if (!sign_option.version_specified)
226 sign_option.version = preamble->kernel_version;
227
228 /* Preserve the flags if not specified */
229 uint32_t kernel_flags = vb2_kernel_get_flags(preamble);
230 if (sign_option.flags_specified == 0)
231 sign_option.flags = kernel_flags;
232
233 /* Replace the keyblock if asked */
234 if (sign_option.keyblock)
235 keyblock = sign_option.keyblock;
236
237 /* Compute the new signature */
238 vblock_data = SignKernelBlob(kblob_data, kblob_size,
239 sign_option.padding,
240 sign_option.version,
241 sign_option.kloadaddr,
242 keyblock,
243 sign_option.signprivate,
244 sign_option.flags,
245 &vblock_size);
246 if (!vblock_data) {
247 ERROR("Unable to sign kernel blob\n");
248 goto done;
249 }
250 VB2_DEBUG("vblock_size = %#x\n", vblock_size);
251
252 if (sign_option.create_new_outfile) {
253 /* Write out what we've been asked for */
254 if (sign_option.vblockonly)
255 rv = WriteSomeParts(sign_option.outfile,
256 vblock_data, vblock_size,
257 NULL, 0);
258 else
259 rv = WriteSomeParts(sign_option.outfile,
260 vblock_data, vblock_size,
261 kblob_data, kblob_size);
262 } else {
263 /* If we're modifying an existing file, it's mmap'ed so that
264 * all our modifications to the buffer will get flushed to
265 * disk when we close it. */
266 memcpy(kpart_data, vblock_data, vblock_size);
267 rv = 0;
268 }
269 done:
270 futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), kpart_data,
271 kpart_size);
272 free(vblock_data);
273 return rv;
274 }
275
276
ft_sign_raw_firmware(const char * fname)277 int ft_sign_raw_firmware(const char *fname)
278 {
279 struct vb2_signature *body_sig = NULL;
280 struct vb2_fw_preamble *preamble = NULL;
281 uint8_t *buf;
282 uint32_t len;
283 int rv = 1;
284 int fd = -1;
285
286 if (futil_open_and_map_file(fname, &fd, FILE_MODE_SIGN(sign_option),
287 &buf, &len))
288 return 1;
289
290 body_sig = vb2_calculate_signature(buf, len, sign_option.signprivate);
291 if (!body_sig) {
292 ERROR("Calculating body signature\n");
293 goto done;
294 }
295
296 preamble = vb2_create_fw_preamble(
297 sign_option.version,
298 (struct vb2_packed_key *)sign_option.kernel_subkey,
299 body_sig,
300 sign_option.signprivate,
301 sign_option.flags);
302 if (!preamble) {
303 ERROR("Creating firmware preamble.\n");
304 goto done;
305 }
306
307 rv = WriteSomeParts(sign_option.outfile,
308 sign_option.keyblock,
309 sign_option.keyblock->keyblock_size,
310 preamble, preamble->preamble_size);
311
312 done:
313 futil_unmap_and_close_file(fd, FILE_MODE_SIGN(sign_option), buf, len);
314 free(preamble);
315 free(body_sig);
316
317 return rv;
318 }
319
load_keyset(void)320 static int load_keyset(void)
321 {
322 char *buf = NULL;
323 int errorcnt = 0;
324 const char *s = NULL;
325 const char *b = NULL;
326 const char *k = NULL;
327 const char *format;
328 struct stat sb;
329
330 if (!sign_option.keysetdir)
331 FATAL("Keyset should never be NULL. Aborting\n");
332
333 /* Failure means this is not a directory */
334 if (stat(sign_option.keysetdir, &sb) == -1 ||
335 (sb.st_mode & S_IFMT) != S_IFDIR)
336 format = "%s%s.%s";
337 else
338 format = "%s/%s.%s";
339
340 switch (sign_option.type) {
341 case FILE_TYPE_BIOS_IMAGE:
342 case FILE_TYPE_RAW_FIRMWARE:
343 s = "firmware_data_key";
344 b = "firmware";
345 k = "kernel_subkey";
346 break;
347 case FILE_TYPE_RAW_KERNEL:
348 s = "kernel_data_key";
349 b = "kernel";
350 break;
351 case FILE_TYPE_KERN_PREAMBLE:
352 s = "kernel_data_key";
353 break;
354 default:
355 return 0;
356 }
357
358 if (s && !sign_option.signprivate) {
359 if (asprintf(&buf, format, sign_option.keysetdir, s,
360 "vbprivk") <= 0)
361 FATAL("Failed to allocate string\n");
362 INFO("Loading private data key from default keyset: %s\n", buf);
363 sign_option.signprivate = vb2_read_private_key(buf);
364 if (!sign_option.signprivate) {
365 ERROR("Reading %s\n", buf);
366 errorcnt++;
367 }
368 free(buf);
369 }
370
371 if (b && !sign_option.keyblock) {
372 if (asprintf(&buf, format, sign_option.keysetdir, b,
373 "keyblock") <= 0)
374 FATAL("Failed to allocate string\n");
375 INFO("Loading keyblock from default keyset: %s\n", buf);
376 sign_option.keyblock = vb2_read_keyblock(buf);
377 if (!sign_option.keyblock) {
378 ERROR("Reading %s\n", buf);
379 errorcnt++;
380 }
381 free(buf);
382 }
383
384 if (k && !sign_option.kernel_subkey) {
385 if (asprintf(&buf, format, sign_option.keysetdir, k,
386 "vbpubk") <= 0)
387 FATAL("Failed to allocate string\n");
388 INFO("Loading kernel subkey from default keyset: %s\n", buf);
389 sign_option.kernel_subkey = vb2_read_packed_key(buf);
390 if (!sign_option.kernel_subkey) {
391 ERROR("Reading %s\n", buf);
392 errorcnt++;
393 }
394 free(buf);
395 }
396
397 return errorcnt;
398 }
399
400 static const char usage_pubkey[] = "\n"
401 "To sign a public key / create a new keyblock:\n"
402 "\n"
403 "Required PARAMS:\n"
404 " [--datapubkey] INFILE The public key to wrap\n"
405 " [--outfile] OUTFILE The resulting keyblock\n"
406 "\n"
407 "Optional PARAMS:\n"
408 " A private signing key, specified as either\n"
409 " -s|--signprivate FILE.vbprivk Signing key in .vbprivk format\n"
410 " Or\n"
411 " --pem_signpriv FILE.pem Signing key in PEM format...\n"
412 " --pem_algo NUM AND the algorithm to use (0 - %d)\n"
413 "\n"
414 " If a signing key is not given, the keyblock will not be signed."
415 "\n\n"
416 "And these, too:\n\n"
417 " -f|--flags NUM Flags specifying use conditions\n"
418 " --pem_external PROGRAM"
419 " External program to compute the signature\n"
420 " (requires a PEM signing key)\n"
421 "\n";
print_help_pubkey(int argc,char * argv[])422 static void print_help_pubkey(int argc, char *argv[])
423 {
424 printf(usage_pubkey, VB2_ALG_COUNT - 1);
425 }
426
427
428 static const char usage_fw_main[] = "\n"
429 "To sign a raw firmware blob (FW_MAIN_A/B):\n"
430 "\n"
431 "Required PARAMS:\n"
432 " -v|--version NUM The firmware version number\n"
433 " [--fv] INFILE"
434 " The raw firmware blob (FW_MAIN_A/B)\n"
435 " [--outfile] OUTFILE Output VBLOCK_A/B\n"
436 "\n"
437 "Optional PARAMS:\n"
438 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
439 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
440 " public firmware data key\n"
441 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
442 " -f|--flags NUM The preamble flags value"
443 " (default is 0)\n"
444 " -K|--keyset PATH Prefix of private firmware data"
445 " key,\n"
446 " keyblock and public kernel"
447 " subkey.\n"
448 " Prefix must be valid path with\n"
449 " optional file name prefix.\n"
450 " Used as defaults for -s, -b and"
451 " -k,\n"
452 " if not passed expliticly\n"
453 " (default is '%s')\n"
454 "\n";
print_help_raw_firmware(int argc,char * argv[])455 static void print_help_raw_firmware(int argc, char *argv[])
456 {
457 printf(usage_fw_main, DEFAULT_KEYSETDIR);
458 }
459
460 static const char usage_bios[] = "\n"
461 "To sign a complete firmware image (image.bin):\n"
462 "\n"
463 "Required PARAMS:\n"
464 " [--infile] INFILE Input firmware image (modified\n"
465 " in place if no OUTFILE given)\n"
466 "\n"
467 "Optional PARAMS:\n"
468 " -s|--signprivate FILE.vbprivk The private firmware data key\n"
469 " -b|--keyblock FILE.keyblock The keyblock containing the\n"
470 " public firmware data key\n"
471 " -k|--kernelkey FILE.vbpubk The public kernel subkey\n"
472 " -v|--version NUM The firmware version number"
473 " (default %d)\n"
474 " -f|--flags NUM The preamble flags value"
475 " (default is\n"
476 " unchanged, or 0 if unknown)\n"
477 " -d|--loemdir DIR Local OEM output vblock directory\n"
478 " -l|--loemid STRING Local OEM vblock suffix\n"
479 " -K|--keyset PATH Prefix of private firmware data"
480 " key,\n"
481 " keyblock and public kernel"
482 " subkey.\n"
483 " Prefix must be valid path with\n"
484 " optional file name prefix.\n"
485 " Used as defaults for -s, -b and"
486 " -k,\n"
487 " if not passed expliticly\n"
488 " (default is '%s')\n"
489 " [--outfile] OUTFILE Output firmware image\n"
490 "\n";
print_help_bios_image(int argc,char * argv[])491 static void print_help_bios_image(int argc, char *argv[])
492 {
493 printf(usage_bios, sign_option.version, DEFAULT_KEYSETDIR);
494 }
495
496 static const char usage_new_kpart[] = "\n"
497 "To create a new kernel partition image (/dev/sda2, /dev/mmcblk0p2):\n"
498 "\n"
499 "Required PARAMS:\n"
500 " --config FILE The kernel commandline file\n"
501 " --arch ARCH The CPU architecture (one of\n"
502 " x86|amd64, arm|aarch64, mips)\n"
503 " [--vmlinuz] INFILE Linux kernel bzImage file\n"
504 " [--outfile] OUTFILE Output kernel partition or vblock\n"
505 "\n"
506 "Optional PARAMS:\n"
507 " -s|--signprivate FILE.vbprivk"
508 " The private key to sign the kernel blob\n"
509 " -b|--keyblock FILE.keyblock Keyblock containing the public\n"
510 " key to verify the kernel blob\n"
511 " -v|--version NUM The kernel version number (def:1)\n"
512 " --bootloader FILE Bootloader stub\n"
513 " --kloadaddr NUM"
514 " RAM address to load the kernel body\n"
515 " (default %#x)\n"
516 " --pad NUM The vblock padding size in bytes\n"
517 " (default %#x)\n"
518 " --vblockonly Emit just the vblock (requires a\n"
519 " distinct outfile)\n"
520 " -f|--flags NUM The preamble flags value\n"
521 " -K|--keyset PATH Prefix of private kernel data key\n"
522 " and keyblock.\n"
523 " Prefix must be valid path with\n"
524 " optional file name prefix.\n"
525 " Used as defaults for -s and -b,\n"
526 " if not passed expliticly\n"
527 " (default is '%s')\n"
528 "\n";
print_help_raw_kernel(int argc,char * argv[])529 static void print_help_raw_kernel(int argc, char *argv[])
530 {
531 printf(usage_new_kpart, sign_option.kloadaddr, sign_option.padding,
532 DEFAULT_KEYSETDIR);
533 }
534
535 static const char usage_old_kpart[] = "\n"
536 "To resign an existing kernel partition (/dev/sda2, /dev/mmcblk0p2):\n"
537 "\n"
538 "Required PARAMS:\n"
539 " [--infile] INFILE Input kernel partition (modified\n"
540 " in place if no OUTFILE given)\n"
541 "\n"
542 "Optional PARAMS:\n"
543 " -s|--signprivate FILE.vbprivk"
544 " The private key to sign the kernel blob\n"
545 " -b|--keyblock FILE.keyblock Keyblock containing the public\n"
546 " key to verify the kernel blob\n"
547 " -v|--version NUM The kernel version number\n"
548 " --config FILE The kernel commandline file\n"
549 " --pad NUM The vblock padding size in bytes\n"
550 " (default %#x)\n"
551 " [--outfile] OUTFILE Output kernel partition or vblock\n"
552 " --vblockonly Emit just the vblock (requires a\n"
553 " distinct OUTFILE)\n"
554 " -f|--flags NUM The preamble flags value\n"
555 " -K|--keyset PATH Prefix of private kernel data"
556 " key.\n"
557 " Prefix must be valid path with\n"
558 " optional file name prefix.\n"
559 " Used as default for -s,\n"
560 " if not passed expliticly\n"
561 " (default is '%s')\n"
562 "\n";
print_help_kern_preamble(int argc,char * argv[])563 static void print_help_kern_preamble(int argc, char *argv[])
564 {
565 printf(usage_old_kpart, sign_option.padding, DEFAULT_KEYSETDIR);
566 }
567
print_help_usbpd1(int argc,char * argv[])568 static void print_help_usbpd1(int argc, char *argv[])
569 {
570 enum vb2_hash_algorithm algo;
571
572 printf("\n"
573 "Usage: " MYNAME " %s --type %s [options] INFILE [OUTFILE]\n"
574 "\n"
575 "This signs a %s.\n"
576 "\n"
577 "The INFILE is assumed to consist of equal-sized RO and RW"
578 " sections,\n"
579 "with the public key at the end of of the RO section and the"
580 " signature\n"
581 "at the end of the RW section (both in an opaque binary"
582 " format).\n"
583 "Signing the image will update both binary blobs, so both"
584 " public and\n"
585 "private keys are required.\n"
586 "\n"
587 "The signing key is specified with:\n"
588 "\n"
589 " --pem "
590 "FILE Signing keypair in PEM format\n"
591 "\n"
592 " --hash_alg "
593 "NUM Hash algorithm to use:\n",
594 argv[0],
595 futil_file_type_name(FILE_TYPE_USBPD1),
596 futil_file_type_desc(FILE_TYPE_USBPD1));
597 for (algo = 0; algo < VB2_HASH_ALG_COUNT; algo++) {
598 const char *name = vb2_get_hash_algorithm_name(algo);
599 if (strcmp(name, VB2_INVALID_ALG_NAME) != 0)
600 printf(" %d / %s%s\n",
601 algo, name,
602 algo == VB2_HASH_SHA256 ? " (default)" : "");
603 }
604 printf("\n"
605 "The size and offset assumptions can be overridden. "
606 "All numbers are in bytes.\n"
607 "Specify a size of 0 to ignore that section.\n"
608 "\n"
609 " --ro_size NUM"
610 " Size of the RO section (default half)\n"
611 " --rw_size NUM"
612 " Size of the RW section (default half)\n"
613 " --ro_offset NUM"
614 " Start of the RO section (default 0)\n"
615 " --rw_offset NUM"
616 " Start of the RW section (default half)\n"
617 "\n");
618 }
619
print_help_rwsig(int argc,char * argv[])620 static void print_help_rwsig(int argc, char *argv[])
621 {
622 printf("\n"
623 "Usage: " MYNAME " %s --type %s [options] INFILE [OUTFILE]\n"
624 "\n"
625 "This signs a %s.\n"
626 "\n"
627 "Data only mode\n"
628 "This mode requires OUTFILE.\n"
629 "The INFILE is a binary blob of arbitrary size. It is signed using the\n"
630 "private key and the vb21_signature blob emitted.\n"
631 "\n"
632 "Data + Signature mode\n"
633 "If no OUTFILE is specified, the INFILE should contain an existing\n"
634 "vb21_signature blob near its end. The data_size from that signature is\n"
635 "used to re-sign a portion of the INFILE, and the old signature blob is\n"
636 "replaced.\n"
637 "\n"
638 "Key + Data + Signature mode\n"
639 "This mode also takes no output file.\n"
640 "If INFILE contains an FMAP, RW and signatures offsets are read from\n"
641 "FMAP. These regions must be named EC_RW and SIG_RW respectively.\n"
642 "If a public key is found in the region named KEY_RO, it will be replaced\n"
643 "in the RO image.\n"
644 "\n"
645 "Options:\n"
646 "\n"
647 " --prikey FILE.vbprik2 Private key in vb2 format. Required\n"
648 " if INFILE is a binary blob. If not\n"
649 " provided, previous signature is copied\n"
650 " and a public key won't be replaced.\n"
651 " --version NUM Public key version if we are replacing\n"
652 " the key in INFILE (default: 1)\n"
653 " --sig_size NUM Offset from the end of INFILE where the\n"
654 " signature blob should be located, if\n"
655 " the file does not contain an FMAP.\n"
656 " (default 1024 bytes)\n"
657 " --data_size NUM Number of bytes of INFILE to sign\n"
658 " --ecrw_out FILE Output path for Key+Data+Signature mode\n"
659 " to extract EC_RW region to\n"
660 "\n",
661 argv[0],
662 futil_file_type_name(FILE_TYPE_RWSIG),
663 futil_file_type_desc(FILE_TYPE_RWSIG));
664 }
665
666 static void (*help_type[NUM_FILE_TYPES])(int argc, char *argv[]) = {
667 [FILE_TYPE_PUBKEY] = &print_help_pubkey,
668 [FILE_TYPE_RAW_FIRMWARE] = &print_help_raw_firmware,
669 [FILE_TYPE_BIOS_IMAGE] = &print_help_bios_image,
670 [FILE_TYPE_RAW_KERNEL] = &print_help_raw_kernel,
671 [FILE_TYPE_KERN_PREAMBLE] = &print_help_kern_preamble,
672 [FILE_TYPE_USBPD1] = &print_help_usbpd1,
673 [FILE_TYPE_RWSIG] = &print_help_rwsig,
674 };
675
676 static const char usage_default[] = "\n"
677 "Usage: " MYNAME " %s [PARAMS] INFILE [OUTFILE]\n"
678 "\n"
679 "The following signing operations are supported:\n"
680 "\n"
681 " INFILE OUTFILE\n"
682 " public key (.vbpubk) keyblock\n"
683 " raw firmware blob (FW_MAIN_A/B) firmware preamble (VBLOCK_A/B)\n"
684 " full firmware image (image.bin) same, or signed in-place\n"
685 " raw linux kernel (vmlinuz) kernel partition image\n"
686 " kernel partition (/dev/sda2) same, or signed in-place\n"
687 " usbpd1 firmware image same, or signed in-place\n"
688 " RW device image same, or signed in-place\n"
689 "\n"
690 "For more information, use \"" MYNAME " help %s TYPE\", where\n"
691 "TYPE is one of:\n\n";
print_help_default(int argc,char * argv[])692 static void print_help_default(int argc, char *argv[])
693 {
694 enum futil_file_type type;
695
696 printf(usage_default, argv[0], argv[0]);
697 for (type = 0; type < NUM_FILE_TYPES; type++)
698 if (help_type[type])
699 printf(" %s", futil_file_type_name(type));
700 printf("\n\n");
701 }
702
print_help(int argc,char * argv[])703 static void print_help(int argc, char *argv[])
704 {
705 enum futil_file_type type = FILE_TYPE_UNKNOWN;
706
707 if (argc > 1)
708 futil_str_to_file_type(argv[1], &type);
709
710 if (help_type[type])
711 help_type[type](argc, argv);
712 else
713 print_help_default(argc, argv);
714 }
715
716 enum no_short_opts {
717 OPT_FV = 1000,
718 OPT_INFILE,
719 OPT_OUTFILE,
720 OPT_BOOTLOADER,
721 OPT_CONFIG,
722 OPT_ARCH,
723 OPT_KLOADADDR,
724 OPT_PADDING,
725 OPT_PEM_SIGNPRIV,
726 OPT_PEM_ALGO,
727 OPT_PEM_EXTERNAL,
728 OPT_TYPE,
729 OPT_HASH_ALG,
730 OPT_RO_SIZE,
731 OPT_RW_SIZE,
732 OPT_RO_OFFSET,
733 OPT_RW_OFFSET,
734 OPT_DATA_SIZE,
735 OPT_SIG_SIZE,
736 OPT_PRIKEY,
737 OPT_ECRW_OUT,
738 OPT_HELP,
739 };
740
741 static const struct option long_opts[] = {
742 /* name hasarg *flag val */
743 {"signprivate", 1, NULL, 's'},
744 {"keyblock", 1, NULL, 'b'},
745 {"kernelkey", 1, NULL, 'k'},
746 {"version", 1, NULL, 'v'},
747 {"flags", 1, NULL, 'f'},
748 {"loemdir", 1, NULL, 'd'},
749 {"loemid", 1, NULL, 'l'},
750 {"keyset", 1, NULL, 'K'},
751 {"fv", 1, NULL, OPT_FV},
752 {"infile", 1, NULL, OPT_INFILE},
753 {"datapubkey", 1, NULL, OPT_INFILE}, /* alias */
754 {"vmlinuz", 1, NULL, OPT_INFILE}, /* alias */
755 {"outfile", 1, NULL, OPT_OUTFILE},
756 {"bootloader", 1, NULL, OPT_BOOTLOADER},
757 {"config", 1, NULL, OPT_CONFIG},
758 {"arch", 1, NULL, OPT_ARCH},
759 {"kloadaddr", 1, NULL, OPT_KLOADADDR},
760 {"pad", 1, NULL, OPT_PADDING},
761 {"pem_signpriv", 1, NULL, OPT_PEM_SIGNPRIV},
762 {"pem", 1, NULL, OPT_PEM_SIGNPRIV}, /* alias */
763 {"pem_algo", 1, NULL, OPT_PEM_ALGO},
764 {"pem_external", 1, NULL, OPT_PEM_EXTERNAL},
765 {"type", 1, NULL, OPT_TYPE},
766 {"vblockonly", 0, &sign_option.vblockonly, 1},
767 {"hash_alg", 1, NULL, OPT_HASH_ALG},
768 {"ro_size", 1, NULL, OPT_RO_SIZE},
769 {"rw_size", 1, NULL, OPT_RW_SIZE},
770 {"ro_offset", 1, NULL, OPT_RO_OFFSET},
771 {"rw_offset", 1, NULL, OPT_RW_OFFSET},
772 {"data_size", 1, NULL, OPT_DATA_SIZE},
773 {"sig_size", 1, NULL, OPT_SIG_SIZE},
774 {"prikey", 1, NULL, OPT_PRIKEY},
775 {"privkey", 1, NULL, OPT_PRIKEY}, /* alias */
776 {"ecrw_out", 1, NULL, OPT_ECRW_OUT},
777 {"help", 0, NULL, OPT_HELP},
778 {NULL, 0, NULL, 0},
779 };
780 static const char *short_opts = ":s:b:k:v:f:d:l:K:";
781
782 /* Return zero on success */
parse_number_opt(const char * arg,const char * name,uint32_t * dest)783 static int parse_number_opt(const char *arg, const char *name, uint32_t *dest)
784 {
785 char *e;
786 uint32_t val = strtoul(arg, &e, 0);
787 if (!*arg || (e && *e)) {
788 ERROR("Invalid --%s \"%s\"\n", name, arg);
789 return 1;
790 }
791 *dest = val;
792 return 0;
793 }
794
do_sign(int argc,char * argv[])795 static int do_sign(int argc, char *argv[])
796 {
797 char *infile = 0;
798 int i;
799 int errorcnt = 0;
800 char *e = 0;
801 int helpind = 0;
802 int longindex;
803
804 opterr = 0; /* quiet, you */
805 while ((i = getopt_long(argc, argv, short_opts, long_opts,
806 &longindex)) != -1) {
807 switch (i) {
808 case 's':
809 sign_option.signprivate = vb2_read_private_key(optarg);
810 if (!sign_option.signprivate) {
811 ERROR("Reading %s\n", optarg);
812 errorcnt++;
813 }
814 break;
815 case 'b':
816 sign_option.keyblock = vb2_read_keyblock(optarg);
817 if (!sign_option.keyblock) {
818 ERROR("Reading %s\n", optarg);
819 errorcnt++;
820 }
821 break;
822 case 'k':
823 sign_option.kernel_subkey = vb2_read_packed_key(optarg);
824 if (!sign_option.kernel_subkey) {
825 ERROR("Reading %s\n", optarg);
826 errorcnt++;
827 }
828 break;
829 case 'v':
830 sign_option.version_specified = 1;
831 sign_option.version = strtoul(optarg, &e, 0);
832 if (!*optarg || (e && *e)) {
833 ERROR("Invalid --version \"%s\"\n", optarg);
834 errorcnt++;
835 }
836 break;
837
838 case 'f':
839 sign_option.flags_specified = 1;
840 errorcnt += parse_number_opt(optarg, "flags",
841 &sign_option.flags);
842 break;
843 case 'd':
844 sign_option.loemdir = optarg;
845 break;
846 case 'l':
847 sign_option.loemid = optarg;
848 break;
849 case 'K':
850 sign_option.keysetdir = optarg;
851 break;
852 case OPT_FV:
853 sign_option.fv_specified = 1;
854 VBOOT_FALLTHROUGH;
855 case OPT_INFILE:
856 sign_option.inout_file_count++;
857 infile = optarg;
858 break;
859 case OPT_OUTFILE:
860 sign_option.inout_file_count++;
861 sign_option.outfile = optarg;
862 break;
863 case OPT_BOOTLOADER:
864 sign_option.bootloader_data = ReadFile(
865 optarg, &sign_option.bootloader_size);
866 if (!sign_option.bootloader_data) {
867 ERROR("Error reading bootloader file: %s\n",
868 strerror(errno));
869 errorcnt++;
870 }
871 VB2_DEBUG("bootloader file size=0x%" PRIx64 "\n",
872 sign_option.bootloader_size);
873 break;
874 case OPT_CONFIG:
875 sign_option.config_data = ReadConfigFile(
876 optarg, &sign_option.config_size);
877 if (!sign_option.config_data) {
878 ERROR("Error reading config file: %s\n",
879 strerror(errno));
880 errorcnt++;
881 }
882 break;
883 case OPT_ARCH:
884 /* check the first 3 characters to also match x86_64 */
885 if ((!strncasecmp(optarg, "x86", 3)) ||
886 (!strcasecmp(optarg, "amd64")))
887 sign_option.arch = ARCH_X86;
888 else if ((!strcasecmp(optarg, "arm")) ||
889 (!strcasecmp(optarg, "aarch64")))
890 sign_option.arch = ARCH_ARM;
891 else if (!strcasecmp(optarg, "mips"))
892 sign_option.arch = ARCH_MIPS;
893 else {
894 ERROR("Unknown architecture: \"%s\"\n",
895 optarg);
896 errorcnt++;
897 }
898 break;
899 case OPT_KLOADADDR:
900 errorcnt += parse_number_opt(optarg, "kloadaddr",
901 &sign_option.kloadaddr);
902 break;
903 case OPT_PADDING:
904 errorcnt += parse_number_opt(optarg, "padding",
905 &sign_option.padding);
906 break;
907 case OPT_RO_SIZE:
908 errorcnt += parse_number_opt(optarg, "ro_size",
909 &sign_option.ro_size);
910 break;
911 case OPT_RW_SIZE:
912 errorcnt += parse_number_opt(optarg, "rw_size",
913 &sign_option.rw_size);
914 break;
915 case OPT_RO_OFFSET:
916 errorcnt += parse_number_opt(optarg, "ro_offset",
917 &sign_option.ro_offset);
918 break;
919 case OPT_RW_OFFSET:
920 errorcnt += parse_number_opt(optarg, "rw_offset",
921 &sign_option.rw_offset);
922 break;
923 case OPT_DATA_SIZE:
924 errorcnt += parse_number_opt(optarg, "data_size",
925 &sign_option.data_size);
926 break;
927 case OPT_SIG_SIZE:
928 errorcnt += parse_number_opt(optarg, "sig_size",
929 &sign_option.sig_size);
930 break;
931 case OPT_PEM_SIGNPRIV:
932 sign_option.pem_signpriv = optarg;
933 break;
934 case OPT_PEM_ALGO:
935 sign_option.pem_algo_specified = 1;
936 sign_option.pem_algo = strtoul(optarg, &e, 0);
937 if (!*optarg || (e && *e) ||
938 (sign_option.pem_algo >= VB2_ALG_COUNT)) {
939 ERROR("Invalid --pem_algo \"%s\"\n", optarg);
940 errorcnt++;
941 }
942 break;
943 case OPT_HASH_ALG:
944 if (!vb2_lookup_hash_alg(optarg,
945 &sign_option.hash_alg)) {
946 ERROR("Invalid hash_alg \"%s\"\n", optarg);
947 errorcnt++;
948 }
949 break;
950 case OPT_PEM_EXTERNAL:
951 sign_option.pem_external = optarg;
952 break;
953 case OPT_TYPE:
954 if (!futil_str_to_file_type(optarg,
955 &sign_option.type)) {
956 if (!strcasecmp("help", optarg))
957 print_file_types_and_exit(errorcnt);
958 ERROR("Invalid --type \"%s\"\n", optarg);
959 errorcnt++;
960 }
961 break;
962 case OPT_PRIKEY:
963 sign_option.prikey = vb2_read_private_key(optarg);
964 if (!sign_option.prikey) {
965 ERROR("Reading %s\n", optarg);
966 errorcnt++;
967 }
968 break;
969 case OPT_ECRW_OUT:
970 sign_option.ecrw_out = optarg;
971 break;
972 case OPT_HELP:
973 helpind = optind - 1;
974 break;
975
976 case '?':
977 if (optopt)
978 ERROR("Unrecognized option: -%c\n",
979 optopt);
980 else
981 ERROR("Unrecognized option: %s\n",
982 argv[optind - 1]);
983 errorcnt++;
984 break;
985 case ':':
986 ERROR("Missing argument to -%c\n", optopt);
987 errorcnt++;
988 break;
989 case 0: /* handled option */
990 break;
991 default:
992 FATAL("Unrecognized getopt output: %d\n", i);
993 }
994 }
995
996 if (helpind) {
997 /* Skip all the options we've already parsed */
998 optind--;
999 argv[optind] = argv[0];
1000 argc -= optind;
1001 argv += optind;
1002 print_help(argc, argv);
1003 return !!errorcnt;
1004 }
1005
1006 /* If we don't have an input file already, we need one */
1007 if (!infile) {
1008 if (argc - optind <= 0) {
1009 errorcnt++;
1010 ERROR("Missing input filename\n");
1011 goto done;
1012 } else {
1013 sign_option.inout_file_count++;
1014 infile = argv[optind++];
1015 }
1016 }
1017
1018 /* Look for an output file if we don't have one, just in case. */
1019 if (!sign_option.outfile && argc - optind > 0) {
1020 sign_option.inout_file_count++;
1021 sign_option.outfile = argv[optind++];
1022 }
1023
1024 /* What are we looking at? */
1025 if (sign_option.type == FILE_TYPE_UNKNOWN &&
1026 futil_file_type(infile, &sign_option.type)) {
1027 errorcnt++;
1028 goto done;
1029 }
1030
1031 /* We may be able to infer the type based on the other args */
1032 if (sign_option.type == FILE_TYPE_UNKNOWN) {
1033 if (sign_option.bootloader_data || sign_option.config_data
1034 || sign_option.arch != ARCH_UNSPECIFIED)
1035 sign_option.type = FILE_TYPE_RAW_KERNEL;
1036 else if (sign_option.kernel_subkey || sign_option.fv_specified)
1037 sign_option.type = FILE_TYPE_RAW_FIRMWARE;
1038 }
1039
1040 /* Load keys and keyblocks from keyset path, if they were not provided
1041 earlier. */
1042 errorcnt += load_keyset();
1043
1044 VB2_DEBUG("type=%s\n", futil_file_type_name(sign_option.type));
1045
1046 /* Check the arguments for the type of thing we want to sign */
1047 switch (sign_option.type) {
1048 case FILE_TYPE_PUBKEY:
1049 sign_option.create_new_outfile = 1;
1050 if (sign_option.signprivate && sign_option.pem_signpriv) {
1051 ERROR("Only one of --signprivate and --pem_signpriv"
1052 " can be specified\n");
1053 errorcnt++;
1054 }
1055 if ((sign_option.signprivate &&
1056 sign_option.pem_algo_specified) ||
1057 (sign_option.pem_signpriv &&
1058 !sign_option.pem_algo_specified)) {
1059 ERROR("--pem_algo must be used with"
1060 " --pem_signpriv\n");
1061 errorcnt++;
1062 }
1063 if (sign_option.pem_external && !sign_option.pem_signpriv) {
1064 ERROR("--pem_external must be used with"
1065 " --pem_signpriv\n");
1066 errorcnt++;
1067 }
1068 /* We'll wait to read the PEM file, since the external signer
1069 * may want to read it instead. */
1070 break;
1071 case FILE_TYPE_BIOS_IMAGE:
1072 errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
1073 errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
1074 errorcnt += no_opt_if(!sign_option.kernel_subkey, "kernelkey");
1075 break;
1076 case FILE_TYPE_KERN_PREAMBLE:
1077 errorcnt += bad_opt_if(sign_option.bootloader_data,
1078 "bootloader");
1079 errorcnt += bad_opt_if(sign_option.arch != ARCH_UNSPECIFIED,
1080 "arch");
1081 errorcnt += bad_opt_if(sign_option.kloadaddr !=
1082 CROS_32BIT_ENTRY_ADDR, "kloadaddr");
1083 errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
1084 if (sign_option.vblockonly || sign_option.inout_file_count > 1)
1085 sign_option.create_new_outfile = 1;
1086 break;
1087 case FILE_TYPE_RAW_FIRMWARE:
1088 sign_option.create_new_outfile = 1;
1089 errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
1090 errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
1091 errorcnt += no_opt_if(!sign_option.kernel_subkey, "kernelkey");
1092 errorcnt += no_opt_if(!sign_option.version_specified,
1093 "version");
1094 break;
1095 case FILE_TYPE_RAW_KERNEL:
1096 sign_option.create_new_outfile = 1;
1097 errorcnt += no_opt_if(!sign_option.signprivate, "signprivate");
1098 errorcnt += no_opt_if(!sign_option.keyblock, "keyblock");
1099 errorcnt += no_opt_if(!sign_option.config_data, "config");
1100 errorcnt += no_opt_if(sign_option.arch == ARCH_UNSPECIFIED,
1101 "arch");
1102 break;
1103 case FILE_TYPE_USBPD1:
1104 errorcnt += no_opt_if(!sign_option.pem_signpriv, "pem");
1105 errorcnt += no_opt_if(sign_option.hash_alg == VB2_HASH_INVALID,
1106 "hash_alg");
1107 break;
1108 case FILE_TYPE_RWSIG:
1109 if (sign_option.inout_file_count > 1)
1110 /* Signing raw data. No signature pre-exists. */
1111 errorcnt += no_opt_if(!sign_option.prikey, "prikey");
1112 break;
1113 default:
1114 /* Anything else we don't care */
1115 break;
1116 }
1117
1118 VB2_DEBUG("infile=%s\n", infile);
1119 VB2_DEBUG("sign_option.inout_file_count=%d\n",
1120 sign_option.inout_file_count);
1121 VB2_DEBUG("sign_option.create_new_outfile=%d\n",
1122 sign_option.create_new_outfile);
1123
1124 /* Make sure we have an output file if one is needed */
1125 if (!sign_option.outfile) {
1126 if (sign_option.create_new_outfile) {
1127 errorcnt++;
1128 ERROR("Missing output filename\n");
1129 goto done;
1130 } else {
1131 sign_option.outfile = infile;
1132 }
1133 }
1134
1135 VB2_DEBUG("sign_option.outfile=%s\n", sign_option.outfile);
1136
1137 if (argc - optind > 0) {
1138 errorcnt++;
1139 ERROR("Too many arguments left over\n");
1140 }
1141
1142 if (errorcnt)
1143 goto done;
1144
1145 if (!sign_option.create_new_outfile) {
1146 /* We'll read-modify-write the output file */
1147 if (sign_option.inout_file_count > 1)
1148 if (futil_copy_file(infile, sign_option.outfile) < 0)
1149 goto done;
1150 infile = sign_option.outfile;
1151 }
1152
1153 errorcnt += futil_file_type_sign(sign_option.type, infile);
1154 done:
1155 free(sign_option.signprivate);
1156 free(sign_option.keyblock);
1157 free(sign_option.kernel_subkey);
1158 if (sign_option.prikey)
1159 vb2_free_private_key(sign_option.prikey);
1160
1161 if (errorcnt)
1162 ERROR("Use --help for usage instructions\n");
1163
1164 return !!errorcnt;
1165 }
1166
1167 DECLARE_FUTIL_COMMAND(sign, do_sign, VBOOT_VERSION_ALL,
1168 "Sign / resign various binary components");
1169