1/*
2 * Copyright 2014 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6#include <errno.h>
7#include <fcntl.h>
8#include <getopt.h>
9#include <inttypes.h>
10#include <limits.h>
11#include <stddef.h>
12#include <stdint.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <unistd.h>
19
20#include "bmpblk_header.h"
21#include "file_type.h"
22#include "fmap.h"
23#include "futility.h"
24#include "gbb_header.h"
25#include "host_common.h"
26#include "kernel_blob.h"
27#include "traversal.h"
28#include "util_misc.h"
29#include "vb1_helper.h"
30#include "vboot_common.h"
31
32/* Local values for cb_area_s._flags */
33enum callback_flags {
34	AREA_IS_VALID =     0x00000001,
35};
36
37/* Local structure for args, etc. */
38static struct local_data_s {
39	VbPrivateKey *signprivate;
40	VbKeyBlockHeader *keyblock;
41	VbPublicKey *kernel_subkey;
42	VbPrivateKey *devsignprivate;
43	VbKeyBlockHeader *devkeyblock;
44	uint32_t version;
45	int version_specified;
46	uint32_t flags;
47	int flags_specified;
48	char *loemdir;
49	char *loemid;
50	uint8_t *bootloader_data;
51	uint64_t bootloader_size;
52	uint8_t *config_data;
53	uint64_t config_size;
54	enum arch_t arch;
55	int fv_specified;
56	uint32_t kloadaddr;
57	uint32_t padding;
58	int vblockonly;
59	char *outfile;
60	int create_new_outfile;
61	char *pem_signpriv;
62	int pem_algo_specified;
63	uint32_t pem_algo;
64	char *pem_external;
65} option = {
66	.version = 1,
67	.arch = ARCH_UNSPECIFIED,
68	.kloadaddr = CROS_32BIT_ENTRY_ADDR,
69	.padding = 65536,
70};
71
72
73/* Helper to complain about invalid args. Returns num errors discovered */
74static int no_opt_if(int expr, const char *optname)
75{
76	if (expr) {
77		fprintf(stderr, "Missing --%s option\n", optname);
78		return 1;
79	}
80	return 0;
81}
82
83/* This wraps/signs a public key, producing a keyblock. */
84int futil_cb_sign_pubkey(struct futil_traverse_state_s *state)
85{
86	VbPublicKey *data_key = (VbPublicKey *)state->my_area->buf;
87	VbKeyBlockHeader *vblock;
88
89	if (option.pem_signpriv) {
90		if (option.pem_external) {
91			/* External signing uses the PEM file directly. */
92			vblock = KeyBlockCreate_external(
93				data_key,
94				option.pem_signpriv,
95				option.pem_algo, option.flags,
96				option.pem_external);
97		} else {
98			option.signprivate = PrivateKeyReadPem(
99				option.pem_signpriv, option.pem_algo);
100			if (!option.signprivate) {
101				fprintf(stderr,
102					"Unable to read PEM signing key: %s\n",
103					strerror(errno));
104				return 1;
105			}
106			vblock = KeyBlockCreate(data_key, option.signprivate,
107						option.flags);
108		}
109	} else {
110		/* Not PEM. Should already have a signing key. */
111		vblock = KeyBlockCreate(data_key, option.signprivate,
112					option.flags);
113	}
114
115	/* Write it out */
116	return WriteSomeParts(option.outfile,
117			      vblock, vblock->key_block_size,
118			      NULL, 0);
119}
120
121/*
122 * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
123 * The data in state->my_area is just the RW firmware blob, so there's nothing
124 * useful to show about it. We'll just mark it as present so when we encounter
125 * corresponding VBLOCK area, we'll have this to verify.
126 */
127int futil_cb_sign_fw_main(struct futil_traverse_state_s *state)
128{
129	state->my_area->_flags |= AREA_IS_VALID;
130	return 0;
131}
132
133/*
134 * This handles VBLOCK_A and VBLOCK_B while processing a BIOS image.
135 * We don't do any signing here. We just check to see if the VBLOCK
136 * area contains a firmware preamble.
137 */
138int futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state)
139{
140	VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
141	uint32_t len = state->my_area->len;
142
143	/*
144	 * If we have a valid keyblock and fw_preamble, then we can use them to
145	 * determine the size of the firmware body. Otherwise, we'll have to
146	 * just sign the whole region.
147	 */
148	if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
149		fprintf(stderr, "Warning: %s keyblock is invalid. "
150			"Signing the entire FW FMAP region...\n",
151			state->name);
152		goto whatever;
153	}
154
155	RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
156	if (!rsa) {
157		fprintf(stderr, "Warning: %s public key is invalid. "
158			"Signing the entire FW FMAP region...\n",
159			state->name);
160		goto whatever;
161	}
162	uint32_t more = key_block->key_block_size;
163	VbFirmwarePreambleHeader *preamble =
164		(VbFirmwarePreambleHeader *)(state->my_area->buf + more);
165	uint32_t fw_size = preamble->body_signature.data_size;
166	struct cb_area_s *fw_body_area = 0;
167
168	switch (state->component) {
169	case CB_FMAP_VBLOCK_A:
170		fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
171		/* Preserve the flags if they're not specified */
172		if (!option.flags_specified)
173			option.flags = preamble->flags;
174		break;
175	case CB_FMAP_VBLOCK_B:
176		fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
177		break;
178	default:
179		DIE;
180	}
181
182	if (fw_size > fw_body_area->len) {
183		fprintf(stderr,
184			"%s says the firmware is larger than we have\n",
185			state->name);
186		return 1;
187	}
188
189	/* Update the firmware size */
190	fw_body_area->len = fw_size;
191
192whatever:
193	state->my_area->_flags |= AREA_IS_VALID;
194
195	return 0;
196}
197
198int futil_cb_create_kernel_part(struct futil_traverse_state_s *state)
199{
200	uint8_t *vmlinuz_data, *kblob_data, *vblock_data;
201	uint64_t vmlinuz_size, kblob_size, vblock_size;
202	int rv;
203
204	vmlinuz_data = state->my_area->buf;
205	vmlinuz_size = state->my_area->len;
206
207	kblob_data = CreateKernelBlob(
208		vmlinuz_data, vmlinuz_size,
209		option.arch, option.kloadaddr,
210		option.config_data, option.config_size,
211		option.bootloader_data, option.bootloader_size,
212		&kblob_size);
213	if (!kblob_data) {
214		fprintf(stderr, "Unable to create kernel blob\n");
215		return 1;
216	}
217	Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
218
219	vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
220				     option.version, option.kloadaddr,
221				     option.keyblock, option.signprivate,
222				     option.flags, &vblock_size);
223	if (!vblock_data) {
224		fprintf(stderr, "Unable to sign kernel blob\n");
225		free(kblob_data);
226		return 1;
227	}
228	Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
229
230	/* We should be creating a completely new output file.
231	 * If not, something's wrong. */
232	if (!option.create_new_outfile)
233		DIE;
234
235	if (option.vblockonly)
236		rv = WriteSomeParts(option.outfile,
237				    vblock_data, vblock_size,
238				    NULL, 0);
239	else
240		rv = WriteSomeParts(option.outfile,
241				    vblock_data, vblock_size,
242				    kblob_data, kblob_size);
243
244	free(vblock_data);
245	free(kblob_data);
246	return rv;
247}
248
249int futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
250{
251	uint8_t *kpart_data, *kblob_data, *vblock_data;
252	uint64_t kpart_size, kblob_size, vblock_size;
253	VbKeyBlockHeader *keyblock = NULL;
254	VbKernelPreambleHeader *preamble = NULL;
255	int rv = 0;
256
257	kpart_data = state->my_area->buf;
258	kpart_size = state->my_area->len;
259
260	/* Note: This just sets some static pointers. It doesn't malloc. */
261	kblob_data = UnpackKPart(kpart_data, kpart_size, option.padding,
262				 &keyblock, &preamble, &kblob_size);
263
264	if (!kblob_data) {
265		fprintf(stderr, "Unable to unpack kernel partition\n");
266		return 1;
267	}
268
269	/*
270	 * We don't let --kloadaddr change when resigning, because the original
271	 * vbutil_kernel program didn't do it right. Since obviously no one
272	 * ever noticed, we'll maintain bug-compatibility by just not allowing
273	 * it here either. To enable it, we'd need to update the zeropage
274	 * table's cmd_line_ptr as well as the preamble.
275	 */
276	option.kloadaddr = preamble->body_load_address;
277
278	/* Replace the config if asked */
279	if (option.config_data &&
280	    0 != UpdateKernelBlobConfig(kblob_data, kblob_size,
281					option.config_data,
282					option.config_size)) {
283		fprintf(stderr, "Unable to update config\n");
284		return 1;
285	}
286
287	/* Preserve the version unless a new one is given */
288	if (!option.version_specified)
289		option.version = preamble->kernel_version;
290
291	/* Preserve the flags if not specified */
292	if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) {
293		if (option.flags_specified == 0)
294			option.flags = preamble->flags;
295	}
296
297	/* Replace the keyblock if asked */
298	if (option.keyblock)
299		keyblock = option.keyblock;
300
301	/* Compute the new signature */
302	vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
303				     option.version, option.kloadaddr,
304				     keyblock, option.signprivate,
305				     option.flags, &vblock_size);
306	if (!vblock_data) {
307		fprintf(stderr, "Unable to sign kernel blob\n");
308		return 1;
309	}
310	Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
311
312	if (option.create_new_outfile) {
313		/* Write out what we've been asked for */
314		if (option.vblockonly)
315			rv = WriteSomeParts(option.outfile,
316					    vblock_data, vblock_size,
317					    NULL, 0);
318		else
319			rv = WriteSomeParts(option.outfile,
320					    vblock_data, vblock_size,
321					    kblob_data, kblob_size);
322	} else {
323		/* If we're modifying an existing file, it's mmap'ed so that
324		 * all our modifications to the buffer will get flushed to
325		 * disk when we close it. */
326		Memcpy(kpart_data, vblock_data, vblock_size);
327	}
328
329	free(vblock_data);
330	return rv;
331}
332
333
334int futil_cb_sign_raw_firmware(struct futil_traverse_state_s *state)
335{
336	VbSignature *body_sig;
337	VbFirmwarePreambleHeader *preamble;
338	int rv;
339
340	body_sig = CalculateSignature(state->my_area->buf, state->my_area->len,
341				      option.signprivate);
342	if (!body_sig) {
343		fprintf(stderr, "Error calculating body signature\n");
344		return 1;
345	}
346
347	preamble = CreateFirmwarePreamble(option.version,
348					  option.kernel_subkey,
349					  body_sig,
350					  option.signprivate,
351					  option.flags);
352	if (!preamble) {
353		fprintf(stderr, "Error creating firmware preamble.\n");
354		free(body_sig);
355		return 1;
356	}
357
358	rv = WriteSomeParts(option.outfile,
359			    option.keyblock, option.keyblock->key_block_size,
360			    preamble, preamble->preamble_size);
361
362	free(preamble);
363	free(body_sig);
364
365	return rv;
366}
367
368
369int futil_cb_sign_begin(struct futil_traverse_state_s *state)
370{
371	if (state->in_type == FILE_TYPE_UNKNOWN) {
372		fprintf(stderr, "Unable to determine type of %s\n",
373			state->in_filename);
374		return 1;
375	}
376
377	return 0;
378}
379
380static int write_new_preamble(struct cb_area_s *vblock,
381			      struct cb_area_s *fw_body,
382			      VbPrivateKey *signkey,
383			      VbKeyBlockHeader *keyblock)
384{
385	VbSignature *body_sig;
386	VbFirmwarePreambleHeader *preamble;
387
388	body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
389	if (!body_sig) {
390		fprintf(stderr, "Error calculating body signature\n");
391		return 1;
392	}
393
394	preamble = CreateFirmwarePreamble(option.version,
395					  option.kernel_subkey,
396					  body_sig,
397					  signkey,
398					  option.flags);
399	if (!preamble) {
400		fprintf(stderr, "Error creating firmware preamble.\n");
401		free(body_sig);
402		return 1;
403	}
404
405	/* Write the new keyblock */
406	uint32_t more = keyblock->key_block_size;
407	memcpy(vblock->buf, keyblock, more);
408	/* and the new preamble */
409	memcpy(vblock->buf + more, preamble, preamble->preamble_size);
410
411	free(preamble);
412	free(body_sig);
413
414	return 0;
415}
416
417static int write_loem(const char *ab, struct cb_area_s *vblock)
418{
419	char filename[PATH_MAX];
420	int n;
421	n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
422		     option.loemdir ? option.loemdir : ".",
423		     ab, option.loemid);
424	if (n >= sizeof(filename)) {
425		fprintf(stderr, "LOEM args produce bogus filename\n");
426		return 1;
427	}
428
429	FILE *fp = fopen(filename, "w");
430	if (!fp) {
431		fprintf(stderr, "Can't open %s for writing: %s\n",
432			filename, strerror(errno));
433		return 1;
434	}
435
436	if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
437		fprintf(stderr, "Can't write to %s: %s\n",
438			filename, strerror(errno));
439		fclose(fp);
440		return 1;
441	}
442	if (fclose(fp)) {
443		fprintf(stderr, "Failed closing loem output: %s\n",
444			strerror(errno));
445		return 1;
446	}
447
448	return 0;
449}
450
451/* This signs a full BIOS image after it's been traversed. */
452static int sign_bios_at_end(struct futil_traverse_state_s *state)
453{
454	struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A];
455	struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B];
456	struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A];
457	struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B];
458	int retval = 0;
459
460	if (state->errors ||
461	    !(vblock_a->_flags & AREA_IS_VALID) ||
462	    !(vblock_b->_flags & AREA_IS_VALID) ||
463	    !(fw_a->_flags & AREA_IS_VALID) ||
464	    !(fw_b->_flags & AREA_IS_VALID)) {
465		fprintf(stderr, "Something's wrong. Not changing anything\n");
466		return 1;
467	}
468
469	/* Do A & B differ ? */
470	if (fw_a->len != fw_b->len ||
471	    memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
472		/* Yes, must use DEV keys for A */
473		if (!option.devsignprivate || !option.devkeyblock) {
474			fprintf(stderr,
475				"FW A & B differ. DEV keys are required.\n");
476			return 1;
477		}
478		retval |= write_new_preamble(vblock_a, fw_a,
479					     option.devsignprivate,
480					     option.devkeyblock);
481	} else {
482		retval |= write_new_preamble(vblock_a, fw_a,
483					     option.signprivate,
484					     option.keyblock);
485	}
486
487	/* FW B is always normal keys */
488	retval |= write_new_preamble(vblock_b, fw_b,
489				     option.signprivate,
490				     option.keyblock);
491
492
493
494
495	if (option.loemid) {
496		retval |= write_loem("A", vblock_a);
497		retval |= write_loem("B", vblock_b);
498	}
499
500	return retval;
501}
502
503int futil_cb_sign_end(struct futil_traverse_state_s *state)
504{
505	switch (state->in_type) {
506	case FILE_TYPE_BIOS_IMAGE:
507	case FILE_TYPE_OLD_BIOS_IMAGE:
508		return sign_bios_at_end(state);
509
510	default:
511		/* Any other cleanup needed? */
512		break;
513	}
514
515	return state->errors;
516}
517
518static const char usage[] = "\n"
519	"Usage:  " MYNAME " %s [PARAMS] INFILE [OUTFILE]\n"
520	"\n"
521	"Where INFILE is a\n"
522	"\n"
523	"  public key (.vbpubk); OUTFILE is a keyblock\n"
524	"  raw firmware blob (FW_MAIN_A/B); OUTFILE is a VBLOCK_A/B\n"
525	"  complete firmware image (bios.bin)\n"
526	"  raw linux kernel; OUTFILE is a kernel partition image\n"
527	"  kernel partition image (/dev/sda2, /dev/mmcblk0p2)\n";
528
529static const char usage_pubkey[] = "\n"
530	"-----------------------------------------------------------------\n"
531	"To sign a public key / create a new keyblock:\n"
532	"\n"
533	"Required PARAMS:\n"
534	"  [--datapubkey]   INFILE          The public key to wrap\n"
535	"  [--outfile]      OUTFILE         The resulting keyblock\n"
536	"\n"
537	"Optional PARAMS:\n"
538	"  A private signing key, specified as either\n"
539	"    -s|--signprivate FILE.vbprivk  Signing key in .vbprivk format\n"
540	"  Or\n"
541	"    --pem_signpriv   FILE.pem      Signing key in PEM format...\n"
542	"    --pem_algo       NUM           AND the algorithm to use (0 - %d)\n"
543	"\n"
544	"  If a signing key is not given, the keyblock will not be signed (duh)."
545	"\n\n"
546	"And these, too:\n\n"
547	"  -f|--flags       NUM             Flags specifying use conditions\n"
548	"  --pem_external   PROGRAM"
549	"         External program to compute the signature\n"
550	"                                     (requires a PEM signing key)\n";
551
552static const char usage_fw_main[] = "\n"
553	"-----------------------------------------------------------------\n"
554	"To sign a raw firmware blob (FW_MAIN_A/B):\n"
555	"\n"
556	"Required PARAMS:\n"
557	"  -s|--signprivate FILE.vbprivk    The private firmware data key\n"
558	"  -b|--keyblock    FILE.keyblock   The keyblock containing the\n"
559	"                                     public firmware data key\n"
560	"  -k|--kernelkey   FILE.vbpubk     The public kernel subkey\n"
561	"  -v|--version     NUM             The firmware version number\n"
562	"  [--fv]           INFILE"
563	"          The raw firmware blob (FW_MAIN_A/B)\n"
564	"  [--outfile]      OUTFILE         Output VBLOCK_A/B\n"
565	"\n"
566	"Optional PARAMS:\n"
567	"  -f|--flags       NUM             The preamble flags value"
568	" (default is 0)\n";
569
570static const char usage_bios[] = "\n"
571	"-----------------------------------------------------------------\n"
572	"To sign a complete firmware image (bios.bin):\n"
573	"\n"
574	"Required PARAMS:\n"
575	"  -s|--signprivate FILE.vbprivk    The private firmware data key\n"
576	"  -b|--keyblock    FILE.keyblock   The keyblock containing the\n"
577	"                                     public firmware data key\n"
578	"  -k|--kernelkey   FILE.vbpubk     The public kernel subkey\n"
579	"  [--infile]       INFILE          Input firmware image (modified\n"
580	"                                     in place if no OUTFILE given)\n"
581	"\n"
582	"These are required if the A and B firmware differ:\n"
583	"  -S|--devsign     FILE.vbprivk    The DEV private firmware data key\n"
584	"  -B|--devkeyblock FILE.keyblock   The keyblock containing the\n"
585	"                                     DEV public firmware data key\n"
586	"\n"
587	"Optional PARAMS:\n"
588	"  -v|--version     NUM             The firmware version number"
589	" (default %d)\n"
590	"  -f|--flags       NUM             The preamble flags value"
591	" (default is\n"
592	"                                     unchanged, or 0 if unknown)\n"
593	"  -d|--loemdir     DIR             Local OEM output vblock directory\n"
594	"  -l|--loemid      STRING          Local OEM vblock suffix\n"
595	"  [--outfile]      OUTFILE         Output firmware image\n";
596
597static const char usage_new_kpart[] = "\n"
598	"-----------------------------------------------------------------\n"
599	"To create a new kernel parition image (/dev/sda2, /dev/mmcblk0p2):\n"
600	"\n"
601	"Required PARAMS:\n"
602	"  -s|--signprivate FILE.vbprivk"
603	"    The private key to sign the kernel blob\n"
604	"  -b|--keyblock    FILE.keyblock   The keyblock containing the public\n"
605	"                                     key to verify the kernel blob\n"
606	"  -v|--version     NUM             The kernel version number\n"
607	"  --bootloader     FILE            Bootloader stub\n"
608	"  --config         FILE            The kernel commandline file\n"
609	"  --arch           ARCH            The CPU architecture (one of\n"
610	"                                     x86|amd64, arm|aarch64, mips)\n"
611	"  [--vmlinuz]      INFILE          Linux kernel bzImage file\n"
612	"  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
613	"\n"
614	"Optional PARAMS:\n"
615	"  --kloadaddr      NUM"
616	"             RAM address to load the kernel body\n"
617	"                                     (default 0x%x)\n"
618	"  --pad            NUM             The vblock padding size in bytes\n"
619	"                                     (default 0x%x)\n"
620	" --vblockonly                      Emit just the vblock (requires a\n"
621	"                                     distinct outfile)\n"
622	"  -f|--flags       NUM             The preamble flags value\n";
623
624static const char usage_old_kpart[] = "\n"
625	"-----------------------------------------------------------------\n"
626	"To resign an existing kernel parition (/dev/sda2, /dev/mmcblk0p2):\n"
627	"\n"
628	"Required PARAMS:\n"
629	"  -s|--signprivate FILE.vbprivk"
630	"    The private key to sign the kernel blob\n"
631	"  [--infile]       INFILE          Input kernel partition (modified\n"
632	"                                     in place if no OUTFILE given)\n"
633	"\n"
634	"Optional PARAMS:\n"
635	"  -b|--keyblock    FILE.keyblock   The keyblock containing the public\n"
636	"                                     key to verify the kernel blob\n"
637	"  -v|--version     NUM             The kernel version number\n"
638	"  --config         FILE            The kernel commandline file\n"
639	"  --pad            NUM             The vblock padding size in bytes\n"
640	"                                     (default 0x%x)\n"
641	"  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
642	"  --vblockonly                     Emit just the vblock (requires a\n"
643	"                                     distinct OUTFILE)\n"
644	"  -f|--flags       NUM             The preamble flags value\n"
645	"\n";
646
647static void print_help(const char *prog)
648{
649	printf(usage, prog);
650	printf(usage_pubkey, kNumAlgorithms - 1);
651	puts(usage_fw_main);
652	printf(usage_bios, option.version);
653	printf(usage_new_kpart, option.kloadaddr, option.padding);
654	printf(usage_old_kpart, option.padding);
655}
656
657enum no_short_opts {
658	OPT_FV = 1000,
659	OPT_INFILE,			/* aka "--vmlinuz" */
660	OPT_OUTFILE,
661	OPT_BOOTLOADER,
662	OPT_CONFIG,
663	OPT_ARCH,
664	OPT_KLOADADDR,
665	OPT_PADDING,
666	OPT_PEM_SIGNPRIV,
667	OPT_PEM_ALGO,
668	OPT_PEM_EXTERNAL,
669};
670
671static const struct option long_opts[] = {
672	/* name    hasarg *flag  val */
673	{"signprivate",  1, NULL, 's'},
674	{"keyblock",     1, NULL, 'b'},
675	{"kernelkey",    1, NULL, 'k'},
676	{"devsign",      1, NULL, 'S'},
677	{"devkeyblock",  1, NULL, 'B'},
678	{"version",      1, NULL, 'v'},
679	{"flags",        1, NULL, 'f'},
680	{"loemdir",      1, NULL, 'd'},
681	{"loemid",       1, NULL, 'l'},
682	{"fv",           1, NULL, OPT_FV},
683	{"infile",       1, NULL, OPT_INFILE},
684	{"datapubkey",   1, NULL, OPT_INFILE},	/* alias */
685	{"vmlinuz",      1, NULL, OPT_INFILE},	/* alias */
686	{"outfile",      1, NULL, OPT_OUTFILE},
687	{"bootloader",   1, NULL, OPT_BOOTLOADER},
688	{"config",       1, NULL, OPT_CONFIG},
689	{"arch",         1, NULL, OPT_ARCH},
690	{"kloadaddr",    1, NULL, OPT_KLOADADDR},
691	{"pad",          1, NULL, OPT_PADDING},
692	{"pem_signpriv", 1, NULL, OPT_PEM_SIGNPRIV},
693	{"pem_algo",     1, NULL, OPT_PEM_ALGO},
694	{"pem_external", 1, NULL, OPT_PEM_EXTERNAL},
695	{"vblockonly",   0, &option.vblockonly, 1},
696	{"debug",        0, &debugging_enabled, 1},
697	{NULL,           0, NULL, 0},
698};
699static char *short_opts = ":s:b:k:S:B:v:f:d:l:";
700
701static int do_sign(int argc, char *argv[])
702{
703	char *infile = 0;
704	int i;
705	int ifd = -1;
706	int errorcnt = 0;
707	struct futil_traverse_state_s state;
708	uint8_t *buf;
709	uint32_t buf_len;
710	char *e = 0;
711	enum futil_file_type type;
712	int inout_file_count = 0;
713	int mapping;
714
715	opterr = 0;		/* quiet, you */
716	while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
717		switch (i) {
718		case 's':
719			option.signprivate = PrivateKeyRead(optarg);
720			if (!option.signprivate) {
721				fprintf(stderr, "Error reading %s\n", optarg);
722				errorcnt++;
723			}
724			break;
725		case 'b':
726			option.keyblock = KeyBlockRead(optarg);
727			if (!option.keyblock) {
728				fprintf(stderr, "Error reading %s\n", optarg);
729				errorcnt++;
730			}
731			break;
732		case 'k':
733			option.kernel_subkey = PublicKeyRead(optarg);
734			if (!option.kernel_subkey) {
735				fprintf(stderr, "Error reading %s\n", optarg);
736				errorcnt++;
737			}
738			break;
739		case 'S':
740			option.devsignprivate = PrivateKeyRead(optarg);
741			if (!option.devsignprivate) {
742				fprintf(stderr, "Error reading %s\n", optarg);
743				errorcnt++;
744			}
745			break;
746		case 'B':
747			option.devkeyblock = KeyBlockRead(optarg);
748			if (!option.devkeyblock) {
749				fprintf(stderr, "Error reading %s\n", optarg);
750				errorcnt++;
751			}
752			break;
753		case 'v':
754			option.version_specified = 1;
755			option.version = strtoul(optarg, &e, 0);
756			if (!*optarg || (e && *e)) {
757				fprintf(stderr,
758					"Invalid --version \"%s\"\n", optarg);
759				errorcnt++;
760			}
761			break;
762
763		case 'f':
764			option.flags_specified = 1;
765			option.flags = strtoul(optarg, &e, 0);
766			if (!*optarg || (e && *e)) {
767				fprintf(stderr,
768					"Invalid --flags \"%s\"\n", optarg);
769				errorcnt++;
770			}
771			break;
772		case 'd':
773			option.loemdir = optarg;
774			break;
775		case 'l':
776			option.loemid = optarg;
777			break;
778		case OPT_FV:
779			option.fv_specified = 1;
780			/* fallthrough */
781		case OPT_INFILE:		/* aka "--vmlinuz" */
782			inout_file_count++;
783			infile = optarg;
784			break;
785		case OPT_OUTFILE:
786			inout_file_count++;
787			option.outfile = optarg;
788			break;
789		case OPT_BOOTLOADER:
790			option.bootloader_data = ReadFile(
791				optarg, &option.bootloader_size);
792			if (!option.bootloader_data) {
793				fprintf(stderr,
794					"Error reading bootloader file: %s\n",
795					strerror(errno));
796				errorcnt++;
797			}
798			Debug("bootloader file size=0x%" PRIx64 "\n",
799			      option.bootloader_size);
800			break;
801		case OPT_CONFIG:
802			option.config_data = ReadConfigFile(
803				optarg, &option.config_size);
804			if (!option.config_data) {
805				fprintf(stderr,
806					"Error reading config file: %s\n",
807					strerror(errno));
808				errorcnt++;
809			}
810			break;
811		case OPT_ARCH:
812			/* check the first 3 characters to also match x86_64 */
813			if ((!strncasecmp(optarg, "x86", 3)) ||
814			    (!strcasecmp(optarg, "amd64")))
815				option.arch = ARCH_X86;
816			else if ((!strcasecmp(optarg, "arm")) ||
817				 (!strcasecmp(optarg, "aarch64")))
818				option.arch = ARCH_ARM;
819			else if (!strcasecmp(optarg, "mips"))
820				option.arch = ARCH_MIPS;
821			else {
822				fprintf(stderr,
823					"Unknown architecture: \"%s\"\n",
824					optarg);
825				errorcnt++;
826			}
827			break;
828		case OPT_KLOADADDR:
829			option.kloadaddr = strtoul(optarg, &e, 0);
830			if (!*optarg || (e && *e)) {
831				fprintf(stderr,
832					"Invalid --kloadaddr \"%s\"\n", optarg);
833				errorcnt++;
834			}
835			break;
836		case OPT_PADDING:
837			option.padding = strtoul(optarg, &e, 0);
838			if (!*optarg || (e && *e)) {
839				fprintf(stderr,
840					"Invalid --padding \"%s\"\n", optarg);
841				errorcnt++;
842			}
843			break;
844		case OPT_PEM_SIGNPRIV:
845			option.pem_signpriv = optarg;
846			break;
847		case OPT_PEM_ALGO:
848			option.pem_algo_specified = 1;
849			option.pem_algo = strtoul(optarg, &e, 0);
850			if (!*optarg || (e && *e) ||
851			    (option.pem_algo >= kNumAlgorithms)) {
852				fprintf(stderr,
853					"Invalid --pem_algo \"%s\"\n", optarg);
854				errorcnt++;
855			}
856			break;
857		case OPT_PEM_EXTERNAL:
858			option.pem_external = optarg;
859			break;
860
861		case '?':
862			if (optopt)
863				fprintf(stderr, "Unrecognized option: -%c\n",
864					optopt);
865			else
866				fprintf(stderr, "Unrecognized option: %s\n",
867					argv[optind - 1]);
868			errorcnt++;
869			break;
870		case ':':
871			fprintf(stderr, "Missing argument to -%c\n", optopt);
872			errorcnt++;
873			break;
874		case 0:				/* handled option */
875			break;
876		default:
877			Debug("i=%d\n", i);
878			DIE;
879		}
880	}
881
882	/* If we don't have an input file already, we need one */
883	if (!infile) {
884		if (argc - optind <= 0) {
885			errorcnt++;
886			fprintf(stderr, "ERROR: missing input filename\n");
887			goto done;
888		} else {
889			inout_file_count++;
890			infile = argv[optind++];
891		}
892	}
893
894	/* Look for an output file if we don't have one, just in case. */
895	if (!option.outfile && argc - optind > 0) {
896		inout_file_count++;
897		option.outfile = argv[optind++];
898	}
899
900	/* What are we looking at? */
901	if (futil_file_type(infile, &type)) {
902		errorcnt++;
903		goto done;
904	}
905
906	/* We may be able to infer the type based on the other args */
907	if (type == FILE_TYPE_UNKNOWN) {
908		if (option.bootloader_data || option.config_data
909		    || option.arch != ARCH_UNSPECIFIED)
910			type = FILE_TYPE_RAW_KERNEL;
911		else if (option.kernel_subkey || option.fv_specified)
912			type = FILE_TYPE_RAW_FIRMWARE;
913	}
914
915	Debug("type=%s\n", futil_file_type_str(type));
916
917	/* Check the arguments for the type of thing we want to sign */
918	switch (type) {
919	case FILE_TYPE_UNKNOWN:
920		fprintf(stderr,
921			"Unable to determine the type of the input file\n");
922		errorcnt++;
923		goto done;
924	case FILE_TYPE_PUBKEY:
925		option.create_new_outfile = 1;
926		if (option.signprivate && option.pem_signpriv) {
927			fprintf(stderr,
928				"Only one of --signprivate and --pem_signpriv"
929				" can be specified\n");
930			errorcnt++;
931		}
932		if ((option.signprivate && option.pem_algo_specified) ||
933		    (option.pem_signpriv && !option.pem_algo_specified)) {
934			fprintf(stderr, "--pem_algo must be used with"
935				" --pem_signpriv\n");
936			errorcnt++;
937		}
938		if (option.pem_external && !option.pem_signpriv) {
939			fprintf(stderr, "--pem_external must be used with"
940				" --pem_signpriv\n");
941			errorcnt++;
942		}
943		/* We'll wait to read the PEM file, since the external signer
944		 * may want to read it instead. */
945		break;
946	case FILE_TYPE_KEYBLOCK:
947		fprintf(stderr, "Resigning a keyblock is kind of pointless.\n");
948		fprintf(stderr, "Just create a new one.\n");
949		errorcnt++;
950		break;
951	case FILE_TYPE_FW_PREAMBLE:
952		fprintf(stderr,
953			"%s IS a signature. Sign the firmware instead\n",
954			infile);
955		break;
956	case FILE_TYPE_GBB:
957		fprintf(stderr, "There's no way to sign a GBB\n");
958		errorcnt++;
959		break;
960	case FILE_TYPE_BIOS_IMAGE:
961	case FILE_TYPE_OLD_BIOS_IMAGE:
962		errorcnt += no_opt_if(!option.signprivate, "signprivate");
963		errorcnt += no_opt_if(!option.keyblock, "keyblock");
964		errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
965		break;
966	case FILE_TYPE_KERN_PREAMBLE:
967		errorcnt += no_opt_if(!option.signprivate, "signprivate");
968		if (option.vblockonly || inout_file_count > 1)
969			option.create_new_outfile = 1;
970		break;
971	case FILE_TYPE_RAW_FIRMWARE:
972		option.create_new_outfile = 1;
973		errorcnt += no_opt_if(!option.signprivate, "signprivate");
974		errorcnt += no_opt_if(!option.keyblock, "keyblock");
975		errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
976		errorcnt += no_opt_if(!option.version_specified, "version");
977		break;
978	case FILE_TYPE_RAW_KERNEL:
979		option.create_new_outfile = 1;
980		errorcnt += no_opt_if(!option.signprivate, "signprivate");
981		errorcnt += no_opt_if(!option.keyblock, "keyblock");
982		errorcnt += no_opt_if(!option.version_specified, "version");
983		errorcnt += no_opt_if(!option.bootloader_data, "bootloader");
984		errorcnt += no_opt_if(!option.config_data, "config");
985		errorcnt += no_opt_if(option.arch == ARCH_UNSPECIFIED, "arch");
986		break;
987	case FILE_TYPE_CHROMIUMOS_DISK:
988		fprintf(stderr, "Signing a %s is not yet supported\n",
989			futil_file_type_str(type));
990		errorcnt++;
991		break;
992	default:
993		DIE;
994	}
995
996	Debug("infile=%s\n", infile);
997	Debug("inout_file_count=%d\n", inout_file_count);
998	Debug("option.create_new_outfile=%d\n", option.create_new_outfile);
999
1000	/* Make sure we have an output file if one is needed */
1001	if (!option.outfile) {
1002		if (option.create_new_outfile) {
1003			errorcnt++;
1004			fprintf(stderr, "Missing output filename\n");
1005			goto done;
1006		} else {
1007			option.outfile = infile;
1008		}
1009	}
1010
1011	Debug("option.outfile=%s\n", option.outfile);
1012
1013	if (argc - optind > 0) {
1014		errorcnt++;
1015		fprintf(stderr, "ERROR: too many arguments left over\n");
1016	}
1017
1018	if (errorcnt)
1019		goto done;
1020
1021	memset(&state, 0, sizeof(state));
1022	state.op = FUTIL_OP_SIGN;
1023
1024	if (option.create_new_outfile) {
1025		/* The input is read-only, the output is write-only. */
1026		mapping = MAP_RO;
1027		state.in_filename = infile;
1028		Debug("open RO %s\n", infile);
1029		ifd = open(infile, O_RDONLY);
1030		if (ifd < 0) {
1031			errorcnt++;
1032			fprintf(stderr, "Can't open %s for reading: %s\n",
1033				infile, strerror(errno));
1034			goto done;
1035		}
1036	} else {
1037		/* We'll read-modify-write the output file */
1038		mapping = MAP_RW;
1039		state.in_filename = option.outfile;
1040		if (inout_file_count > 1)
1041			futil_copy_file_or_die(infile, option.outfile);
1042		Debug("open RW %s\n", option.outfile);
1043		ifd = open(option.outfile, O_RDWR);
1044		if (ifd < 0) {
1045			errorcnt++;
1046			fprintf(stderr, "Can't open %s for writing: %s\n",
1047				option.outfile, strerror(errno));
1048			goto done;
1049		}
1050	}
1051
1052	if (0 != futil_map_file(ifd, mapping, &buf, &buf_len)) {
1053		errorcnt++;
1054		goto done;
1055	}
1056
1057	errorcnt += futil_traverse(buf, buf_len, &state, type);
1058
1059	errorcnt += futil_unmap_file(ifd, MAP_RW, buf, buf_len);
1060
1061done:
1062	if (ifd >= 0 && close(ifd)) {
1063		errorcnt++;
1064		fprintf(stderr, "Error when closing ifd: %s\n",
1065			strerror(errno));
1066	}
1067
1068	if (option.signprivate)
1069		free(option.signprivate);
1070	if (option.keyblock)
1071		free(option.keyblock);
1072	if (option.kernel_subkey)
1073		free(option.kernel_subkey);
1074
1075	if (errorcnt)
1076		fprintf(stderr, "Use --help for usage instructions\n");
1077
1078	return !!errorcnt;
1079}
1080
1081DECLARE_FUTIL_COMMAND(sign, do_sign,
1082		      VBOOT_VERSION_ALL,
1083		      "Sign / resign various binary components",
1084		      print_help);
1085