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