futility: rolled back vbutil_kernel change

When disabling verity with make_dev_ssh.sh, a bug in
vbutil_kernel caused the re-signed kernel size to be the entire
kernel partition instead of just the necessary bits. Until we can
improve the test coverage, I'm rolling back the changes that
introduced this bug.

BUG=chromium:418647
BRANCH=ToT
TEST=manual

Created a new test image with these changes. You can install it
and disable dm-verity and it works (although there seems to be an
unrelated browser startup issue on ToT).

Original-Change-Id: I48e8427b05e191c9894c42056429a79d57bfc78d
Signed-off-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/220935
Reviewed-by: Randall Spangler <rspangler@chromium.org>
(cherry picked from commit f1dba02034fba650c84cec52630755cd3c063e88)

Change-Id: Id008ce5d467c87949885de960e8dabb8d8461e7f
Reviewed-on: https://chromium-review.googlesource.com/224983
Commit-Queue: Bill Richardson <wfrichar@chromium.org>
Tested-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
diff --git a/Makefile b/Makefile
index b26e2ab..d5f0088 100644
--- a/Makefile
+++ b/Makefile
@@ -545,6 +545,7 @@
 	futility/cmd_sign.c \
 	futility/cmd_vbutil_firmware.c \
 	futility/cmd_vbutil_kernel.c \
+	futility/cmd_vbutil_kernel0.c \
 	futility/cmd_vbutil_key.c \
 	futility/cmd_vbutil_keyblock.c \
 	futility/cmd_verify_kernel.c \
diff --git a/futility/cmd_vbutil_kernel.c b/futility/cmd_vbutil_kernel.c
index 92061f4..4886607 100644
--- a/futility/cmd_vbutil_kernel.c
+++ b/futility/cmd_vbutil_kernel.c
@@ -477,6 +477,7 @@
 				Fatal("Error reading key block.\n");
 		}
 
+		/* Reuse previous body size */
 		vblock_data = SignKernelBlob(kblob_data, kblob_size, opt_pad,
 					     version, kernel_body_load_address,
 					     t_keyblock ? t_keyblock : keyblock,
@@ -526,6 +527,6 @@
 	return 1;
 }
 
-DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel2,
+DECLARE_FUTIL_COMMAND(vbutil_kernel2, do_vbutil_kernel2,
 		      "Creates, signs, and verifies the kernel partition",
 		      print_help);
diff --git a/futility/cmd_vbutil_kernel0.c b/futility/cmd_vbutil_kernel0.c
new file mode 100644
index 0000000..855c7a5
--- /dev/null
+++ b/futility/cmd_vbutil_kernel0.c
@@ -0,0 +1,974 @@
+/* Copyright 2012 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Verified boot kernel utility
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <inttypes.h>		/* For PRIu64 */
+#include <sys/ioctl.h>
+#include <linux/fs.h>		/* For BLKGETSIZE64 */
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "cryptolib.h"
+#include "futility.h"
+#include "host_common.h"
+#include "kernel_blob.h"
+#include "util_misc.h"
+#include "vboot_common.h"
+
+/* Global opts */
+static int opt_verbose;
+static int opt_vblockonly;
+static uint64_t opt_pad = 65536;
+
+/* Command line options */
+enum {
+	OPT_MODE_PACK = 1000,
+	OPT_MODE_REPACK,
+	OPT_MODE_VERIFY,
+	OPT_ARCH,
+	OPT_OLDBLOB,
+	OPT_KLOADADDR,
+	OPT_KEYBLOCK,
+	OPT_SIGNPUBKEY,
+	OPT_SIGNPRIVATE,
+	OPT_VERSION,
+	OPT_VMLINUZ,
+	OPT_BOOTLOADER,
+	OPT_CONFIG,
+	OPT_VBLOCKONLY,
+	OPT_PAD,
+	OPT_VERBOSE,
+	OPT_MINVERSION,
+};
+
+static const struct option long_opts[] = {
+	{"pack", 1, 0, OPT_MODE_PACK},
+	{"repack", 1, 0, OPT_MODE_REPACK},
+	{"verify", 1, 0, OPT_MODE_VERIFY},
+	{"arch", 1, 0, OPT_ARCH},
+	{"oldblob", 1, 0, OPT_OLDBLOB},
+	{"kloadaddr", 1, 0, OPT_KLOADADDR},
+	{"keyblock", 1, 0, OPT_KEYBLOCK},
+	{"signpubkey", 1, 0, OPT_SIGNPUBKEY},
+	{"signprivate", 1, 0, OPT_SIGNPRIVATE},
+	{"version", 1, 0, OPT_VERSION},
+	{"minversion", 1, 0, OPT_MINVERSION},
+	{"vmlinuz", 1, 0, OPT_VMLINUZ},
+	{"bootloader", 1, 0, OPT_BOOTLOADER},
+	{"config", 1, 0, OPT_CONFIG},
+	{"vblockonly", 0, 0, OPT_VBLOCKONLY},
+	{"pad", 1, 0, OPT_PAD},
+	{"verbose", 0, &opt_verbose, 1},
+	{"debug", 0, &debugging_enabled, 1},
+	{NULL, 0, 0, 0}
+};
+
+
+
+static const char usage[] =
+	"\n"
+	"Usage:  " MYNAME " %s --pack <file> [PARAMETERS]\n"
+	"\n"
+	"  Required parameters:\n"
+	"    --keyblock <file>         Key block in .keyblock format\n"
+	"    --signprivate <file>      Private key to sign kernel data,\n"
+	"                                in .vbprivk format\n"
+	"    --version <number>        Kernel version\n"
+	"    --vmlinuz <file>          Linux kernel bzImage file\n"
+	"    --bootloader <file>       Bootloader stub\n"
+	"    --config <file>           Command line file\n"
+	"    --arch <arch>             Cpu architecture (default x86)\n"
+	"\n"
+	"  Optional:\n"
+	"    --kloadaddr <address>     Assign kernel body load address\n"
+	"    --pad <number>            Verification padding size in bytes\n"
+	"    --vblockonly              Emit just the verification blob\n"
+	"\nOR\n\n"
+	"Usage:  " MYNAME " %s --repack <file> [PARAMETERS]\n"
+	"\n"
+	"  Required parameters:\n"
+	"    --signprivate <file>      Private key to sign kernel data,\n"
+	"                                in .vbprivk format\n"
+	"    --oldblob <file>          Previously packed kernel blob\n"
+	"                                (including verfication blob)\n"
+	"\n"
+	"  Optional:\n"
+	"    --keyblock <file>         Key block in .keyblock format\n"
+	"    --config <file>           New command line file\n"
+	"    --version <number>        Kernel version\n"
+	"    --kloadaddr <address>     Assign kernel body load address\n"
+	"    --pad <number>            Verification blob size in bytes\n"
+	"    --vblockonly              Emit just the verification blob\n"
+	"\nOR\n\n"
+	"Usage:  " MYNAME " %s --verify <file> [PARAMETERS]\n"
+	"\n"
+	"  Optional:\n"
+	"    --signpubkey <file>"
+	"       Public key to verify kernel keyblock,\n"
+	"                                in .vbpubk format\n"
+	"    --verbose                 Print a more detailed report\n"
+	"    --keyblock <file>         Outputs the verified key block,\n"
+	"                                in .keyblock format\n"
+	"    --pad <number>            Verification padding size in bytes\n"
+	"    --minversion <number>     Minimum combined kernel key version\n"
+	"                              and kernel version\n"
+	"\n";
+
+
+/* Print help and return error */
+static void print_help(const char *progname)
+{
+	printf(usage, progname, progname, progname);
+}
+
+static void Fatal(const char *format, ...)
+{
+	va_list ap;
+	va_start(ap, format);
+	fprintf(stderr, "ERROR: ");
+	vfprintf(stderr, format, ap);
+	va_end(ap);
+	exit(1);
+}
+
+/* Return an explanation when fread() fails. */
+static const char *error_fread(FILE *fp)
+{
+	const char *retval = "beats me why";
+	if (feof(fp))
+		retval = "EOF";
+	else if (ferror(fp))
+		retval = strerror(errno);
+	clearerr(fp);
+	return retval;
+}
+
+/* Return the smallest integral multiple of [alignment] that is equal
+ * to or greater than [val]. Used to determine the number of
+ * pages/sectors/blocks/whatever needed to contain [val]
+ * items/bytes/etc. */
+static uint64_t roundup(uint64_t val, uint64_t alignment)
+{
+	uint64_t rem = val % alignment;
+	if (rem)
+		return val + (alignment - rem);
+	return val;
+}
+
+/* Match regexp /\b--\b/ to delimit the start of the kernel commandline. If we
+ * don't find one, we'll use the whole thing. */
+static unsigned int find_cmdline_start(char *input, unsigned int max_len)
+{
+	int start = 0;
+	int i;
+	for (i = 0; i < max_len - 1 && input[i]; i++) {
+		if ('-' == input[i] && '-' == input[i + 1]) {
+			if ((i == 0 || ' ' == input[i - 1]) &&
+			    (i + 2 >= max_len || ' ' == input[i + 2])) {
+				/* found "--" with nothing before or after it */
+				start = i + 2;	/* hope for a trailing '\0' */
+				break;
+			}
+		}
+	}
+	while (' ' == input[start])	/* skip leading spaces */
+		start++;
+
+	return start;
+}
+
+/****************************************************************************/
+/* Here are globals containing all the bits & pieces I'm working on. */
+
+/* The individual parts that go into the kernel blob */
+static uint8_t *g_kernel_data;
+static uint64_t g_kernel_size;
+static uint8_t *g_param_data;
+static uint64_t g_param_size;
+static uint8_t *g_config_data;
+static uint64_t g_config_size;
+static uint8_t *g_bootloader_data;
+static uint64_t g_bootloader_size;
+static uint64_t g_bootloader_address;
+
+/* The individual parts of the verification blob (including the data that
+ * immediately follows the headers) */
+static VbKeyBlockHeader *g_keyblock;
+static VbKernelPreambleHeader *g_preamble;
+
+/****************************************************************************/
+
+/*
+ * Read the kernel command line from a file. Get rid of \n characters along
+ * the way and verify that the line fits into a 4K buffer.
+ *
+ * Return the buffer contaning the line on success (and set the line length
+ * using the passed in parameter), or NULL in case something goes wrong.
+ */
+static uint8_t *sReadConfigFile(const char *config_file, uint64_t *config_size)
+{
+	uint8_t *config_buf;
+	int ii;
+
+	config_buf = ReadFile(config_file, config_size);
+	Debug(" config file size=0x%" PRIx64 "\n", *config_size);
+	if (CROS_CONFIG_SIZE <= *config_size) {	/* room for trailing '\0' */
+		VbExError("Config file %s is too large (>= %d bytes)\n",
+			  config_file, CROS_CONFIG_SIZE);
+		return NULL;
+	}
+
+	/* Replace newlines with spaces */
+	for (ii = 0; ii < *config_size; ii++)
+		if ('\n' == config_buf[ii])
+			config_buf[ii] = ' ';
+
+	return config_buf;
+}
+
+/* Offset of kernel command line string from start of packed kernel blob */
+static uint64_t CmdLineOffset(VbKernelPreambleHeader *preamble)
+{
+	return preamble->bootloader_address - preamble->body_load_address -
+	    CROS_CONFIG_SIZE - CROS_PARAMS_SIZE;
+}
+
+/* This initializes g_vmlinuz and g_param from a standard vmlinuz file.
+ * It returns 0 on error. */
+static int ImportVmlinuzFile(const char *vmlinuz_file, enum arch_t arch,
+			     uint64_t kernel_body_load_address)
+{
+	uint8_t *kernel_buf;
+	uint64_t kernel_size;
+	uint64_t kernel32_start = 0;
+	uint64_t kernel32_size = 0;
+	struct linux_kernel_params *params = NULL, *lh = NULL;
+
+	/* Read the kernel */
+	Debug("Reading %s\n", vmlinuz_file);
+	kernel_buf = ReadFile(vmlinuz_file, &kernel_size);
+	if (!kernel_buf)
+		return 0;
+	Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
+	if (!kernel_size)
+		Fatal("Empty kernel file\n");
+
+	/* Go ahead and allocate the param region anyway. I don't think we need
+	 * it for non-x86, but let's keep it for now. */
+	g_param_size = CROS_PARAMS_SIZE;
+	g_param_data = VbExMalloc(g_param_size);
+	Memset(g_param_data, 0, g_param_size);
+
+	/* Unless we're handling x86, the kernel is the kernel; we're done. */
+	if (arch != ARCH_X86) {
+		g_kernel_data = kernel_buf;
+		g_kernel_size = kernel_size;
+		return 1;
+	}
+
+	/* The first part of the x86 vmlinuz is a header, followed by a
+	 * real-mode boot stub.  We only want the 32-bit part. */
+	lh = (struct linux_kernel_params *)kernel_buf;
+	kernel32_start = (lh->setup_sects + 1) << 9;
+	if (kernel32_start >= kernel_size)
+		Fatal("Malformed kernel\n");
+	kernel32_size = kernel_size - kernel32_start;
+
+	Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
+	Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
+
+	/* Keep just the 32-bit kernel. */
+	if (kernel32_size) {
+		g_kernel_size = kernel32_size;
+		g_kernel_data = VbExMalloc(g_kernel_size);
+		Memcpy(g_kernel_data, kernel_buf + kernel32_start,
+		       kernel32_size);
+	}
+
+	/* Copy the original zeropage data from kernel_buf into g_param_data,
+	 * then tweak a few fields for our purposes */
+	params = (struct linux_kernel_params *)(g_param_data);
+	Memcpy(&(params->setup_sects), &(lh->setup_sects),
+	       offsetof(struct linux_kernel_params, e820_entries)
+	       - offsetof(struct linux_kernel_params, setup_sects));
+	params->boot_flag = 0;
+	params->ramdisk_image = 0;	/* we don't support initrd */
+	params->ramdisk_size = 0;
+	params->type_of_loader = 0xff;
+	/* We need to point to the kernel commandline arg. On disk, it will come
+	 *  right after the 32-bit part of the kernel. */
+	params->cmd_line_ptr = kernel_body_load_address +
+	    roundup(kernel32_size, CROS_ALIGN) +
+	    find_cmdline_start((char *)g_config_data, g_config_size);
+	Debug(" cmdline_addr=0x%x\n", params->cmd_line_ptr);
+	Debug(" version=0x%x\n", params->version);
+	Debug(" kernel_alignment=0x%x\n", params->kernel_alignment);
+	Debug(" relocatable_kernel=0x%x\n", params->relocatable_kernel);
+	/* A fake e820 memory map with 2 entries */
+	params->n_e820_entry = 2;
+	params->e820_entries[0].start_addr = 0x00000000;
+	params->e820_entries[0].segment_size = 0x00001000;
+	params->e820_entries[0].segment_type = E820_TYPE_RAM;
+	params->e820_entries[1].start_addr = 0xfffff000;
+	params->e820_entries[1].segment_size = 0x00001000;
+	params->e820_entries[1].segment_type = E820_TYPE_RESERVED;
+
+	/* done */
+	free(kernel_buf);
+	return 1;
+}
+
+/* This returns just the kernel blob, with the verification blob separated
+ * and copied to new memory in g_keyblock and g_preamble. */
+static uint8_t *ReadOldBlobFromFileOrDie(const char *filename,
+					 uint64_t *size_ptr)
+{
+	FILE *fp = NULL;
+	struct stat statbuf;
+	VbKeyBlockHeader *key_block;
+	VbKernelPreambleHeader *preamble;
+	uint64_t now = 0;
+	uint8_t *buf;
+	uint8_t *kernel_blob_data;
+	uint64_t kernel_blob_size;
+	uint64_t file_size = 0;
+
+	if (0 != stat(filename, &statbuf))
+		Fatal("Unable to stat %s: %s\n", filename, strerror(errno));
+
+	if (S_ISBLK(statbuf.st_mode)) {
+		int fd = open(filename, O_RDONLY);
+		if (fd >= 0) {
+			ioctl(fd, BLKGETSIZE64, &file_size);
+			close(fd);
+		}
+	} else {
+		file_size = statbuf.st_size;
+	}
+	Debug("%s size is 0x%" PRIx64 "\n", filename, file_size);
+	if (file_size < opt_pad)
+		Fatal("%s is too small to be a valid kernel blob\n");
+
+	Debug("Reading %s\n", filename);
+	fp = fopen(filename, "rb");
+	if (!fp)
+		Fatal("Unable to open file %s: %s\n", filename,
+		      strerror(errno));
+
+	buf = VbExMalloc(opt_pad);
+	if (1 != fread(buf, opt_pad, 1, fp))
+		Fatal("Unable to read header from %s: %s\n", filename,
+		      error_fread(fp));
+
+	/* Sanity-check the key_block */
+	key_block = (VbKeyBlockHeader *) buf;
+	Debug("Keyblock is 0x%" PRIx64 " bytes\n", key_block->key_block_size);
+	now += key_block->key_block_size;
+	if (now > file_size)
+		Fatal("key_block_size advances past the end of the blob\n");
+	if (now > opt_pad)
+		Fatal("key_block_size advances past %" PRIu64 " byte padding\n",
+		      opt_pad);
+	/* LGTM */
+	g_keyblock = (VbKeyBlockHeader *) VbExMalloc(key_block->key_block_size);
+	Memcpy(g_keyblock, key_block, key_block->key_block_size);
+
+	/* And the preamble */
+	preamble = (VbKernelPreambleHeader *) (buf + now);
+	Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
+	now += preamble->preamble_size;
+	if (now > file_size)
+		Fatal("preamble_size advances past the end of the blob\n");
+	if (now > opt_pad)
+		Fatal("preamble_size advances past %" PRIu64 " byte padding\n",
+		      opt_pad);
+	/* LGTM */
+	Debug(" kernel_version = %d\n", preamble->kernel_version);
+	Debug(" bootloader_address = 0x%" PRIx64 "\n",
+	      preamble->bootloader_address);
+	Debug(" bootloader_size = 0x%" PRIx64 "\n", preamble->bootloader_size);
+	Debug(" kern_blob_size = 0x%" PRIx64 "\n",
+	      preamble->body_signature.data_size);
+	g_preamble =
+	    (VbKernelPreambleHeader *) VbExMalloc(preamble->preamble_size);
+	Memcpy(g_preamble, preamble, preamble->preamble_size);
+
+	/* Now for the kernel blob */
+	Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
+	if (0 != fseek(fp, now, SEEK_SET))
+		Fatal("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now,
+		      filename, strerror(errno));
+
+	/* Sanity check */
+	kernel_blob_size = file_size - now;
+	if (!kernel_blob_size)
+		Fatal("No kernel blob found\n");
+	if (kernel_blob_size < preamble->body_signature.data_size)
+		fprintf(stderr,
+			"Warning: kernel file only has 0x%" PRIx64 " bytes\n",
+			kernel_blob_size);
+	kernel_blob_data = VbExMalloc(kernel_blob_size);
+
+	/* Read it in */
+	if (1 != fread(kernel_blob_data, kernel_blob_size, 1, fp))
+		Fatal("Unable to read kernel blob from %s: %s\n", filename,
+		      error_fread(fp));
+
+	/* Done */
+	VbExFree(buf);
+
+	if (size_ptr)
+		*size_ptr = kernel_blob_size;
+
+	return kernel_blob_data;
+}
+
+/* Split a kernel blob into separate g_kernel, g_param, g_config, and
+ * g_bootloader parts. */
+static void UnpackKernelBlob(uint8_t *kernel_blob_data,
+			     uint64_t kernel_blob_size)
+{
+
+	uint64_t k_blob_size = g_preamble->body_signature.data_size;
+	uint64_t k_blob_ofs = 0;
+	uint64_t b_size = g_preamble->bootloader_size;
+	uint64_t b_ofs = k_blob_ofs + g_preamble->bootloader_address -
+	    g_preamble->body_load_address;
+	uint64_t p_ofs = b_ofs - CROS_CONFIG_SIZE;
+	uint64_t c_ofs = p_ofs - CROS_PARAMS_SIZE;
+
+	Debug("k_blob_size    = 0x%" PRIx64 "\n", k_blob_size);
+	Debug("k_blob_ofs     = 0x%" PRIx64 "\n", k_blob_ofs);
+	Debug("b_size         = 0x%" PRIx64 "\n", b_size);
+	Debug("b_ofs          = 0x%" PRIx64 "\n", b_ofs);
+	Debug("p_ofs          = 0x%" PRIx64 "\n", p_ofs);
+	Debug("c_ofs          = 0x%" PRIx64 "\n", c_ofs);
+
+	g_kernel_size = c_ofs;
+	g_kernel_data = VbExMalloc(g_kernel_size);
+	Memcpy(g_kernel_data, kernel_blob_data, g_kernel_size);
+
+	g_param_size = CROS_PARAMS_SIZE;
+	g_param_data = VbExMalloc(g_param_size);
+	Memcpy(g_param_data, kernel_blob_data + p_ofs, g_param_size);
+
+	g_config_size = CROS_CONFIG_SIZE;
+	g_config_data = VbExMalloc(g_config_size);
+	Memcpy(g_config_data, kernel_blob_data + c_ofs, g_config_size);
+
+	g_bootloader_size = b_size;
+	g_bootloader_data = VbExMalloc(g_bootloader_size);
+	Memcpy(g_bootloader_data, kernel_blob_data + b_ofs, g_bootloader_size);
+}
+
+/****************************************************************************/
+
+static uint8_t *CreateKernBlob(uint64_t kernel_body_load_address,
+			       enum arch_t arch, uint64_t *size_ptr)
+{
+	uint8_t *kern_blob;
+	uint64_t kern_blob_size;
+	uint64_t now;
+	uint64_t bootloader_size = roundup(g_bootloader_size, CROS_ALIGN);
+
+	/* Put the kernel blob together */
+	kern_blob_size = roundup(g_kernel_size, CROS_ALIGN) +
+	    CROS_CONFIG_SIZE + CROS_PARAMS_SIZE + bootloader_size;
+	Debug("kern_blob_size=0x%" PRIx64 "\n", kern_blob_size);
+	kern_blob = VbExMalloc(kern_blob_size);
+	Memset(kern_blob, 0, kern_blob_size);
+	now = 0;
+
+	Debug("kernel goes at kern_blob+0x%" PRIx64 "\n", now);
+
+	Memcpy(kern_blob + now, g_kernel_data, g_kernel_size);
+	now += roundup(g_kernel_size, CROS_ALIGN);
+
+	Debug("config goes at kern_blob+0x%" PRIx64 "\n", now);
+	if (g_config_size)
+		Memcpy(kern_blob + now, g_config_data, g_config_size);
+	now += CROS_CONFIG_SIZE;
+
+	Debug("params goes at kern_blob+0x%" PRIx64 "\n", now);
+	if (g_param_size)
+		Memcpy(kern_blob + now, g_param_data, g_param_size);
+	now += CROS_PARAMS_SIZE;
+
+	Debug("bootloader goes at kern_blob+0x%" PRIx64 "\n", now);
+	g_bootloader_address = kernel_body_load_address + now;
+	Debug(" bootloader_address=0x%" PRIx64 "\n", g_bootloader_address);
+	Debug(" bootloader_size=0x%" PRIx64 "\n", bootloader_size);
+	if (bootloader_size)
+		Memcpy(kern_blob + now, g_bootloader_data, g_bootloader_size);
+	now += bootloader_size;
+	Debug("end of kern_blob at kern_blob+0x%" PRIx64 "\n", now);
+
+	/* Done */
+	if (size_ptr)
+		*size_ptr = kern_blob_size;
+
+	return kern_blob;
+}
+
+static int Pack(const char *outfile,
+		uint8_t *kernel_blob,
+		uint64_t kernel_size,
+		int version,
+		uint64_t kernel_body_load_address,
+		VbPrivateKey *signpriv_key)
+{
+	VbSignature *body_sig;
+	FILE *f;
+	uint64_t i;
+	uint64_t written = 0;
+
+	/* Sign the kernel data */
+	body_sig = CalculateSignature(kernel_blob, kernel_size, signpriv_key);
+	if (!body_sig)
+		Fatal("Error calculating body signature\n");
+
+	/* Create preamble */
+	g_preamble = CreateKernelPreamble(version,
+					  kernel_body_load_address,
+					  g_bootloader_address,
+					  roundup(g_bootloader_size,
+						  CROS_ALIGN), body_sig,
+					  opt_pad - g_keyblock->key_block_size,
+					  signpriv_key);
+	if (!g_preamble) {
+		VbExError("Error creating preamble.\n");
+		return 1;
+	}
+	/* Write the output file */
+	Debug("writing %s...\n", outfile);
+	f = fopen(outfile, "wb");
+	if (!f) {
+		VbExError("Can't open output file %s\n", outfile);
+		return 1;
+	}
+	Debug("0x%" PRIx64 " bytes of key_block\n", g_keyblock->key_block_size);
+	Debug("0x%" PRIx64 " bytes of preamble\n", g_preamble->preamble_size);
+	i = ((1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f)) ||
+	     (1 != fwrite(g_preamble, g_preamble->preamble_size, 1, f)));
+	if (i) {
+		VbExError("Can't write output file %s\n", outfile);
+		fclose(f);
+		unlink(outfile);
+		return 1;
+	}
+	written += g_keyblock->key_block_size;
+	written += g_preamble->preamble_size;
+
+	if (!opt_vblockonly) {
+		Debug("0x%" PRIx64 " bytes of kern_blob\n", kernel_size);
+		i = (1 != fwrite(kernel_blob, kernel_size, 1, f));
+		if (i) {
+			fclose(f);
+			unlink(outfile);
+			Fatal("Can't write output file %s\n", outfile);
+		}
+		written += kernel_size;
+	}
+	Debug("0x%" PRIx64 " bytes total\n", written);
+	fclose(f);
+
+	/* Success */
+	return 0;
+}
+
+static int Verify(uint8_t *kernel_blob,
+		  uint64_t kernel_size,
+		  VbPublicKey *signpub_key,
+		  const char *keyblock_outfile,
+		  uint64_t min_version)
+{
+	VbPublicKey *data_key;
+	RSAPublicKey *rsa;
+
+	if (0 != KeyBlockVerify(g_keyblock, g_keyblock->key_block_size,
+				signpub_key, (0 == signpub_key)))
+		Fatal("Error verifying key block.\n");
+
+	printf("Key block:\n");
+	data_key = &g_keyblock->data_key;
+	if (opt_verbose)
+		printf("  Signature:           %s\n",
+		       signpub_key ? "valid" : "ignored");
+	printf("  Size:                0x%" PRIx64 "\n",
+	       g_keyblock->key_block_size);
+	printf("  Flags:               %" PRIu64 " ",
+	       g_keyblock->key_block_flags);
+	if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_0)
+		printf(" !DEV");
+	if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_DEVELOPER_1)
+		printf(" DEV");
+	if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_0)
+		printf(" !REC");
+	if (g_keyblock->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)
+		printf(" REC");
+	printf("\n");
+	printf("  Data key algorithm:  %" PRIu64 " %s\n", data_key->algorithm,
+	       (data_key->algorithm < kNumAlgorithms ?
+		algo_strings[data_key->algorithm] : "(invalid)"));
+	printf("  Data key version:    %" PRIu64 "\n", data_key->key_version);
+	printf("  Data key sha1sum:    ");
+	PrintPubKeySha1Sum(data_key);
+	printf("\n");
+
+	if (keyblock_outfile) {
+		FILE *f = NULL;
+		f = fopen(keyblock_outfile, "wb");
+		if (!f)
+			Fatal("Can't open key block file %s\n",
+			      keyblock_outfile);
+		if (1 != fwrite(g_keyblock, g_keyblock->key_block_size, 1, f))
+			Fatal("Can't write key block file %s\n",
+			      keyblock_outfile);
+		fclose(f);
+	}
+
+	if (data_key->key_version < (min_version >> 16))
+		Fatal("Data key version %" PRIu64
+		      " is lower than minimum %" PRIu64 ".\n",
+		      data_key->key_version, (min_version >> 16));
+
+	rsa = PublicKeyToRSA(data_key);
+	if (!rsa)
+		Fatal("Error parsing data key.\n");
+
+	/* Verify preamble */
+	if (0 !=
+	    VerifyKernelPreamble(g_preamble, g_preamble->preamble_size, rsa))
+		Fatal("Error verifying preamble.\n");
+
+	printf("Preamble:\n");
+	printf("  Size:                0x%" PRIx64 "\n",
+	       g_preamble->preamble_size);
+	printf("  Header version:      %" PRIu32 ".%" PRIu32 "\n",
+	       g_preamble->header_version_major,
+	       g_preamble->header_version_minor);
+	printf("  Kernel version:      %" PRIu64 "\n",
+	       g_preamble->kernel_version);
+	printf("  Body load address:   0x%" PRIx64 "\n",
+	       g_preamble->body_load_address);
+	printf("  Body size:           0x%" PRIx64 "\n",
+	       g_preamble->body_signature.data_size);
+	printf("  Bootloader address:  0x%" PRIx64 "\n",
+	       g_preamble->bootloader_address);
+	printf("  Bootloader size:     0x%" PRIx64 "\n",
+	       g_preamble->bootloader_size);
+
+	if (g_preamble->kernel_version < (min_version & 0xFFFF))
+		Fatal("Kernel version %" PRIu64 " is lower than minimum %"
+		      PRIu64 ".\n", g_preamble->kernel_version,
+		      (min_version & 0xFFFF));
+
+	/* Verify body */
+	if (0 != VerifyData(kernel_blob, kernel_size,
+			    &g_preamble->body_signature, rsa))
+		Fatal("Error verifying kernel body.\n");
+	printf("Body verification succeeded.\n");
+
+	if (opt_verbose)
+		printf("Config:\n%s\n",
+		       kernel_blob + CmdLineOffset(g_preamble));
+
+	return 0;
+}
+
+/****************************************************************************/
+
+static int do_vbutil_kernel(int argc, char *argv[])
+{
+	char *filename = NULL;
+	char *oldfile = NULL;
+	char *keyblock_file = NULL;
+	char *signpubkey_file = NULL;
+	char *signprivkey_file = NULL;
+	char *version_str = NULL;
+	int version = -1;
+	char *vmlinuz_file = NULL;
+	char *bootloader_file = NULL;
+	char *config_file = NULL;
+	enum arch_t arch = ARCH_X86;
+	char *address_str = NULL;
+	uint64_t kernel_body_load_address = CROS_32BIT_ENTRY_ADDR;
+	int mode = 0;
+	int parse_error = 0;
+	uint64_t min_version = 0;
+	char *e;
+	int i;
+	VbPrivateKey *signpriv_key = NULL;
+	VbPublicKey *signpub_key = NULL;
+	uint8_t *kernel_blob = NULL;
+	uint64_t kernel_size = 0;
+
+	while (((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) &&
+	       !parse_error) {
+		switch (i) {
+		default:
+		case '?':
+			/* Unhandled option */
+			parse_error = 1;
+			break;
+
+		case 0:
+			/* silently handled option */
+			break;
+
+		case OPT_MODE_PACK:
+		case OPT_MODE_REPACK:
+		case OPT_MODE_VERIFY:
+			if (mode && (mode != i)) {
+				fprintf(stderr,
+					"Only one mode can be specified\n");
+				parse_error = 1;
+				break;
+			}
+			mode = i;
+			filename = optarg;
+			break;
+
+		case OPT_ARCH:
+			/* check the first 3 characters to also detect x86_64 */
+			if ((!strncasecmp(optarg, "x86", 3)) ||
+			    (!strcasecmp(optarg, "amd64")))
+				arch = ARCH_X86;
+			else if ((!strcasecmp(optarg, "arm")) ||
+				 (!strcasecmp(optarg, "aarch64")))
+				arch = ARCH_ARM;
+			else if (!strcasecmp(optarg, "mips"))
+				arch = ARCH_MIPS;
+			else {
+				fprintf(stderr,
+					"Unknown architecture string: %s\n",
+					optarg);
+				parse_error = 1;
+			}
+			break;
+
+		case OPT_OLDBLOB:
+			oldfile = optarg;
+			break;
+
+		case OPT_KLOADADDR:
+			address_str = optarg;
+			kernel_body_load_address = strtoul(optarg, &e, 0);
+			if (!*optarg || (e && *e)) {
+				fprintf(stderr, "Invalid --kloadaddr\n");
+				parse_error = 1;
+			}
+			break;
+
+		case OPT_KEYBLOCK:
+			keyblock_file = optarg;
+			break;
+
+		case OPT_SIGNPUBKEY:
+			signpubkey_file = optarg;
+			break;
+
+		case OPT_SIGNPRIVATE:
+			signprivkey_file = optarg;
+			break;
+
+		case OPT_VMLINUZ:
+			vmlinuz_file = optarg;
+			break;
+
+		case OPT_BOOTLOADER:
+			bootloader_file = optarg;
+			break;
+
+		case OPT_CONFIG:
+			config_file = optarg;
+			break;
+
+		case OPT_VBLOCKONLY:
+			opt_vblockonly = 1;
+			break;
+
+		case OPT_VERSION:
+			version_str = optarg;
+			version = strtoul(optarg, &e, 0);
+			if (!*optarg || (e && *e)) {
+				fprintf(stderr, "Invalid --version\n");
+				parse_error = 1;
+			}
+			break;
+
+		case OPT_MINVERSION:
+			min_version = strtoul(optarg, &e, 0);
+			if (!*optarg || (e && *e)) {
+				fprintf(stderr, "Invalid --minversion\n");
+				parse_error = 1;
+			}
+			break;
+
+		case OPT_PAD:
+			opt_pad = strtoul(optarg, &e, 0);
+			if (!*optarg || (e && *e)) {
+				fprintf(stderr, "Invalid --pad\n");
+				parse_error = 1;
+			}
+			break;
+		}
+	}
+
+	if (parse_error) {
+		print_help(argv[0]);
+		return 1;
+	}
+
+	switch (mode) {
+	case OPT_MODE_PACK:
+
+		/* Required */
+
+		if (!keyblock_file)
+			Fatal("Missing required keyblock file.\n");
+
+		g_keyblock = (VbKeyBlockHeader *) ReadFile(keyblock_file, 0);
+		if (!g_keyblock)
+			Fatal("Error reading key block.\n");
+
+		if (!signprivkey_file)
+			Fatal("Missing required signprivate file.\n");
+
+		signpriv_key = PrivateKeyRead(signprivkey_file);
+		if (!signpriv_key)
+			Fatal("Error reading signing key.\n");
+
+		/* Optional */
+
+		if (config_file) {
+			Debug("Reading %s\n", config_file);
+			g_config_data =
+			    sReadConfigFile(config_file, &g_config_size);
+			if (!g_config_data)
+				Fatal("Error reading config file.\n");
+		}
+
+		if (vmlinuz_file)
+			if (!ImportVmlinuzFile
+			    (vmlinuz_file, arch, kernel_body_load_address))
+				Fatal("Error reading kernel file.\n");
+
+		if (bootloader_file) {
+			Debug("Reading %s\n", bootloader_file);
+			g_bootloader_data =
+			    ReadFile(bootloader_file, &g_bootloader_size);
+			if (!g_bootloader_data)
+				Fatal("Error reading bootloader file.\n");
+			Debug(" bootloader file size=0x%" PRIx64 "\n",
+			      g_bootloader_size);
+		}
+
+		/* Do it */
+
+		kernel_blob = CreateKernBlob(kernel_body_load_address, arch,
+					     &kernel_size);
+
+		return Pack(filename, kernel_blob, kernel_size,
+			    version, kernel_body_load_address, signpriv_key);
+
+	case OPT_MODE_REPACK:
+
+		/* Required */
+
+		if (!signprivkey_file)
+			Fatal("Missing required signprivate file.\n");
+
+		signpriv_key = PrivateKeyRead(signprivkey_file);
+		if (!signpriv_key)
+			Fatal("Error reading signing key.\n");
+
+		if (!oldfile)
+			Fatal("Missing previously packed blob.\n");
+
+		/* Load the old blob */
+
+		kernel_blob = ReadOldBlobFromFileOrDie(oldfile, &kernel_size);
+		if (0 != Verify(kernel_blob, kernel_size, 0, 0, 0))
+			Fatal("The oldblob doesn't verify\n");
+
+		/* Take it apart */
+
+		UnpackKernelBlob(kernel_blob, kernel_size);
+		free(kernel_blob);
+
+		/* Load optional params */
+
+		if (!version_str)
+			version = g_preamble->kernel_version;
+
+		if (!address_str)
+			kernel_body_load_address =
+			    g_preamble->body_load_address;
+
+		if (config_file) {
+			if (g_config_data)
+				free(g_config_data);
+			Debug("Reading %s\n", config_file);
+			g_config_data =
+			    sReadConfigFile(config_file, &g_config_size);
+			if (!g_config_data)
+				Fatal("Error reading config file.\n");
+		}
+
+		if (keyblock_file) {
+			if (g_keyblock)
+				free(g_keyblock);
+			g_keyblock =
+			    (VbKeyBlockHeader *) ReadFile(keyblock_file, 0);
+			if (!g_keyblock)
+				Fatal("Error reading key block.\n");
+		}
+
+		/* Put it back together */
+
+		kernel_blob = CreateKernBlob(kernel_body_load_address, arch,
+					     &kernel_size);
+
+		return Pack(filename, kernel_blob, kernel_size,
+			    version, kernel_body_load_address, signpriv_key);
+
+	case OPT_MODE_VERIFY:
+
+		/* Optional */
+
+		if (signpubkey_file) {
+			signpub_key = PublicKeyRead(signpubkey_file);
+			if (!signpub_key)
+				Fatal("Error reading public key.\n");
+		}
+
+		/* Do it */
+
+		kernel_blob = ReadOldBlobFromFileOrDie(filename, &kernel_size);
+
+		return Verify(kernel_blob, kernel_size, signpub_key,
+			      keyblock_file, min_version);
+	}
+
+	fprintf(stderr,
+		"You must specify a mode: --pack, --repack or --verify\n");
+	print_help(argv[0]);
+	return 1;
+}
+
+DECLARE_FUTIL_COMMAND(vbutil_kernel, do_vbutil_kernel,
+		      "Creates, signs, and verifies the kernel blob",
+		      print_help);
diff --git a/futility/vb1_helper.c b/futility/vb1_helper.c
index d0dbefc..f67c163 100644
--- a/futility/vb1_helper.c
+++ b/futility/vb1_helper.c
@@ -221,6 +221,8 @@
 	/* Bootloader is at the end */
 	g_bootloader_size = g_preamble->bootloader_size;
 	g_bootloader_data = kernel_blob_data + now;
+	/* TODO: What to do if this is beyond the end of the blob? */
+
 	Debug("bootloader_size     = 0x%" PRIx64 "\n", g_bootloader_size);
 	Debug("bootloader_ofs      = 0x%" PRIx64 "\n", now);
 
diff --git a/tests/futility/test_sign_kernel.sh b/tests/futility/test_sign_kernel.sh
index 2a8e8c1..fdc4daf 100755
--- a/tests/futility/test_sign_kernel.sh
+++ b/tests/futility/test_sign_kernel.sh
@@ -17,12 +17,12 @@
 dd if=/dev/urandom bs=512 count=1 of=${TMP}.bootloader2.bin
 
 # default padding
-padding=49152
+padding=65536
 
 try_arch () {
   local arch=$1
 
-  echo -n "${arch}: 1 " 1>&3
+  echo -n "${arch}.a " 1>&3
 
   # pack it up the old way
   ${FUTILITY} vbutil_kernel --debug \
@@ -34,19 +34,17 @@
     --bootloader ${TMP}.bootloader.bin \
     --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \
     --arch ${arch} \
-    --pad ${padding} \
     --kloadaddr 0x11000
 
   # verify the old way
   ${FUTILITY} vbutil_kernel --verify ${TMP}.blob1.${arch} \
-    --pad ${padding} \
     --signpubkey ${DEVKEYS}/recovery_key.vbpubk
-  ${FUTILITY} vbutil_kernel --verify ${TMP}.blob1.${arch} \
-    --pad ${padding} \
+  ${FUTILITY} vbutil_kernel2 --verify ${TMP}.blob1.${arch} \
     --signpubkey ${DEVKEYS}/recovery_key.vbpubk --debug
 
   # pack it up the new way
-  ${FUTILITY} sign --debug \
+  ${FUTILITY} vbutil_kernel2 --debug \
+    --pack ${TMP}.blob2.${arch} \
     --keyblock ${DEVKEYS}/recovery_kernel.keyblock \
     --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \
     --version 1 \
@@ -54,15 +52,11 @@
     --bootloader ${TMP}.bootloader.bin \
     --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \
     --arch ${arch} \
-    --pad ${padding} \
-    --kloadaddr 0x11000 \
-    --outfile ${TMP}.blob2.${arch}
+    --kloadaddr 0x11000
 
   # they should be identical
   cmp ${TMP}.blob1.${arch} ${TMP}.blob2.${arch}
 
-  echo -n "2 " 1>&3
-
   # repack it the old way
   ${FUTILITY} vbutil_kernel \
     --repack ${TMP}.blob3.${arch} \
@@ -70,51 +64,30 @@
     --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \
     --keyblock ${DEVKEYS}/kernel.keyblock \
     --version 2 \
-    --pad ${padding} \
     --config ${TMP}.config2.txt \
     --bootloader ${TMP}.bootloader2.bin
 
   # verify the old way
   ${FUTILITY} vbutil_kernel --verify ${TMP}.blob3.${arch} \
-    --pad ${padding} \
     --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk
-  ${FUTILITY} vbutil_kernel --verify ${TMP}.blob3.${arch} \
-    --pad ${padding} \
+  ${FUTILITY} vbutil_kernel2 --verify ${TMP}.blob3.${arch} \
     --signpubkey ${DEVKEYS}/kernel_subkey.vbpubk
 
   # repack it the new way
-  ${FUTILITY} sign --debug \
+  ${FUTILITY} vbutil_kernel2 \
+    --repack ${TMP}.blob4.${arch} \
+    --oldblob ${TMP}.blob2.${arch} \
     --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \
     --keyblock ${DEVKEYS}/kernel.keyblock \
     --version 2 \
-    --pad ${padding} \
     --config ${TMP}.config2.txt \
-    --bootloader ${TMP}.bootloader2.bin \
-    ${TMP}.blob2.${arch} \
-    ${TMP}.blob4.${arch}
+    --bootloader ${TMP}.bootloader2.bin
 
   # they should be identical
   cmp ${TMP}.blob3.${arch} ${TMP}.blob4.${arch}
 
-  echo -n "3 " 1>&3
-
-  # repack it the new way, in-place
-  cp ${TMP}.blob2.${arch} ${TMP}.blob5.${arch}
-  ${FUTILITY} sign --debug \
-    --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \
-    --keyblock ${DEVKEYS}/kernel.keyblock \
-    --version 2 \
-    --pad ${padding} \
-    --config ${TMP}.config2.txt \
-    --bootloader ${TMP}.bootloader2.bin \
-    ${TMP}.blob5.${arch}
-
-  # they should be identical
-  cmp ${TMP}.blob3.${arch} ${TMP}.blob5.${arch}
-
-
   # and now just the vblocks...
-  echo -n "4 " 1>&3
+  echo -n "${arch}.v " 1>&3
 
   dd bs=${padding} count=1 if=${TMP}.blob1.${arch} of=${TMP}.blob1.${arch}.vb0
   ${FUTILITY} vbutil_kernel \
@@ -127,12 +100,13 @@
     --bootloader ${TMP}.bootloader.bin \
     --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \
     --arch ${arch} \
-    --pad ${padding} \
     --kloadaddr 0x11000
   cmp ${TMP}.blob1.${arch}.vb0 ${TMP}.blob1.${arch}.vb1
 
   dd bs=${padding} count=1 if=${TMP}.blob2.${arch} of=${TMP}.blob2.${arch}.vb0
-  ${FUTILITY} sign --debug \
+  ${FUTILITY} vbutil_kernel2 \
+    --pack ${TMP}.blob2.${arch}.vb1 \
+    --vblockonly \
     --keyblock ${DEVKEYS}/recovery_kernel.keyblock \
     --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \
     --version 1 \
@@ -140,23 +114,9 @@
     --bootloader ${TMP}.bootloader.bin \
     --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \
     --arch ${arch} \
-    --pad ${padding} \
-    --kloadaddr 0x11000 \
-    --vblockonly \
-    ${TMP}.blob2.${arch}.vb1
-
+    --kloadaddr 0x11000
   cmp ${TMP}.blob2.${arch}.vb0 ${TMP}.blob2.${arch}.vb1
 
-  # and verify it the new way
-  dd bs=${padding} skip=1 if=${TMP}.blob2.${arch} of=${TMP}.blob2.${arch}.kb1
-  ${FUTILITY} verify --debug \
-    --pad ${padding} \
-    --publickey ${DEVKEYS}/recovery_key.vbpubk \
-    --fv ${TMP}.blob2.${arch}.kb1 \
-    ${TMP}.blob2.${arch}.vb1
-
-  echo -n "5 " 1>&3
-
   dd bs=${padding} count=1 if=${TMP}.blob3.${arch} of=${TMP}.blob3.${arch}.vb0
   ${FUTILITY} vbutil_kernel \
     --repack ${TMP}.blob3.${arch}.vb1 \
@@ -165,36 +125,39 @@
     --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \
     --keyblock ${DEVKEYS}/kernel.keyblock \
     --version 2 \
-    --pad ${padding} \
     --config ${TMP}.config2.txt \
     --bootloader ${TMP}.bootloader2.bin
   cmp ${TMP}.blob3.${arch}.vb0 ${TMP}.blob3.${arch}.vb1
 
   dd bs=${padding} count=1 if=${TMP}.blob4.${arch} of=${TMP}.blob4.${arch}.vb0
-  ${FUTILITY} sign --debug \
+  ${FUTILITY} vbutil_kernel2 \
+    --repack ${TMP}.blob4.${arch}.vb1 \
+    --vblockonly \
+    --oldblob ${TMP}.blob2.${arch} \
     --signprivate ${DEVKEYS}/kernel_data_key.vbprivk \
     --keyblock ${DEVKEYS}/kernel.keyblock \
     --version 2 \
     --config ${TMP}.config2.txt \
-    --bootloader ${TMP}.bootloader2.bin \
-    --pad ${padding} \
-    --vblockonly \
-    ${TMP}.blob2.${arch} \
-    ${TMP}.blob4.${arch}.vb1 \
-
+    --bootloader ${TMP}.bootloader2.bin
   cmp ${TMP}.blob4.${arch}.vb0 ${TMP}.blob4.${arch}.vb1
 
-  dd bs=${padding} skip=1 if=${TMP}.blob4.${arch} of=${TMP}.blob4.${arch}.kb1
-  ${FUTILITY} verify --debug \
-    --pad ${padding} \
-    --publickey ${DEVKEYS}/kernel_subkey.vbpubk \
-    --fv ${TMP}.blob4.${arch}.kb1 \
-    ${TMP}.blob4.${arch}.vb1
 
   # Note: We specifically do not test repacking with a different --kloadaddr,
   # because the old way has a bug and does not update params->cmd_line_ptr to
   # point at the new on-disk location. Apparently (and not surprisingly), no
   # one has ever done that.
+
+#HEY  # pack it up the new way
+#HEY  ${FUTILITY} sign --debug \
+#HEY    --vmlinuz ${SCRIPTDIR}/data/vmlinuz-${arch}.bin \
+#HEY    --config ${TMP}.config.txt \
+#HEY    --bootloader ${TMP}.bootloader.bin \
+#HEY    --arch ${arch} \
+#HEY    --keyblock ${DEVKEYS}/recovery_kernel.keyblock \
+#HEY    --signprivate ${DEVKEYS}/recovery_kernel_data_key.vbprivk \
+#HEY    --version 1 \
+#HEY    --outfile ${TMP}.blob2.${arch}
+
 }
 
 try_arch amd64