xref: /aosp_15_r20/external/vboot_reference/futility/cmd_sign.c (revision 8617a60d3594060b7ecbd21bc622a7c14f3cf2bc)
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