115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson/*
215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson * Copyright 2014 The Chromium OS Authors. All rights reserved.
315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson * Use of this source code is governed by a BSD-style license that can be
415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson * found in the LICENSE file.
515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson */
615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <errno.h>
715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <fcntl.h>
815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <getopt.h>
915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <inttypes.h>
1015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <limits.h>
1115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <stddef.h>
1215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <stdint.h>
1315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <stdio.h>
1415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <stdlib.h>
1515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <string.h>
1615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <sys/stat.h>
1715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <sys/types.h>
1815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include <unistd.h>
1915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
2015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include "bmpblk_header.h"
212559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson#include "file_type.h"
2215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include "fmap.h"
2315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include "futility.h"
2415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include "gbb_header.h"
2515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include "host_common.h"
265f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson#include "kernel_blob.h"
2715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include "traversal.h"
2815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include "util_misc.h"
295f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson#include "vb1_helper.h"
3015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson#include "vboot_common.h"
3115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
3215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson/* Local values for cb_area_s._flags */
3315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonenum callback_flags {
3415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	AREA_IS_VALID =     0x00000001,
3515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson};
3615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
3715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson/* Local structure for args, etc. */
385f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonstatic struct local_data_s {
3915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbPrivateKey *signprivate;
4015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbKeyBlockHeader *keyblock;
4115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbPublicKey *kernel_subkey;
4215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbPrivateKey *devsignprivate;
4315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbKeyBlockHeader *devkeyblock;
4415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	uint32_t version;
455f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int version_specified;
4615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	uint32_t flags;
47a19b00dfd0c17681b71bd61994854dff3f3576a3Bill Richardson	int flags_specified;
4815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	char *loemdir;
4915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	char *loemid;
505f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint8_t *bootloader_data;
515f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint64_t bootloader_size;
525f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint8_t *config_data;
535f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint64_t config_size;
545f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	enum arch_t arch;
55c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	int fv_specified;
565f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint32_t kloadaddr;
575f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint32_t padding;
585f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int vblockonly;
595f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	char *outfile;
605f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int create_new_outfile;
61c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	char *pem_signpriv;
62c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	int pem_algo_specified;
63c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	uint32_t pem_algo;
64c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	char *pem_external;
6515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson} option = {
6615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	.version = 1,
675f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	.arch = ARCH_UNSPECIFIED,
685f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	.kloadaddr = CROS_32BIT_ENTRY_ADDR,
695f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	.padding = 65536,
7015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson};
7115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
7215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
735f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson/* Helper to complain about invalid args. Returns num errors discovered */
745f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonstatic int no_opt_if(int expr, const char *optname)
7515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
765f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (expr) {
775f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Missing --%s option\n", optname);
785f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		return 1;
795f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
805f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	return 0;
8115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
8215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
835f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson/* This wraps/signs a public key, producing a keyblock. */
845f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonint futil_cb_sign_pubkey(struct futil_traverse_state_s *state)
8515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
86c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	VbPublicKey *data_key = (VbPublicKey *)state->my_area->buf;
87c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	VbKeyBlockHeader *vblock;
88c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
89c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	if (option.pem_signpriv) {
90c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		if (option.pem_external) {
91c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			/* External signing uses the PEM file directly. */
92c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			vblock = KeyBlockCreate_external(
93c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				data_key,
94c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				option.pem_signpriv,
95c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				option.pem_algo, option.flags,
96c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				option.pem_external);
97c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		} else {
98c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			option.signprivate = PrivateKeyReadPem(
99c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				option.pem_signpriv, option.pem_algo);
100c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			if (!option.signprivate) {
101c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				fprintf(stderr,
102c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson					"Unable to read PEM signing key: %s\n",
103c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson					strerror(errno));
104c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				return 1;
105c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			}
106c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			vblock = KeyBlockCreate(data_key, option.signprivate,
107c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson						option.flags);
108c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		}
109c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	} else {
110c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		/* Not PEM. Should already have a signing key. */
111c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		vblock = KeyBlockCreate(data_key, option.signprivate,
112c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson					option.flags);
113c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	}
114c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
115c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	/* Write it out */
116c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	return WriteSomeParts(option.outfile,
117c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			      vblock, vblock->key_block_size,
118c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			      NULL, 0);
11915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
12015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
12115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson/*
12215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson * This handles FW_MAIN_A and FW_MAIN_B while processing a BIOS image.
12315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson * The data in state->my_area is just the RW firmware blob, so there's nothing
12415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson * useful to show about it. We'll just mark it as present so when we encounter
12515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson * corresponding VBLOCK area, we'll have this to verify.
12615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson */
12715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonint futil_cb_sign_fw_main(struct futil_traverse_state_s *state)
12815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
12915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	state->my_area->_flags |= AREA_IS_VALID;
13015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	return 0;
13115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
13215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
133779796f57e1e0236ea502248ede2cbea986fca21Bill Richardson/*
134779796f57e1e0236ea502248ede2cbea986fca21Bill Richardson * This handles VBLOCK_A and VBLOCK_B while processing a BIOS image.
135779796f57e1e0236ea502248ede2cbea986fca21Bill Richardson * We don't do any signing here. We just check to see if the VBLOCK
136779796f57e1e0236ea502248ede2cbea986fca21Bill Richardson * area contains a firmware preamble.
137779796f57e1e0236ea502248ede2cbea986fca21Bill Richardson */
1385f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonint futil_cb_sign_fw_vblock(struct futil_traverse_state_s *state)
13915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
14015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)state->my_area->buf;
141e051975c900caf43046a97cda682629915c62c7eBill Richardson	uint32_t len = state->my_area->len;
14215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
14315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	/*
144e051975c900caf43046a97cda682629915c62c7eBill Richardson	 * If we have a valid keyblock and fw_preamble, then we can use them to
145e051975c900caf43046a97cda682629915c62c7eBill Richardson	 * determine the size of the firmware body. Otherwise, we'll have to
146e051975c900caf43046a97cda682629915c62c7eBill Richardson	 * just sign the whole region.
14715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	 */
148e051975c900caf43046a97cda682629915c62c7eBill Richardson	if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) {
149e051975c900caf43046a97cda682629915c62c7eBill Richardson		fprintf(stderr, "Warning: %s keyblock is invalid. "
150e051975c900caf43046a97cda682629915c62c7eBill Richardson			"Signing the entire FW FMAP region...\n",
151779796f57e1e0236ea502248ede2cbea986fca21Bill Richardson			state->name);
152e051975c900caf43046a97cda682629915c62c7eBill Richardson		goto whatever;
153e051975c900caf43046a97cda682629915c62c7eBill Richardson	}
15415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
155e051975c900caf43046a97cda682629915c62c7eBill Richardson	RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key);
156e051975c900caf43046a97cda682629915c62c7eBill Richardson	if (!rsa) {
157e051975c900caf43046a97cda682629915c62c7eBill Richardson		fprintf(stderr, "Warning: %s public key is invalid. "
158e051975c900caf43046a97cda682629915c62c7eBill Richardson			"Signing the entire FW FMAP region...\n",
159e051975c900caf43046a97cda682629915c62c7eBill Richardson			state->name);
160e051975c900caf43046a97cda682629915c62c7eBill Richardson		goto whatever;
161e051975c900caf43046a97cda682629915c62c7eBill Richardson	}
16215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	uint32_t more = key_block->key_block_size;
16315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbFirmwarePreambleHeader *preamble =
16415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		(VbFirmwarePreambleHeader *)(state->my_area->buf + more);
16515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	uint32_t fw_size = preamble->body_signature.data_size;
166e051975c900caf43046a97cda682629915c62c7eBill Richardson	struct cb_area_s *fw_body_area = 0;
16715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
16815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	switch (state->component) {
16915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	case CB_FMAP_VBLOCK_A:
17015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_A];
17108efd1ee358c546c968918a24b45219d7003cecaBill Richardson		/* Preserve the flags if they're not specified */
172a19b00dfd0c17681b71bd61994854dff3f3576a3Bill Richardson		if (!option.flags_specified)
17308efd1ee358c546c968918a24b45219d7003cecaBill Richardson			option.flags = preamble->flags;
17415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		break;
17515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	case CB_FMAP_VBLOCK_B:
17615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fw_body_area = &state->cb_area[CB_FMAP_FW_MAIN_B];
17715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		break;
17815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	default:
17915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		DIE;
18015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
18115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
18215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (fw_size > fw_body_area->len) {
18315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr,
18415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			"%s says the firmware is larger than we have\n",
185779796f57e1e0236ea502248ede2cbea986fca21Bill Richardson			state->name);
18615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
18715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
18815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
18915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	/* Update the firmware size */
19015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	fw_body_area->len = fw_size;
19115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
192e051975c900caf43046a97cda682629915c62c7eBill Richardsonwhatever:
19315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	state->my_area->_flags |= AREA_IS_VALID;
19415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
19515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	return 0;
19615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
19715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
1985f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonint futil_cb_create_kernel_part(struct futil_traverse_state_s *state)
1995f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson{
2005f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint8_t *vmlinuz_data, *kblob_data, *vblock_data;
2015f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint64_t vmlinuz_size, kblob_size, vblock_size;
2025f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int rv;
2035f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2045f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	vmlinuz_data = state->my_area->buf;
2055f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	vmlinuz_size = state->my_area->len;
2065f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2075f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	kblob_data = CreateKernelBlob(
2085f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		vmlinuz_data, vmlinuz_size,
2095f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		option.arch, option.kloadaddr,
2105f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		option.config_data, option.config_size,
2115f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		option.bootloader_data, option.bootloader_size,
2125f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		&kblob_size);
2135f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (!kblob_data) {
2145f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Unable to create kernel blob\n");
2155f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		return 1;
2165f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
2175f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	Debug("kblob_size = 0x%" PRIx64 "\n", kblob_size);
2185f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2195f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
2205f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				     option.version, option.kloadaddr,
2215f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				     option.keyblock, option.signprivate,
22280e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh				     option.flags, &vblock_size);
2235f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (!vblock_data) {
2245f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Unable to sign kernel blob\n");
2255f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		free(kblob_data);
2265f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		return 1;
2275f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
2285f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
2295f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2305f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* We should be creating a completely new output file.
2315f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	 * If not, something's wrong. */
2325f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (!option.create_new_outfile)
2335f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		DIE;
2345f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2355f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (option.vblockonly)
2365f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		rv = WriteSomeParts(option.outfile,
2375f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				    vblock_data, vblock_size,
2385f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				    NULL, 0);
2395f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	else
2405f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		rv = WriteSomeParts(option.outfile,
2415f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				    vblock_data, vblock_size,
2425f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				    kblob_data, kblob_size);
2435f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2445f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	free(vblock_data);
2455f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	free(kblob_data);
2465f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	return rv;
2475f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson}
2485f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2495f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonint futil_cb_resign_kernel_part(struct futil_traverse_state_s *state)
2505f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson{
2515f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint8_t *kpart_data, *kblob_data, *vblock_data;
2525f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	uint64_t kpart_size, kblob_size, vblock_size;
2535f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	VbKeyBlockHeader *keyblock = NULL;
2545f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	VbKernelPreambleHeader *preamble = NULL;
2555f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int rv = 0;
2565f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2575f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	kpart_data = state->my_area->buf;
2585f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	kpart_size = state->my_area->len;
2595f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2605f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* Note: This just sets some static pointers. It doesn't malloc. */
2615f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	kblob_data = UnpackKPart(kpart_data, kpart_size, option.padding,
2625f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				 &keyblock, &preamble, &kblob_size);
2635f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2645f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (!kblob_data) {
2655f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Unable to unpack kernel partition\n");
2665f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		return 1;
2675f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
2685f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2695f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/*
2705f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	 * We don't let --kloadaddr change when resigning, because the original
2715f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	 * vbutil_kernel program didn't do it right. Since obviously no one
2725f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	 * ever noticed, we'll maintain bug-compatibility by just not allowing
2735f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	 * it here either. To enable it, we'd need to update the zeropage
2745f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	 * table's cmd_line_ptr as well as the preamble.
2755f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	 */
2765f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	option.kloadaddr = preamble->body_load_address;
2775f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2785f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* Replace the config if asked */
2795f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (option.config_data &&
2805f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	    0 != UpdateKernelBlobConfig(kblob_data, kblob_size,
2815f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					option.config_data,
2825f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					option.config_size)) {
2835f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Unable to update config\n");
2845f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		return 1;
2855f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
2865f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
2875f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* Preserve the version unless a new one is given */
2885f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (!option.version_specified)
2895f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		option.version = preamble->kernel_version;
2905f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
29180e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh	/* Preserve the flags if not specified */
29280e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh	if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) {
29380e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh		if (option.flags_specified == 0)
29480e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh			option.flags = preamble->flags;
29580e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh	}
29680e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh
2975f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* Replace the keyblock if asked */
2985f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (option.keyblock)
2995f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		keyblock = option.keyblock;
3005f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
3015f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* Compute the new signature */
3025f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	vblock_data = SignKernelBlob(kblob_data, kblob_size, option.padding,
3035f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				     option.version, option.kloadaddr,
3045f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				     keyblock, option.signprivate,
30580e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh				     option.flags, &vblock_size);
3065f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (!vblock_data) {
3075f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Unable to sign kernel blob\n");
3085f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		return 1;
3095f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
3105f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	Debug("vblock_size = 0x%" PRIx64 "\n", vblock_size);
3115f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
312b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson	if (option.create_new_outfile) {
313b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		/* Write out what we've been asked for */
314b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		if (option.vblockonly)
315b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson			rv = WriteSomeParts(option.outfile,
316b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson					    vblock_data, vblock_size,
317b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson					    NULL, 0);
318b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		else
319b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson			rv = WriteSomeParts(option.outfile,
320b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson					    vblock_data, vblock_size,
321b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson					    kblob_data, kblob_size);
3225f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	} else {
323b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		/* If we're modifying an existing file, it's mmap'ed so that
324b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		 * all our modifications to the buffer will get flushed to
325b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		 * disk when we close it. */
3265f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		Memcpy(kpart_data, vblock_data, vblock_size);
3275f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
3285f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
3295f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	free(vblock_data);
3305f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	return rv;
3315f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson}
3325f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
3335f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
3345f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonint futil_cb_sign_raw_firmware(struct futil_traverse_state_s *state)
3355f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson{
336c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	VbSignature *body_sig;
337c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	VbFirmwarePreambleHeader *preamble;
338c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	int rv;
339c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
340c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	body_sig = CalculateSignature(state->my_area->buf, state->my_area->len,
341c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				      option.signprivate);
342c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	if (!body_sig) {
343c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		fprintf(stderr, "Error calculating body signature\n");
344c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		return 1;
345c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	}
346c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
347c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	preamble = CreateFirmwarePreamble(option.version,
348c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson					  option.kernel_subkey,
349c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson					  body_sig,
350c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson					  option.signprivate,
351c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson					  option.flags);
352c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	if (!preamble) {
353c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		fprintf(stderr, "Error creating firmware preamble.\n");
354c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		free(body_sig);
355c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		return 1;
356c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	}
357c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
358c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	rv = WriteSomeParts(option.outfile,
359c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			    option.keyblock, option.keyblock->key_block_size,
360c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			    preamble, preamble->preamble_size);
361c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
362c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	free(preamble);
363c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	free(body_sig);
364c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
365c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	return rv;
3665f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson}
3675f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
3685f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
36915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonint futil_cb_sign_begin(struct futil_traverse_state_s *state)
37015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
37115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (state->in_type == FILE_TYPE_UNKNOWN) {
37215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr, "Unable to determine type of %s\n",
37315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			state->in_filename);
37415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
37515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
37615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
37715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	return 0;
37815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
37915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
38015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonstatic int write_new_preamble(struct cb_area_s *vblock,
38115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			      struct cb_area_s *fw_body,
38215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			      VbPrivateKey *signkey,
38315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			      VbKeyBlockHeader *keyblock)
38415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
38515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbSignature *body_sig;
38615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	VbFirmwarePreambleHeader *preamble;
38715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
38815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	body_sig = CalculateSignature(fw_body->buf, fw_body->len, signkey);
38915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (!body_sig) {
39015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr, "Error calculating body signature\n");
39115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
39215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
39315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
39415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	preamble = CreateFirmwarePreamble(option.version,
39515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					  option.kernel_subkey,
39615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					  body_sig,
39715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					  signkey,
39815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					  option.flags);
39915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (!preamble) {
40015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr, "Error creating firmware preamble.\n");
40115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		free(body_sig);
40215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
40315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
40415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
40515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	/* Write the new keyblock */
40615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	uint32_t more = keyblock->key_block_size;
40715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	memcpy(vblock->buf, keyblock, more);
40815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	/* and the new preamble */
40915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	memcpy(vblock->buf + more, preamble, preamble->preamble_size);
41015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
41115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	free(preamble);
41215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	free(body_sig);
41315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
41415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	return 0;
41515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
41615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
41715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonstatic int write_loem(const char *ab, struct cb_area_s *vblock)
41815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
41915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	char filename[PATH_MAX];
42015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	int n;
42115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	n = snprintf(filename, sizeof(filename), "%s/vblock_%s.%s",
42215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		     option.loemdir ? option.loemdir : ".",
42315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		     ab, option.loemid);
42415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (n >= sizeof(filename)) {
42515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr, "LOEM args produce bogus filename\n");
42615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
42715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
42815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
42915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	FILE *fp = fopen(filename, "w");
43015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (!fp) {
43115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr, "Can't open %s for writing: %s\n",
43215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			filename, strerror(errno));
43315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
43415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
43515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
43615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (1 != fwrite(vblock->buf, vblock->len, 1, fp)) {
43715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr, "Can't write to %s: %s\n",
43815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			filename, strerror(errno));
43915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fclose(fp);
44015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
44115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
44215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (fclose(fp)) {
44315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr, "Failed closing loem output: %s\n",
44415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			strerror(errno));
44515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
44615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
44715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
44815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	return 0;
44915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
45015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
4515f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson/* This signs a full BIOS image after it's been traversed. */
4525f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonstatic int sign_bios_at_end(struct futil_traverse_state_s *state)
45315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
45415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	struct cb_area_s *vblock_a = &state->cb_area[CB_FMAP_VBLOCK_A];
45515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	struct cb_area_s *vblock_b = &state->cb_area[CB_FMAP_VBLOCK_B];
45615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	struct cb_area_s *fw_a = &state->cb_area[CB_FMAP_FW_MAIN_A];
45715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	struct cb_area_s *fw_b = &state->cb_area[CB_FMAP_FW_MAIN_B];
45815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	int retval = 0;
45915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
46015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (state->errors ||
46115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	    !(vblock_a->_flags & AREA_IS_VALID) ||
46215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	    !(vblock_b->_flags & AREA_IS_VALID) ||
46315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	    !(fw_a->_flags & AREA_IS_VALID) ||
46415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	    !(fw_b->_flags & AREA_IS_VALID)) {
46515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr, "Something's wrong. Not changing anything\n");
46615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		return 1;
46715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
46815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
46915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	/* Do A & B differ ? */
47015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (fw_a->len != fw_b->len ||
47115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	    memcmp(fw_a->buf, fw_b->buf, fw_a->len)) {
47215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		/* Yes, must use DEV keys for A */
47315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		if (!option.devsignprivate || !option.devkeyblock) {
47415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			fprintf(stderr,
47515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				"FW A & B differ. DEV keys are required.\n");
47615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			return 1;
47715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		}
47815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		retval |= write_new_preamble(vblock_a, fw_a,
47915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					     option.devsignprivate,
48015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					     option.devkeyblock);
48115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	} else {
48215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		retval |= write_new_preamble(vblock_a, fw_a,
48315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					     option.signprivate,
48415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					     option.keyblock);
48515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
48615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
48715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	/* FW B is always normal keys */
48815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	retval |= write_new_preamble(vblock_b, fw_b,
48915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				     option.signprivate,
49015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				     option.keyblock);
49115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
49215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
49315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
49415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
49515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (option.loemid) {
49615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		retval |= write_loem("A", vblock_a);
49715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		retval |= write_loem("B", vblock_b);
49815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
49915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
50015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	return retval;
50115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
50215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
5035f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonint futil_cb_sign_end(struct futil_traverse_state_s *state)
5045f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson{
5055f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	switch (state->in_type) {
5065f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_BIOS_IMAGE:
5075f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_OLD_BIOS_IMAGE:
5085f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		return sign_bios_at_end(state);
5095f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
5105f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	default:
5115f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		/* Any other cleanup needed? */
5125f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		break;
5135f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
5145f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
5155f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	return state->errors;
5165f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson}
5175f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
51815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonstatic const char usage[] = "\n"
5195f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"Usage:  " MYNAME " %s [PARAMS] INFILE [OUTFILE]\n"
52015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"\n"
5215f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"Where INFILE is a\n"
5225f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"\n"
523c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  public key (.vbpubk); OUTFILE is a keyblock\n"
524c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  raw firmware blob (FW_MAIN_A/B); OUTFILE is a VBLOCK_A/B\n"
5255f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  complete firmware image (bios.bin)\n"
5265f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  raw linux kernel; OUTFILE is a kernel partition image\n"
5275f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  kernel partition image (/dev/sda2, /dev/mmcblk0p2)\n";
5285f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
529c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardsonstatic const char usage_pubkey[] = "\n"
530c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"-----------------------------------------------------------------\n"
531c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"To sign a public key / create a new keyblock:\n"
532c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"\n"
533c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"Required PARAMS:\n"
534c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  [--datapubkey]   INFILE          The public key to wrap\n"
535c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  [--outfile]      OUTFILE         The resulting keyblock\n"
536c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"\n"
537c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"Optional PARAMS:\n"
538c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  A private signing key, specified as either\n"
539c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"    -s|--signprivate FILE.vbprivk  Signing key in .vbprivk format\n"
540c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  Or\n"
541c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"    --pem_signpriv   FILE.pem      Signing key in PEM format...\n"
542c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"    --pem_algo       NUM           AND the algorithm to use (0 - %d)\n"
543c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"\n"
544c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  If a signing key is not given, the keyblock will not be signed (duh)."
545c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"\n\n"
546c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"And these, too:\n\n"
547c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  -f|--flags       NUM             Flags specifying use conditions\n"
548c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  --pem_external   PROGRAM"
549c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"         External program to compute the signature\n"
550c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"                                     (requires a PEM signing key)\n";
551c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
552c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardsonstatic const char usage_fw_main[] = "\n"
553c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"-----------------------------------------------------------------\n"
554c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"To sign a raw firmware blob (FW_MAIN_A/B):\n"
555c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"\n"
556c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"Required PARAMS:\n"
557c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  -s|--signprivate FILE.vbprivk    The private firmware data key\n"
558c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  -b|--keyblock    FILE.keyblock   The keyblock containing the\n"
559c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"                                     public firmware data key\n"
560c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  -k|--kernelkey   FILE.vbpubk     The public kernel subkey\n"
561c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  -v|--version     NUM             The firmware version number\n"
562c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  [--fv]           INFILE"
563c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"          The raw firmware blob (FW_MAIN_A/B)\n"
564c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  [--outfile]      OUTFILE         Output VBLOCK_A/B\n"
565c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"\n"
566c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"Optional PARAMS:\n"
567c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	"  -f|--flags       NUM             The preamble flags value"
568c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	" (default is 0)\n";
569c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
5705f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonstatic const char usage_bios[] = "\n"
5715f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"-----------------------------------------------------------------\n"
5725f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"To sign a complete firmware image (bios.bin):\n"
57315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"\n"
5745f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"Required PARAMS:\n"
57515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"  -s|--signprivate FILE.vbprivk    The private firmware data key\n"
57615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"  -b|--keyblock    FILE.keyblock   The keyblock containing the\n"
57715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"                                     public firmware data key\n"
57815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"  -k|--kernelkey   FILE.vbpubk     The public kernel subkey\n"
5795f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  [--infile]       INFILE          Input firmware image (modified\n"
5805f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     in place if no OUTFILE given)\n"
58115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"\n"
58215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"These are required if the A and B firmware differ:\n"
58315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"  -S|--devsign     FILE.vbprivk    The DEV private firmware data key\n"
58415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"  -B|--devkeyblock FILE.keyblock   The keyblock containing the\n"
58515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"                                     DEV public firmware data key\n"
58615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"\n"
5875f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"Optional PARAMS:\n"
58808efd1ee358c546c968918a24b45219d7003cecaBill Richardson	"  -v|--version     NUM             The firmware version number"
58908efd1ee358c546c968918a24b45219d7003cecaBill Richardson	" (default %d)\n"
59008efd1ee358c546c968918a24b45219d7003cecaBill Richardson	"  -f|--flags       NUM             The preamble flags value"
59108efd1ee358c546c968918a24b45219d7003cecaBill Richardson	" (default is\n"
59208efd1ee358c546c968918a24b45219d7003cecaBill Richardson	"                                     unchanged, or 0 if unknown)\n"
59315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"  -d|--loemdir     DIR             Local OEM output vblock directory\n"
59415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"  -l|--loemid      STRING          Local OEM vblock suffix\n"
5955f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  [--outfile]      OUTFILE         Output firmware image\n";
5965f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
5975f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonstatic const char usage_new_kpart[] = "\n"
5985f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"-----------------------------------------------------------------\n"
5995f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"To create a new kernel parition image (/dev/sda2, /dev/mmcblk0p2):\n"
6005f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"\n"
6015f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"Required PARAMS:\n"
6025f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  -s|--signprivate FILE.vbprivk"
6035f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"    The private key to sign the kernel blob\n"
6045f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  -b|--keyblock    FILE.keyblock   The keyblock containing the public\n"
6055f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     key to verify the kernel blob\n"
6065f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  -v|--version     NUM             The kernel version number\n"
6075f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  --bootloader     FILE            Bootloader stub\n"
6085f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  --config         FILE            The kernel commandline file\n"
6095f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  --arch           ARCH            The CPU architecture (one of\n"
6105f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     x86|amd64, arm|aarch64, mips)\n"
6115f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  [--vmlinuz]      INFILE          Linux kernel bzImage file\n"
6125f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
6135f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"\n"
6145f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"Optional PARAMS:\n"
6155f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  --kloadaddr      NUM"
6165f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"             RAM address to load the kernel body\n"
6175f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     (default 0x%x)\n"
6185f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  --pad            NUM             The vblock padding size in bytes\n"
6195f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     (default 0x%x)\n"
6205f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	" --vblockonly                      Emit just the vblock (requires a\n"
62180e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh	"                                     distinct outfile)\n"
62280e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh	"  -f|--flags       NUM             The preamble flags value\n";
6235f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
6245f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonstatic const char usage_old_kpart[] = "\n"
6255f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"-----------------------------------------------------------------\n"
6265f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"To resign an existing kernel parition (/dev/sda2, /dev/mmcblk0p2):\n"
6275f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"\n"
6285f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"Required PARAMS:\n"
6295f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  -s|--signprivate FILE.vbprivk"
6305f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"    The private key to sign the kernel blob\n"
6315f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  [--infile]       INFILE          Input kernel partition (modified\n"
6325f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     in place if no OUTFILE given)\n"
6335f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"\n"
6345f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"Optional PARAMS:\n"
6355f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  -b|--keyblock    FILE.keyblock   The keyblock containing the public\n"
6365f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     key to verify the kernel blob\n"
6375f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  -v|--version     NUM             The kernel version number\n"
6385f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  --config         FILE            The kernel commandline file\n"
6395f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  --pad            NUM             The vblock padding size in bytes\n"
6405f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     (default 0x%x)\n"
6415f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  [--outfile]      OUTFILE         Output kernel partition or vblock\n"
6425f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"  --vblockonly                     Emit just the vblock (requires a\n"
6435f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	"                                     distinct OUTFILE)\n"
64480e779d50b52cd97c9d5896a3b75fa8118ee488fFurquan Shaikh	"  -f|--flags       NUM             The preamble flags value\n"
64515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	"\n";
64615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
647779796f57e1e0236ea502248ede2cbea986fca21Bill Richardsonstatic void print_help(const char *prog)
64815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
6495f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	printf(usage, prog);
650c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	printf(usage_pubkey, kNumAlgorithms - 1);
651c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	puts(usage_fw_main);
6525f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	printf(usage_bios, option.version);
6535f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	printf(usage_new_kpart, option.kloadaddr, option.padding);
6545f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	printf(usage_old_kpart, option.padding);
65515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
65615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
6575f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsonenum no_short_opts {
6585f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	OPT_FV = 1000,
6595f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	OPT_INFILE,			/* aka "--vmlinuz" */
6605f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	OPT_OUTFILE,
6615f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	OPT_BOOTLOADER,
6625f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	OPT_CONFIG,
6635f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	OPT_ARCH,
6645f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	OPT_KLOADADDR,
6655f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	OPT_PADDING,
666c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	OPT_PEM_SIGNPRIV,
667c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	OPT_PEM_ALGO,
668c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	OPT_PEM_EXTERNAL,
6695f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson};
6705f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
67115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonstatic const struct option long_opts[] = {
67215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	/* name    hasarg *flag  val */
6735f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"signprivate",  1, NULL, 's'},
6745f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"keyblock",     1, NULL, 'b'},
6755f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"kernelkey",    1, NULL, 'k'},
6765f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"devsign",      1, NULL, 'S'},
6775f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"devkeyblock",  1, NULL, 'B'},
6785f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"version",      1, NULL, 'v'},
6795f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"flags",        1, NULL, 'f'},
6805f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"loemdir",      1, NULL, 'd'},
6815f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"loemid",       1, NULL, 'l'},
6825f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"fv",           1, NULL, OPT_FV},
6835f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"infile",       1, NULL, OPT_INFILE},
6845f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"datapubkey",   1, NULL, OPT_INFILE},	/* alias */
6855f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"vmlinuz",      1, NULL, OPT_INFILE},	/* alias */
6865f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"outfile",      1, NULL, OPT_OUTFILE},
6875f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"bootloader",   1, NULL, OPT_BOOTLOADER},
6885f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"config",       1, NULL, OPT_CONFIG},
6895f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"arch",         1, NULL, OPT_ARCH},
6905f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"kloadaddr",    1, NULL, OPT_KLOADADDR},
6915f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"pad",          1, NULL, OPT_PADDING},
692c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	{"pem_signpriv", 1, NULL, OPT_PEM_SIGNPRIV},
693c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	{"pem_algo",     1, NULL, OPT_PEM_ALGO},
694c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	{"pem_external", 1, NULL, OPT_PEM_EXTERNAL},
6955f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"vblockonly",   0, &option.vblockonly, 1},
6965f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{"debug",        0, &debugging_enabled, 1},
6975f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	{NULL,           0, NULL, 0},
69815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson};
69915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonstatic char *short_opts = ":s:b:k:S:B:v:f:d:l:";
70015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
70115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardsonstatic int do_sign(int argc, char *argv[])
70215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson{
70315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	char *infile = 0;
7045f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int i;
7055f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int ifd = -1;
70615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	int errorcnt = 0;
70715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	struct futil_traverse_state_s state;
708b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson	uint8_t *buf;
709b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson	uint32_t buf_len;
7105f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	char *e = 0;
7115f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	enum futil_file_type type;
7125f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int inout_file_count = 0;
7135f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	int mapping;
71415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
71515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	opterr = 0;		/* quiet, you */
71615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	while ((i = getopt_long(argc, argv, short_opts, long_opts, 0)) != -1) {
71715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		switch (i) {
71815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 's':
71915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.signprivate = PrivateKeyRead(optarg);
72015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			if (!option.signprivate) {
72115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				fprintf(stderr, "Error reading %s\n", optarg);
72215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				errorcnt++;
72315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			}
72415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
72515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 'b':
72615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.keyblock = KeyBlockRead(optarg);
72715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			if (!option.keyblock) {
72815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				fprintf(stderr, "Error reading %s\n", optarg);
72915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				errorcnt++;
73015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			}
73115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
73215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 'k':
73315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.kernel_subkey = PublicKeyRead(optarg);
73415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			if (!option.kernel_subkey) {
73515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				fprintf(stderr, "Error reading %s\n", optarg);
73615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				errorcnt++;
73715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			}
73815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
73915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 'S':
74015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.devsignprivate = PrivateKeyRead(optarg);
74115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			if (!option.devsignprivate) {
74215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				fprintf(stderr, "Error reading %s\n", optarg);
74315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				errorcnt++;
74415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			}
74515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
74615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 'B':
74715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.devkeyblock = KeyBlockRead(optarg);
74815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			if (!option.devkeyblock) {
74915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				fprintf(stderr, "Error reading %s\n", optarg);
75015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				errorcnt++;
75115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			}
75215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
75315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 'v':
7545f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			option.version_specified = 1;
75515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.version = strtoul(optarg, &e, 0);
75615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			if (!*optarg || (e && *e)) {
75715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				fprintf(stderr,
75815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					"Invalid --version \"%s\"\n", optarg);
75915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				errorcnt++;
76015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			}
76115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
76215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
76315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 'f':
764a19b00dfd0c17681b71bd61994854dff3f3576a3Bill Richardson			option.flags_specified = 1;
76515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.flags = strtoul(optarg, &e, 0);
76615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			if (!*optarg || (e && *e)) {
76715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				fprintf(stderr,
76815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					"Invalid --flags \"%s\"\n", optarg);
76915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				errorcnt++;
77015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			}
771a19b00dfd0c17681b71bd61994854dff3f3576a3Bill Richardson			break;
77215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 'd':
77315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.loemdir = optarg;
77415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
77515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case 'l':
77615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			option.loemid = optarg;
77715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
778c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		case OPT_FV:
779c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			option.fv_specified = 1;
780c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			/* fallthrough */
7815f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		case OPT_INFILE:		/* aka "--vmlinuz" */
7825f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			inout_file_count++;
7835f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			infile = optarg;
7845f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			break;
7855f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		case OPT_OUTFILE:
7865f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			inout_file_count++;
7875f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			option.outfile = optarg;
7885f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			break;
7895f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		case OPT_BOOTLOADER:
7905f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			option.bootloader_data = ReadFile(
7915f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				optarg, &option.bootloader_size);
7925f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			if (!option.bootloader_data) {
7935f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				fprintf(stderr,
7945f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					"Error reading bootloader file: %s\n",
7955f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					strerror(errno));
7965f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				errorcnt++;
7975f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			}
7985f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			Debug("bootloader file size=0x%" PRIx64 "\n",
7995f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			      option.bootloader_size);
8005f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			break;
8015f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		case OPT_CONFIG:
8025f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			option.config_data = ReadConfigFile(
8035f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				optarg, &option.config_size);
8045f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			if (!option.config_data) {
8055f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				fprintf(stderr,
8065f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					"Error reading config file: %s\n",
8075f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					strerror(errno));
8085f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				errorcnt++;
8095f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			}
8105f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			break;
8115f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		case OPT_ARCH:
8125f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			/* check the first 3 characters to also match x86_64 */
8135f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			if ((!strncasecmp(optarg, "x86", 3)) ||
8145f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			    (!strcasecmp(optarg, "amd64")))
8155f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				option.arch = ARCH_X86;
8165f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			else if ((!strcasecmp(optarg, "arm")) ||
8175f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				 (!strcasecmp(optarg, "aarch64")))
8185f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				option.arch = ARCH_ARM;
8195f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			else if (!strcasecmp(optarg, "mips"))
8205f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				option.arch = ARCH_MIPS;
8215f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			else {
8225f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				fprintf(stderr,
8235f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					"Unknown architecture: \"%s\"\n",
8245f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					optarg);
8255f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				errorcnt++;
8265f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			}
8275f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			break;
8285f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		case OPT_KLOADADDR:
8295f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			option.kloadaddr = strtoul(optarg, &e, 0);
8305f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			if (!*optarg || (e && *e)) {
8315f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				fprintf(stderr,
8325f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					"Invalid --kloadaddr \"%s\"\n", optarg);
8335f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				errorcnt++;
8345f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			}
8355f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			break;
8365f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		case OPT_PADDING:
8375f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			option.padding = strtoul(optarg, &e, 0);
8385f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			if (!*optarg || (e && *e)) {
8395f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				fprintf(stderr,
8405f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					"Invalid --padding \"%s\"\n", optarg);
8415f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				errorcnt++;
8425f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			}
8435f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			break;
844c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		case OPT_PEM_SIGNPRIV:
845c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			option.pem_signpriv = optarg;
846c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			break;
847c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		case OPT_PEM_ALGO:
848c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			option.pem_algo_specified = 1;
849c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			option.pem_algo = strtoul(optarg, &e, 0);
850c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			if (!*optarg || (e && *e) ||
851c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			    (option.pem_algo >= kNumAlgorithms)) {
852c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				fprintf(stderr,
853c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson					"Invalid --pem_algo \"%s\"\n", optarg);
854c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				errorcnt++;
855c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			}
856c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			break;
857c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		case OPT_PEM_EXTERNAL:
858c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			option.pem_external = optarg;
859c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			break;
860c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson
86115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case '?':
86215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			if (optopt)
86315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson				fprintf(stderr, "Unrecognized option: -%c\n",
86415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson					optopt);
86515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			else
8665f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				fprintf(stderr, "Unrecognized option: %s\n",
8675f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson					argv[optind - 1]);
86815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			errorcnt++;
86915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
87015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		case ':':
87115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			fprintf(stderr, "Missing argument to -%c\n", optopt);
87215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			errorcnt++;
87315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			break;
8745f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		case 0:				/* handled option */
8755f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			break;
87615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		default:
8775f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			Debug("i=%d\n", i);
87815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson			DIE;
87915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		}
88015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
88115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
8825f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* If we don't have an input file already, we need one */
8835f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (!infile) {
8845f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		if (argc - optind <= 0) {
8855f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			errorcnt++;
8865f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			fprintf(stderr, "ERROR: missing input filename\n");
8875f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			goto done;
8885f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		} else {
8895f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			inout_file_count++;
8905f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			infile = argv[optind++];
8915f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		}
89215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
89315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
894b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson	/* Look for an output file if we don't have one, just in case. */
895b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson	if (!option.outfile && argc - optind > 0) {
896b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		inout_file_count++;
897b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		option.outfile = argv[optind++];
898b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson	}
899b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson
9005f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* What are we looking at? */
9012559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	if (futil_file_type(infile, &type)) {
9022559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		errorcnt++;
9032559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		goto done;
9042559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	}
9055f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
9065f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* We may be able to infer the type based on the other args */
9075f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (type == FILE_TYPE_UNKNOWN) {
9085f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		if (option.bootloader_data || option.config_data
9095f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		    || option.arch != ARCH_UNSPECIFIED)
9105f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			type = FILE_TYPE_RAW_KERNEL;
911c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		else if (option.kernel_subkey || option.fv_specified)
912c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			type = FILE_TYPE_RAW_FIRMWARE;
91315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
91415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
9152559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	Debug("type=%s\n", futil_file_type_str(type));
916b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson
9175f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	/* Check the arguments for the type of thing we want to sign */
9185f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	switch (type) {
9195f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_UNKNOWN:
92015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		fprintf(stderr,
9215f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			"Unable to determine the type of the input file\n");
9225f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt++;
9235f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		goto done;
924c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	case FILE_TYPE_PUBKEY:
925c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		option.create_new_outfile = 1;
926c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		if (option.signprivate && option.pem_signpriv) {
927c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			fprintf(stderr,
928c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				"Only one of --signprivate and --pem_signpriv"
929c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				" can be specified\n");
930c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			errorcnt++;
931c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		}
932c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		if ((option.signprivate && option.pem_algo_specified) ||
933c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		    (option.pem_signpriv && !option.pem_algo_specified)) {
934c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			fprintf(stderr, "--pem_algo must be used with"
935c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				" --pem_signpriv\n");
936c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			errorcnt++;
937c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		}
938c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		if (option.pem_external && !option.pem_signpriv) {
939c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			fprintf(stderr, "--pem_external must be used with"
940c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson				" --pem_signpriv\n");
941c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson			errorcnt++;
942c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		}
943c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		/* We'll wait to read the PEM file, since the external signer
944c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		 * may want to read it instead. */
945c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		break;
9465f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_KEYBLOCK:
9475f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Resigning a keyblock is kind of pointless.\n");
9485f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Just create a new one.\n");
9495f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt++;
9505f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		break;
9515f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_FW_PREAMBLE:
9525f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr,
9535f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			"%s IS a signature. Sign the firmware instead\n",
9545f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			infile);
9555f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		break;
9565f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_GBB:
9575f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "There's no way to sign a GBB\n");
95815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		errorcnt++;
95915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		break;
9605f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_BIOS_IMAGE:
9615f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_OLD_BIOS_IMAGE:
9625f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.signprivate, "signprivate");
9635f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.keyblock, "keyblock");
9645f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
96515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		break;
9665f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_KERN_PREAMBLE:
9675f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.signprivate, "signprivate");
968b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		if (option.vblockonly || inout_file_count > 1)
9695f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			option.create_new_outfile = 1;
9705f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		break;
971c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson	case FILE_TYPE_RAW_FIRMWARE:
972c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		option.create_new_outfile = 1;
973c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		errorcnt += no_opt_if(!option.signprivate, "signprivate");
974c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		errorcnt += no_opt_if(!option.keyblock, "keyblock");
975c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		errorcnt += no_opt_if(!option.kernel_subkey, "kernelkey");
976c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		errorcnt += no_opt_if(!option.version_specified, "version");
977c540f59be047d69251b7f9ce0637a8a0c6fe150fBill Richardson		break;
9785f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	case FILE_TYPE_RAW_KERNEL:
9795f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		option.create_new_outfile = 1;
9805f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.signprivate, "signprivate");
9815f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.keyblock, "keyblock");
9825f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.version_specified, "version");
9835f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.bootloader_data, "bootloader");
9845f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(!option.config_data, "config");
9855f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt += no_opt_if(option.arch == ARCH_UNSPECIFIED, "arch");
98615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		break;
9872559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson	case FILE_TYPE_CHROMIUMOS_DISK:
9882559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		fprintf(stderr, "Signing a %s is not yet supported\n",
9892559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson			futil_file_type_str(type));
9902559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		errorcnt++;
9912559338dbdacbcbd3ae426337403196135bbc7e8Bill Richardson		break;
99215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	default:
9935f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		DIE;
99415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
99515dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
996b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson	Debug("infile=%s\n", infile);
997b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson	Debug("inout_file_count=%d\n", inout_file_count);
998b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson	Debug("option.create_new_outfile=%d\n", option.create_new_outfile);
999b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson
1000b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson	/* Make sure we have an output file if one is needed */
10015f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (!option.outfile) {
1002b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		if (option.create_new_outfile) {
1003b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson			errorcnt++;
1004b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson			fprintf(stderr, "Missing output filename\n");
1005b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson			goto done;
10065f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		} else {
1007b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson			option.outfile = infile;
10085f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		}
100915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
101015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
10115f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	Debug("option.outfile=%s\n", option.outfile);
10125f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
10135f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (argc - optind > 0) {
1014b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson		errorcnt++;
10155f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "ERROR: too many arguments left over\n");
1016b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson	}
1017b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson
10185f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (errorcnt)
10195f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		goto done;
10205f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
102115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	memset(&state, 0, sizeof(state));
102215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	state.op = FUTIL_OP_SIGN;
102315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
10245f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (option.create_new_outfile) {
10255f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		/* The input is read-only, the output is write-only. */
10265f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		mapping = MAP_RO;
10275f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		state.in_filename = infile;
1028b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		Debug("open RO %s\n", infile);
10295f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		ifd = open(infile, O_RDONLY);
10305f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		if (ifd < 0) {
10315f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			errorcnt++;
10325f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			fprintf(stderr, "Can't open %s for reading: %s\n",
10335f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				infile, strerror(errno));
10345f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			goto done;
10355f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		}
10365f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	} else {
10375f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		/* We'll read-modify-write the output file */
10385f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		mapping = MAP_RW;
10395f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		state.in_filename = option.outfile;
10405f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		if (inout_file_count > 1)
10415f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			futil_copy_file_or_die(infile, option.outfile);
1042b406c1064b3a37002b3d4d953a4932628408f25bBill Richardson		Debug("open RW %s\n", option.outfile);
10435f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		ifd = open(option.outfile, O_RDWR);
10445f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		if (ifd < 0) {
10455f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			errorcnt++;
10465f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			fprintf(stderr, "Can't open %s for writing: %s\n",
10475f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson				option.outfile, strerror(errno));
10485f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			goto done;
10495f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		}
10505f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
10515f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
10525f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (0 != futil_map_file(ifd, mapping, &buf, &buf_len)) {
10535f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		errorcnt++;
10545f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		goto done;
10555f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	}
10565f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
10575f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	errorcnt += futil_traverse(buf, buf_len, &state, type);
1058b0f1cc5e22e87a3ef1655643116991673dd1b531Bill Richardson
10595f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	errorcnt += futil_unmap_file(ifd, MAP_RW, buf, buf_len);
106015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
10615f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardsondone:
10625f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (ifd >= 0 && close(ifd)) {
106315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		errorcnt++;
10645f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Error when closing ifd: %s\n",
10655f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson			strerror(errno));
106615dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	}
106715dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
106815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (option.signprivate)
106915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		free(option.signprivate);
107015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (option.keyblock)
107115dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		free(option.keyblock);
107215dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	if (option.kernel_subkey)
107315dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson		free(option.kernel_subkey);
107415dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
10755f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson	if (errorcnt)
10765f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		fprintf(stderr, "Use --help for usage instructions\n");
10775f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson
107815dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson	return !!errorcnt;
107915dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson}
108015dc6fc5eabc1b1756aca1dbed38cb9d26259bf2Bill Richardson
1081779796f57e1e0236ea502248ede2cbea986fca21Bill RichardsonDECLARE_FUTIL_COMMAND(sign, do_sign,
10821eae873b6194db25781233d7a4aaee6a34160eecBill Richardson		      VBOOT_VERSION_ALL,
10835f2696d2ff09d7c9c5c6125e9f0a62e56e54e0b8Bill Richardson		      "Sign / resign various binary components",
1084779796f57e1e0236ea502248ede2cbea986fca21Bill Richardson		      print_help);
1085