Adding --repack and --headeronly options to vbutil_kernel

The --repack option lets us sign a previously signed kernel blob with a new
kernel data key.

The --headeronly option is so we can emit the new verification header
separately from the kernel blob.

More work to come...

Review URL: http://codereview.chromium.org/2812034
diff --git a/Makefile b/Makefile
index 29d2e09..b4fce9d 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@
 
 export CC ?= gcc
 export CXX ?= g++
-export CFLAGS = -Wall -DNDEBUG -O3 -Werror -DCHROMEOS_ENVIRONMENT -DVBOOT_DEBUG
+export CFLAGS = -Wall -DNDEBUG -O3 -Werror -DCHROMEOS_ENVIRONMENT
 export TOP = $(shell pwd)
 export FWDIR=$(TOP)/firmware
 export HOSTDIR=$(TOP)/host
diff --git a/host/include/host_key.h b/host/include/host_key.h
index 9ce1fa5..e7b1815 100644
--- a/host/include/host_key.h
+++ b/host/include/host_key.h
@@ -22,9 +22,9 @@
 } VbPrivateKey;
 
 
-/* Read a private key from a file.  Caller owns the returned pointer,
+/* Read a private key from a .pem file.  Caller owns the returned pointer,
  * and must free it with PrivateKeyFree(). */
-VbPrivateKey* PrivateKeyRead(const char* filename, uint64_t algorithm);
+VbPrivateKey* PrivateKeyReadPem(const char* filename, uint64_t algorithm);
 
 
 /* Free a private key. */
diff --git a/host/lib/host_key.c b/host/lib/host_key.c
index da350fd..fd25afd 100644
--- a/host/lib/host_key.c
+++ b/host/lib/host_key.c
@@ -24,27 +24,27 @@
 #include "vboot_common.h"
 
 
-VbPrivateKey* PrivateKeyRead(const char* filename, uint64_t algorithm) {
+VbPrivateKey* PrivateKeyReadPem(const char* filename, uint64_t algorithm) {
 
   VbPrivateKey* key;
   RSA* rsa_key;
   FILE* f;
 
   if (algorithm >= kNumAlgorithms) {
-    debug("PrivateKeyRead() called with invalid algorithm!\n");
+    debug("%s() called with invalid algorithm!\n", __FUNCTION__);
     return NULL;
   }
 
   /* Read private key */
   f = fopen(filename, "r");
   if (!f) {
-    debug("PrivateKeyRead(): Couldn't open key file: %s\n", filename);
+    debug("%s(): Couldn't open key file: %s\n", __FUNCTION__, filename);
     return NULL;
   }
   rsa_key = PEM_read_RSAPrivateKey(f, NULL, NULL, NULL);
   fclose(f);
   if (!rsa_key) {
-    debug("PrivateKeyRead(): Couldn't read private key from file: %s\n",
+    debug("%s(): Couldn't read private key from file: %s\n", __FUNCTION__,
           filename);
     return NULL;
   }
diff --git a/host/linktest/main.c b/host/linktest/main.c
index 93c5ac2..a067e1b 100644
--- a/host/linktest/main.c
+++ b/host/linktest/main.c
@@ -7,7 +7,7 @@
 int main(void)
 {
   /* host_key.h */
-  PrivateKeyRead(0, 0);
+  PrivateKeyReadPem(0, 0);
   PrivateKeyFree(0);
   PublicKeyAlloc(0, 0, 0);
   PublicKeyRead(0);
diff --git a/tests/vboot_common2_tests.c b/tests/vboot_common2_tests.c
index 89ba1f8..f581574 100644
--- a/tests/vboot_common2_tests.c
+++ b/tests/vboot_common2_tests.c
@@ -213,7 +213,7 @@
   /* Read verification keys and create a test image. */
   key_algorithm = atoi(argv[1]);
 
-  private_key = PrivateKeyRead(argv[2], key_algorithm);
+  private_key = PrivateKeyReadPem(argv[2], key_algorithm);
   if (!private_key) {
     fprintf(stderr, "Error reading private_key");
     return 1;
diff --git a/tests/vboot_common3_tests.c b/tests/vboot_common3_tests.c
index ff75906..8b7e470 100644
--- a/tests/vboot_common3_tests.c
+++ b/tests/vboot_common3_tests.c
@@ -264,7 +264,7 @@
   signing_key_algorithm = atoi(argv[1]);
   data_key_algorithm = atoi(argv[2]);
 
-  signing_private_key = PrivateKeyRead(argv[3], signing_key_algorithm);
+  signing_private_key = PrivateKeyReadPem(argv[3], signing_key_algorithm);
   if (!signing_private_key) {
     fprintf(stderr, "Error reading signing_private_key");
     return 1;
diff --git a/utility/vbutil_firmware.c b/utility/vbutil_firmware.c
index efc9127..4966e19 100644
--- a/utility/vbutil_firmware.c
+++ b/utility/vbutil_firmware.c
@@ -101,7 +101,7 @@
     return 1;
   }
 
-  signing_key = PrivateKeyRead(signprivate, key_block->data_key.algorithm);
+  signing_key = PrivateKeyReadPem(signprivate, key_block->data_key.algorithm);
   if (!signing_key) {
     error("Error reading signing key.\n");
     return 1;
diff --git a/utility/vbutil_kernel.c b/utility/vbutil_kernel.c
index 81b9e44..8b67051 100644
--- a/utility/vbutil_kernel.c
+++ b/utility/vbutil_kernel.c
@@ -5,12 +5,16 @@
  * Verified boot kernel utility
  */
 
+#include <errno.h>
 #include <getopt.h>
 #include <inttypes.h>  /* For PRIu64 */
 #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"
@@ -22,11 +26,14 @@
 /* Global opt */
 static int opt_debug = 0;
 
+static const int DEFAULT_PADDING = 65536;
 
 /* Command line options */
 enum {
   OPT_MODE_PACK = 1000,
+  OPT_MODE_REPACK,
   OPT_MODE_VERIFY,
+  OPT_OLDBLOB,
   OPT_KEYBLOCK,
   OPT_SIGNPUBKEY,
   OPT_SIGNPRIVATE,
@@ -34,12 +41,15 @@
   OPT_VMLINUZ,
   OPT_BOOTLOADER,
   OPT_CONFIG,
+  OPT_VBLOCKONLY,
   OPT_PAD,
 };
 
 static struct option long_opts[] = {
   {"pack", 1, 0,                      OPT_MODE_PACK               },
+  {"repack", 1, 0,                    OPT_MODE_REPACK             },
   {"verify", 1, 0,                    OPT_MODE_VERIFY             },
+  {"oldblob", 1, 0,                   OPT_OLDBLOB                 },
   {"keyblock", 1, 0,                  OPT_KEYBLOCK                },
   {"signpubkey", 1, 0,                OPT_SIGNPUBKEY              },
   {"signprivate", 1, 0,               OPT_SIGNPRIVATE             },
@@ -47,6 +57,7 @@
   {"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                     },
   {"debug", 0, &opt_debug, 1                                      },
   {NULL, 0, 0, 0}
@@ -54,25 +65,46 @@
 
 
 /* Print help and return error */
-static int PrintHelp(void) {
-
-  puts("vbutil_kernel - Verified boot key block utility\n"
-       "\n"
-       "Usage:  vbutil_kernel <--pack|--verify> <file> [OPTIONS]\n"
-       "\n"
-       "For '--pack <file>', required OPTIONS are:\n"
-       "  --keyblock <file>           Key block in .keyblock format\n"
-       "  --signprivate <file>        Signing private key in .pem format\n"
-       "  --version <number>          Kernel version\n"
-       "  --vmlinuz <file>            Linux kernel image\n"
-       "  --bootloader <file>         Bootloader stub\n"
-       "  --config <file>             Config file\n"
-       "Optional OPTIONS are:\n"
-       "  --pad <number>              Padding size in bytes\n"
-       "\n"
-       "For '--verify <file>', required OPTIONS are:\n"
-       "  --signpubkey <file>         Signing public key in .vbpubk format\n"
-       "");
+static int PrintHelp(char *progname) {
+  fprintf(stderr,
+          "This program creates, signs, and verifies the kernel blob\n");
+  fprintf(stderr,
+          "\n"
+          "Usage:  %s --pack <file> [PARAMETERS]\n"
+          "\n"
+          "  Required parameters:\n"
+          "    --keyblock <file>         Key block in .keyblock format\n"
+          "    --signprivate <file>      Signing private key in .pem format\n"
+          "    --version <number>        Kernel version\n"
+          "    --vmlinuz <file>          Linux kernel bzImage file\n"
+          "    --bootloader <file>       Bootloader stub\n"
+          "    --config <file>           Config file\n"
+          "\n"
+          "  Optional:\n"
+          "    --pad <number>            Verification padding size in bytes\n"
+          "    --vblockonly              Emit just the verification blob\n",
+          progname);
+  fprintf(stderr,
+          "\nOR\n\n"
+          "Usage:  %s --repack <file> [PARAMETERS]\n"
+          "\n"
+          "  Required parameters:\n"
+          "    --keyblock <file>         Key block in .keyblock format\n"
+          "    --signprivate <file>      Signing private key in .pem format\n"
+          "    --oldblob <file>          Previously packed kernel blob\n"
+          "\n"
+          "  Optional:\n"
+          "    --pad <number>            Verification padding size in bytes\n"
+          "    --vblockonly              Emit just the verification blob\n",
+          progname);
+  fprintf(stderr,
+          "\nOR\n\n"
+          "Usage:  %s --verify <file> [PARAMETERS]\n"
+          "\n"
+          "  Required parameters:\n"
+          "    --signpubkey <file>       Signing public key in .vbpubk format\n"
+          "\n",
+          progname);
   return 1;
 }
 
@@ -121,76 +153,68 @@
 }
 
 
-/* Pack a .kernel */
-static int Pack(const char* outfile, const char* keyblock_file,
-                const char* signprivate, uint64_t version,
-                const char* vmlinuz, const char* bootloader_file,
-                const char* config_file, uint64_t pad) {
+typedef struct blob_s {
+  /* Stuff needed by VbKernelPreambleHeader */
+  uint64_t kernel_version;
+  uint64_t bootloader_address;
+  uint64_t bootloader_size;
+  /* Raw kernel blob data */
+  uint64_t blob_size;
+  uint8_t *blob;
+} blob_t;
 
+
+static void FreeBlob(blob_t *bp) {
+  if (bp) {
+    if (bp->blob)
+      Free(bp->blob);
+    Free(bp);
+  }
+}
+
+/* Create a blob from its components */
+static blob_t *NewBlob(uint64_t version,
+                       const char* vmlinuz,
+                       const char* bootloader_file,
+                       const char* config_file) {
+  blob_t *bp;
   struct linux_kernel_header *lh = 0;
   struct linux_kernel_params *params = 0;
-  VbPrivateKey* signing_key;
-  VbSignature* body_sig;
-  VbKernelPreambleHeader* preamble;
-  VbKeyBlockHeader* key_block;
-  uint64_t key_block_size;
   uint8_t* config_buf;
   uint64_t config_size;
   uint8_t* bootloader_buf;
   uint64_t bootloader_size;
-  uint64_t bootloader_mem_start;
-  uint64_t bootloader_mem_size;
   uint8_t* kernel_buf;
   uint64_t kernel_size;
   uint64_t kernel32_start = 0;
   uint64_t kernel32_size = 0;
   uint32_t cmdline_addr;
   uint8_t* blob = NULL;
-  uint64_t blob_size;
   uint64_t now = 0;
-  FILE* f;
   uint64_t i;
 
-  if (!outfile) {
-    error("Must specify output filename\n");
-    return 1;
-  }
-  if (!keyblock_file || !signprivate) {
-    error("Must specify all keys\n");
-    return 1;
-  }
   if (!vmlinuz || !bootloader_file || !config_file) {
     error("Must specify all input files\n");
-    return 1;
+    return 0;
   }
 
-  /* Read the key block and private key */
-  key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
-  if (!key_block) {
-    error("Error reading key block.\n");
-    return 1;
+  bp = (blob_t *)Malloc(sizeof(blob_t));
+  if (!bp) {
+    error("Couldn't allocate bytes for blob_t.\n");
+    return 0;
   }
-  if (pad < key_block->key_block_size) {
-    error("Pad too small\n");
-    return 1;
-  }
-
-  signing_key = PrivateKeyRead(signprivate, key_block->data_key.algorithm);
-  if (!signing_key) {
-    error("Error reading signing key.\n");
-    return 1;
-  }
+  bp->kernel_version = version;
 
   /* Read the config file */
   Debug("Reading %s\n", config_file);
   config_buf = ReadFile(config_file, &config_size);
   if (!config_buf)
-    return 1;
+    return 0;
   Debug(" config file size=0x%" PRIx64 "\n", config_size);
   if (CROS_CONFIG_SIZE <= config_size) {  /* need room for trailing '\0' */
     error("Config file %s is too large (>= %d bytes)\n",
           config_file, CROS_CONFIG_SIZE);
-    return 1;
+    return 0;
   }
   /* Replace newlines with spaces */
   for (i = 0; i < config_size; i++)
@@ -201,18 +225,18 @@
   Debug("Reading %s\n", bootloader_file);
   bootloader_buf = ReadFile(bootloader_file, &bootloader_size);
   if (!bootloader_buf)
-    return 1;
+    return 0;
   Debug(" bootloader file size=0x%" PRIx64 "\n", bootloader_size);
 
   /* Read the kernel */
   Debug("Reading %s\n", vmlinuz);
   kernel_buf = ReadFile(vmlinuz, &kernel_size);
   if (!kernel_buf)
-    return 1;
+    return 0;
   Debug(" kernel file size=0x%" PRIx64 "\n", kernel_size);
   if (!kernel_size) {
     error("Empty kernel file\n");
-    return 1;
+    return 0;
   }
 
   /* The first part of vmlinuz is a header, followed by a real-mode
@@ -221,24 +245,25 @@
   kernel32_start = (lh->setup_sects + 1) << 9;
   if (kernel32_start >= kernel_size) {
     error("Malformed kernel\n");
-    return 1;
+    return 0;
   }
   kernel32_size = kernel_size - kernel32_start;
   Debug(" kernel32_start=0x%" PRIx64 "\n", kernel32_start);
   Debug(" kernel32_size=0x%" PRIx64 "\n", kernel32_size);
 
   /* Allocate and zero the blob we need. */
-  blob_size = roundup(kernel32_size, CROS_ALIGN) +
+  bp->blob_size = roundup(kernel32_size, CROS_ALIGN) +
       CROS_CONFIG_SIZE +
       CROS_PARAMS_SIZE +
       roundup(bootloader_size, CROS_ALIGN);
-  blob = (uint8_t *)Malloc(blob_size);
-  Debug("blob_size=0x%" PRIx64 "\n", blob_size);
+  blob = (uint8_t *)Malloc(bp->blob_size);
+  Debug("blob_size=0x%" PRIx64 "\n", bp->blob_size);
   if (!blob) {
-    error("Couldn't allocate %ld bytes.\n", blob_size);
-    return 1;
+    error("Couldn't allocate %ld bytes.\n", bp->blob_size);
+    return 0;
   }
-  Memset(blob, 0, blob_size);
+  Memset(blob, 0, bp->blob_size);
+  bp->blob = blob;
 
   /* Copy the 32-bit kernel. */
   Debug("kernel goes at blob+=0x%" PRIx64 "\n", now);
@@ -273,13 +298,13 @@
   /* Finally, append the bootloader. Remember where it will load in
    * memory, too. */
   Debug("bootloader goes at blob+=0x%" PRIx64 "\n", now);
-  bootloader_mem_start = CROS_32BIT_ENTRY_ADDR + now;
-  bootloader_mem_size = roundup(bootloader_size, CROS_ALIGN);
-  Debug(" bootloader_mem_start=0x%" PRIx64 "\n", bootloader_mem_start);
-  Debug(" bootloader_mem_size=0x%" PRIx64 "\n", bootloader_mem_size);
+  bp->bootloader_address = CROS_32BIT_ENTRY_ADDR + now;
+  bp->bootloader_size = roundup(bootloader_size, CROS_ALIGN);
+  Debug(" bootloader_address=0x%" PRIx64 "\n", bp->bootloader_address);
+  Debug(" bootloader_size=0x%" PRIx64 "\n", bp->bootloader_size);
   if (bootloader_size)
     Memcpy(blob + now, bootloader_buf, bootloader_size);
-  now += bootloader_mem_size;
+  now += bp->bootloader_size;
   Debug("end of blob is 0x%" PRIx64 "\n", now);
 
   /* Free input buffers */
@@ -287,18 +312,172 @@
   Free(config_buf);
   Free(bootloader_buf);
 
+  /* Success */
+  return bp;
+}
+
+
+/* Pull the blob_t stuff out of a prepacked kernel blob file */
+static blob_t *OldBlob(const char* filename) {
+  FILE* fp;
+  blob_t *bp;
+  struct stat statbuf;
+  VbKeyBlockHeader* key_block;
+  VbKernelPreambleHeader* preamble;
+  uint64_t now = 0;
+  uint8_t buf[DEFAULT_PADDING];
+
+  if (!filename) {
+    error("Must specify prepacked blob to read\n");
+    return 0;
+  }
+
+  if (0 != stat(filename, &statbuf)) {
+    error("unable to stat %s: %s\n", filename, strerror(errno));
+    return 0;
+  }
+
+  Debug("%s size is 0x%" PRIx64 "\n", filename, statbuf.st_size);
+  if (statbuf.st_size < DEFAULT_PADDING) {
+    error("%s is too small to be a valid kernel blob\n");
+    return 0;
+  }
+
+  Debug("Reading %s\n", filename);
+  fp = fopen(filename, "rb");
+  if (!fp) {
+    error("Unable to open file %s: %s\n", filename, strerror(errno));
+    return 0;
+  }
+
+  if (1 != fread(buf, sizeof(buf), 1, fp)) {
+    error("Unable to read header from %s: %s\n", filename, strerror(errno));
+    fclose(fp);
+    return 0;
+  }
+
+  /* Skip 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 > statbuf.st_size) {
+    error("key_block_size advances past the end of the blob\n");
+    return 0;
+  }
+
+  /* Skip the preamble */
+  preamble = (VbKernelPreambleHeader*)(buf + now);
+  Debug("Preamble is 0x%" PRIx64 " bytes\n", preamble->preamble_size);
+  now += preamble->preamble_size;
+  if (now > statbuf.st_size) {
+    error("preamble_size advances past the end of the blob\n");
+    return 0;
+  }
+
+  /* Go find the kernel blob */
+  Debug("kernel blob is at offset 0x%" PRIx64 "\n", now);
+  if (0 != fseek(fp, now, SEEK_SET)) {
+    error("Unable to seek to 0x%" PRIx64 " in %s: %s\n", now, filename,
+          strerror(errno));
+    fclose(fp);
+    return 0;
+  }
+
+  /* Remember what we've got */
+  bp = (blob_t *)Malloc(sizeof(blob_t));
+  if (!bp) {
+    error("Couldn't allocate bytes for blob_t.\n");
+    fclose(fp);
+    return 0;
+  }
+
+  bp->kernel_version = preamble->kernel_version;
+  bp->bootloader_address = preamble->bootloader_address;
+  bp->bootloader_size = preamble->bootloader_size;
+  bp->blob_size = preamble->body_signature.data_size;
+
+  Debug(" kernel_version = %d\n", bp->kernel_version);
+  Debug(" bootloader_address = 0x%" PRIx64 "\n", bp->bootloader_address);
+  Debug(" bootloader_size = 0x%" PRIx64 "\n", bp->bootloader_size);
+  Debug(" blob_size = 0x%" PRIx64 "\n", bp->blob_size);
+
+  bp->blob = (uint8_t *)Malloc(bp->blob_size);
+  if (!bp->blob) {
+    error("Couldn't allocate 0x%" PRIx64 " bytes for blob_t.\n", bp->blob_size);
+    fclose(fp);
+    Free(bp);
+    return 0;
+  }
+
+  /* read it in */
+  if (1 != fread(bp->blob, bp->blob_size, 1, fp)) {
+    error("Unable to read kernel blob from %s: %s\n", filename, strerror(errno));
+    fclose(fp);
+    Free(bp);
+    return 0;
+  }
+
+  /* done */
+  fclose(fp);
+
+  return bp;
+}
+
+
+/* Pack a .kernel */
+static int Pack(const char* outfile, const char* keyblock_file,
+                const char* signprivate, blob_t *bp, uint64_t pad,
+                int vblockonly) {
+  VbPrivateKey* signing_key;
+  VbSignature* body_sig;
+  VbKernelPreambleHeader* preamble;
+  VbKeyBlockHeader* key_block;
+  uint64_t key_block_size;
+  FILE* f;
+  uint64_t i;
+
+  if (!outfile) {
+    error("Must specify output filename\n");
+    return 1;
+  }
+  if (!keyblock_file || !signprivate) {
+    error("Must specify all keys\n");
+    return 1;
+  }
+  if (!bp) {
+    error("Refusing to pack invalid kernel blob\n");
+    return 1;
+  }    
+
+  /* Read the key block and private key */
+  key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
+  if (!key_block) {
+    error("Error reading key block.\n");
+    return 1;
+  }
+  if (pad < key_block->key_block_size) {
+    error("Pad too small\n");
+    return 1;
+  }
+
+  signing_key = PrivateKeyReadPem(signprivate, key_block->data_key.algorithm);
+  if (!signing_key) {
+    error("Error reading signing key.\n");
+    return 1;
+  }
+
   /* Sign the kernel data */
-  body_sig = CalculateSignature(blob, blob_size, signing_key);
+  body_sig = CalculateSignature(bp->blob, bp->blob_size, signing_key);
   if (!body_sig) {
     error("Error calculating body signature\n");
     return 1;
   }
 
   /* Create preamble */
-  preamble = CreateKernelPreamble(version,
+  preamble = CreateKernelPreamble(bp->kernel_version,
                                   CROS_32BIT_ENTRY_ADDR,
-                                  bootloader_mem_start,
-                                  bootloader_mem_size,
+                                  bp->bootloader_address,
+                                  bp->bootloader_size,
                                   body_sig,
                                   pad - key_block_size,
                                   signing_key);
@@ -316,17 +495,28 @@
   }
   Debug("0x%" PRIx64 " bytes of key_block\n", key_block_size);
   Debug("0x%" PRIx64 " bytes of preamble\n", preamble->preamble_size);
-  Debug("0x%" PRIx64 " bytes of blob\n", blob_size);
   i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
-       (1 != fwrite(preamble, preamble->preamble_size, 1, f)) ||
-       (1 != fwrite(blob, blob_size, 1, f)));
-  fclose(f);
+       (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
   if (i) {
     error("Can't write output file %s\n", outfile);
+    fclose(f);
     unlink(outfile);
     return 1;
   }
 
+  if (!vblockonly) {
+    Debug("0x%" PRIx64 " bytes of blob\n", bp->blob_size);
+    i = (1 != fwrite(bp->blob, bp->blob_size, 1, f));
+    if (i) {
+      error("Can't write output file %s\n", outfile);
+      fclose(f);
+      unlink(outfile);
+      return 1;
+    }
+  }
+
+  fclose(f);
+
   /* Success */
   return 0;
 }
@@ -373,7 +563,7 @@
 
   printf("Key block:\n");
   data_key = &key_block->data_key;
-  printf("  Size:                %" PRIu64 "\n", key_block->key_block_size);
+  printf("  Size:                0x%" PRIx64 "\n", key_block->key_block_size);
   printf("  Data key algorithm:  %" PRIu64 " %s\n", data_key->algorithm,
          (data_key->algorithm < kNumAlgorithms ?
           algo_strings[data_key->algorithm] : "(invalid)"));
@@ -395,7 +585,7 @@
   now += preamble->preamble_size;
 
   printf("Preamble:\n");
-  printf("  Size:                %" PRIu64 "\n", preamble->preamble_size);
+  printf("  Size:                0x%" PRIx64 "\n", preamble->preamble_size);
   printf("  Header version:      %" PRIu32 ".%" PRIu32"\n",
          preamble->header_version_major, preamble->header_version_minor);
   printf("  Kernel version:      %" PRIu64 "\n", preamble->kernel_version);
@@ -416,8 +606,8 @@
 
 
 int main(int argc, char* argv[]) {
-
   char* filename = NULL;
+  char* oldfile = NULL;
   char* key_block_file = NULL;
   char* signpubkey = NULL;
   char* signprivate = NULL;
@@ -425,26 +615,39 @@
   char* vmlinuz = NULL;
   char* bootloader = NULL;
   char* config_file = NULL;
-  uint64_t pad = 65536;
+  int vblockonly = 0;
+  uint64_t pad = DEFAULT_PADDING;
   int mode = 0;
   int parse_error = 0;
   char* e;
-  int i;
+  int i,r;
+  blob_t *bp;
 
-  while ((i = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
+
+  char *progname = strrchr(argv[0], '/');
+  if (progname)
+    progname++;
+  else
+    progname = argv[0];
+
+  while ((i = getopt_long(argc, argv, ":", long_opts, NULL)) != -1) {
     switch (i) {
       case '?':
         /* Unhandled option */
-        printf("Unknown option\n");
         parse_error = 1;
         break;
 
       case OPT_MODE_PACK:
+      case OPT_MODE_REPACK:
       case OPT_MODE_VERIFY:
         mode = i;
         filename = optarg;
         break;
 
+      case OPT_OLDBLOB:
+        oldfile = optarg;
+        break;
+
       case OPT_KEYBLOCK:
         key_block_file = optarg;
         break;
@@ -469,10 +672,14 @@
         config_file = optarg;
         break;
 
+      case OPT_VBLOCKONLY:
+        vblockonly = 1;
+        break;
+
       case OPT_VERSION:
         version = strtoul(optarg, &e, 0);
         if (!*optarg || (e && *e)) {
-          printf("Invalid --version\n");
+          fprintf(stderr, "Invalid --version\n");
           parse_error = 1;
         }
         break;
@@ -480,7 +687,7 @@
       case OPT_PAD:
         pad = strtoul(optarg, &e, 0);
         if (!*optarg || (e && *e)) {
-          printf("Invalid --pad\n");
+          fprintf(stderr, "Invalid --pad\n");
           parse_error = 1;
         }
         break;
@@ -488,16 +695,31 @@
   }
 
   if (parse_error)
-    return PrintHelp();
+    return PrintHelp(progname);
 
   switch(mode) {
     case OPT_MODE_PACK:
-      return Pack(filename, key_block_file, signprivate, version, vmlinuz,
-                  bootloader, config_file, pad);
+      bp = NewBlob(version, vmlinuz, bootloader, config_file);
+      if (!bp)
+        return 1;
+      r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly);
+      FreeBlob(bp);
+      return r;
+
+    case OPT_MODE_REPACK:
+      bp = OldBlob(oldfile);
+      if (!bp)
+        return 1;
+      r = Pack(filename, key_block_file, signprivate, bp, pad, vblockonly);
+      FreeBlob(bp);
+      return r;
+
     case OPT_MODE_VERIFY:
       return Verify(filename, signpubkey);
+
     default:
-      printf("Must specify a mode.\n");
-      return PrintHelp();
+      fprintf(stderr,
+              "You must specify a mode: --pack, --repack or --verify\n");
+      return PrintHelp(progname);
   }
 }
diff --git a/utility/vbutil_keyblock.c b/utility/vbutil_keyblock.c
index 43c5f06..dbdcbd3 100644
--- a/utility/vbutil_keyblock.c
+++ b/utility/vbutil_keyblock.c
@@ -93,7 +93,7 @@
     fprintf(stderr, "vbutil_keyblock: Error reading data key.\n");
     return 1;
   }
-  signing_key = PrivateKeyRead(signprivate, algorithm);
+  signing_key = PrivateKeyReadPem(signprivate, algorithm);
   if (!signing_key) {
     fprintf(stderr, "vbutil_keyblock: Error reading signing key.\n");
     return 1;