Create vbutil_ec tool for signing EC firmware.

This just adds the vbutil_ec tool (and a simple test of the library
functions related to it).

BUG=chrome-os-partner:7459, chromium-os:27142
TEST=manual

  make
  make runtests

Change-Id: I2a2c4e7cfb8ac6ce2229c5de4252a5cc89321fa5
Reviewed-on: https://gerrit.chromium.org/gerrit/21868
Commit-Ready: Bill Richardson <wfrichar@chromium.org>
Tested-by: Bill Richardson <wfrichar@chromium.org>
Reviewed-by: Stefan Reinauer <reinauer@google.com>
Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h
index 48a4f6b..0f6b98d 100644
--- a/firmware/include/vboot_struct.h
+++ b/firmware/include/vboot_struct.h
@@ -76,6 +76,42 @@
 
 #define EXPECTED_VBKEYBLOCKHEADER_SIZE 112
 
+/****************************************************************************/
+
+#define EC_PREAMBLE_HEADER_VERSION_MAJOR 1
+#define EC_PREAMBLE_HEADER_VERSION_MINOR 0
+
+/* Flags for VbECPreambleHeader.flags */
+
+/* Use the normal boot path from the read-only firmware, instead
+ * of verifying the body signature. */
+#define VB_EC_PREAMBLE_USE_RO_NORMAL 0x00000001
+
+/* Premable block for EC rewritable firmware, version 1.0 */
+typedef struct VbECPreambleHeader {
+  uint64_t preamble_size;            /* Size of this preamble, including keys,
+                                      * signatures, and padding, in bytes */
+  VbSignature preamble_signature;    /* Signature for this preamble
+                                      * (header + * body signature) */
+  uint32_t header_version_major;     /* Version of this header format */
+  uint32_t header_version_minor;     /* Version of this header format */
+
+  uint64_t firmware_version;         /* Firmware version */
+  VbSignature body_digest;           /* Digest for the firmware body */
+
+  uint32_t flags;                    /* Flags; see VB_EC_PREAMBLE_* */
+  char name[128];                    /* Human-readable ASCII, null-padded */
+} __attribute__((packed)) VbECPreambleHeader;
+
+#define EXPECTED_VB_EC_PREAMBLE_HEADER1_0_SIZE 76
+
+/* The firmware preamble header should be followed by:
+ *   2) The signature data for the firmware body, pointed to by
+ *      body_signature.sig_offset.
+ *   3) The signature data for (header + body signature data), pointed
+ *      to by preamble_signature.sig_offset. */
+
+/****************************************************************************/
 
 #define FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR 2
 #define FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR 1
@@ -134,6 +170,7 @@
  *   3) The signature data for (header + kernel_subkey data + body signature
  *      data), pointed to by preamble_signature.sig_offset. */
 
+/****************************************************************************/
 
 #define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2
 #define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 0
@@ -162,6 +199,8 @@
 
 #define EXPECTED_VBKERNELPREAMBLEHEADER_SIZE 96
 
+/****************************************************************************/
+
 /* Constants and sub-structures for VbSharedDataHeader */
 
 /* Magic number for recognizing VbSharedDataHeader ("VbSD") */
diff --git a/firmware/lib/include/vboot_common.h b/firmware/lib/include/vboot_common.h
index 3203106..7032def 100644
--- a/firmware/lib/include/vboot_common.h
+++ b/firmware/lib/include/vboot_common.h
@@ -81,10 +81,14 @@
 
 
 /* Verifies a secure hash digest from DigestBuf() or DigestFinal(),
- * using [key]. */
+ * using [key]. Returns 0 on success. */
 int VerifyDigest(const uint8_t* digest, const VbSignature *sig,
                  const RSAPublicKey* key);
 
+/* Uses [key] algorithm to hash [data], then compares that to the expected
+ * [hash]. Returns 0 if they're equal, non-zero if error. */
+int EqualData(const uint8_t* data, uint64_t size, const VbSignature *hash,
+              const RSAPublicKey* key);
 
 /* Checks the sanity of a key block of size [size] bytes, using public
  * key [key].  If hash_only is non-zero, uses only the block checksum
@@ -94,6 +98,14 @@
                    const VbPublicKey *key, int hash_only);
 
 
+/* Checks the sanity of an EC preamble of size [size] bytes,
+ * using public key [key].
+ *
+ * Returns VBOOT_SUCCESS if successful. */
+int VerifyECPreamble(const VbECPreambleHeader* preamble,
+                     uint64_t size, const RSAPublicKey* key);
+
+
 /* Checks the sanity of a firmware preamble of size [size] bytes,
  * using public key [key].
  *
diff --git a/firmware/lib/vboot_common.c b/firmware/lib/vboot_common.c
index 5622d13..e074d61 100644
--- a/firmware/lib/vboot_common.c
+++ b/firmware/lib/vboot_common.c
@@ -173,6 +173,28 @@
 }
 
 
+int EqualData(const uint8_t* data, uint64_t size, const VbSignature *hash,
+              const RSAPublicKey* key) {
+  uint8_t* digest = NULL;
+  int rv;
+
+  if (hash->sig_size != hash_size_map[key->algorithm]) {
+    VBDEBUG(("Wrong hash size for algorithm.\n"));
+    return 1;
+  }
+  if (hash->data_size > size) {
+    VBDEBUG(("Data buffer smaller than length of signed data.\n"));
+    return 1;
+  }
+
+  digest = DigestBuf(data, hash->data_size, key->algorithm);
+
+  rv = SafeMemcmp(digest, GetSignatureDataC(hash), hash->sig_size);
+  VbExFree(digest);
+  return rv;
+}
+
+
 int KeyBlockVerify(const VbKeyBlockHeader* block, uint64_t size,
                    const VbPublicKey *key, int hash_only) {
 
@@ -291,6 +313,62 @@
 }
 
 
+int VerifyECPreamble(const VbECPreambleHeader* preamble,
+                           uint64_t size, const RSAPublicKey* key) {
+
+  const VbSignature* sig = &preamble->preamble_signature;
+
+  /* Sanity checks before attempting signature of data */
+  if(size < EXPECTED_VB_EC_PREAMBLE_HEADER1_0_SIZE) {
+    VBDEBUG(("Not enough data for EC preamble header.\n"));
+    return VBOOT_PREAMBLE_INVALID;
+  }
+  if (preamble->header_version_major !=
+      EC_PREAMBLE_HEADER_VERSION_MAJOR) {
+    VBDEBUG(("Incompatible EC preamble header version (%d, not %d).\n",
+             preamble->header_version_major,
+             EC_PREAMBLE_HEADER_VERSION_MAJOR));
+    return VBOOT_PREAMBLE_INVALID;
+  }
+  if (size < preamble->preamble_size) {
+    VBDEBUG(("Not enough data for EC preamble.\n"));
+    return VBOOT_PREAMBLE_INVALID;
+  }
+
+  /* Check signature */
+  if (VerifySignatureInside(preamble, preamble->preamble_size, sig)) {
+    VBDEBUG(("EC preamble signature off end of preamble\n"));
+    return VBOOT_PREAMBLE_INVALID;
+  }
+
+  /* Make sure advertised signature data sizes are sane. */
+  if (preamble->preamble_size < sig->data_size) {
+    VBDEBUG(("EC signature calculated past end of the block\n"));
+    return VBOOT_PREAMBLE_INVALID;
+  }
+
+  if (VerifyData((const uint8_t*)preamble, size, sig, key)) {
+    VBDEBUG(("EC preamble signature validation failed\n"));
+    return VBOOT_PREAMBLE_SIGNATURE;
+  }
+
+  /* Verify we signed enough data */
+  if (sig->data_size < sizeof(VbFirmwarePreambleHeader)) {
+    VBDEBUG(("Didn't sign enough data\n"));
+    return VBOOT_PREAMBLE_INVALID;
+  }
+
+  /* Verify body digest is inside the signed data */
+  if (VerifySignatureInside(preamble, sig->data_size,
+                            &preamble->body_digest)) {
+    VBDEBUG(("EC body digest off end of preamble\n"));
+    return VBOOT_PREAMBLE_INVALID;
+  }
+
+  /* Success */
+  return VBOOT_SUCCESS;
+}
+
 int VerifyFirmwarePreamble(const VbFirmwarePreambleHeader* preamble,
                            uint64_t size, const RSAPublicKey* key) {
 
diff --git a/host/include/host_common.h b/host/include/host_common.h
index 5d20630..6fa8b3e 100644
--- a/host/include/host_common.h
+++ b/host/include/host_common.h
@@ -22,6 +22,18 @@
 #include "vboot_struct.h"
 
 
+/* Creates an EC preamble, signed with [signing_key].
+ * Caller owns the returned pointer, and must free it with Free().
+ *
+ * Returns NULL if error. */
+VbECPreambleHeader* CreateECPreamble(
+    uint64_t firmware_version,
+    const VbSignature* body_signature,
+    const VbPrivateKey* signing_key,
+    uint32_t flags,
+    const char* name);
+
+
 /* Creates a firmware preamble, signed with [signing_key].
  * Caller owns the returned pointer, and must free it with Free().
  *
diff --git a/host/include/host_signature.h b/host/include/host_signature.h
index f08547c..fb03c6c 100644
--- a/host/include/host_signature.h
+++ b/host/include/host_signature.h
@@ -36,6 +36,13 @@
 VbSignature* CalculateChecksum(const uint8_t* data, uint64_t size);
 
 
+/* Calculates a hash of the data using the algorithm from the specified key.
+ * Caller owns the returned pointer, and must free it with Free().
+ *
+ * Returns NULL on error. */
+VbSignature* CalculateHash(const uint8_t* data, uint64_t size,
+                           const VbPrivateKey* key);
+
 /* Calculates a signature for the data using the specified key.
  * Caller owns the returned pointer, and must free it with Free().
  *
diff --git a/host/lib/host_common.c b/host/lib/host_common.c
index cb51392..3aceddd 100644
--- a/host/lib/host_common.c
+++ b/host/lib/host_common.c
@@ -6,6 +6,7 @@
  */
 
 /* TODO: change all 'return 0', 'return 1' into meaningful return codes */
+#include <string.h>
 
 #include "host_common.h"
 
@@ -13,6 +14,53 @@
 #include "utility.h"
 #include "vboot_common.h"
 
+VbECPreambleHeader* CreateECPreamble(
+    uint64_t firmware_version,
+    const VbSignature* body_digest,
+    const VbPrivateKey* signing_key,
+    uint32_t flags,
+    const char* name) {
+
+  VbECPreambleHeader* h;
+  uint64_t signed_size = (sizeof(VbECPreambleHeader) + body_digest->sig_size);
+  uint64_t block_size = signed_size + siglen_map[signing_key->algorithm];
+  uint8_t* body_digest_dest;
+  uint8_t* block_sig_dest;
+  VbSignature *sigtmp;
+
+  /* Allocate key block */
+  h = (VbECPreambleHeader*)malloc(block_size);
+  if (!h)
+    return NULL;
+  Memset(h, 0, block_size);
+  body_digest_dest = (uint8_t*)(h + 1);
+  block_sig_dest = body_digest_dest + body_digest->sig_size;
+
+  h->header_version_major = EC_PREAMBLE_HEADER_VERSION_MAJOR;
+  h->header_version_minor = EC_PREAMBLE_HEADER_VERSION_MINOR;
+  h->preamble_size = block_size;
+  h->firmware_version = firmware_version;
+  h->flags = flags;
+  if (name)
+    strncpy(h->name, name, sizeof(h->name));
+
+  /* Copy body hash */
+  SignatureInit(&h->body_digest, body_digest_dest,
+                body_digest->sig_size, 0);
+  SignatureCopy(&h->body_digest, body_digest);
+
+  /* Set up signature struct so we can calculate the signature */
+  SignatureInit(&h->preamble_signature, block_sig_dest,
+                siglen_map[signing_key->algorithm], signed_size);
+
+  /* Calculate signature */
+  sigtmp = CalculateSignature((uint8_t*)h, signed_size, signing_key);
+  SignatureCopy(&h->preamble_signature, sigtmp);
+  free(sigtmp);
+
+  /* Return the header */
+  return h;
+}
 
 VbFirmwarePreambleHeader* CreateFirmwarePreamble(
     uint64_t firmware_version,
diff --git a/host/lib/host_signature.c b/host/lib/host_signature.c
index 4dbac49..0ebbca6 100644
--- a/host/lib/host_signature.c
+++ b/host/lib/host_signature.c
@@ -78,6 +78,32 @@
   return sig;
 }
 
+VbSignature* CalculateHash(const uint8_t* data, uint64_t size,
+                           const VbPrivateKey* key) {
+  uint8_t* digest = NULL;
+  int digest_size = hash_size_map[key->algorithm];
+  VbSignature* sig = NULL;
+
+  /* Calculate the digest */
+  digest = DigestBuf(data, size, key->algorithm);
+  if (!digest)
+    return NULL;
+
+  /* Allocate output signature */
+  sig = SignatureAlloc(digest_size, size);
+  if (!sig) {
+    free(digest);
+    return NULL;
+  }
+
+  /* The digest itself is the signature data */
+  Memcpy(GetSignatureData(sig), digest, digest_size);
+  free(digest);
+
+  /* Return the signature */
+  return sig;
+}
+
 VbSignature* CalculateSignature(const uint8_t* data, uint64_t size,
                                 const VbPrivateKey* key) {
 
diff --git a/scripts/keygeneration/common.sh b/scripts/keygeneration/common.sh
index 1d08fdb..b6e20c6 100755
--- a/scripts/keygeneration/common.sh
+++ b/scripts/keygeneration/common.sh
@@ -23,7 +23,10 @@
   echo $(( 1 << (10 + ($1 / 3)) ))
 }
 
-# Default alrogithms.
+# Default algorithms.
+EC_ROOT_KEY_ALGOID=7
+EC_DATAKEY_ALGOID=7
+
 ROOT_KEY_ALGOID=11
 RECOVERY_KEY_ALGOID=11
 
@@ -37,13 +40,13 @@
 
 # Keyblock modes determine which boot modes a signing key is valid for use
 # in verification.
-FIRMWARE_KEYBLOCK_MODE=7
+EC_KEYBLOCK_MODE=7  # Only allow RW EC firmware in non-recovery.
+FIRMWARE_KEYBLOCK_MODE=7  # Only allow RW firmware in non-recovery.
 DEV_FIRMWARE_KEYBLOCK_MODE=6  # Only allow in dev mode.
-RECOVERY_KERNEL_KEYBLOCK_MODE=11
+RECOVERY_KERNEL_KEYBLOCK_MODE=11 # Only in recovery mode.
 KERNEL_KEYBLOCK_MODE=7  # Only allow in non-recovery.
 INSTALLER_KERNEL_KEYBLOCK_MODE=10  # Only allow in Dev + Recovery.
 
-
 # Emit .vbpubk and .vbprivk using given basename and algorithm
 # NOTE: This function also appears in ../../utility/dev_make_keypair. Making
 # the two implementations the same would require some common.sh, which is more
diff --git a/scripts/keygeneration/create_new_keys.sh b/scripts/keygeneration/create_new_keys.sh
index 054a3ed..722d69d 100755
--- a/scripts/keygeneration/create_new_keys.sh
+++ b/scripts/keygeneration/create_new_keys.sh
@@ -32,6 +32,7 @@
 fi
 
 # Get the key versions for normal keypairs
+ECKEY_VERSION=$(get_version "ec_key_version")
 FKEY_VERSION=$(get_version "firmware_key_version")
 # Firmware version is the kernel subkey version.
 KSUBKEY_VERSION=$(get_version "firmware_version")
@@ -39,6 +40,8 @@
 KDATAKEY_VERSION=$(get_version "kernel_key_version")
 
 # Create the normal keypairs
+make_pair ec_root_key              $EC_ROOT_KEY_ALGOID
+make_pair ec_data_key              $EC_DATAKEY_ALGOID $ECKEY_VERSION
 make_pair root_key                 $ROOT_KEY_ALGOID
 make_pair firmware_data_key        $FIRMWARE_DATAKEY_ALGOID $FKEY_VERSION
 if [ -n "$DEV_KEYBLOCK_FLAG" ]; then
@@ -55,14 +58,14 @@
 # Create the firmware keyblock for use only in Normal mode. This is redundant,
 # since it's never even checked during Recovery mode.
 make_keyblock firmware $FIRMWARE_KEYBLOCK_MODE firmware_data_key root_key
-
+# Ditto EC keyblock
+make_keyblock ec $EC_KEYBLOCK_MODE ec_data_key ec_root_key
 
 if [ -n "$DEV_KEYBLOCK_FLAG" ]; then
   # Create the dev firmware keyblock for use only in Developer mode.
   make_keyblock dev_firmware $DEV_FIRMWARE_KEYBLOCK_MODE dev_firmware_data_key root_key
 fi
 
-
 # Create the recovery kernel keyblock for use only in Recovery mode.
 make_keyblock recovery_kernel $RECOVERY_KERNEL_KEYBLOCK_MODE recovery_kernel_data_key recovery_key
 
diff --git a/tests/Makefile b/tests/Makefile
index f7f0cba..9df9a69 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -40,6 +40,7 @@
 	     vboot_common_tests \
 	     vboot_common2_tests \
 	     vboot_common3_tests \
+	     vboot_ec_tests \
 	     vboot_firmware_tests \
 	     vboot_nvstorage_test \
 	     vboot_api_devmode_tests \
@@ -150,6 +151,7 @@
 	${BUILD_ROOT}/rsa_utility_tests
 	${BUILD_ROOT}/sha_tests
 	./run_vboot_common_tests.sh
+	./run_vboot_ec_tests.sh
 
 # Run other misc tests
 runmisctests:
diff --git a/tests/devkeys/ec.keyblock b/tests/devkeys/ec.keyblock
new file mode 100644
index 0000000..6b088f3
--- /dev/null
+++ b/tests/devkeys/ec.keyblock
Binary files differ
diff --git a/tests/devkeys/ec_data_key.vbprivk b/tests/devkeys/ec_data_key.vbprivk
new file mode 100644
index 0000000..9f194ce
--- /dev/null
+++ b/tests/devkeys/ec_data_key.vbprivk
Binary files differ
diff --git a/tests/devkeys/ec_data_key.vbpubk b/tests/devkeys/ec_data_key.vbpubk
new file mode 100644
index 0000000..5804dfd
--- /dev/null
+++ b/tests/devkeys/ec_data_key.vbpubk
Binary files differ
diff --git a/tests/devkeys/ec_root_key.vbprivk b/tests/devkeys/ec_root_key.vbprivk
new file mode 100644
index 0000000..4914472
--- /dev/null
+++ b/tests/devkeys/ec_root_key.vbprivk
Binary files differ
diff --git a/tests/devkeys/ec_root_key.vbpubk b/tests/devkeys/ec_root_key.vbpubk
new file mode 100644
index 0000000..76c26f9
--- /dev/null
+++ b/tests/devkeys/ec_root_key.vbpubk
Binary files differ
diff --git a/tests/run_vboot_common_tests.sh b/tests/run_vboot_common_tests.sh
index 6295f40..9d4373f 100755
--- a/tests/run_vboot_common_tests.sh
+++ b/tests/run_vboot_common_tests.sh
@@ -4,7 +4,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# Run verified boot firmware and kernel verification tests. 
+# Run verified boot firmware and kernel verification tests.
 
 # Load common constants and variables.
 . "$(dirname "$0")/common.sh"
diff --git a/tests/run_vboot_ec_tests.sh b/tests/run_vboot_ec_tests.sh
new file mode 100755
index 0000000..b5b0e7b
--- /dev/null
+++ b/tests/run_vboot_ec_tests.sh
@@ -0,0 +1,19 @@
+#!/bin/bash -eu
+
+# Copyright (c) 2010 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.
+
+# Run verified boot firmware and kernel verification tests.
+
+# Load common constants and variables.
+. "$(dirname "$0")/common.sh"
+
+check_test_keys
+
+for priv in ${TESTKEY_DIR}/*.vbprivk; do
+  root=$(basename ${i%.vbprivk})
+  pub="${priv%.vbprivk}.vbpubk"
+  echo "Trying $root ..."
+  ${TEST_DIR}/vboot_ec_tests "$priv" "$pub"
+done
diff --git a/tests/vboot_ec_tests.c b/tests/vboot_ec_tests.c
new file mode 100644
index 0000000..831565f
--- /dev/null
+++ b/tests/vboot_ec_tests.c
@@ -0,0 +1,160 @@
+/* Copyright (c) 2011 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.
+ *
+ * Tests for EC firmware vboot stuff.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cryptolib.h"
+#include "file_keys.h"
+#include "host_common.h"
+#include "test_common.h"
+#include "vboot_common.h"
+
+static void ReSignECPreamble(VbECPreambleHeader* h,
+                                   const VbPrivateKey* key) {
+  VbSignature *sig = CalculateSignature((const uint8_t*)h,
+                                        h->preamble_signature.data_size, key);
+
+  SignatureCopy(&h->preamble_signature, sig);
+  free(sig);
+}
+
+
+static void VerifyECPreambleTest(const VbPublicKey* public_key,
+                                 const VbPrivateKey* private_key) {
+  VbECPreambleHeader* hdr;
+  VbECPreambleHeader* h;
+  RSAPublicKey* rsa;
+  unsigned hsize;
+
+  /* Create a dummy signature */
+  VbSignature* body_sig = SignatureAlloc(56, 78);
+
+  rsa = PublicKeyToRSA(public_key);
+  hdr = CreateECPreamble(0x1234, body_sig, private_key,
+                         0x5678, "Foo bar");
+  TEST_NEQ(hdr && rsa, 0, "VerifyECPreamble() prerequisites");
+  if (!hdr)
+    return;
+
+  hsize = (unsigned) hdr->preamble_size;
+  h = (VbECPreambleHeader*)malloc(hsize + 16384);
+
+  TEST_EQ(VerifyECPreamble(hdr, hsize, rsa), 0,
+          "VerifyECPreamble() ok using key");
+  TEST_NEQ(VerifyECPreamble(hdr, hsize - 1, rsa), 0,
+           "VerifyECPreamble() size--");
+  TEST_EQ(VerifyECPreamble(hdr, hsize + 1, rsa), 0,
+           "VerifyECPreamble() size++");
+
+  TEST_EQ(hdr->firmware_version, 0x1234,
+          "VerifyECPreamble() firmware version");
+  TEST_EQ(hdr->flags, 0x5678,
+          "VerifyECPreamble() flags");
+  TEST_EQ(strncmp(hdr->name, "Foo bar", sizeof(hdr->name)), 0,
+          "VerifyECPreamble() name");
+
+  /* Care about major version but not minor */
+  Memcpy(h, hdr, hsize);
+  h->header_version_major++;
+  ReSignECPreamble(h, private_key);
+  TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
+           "VerifyECPreamble() major++");
+
+  Memcpy(h, hdr, hsize);
+  h->header_version_major--;
+  ReSignECPreamble(h, private_key);
+  TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
+           "VerifyECPreamble() major--");
+
+  Memcpy(h, hdr, hsize);
+  h->header_version_minor++;
+  ReSignECPreamble(h, private_key);
+  TEST_EQ(VerifyECPreamble(h, hsize, rsa), 0,
+          "VerifyECPreamble() minor++");
+
+  Memcpy(h, hdr, hsize);
+  h->header_version_minor--;
+  ReSignECPreamble(h, private_key);
+  TEST_EQ(VerifyECPreamble(h, hsize, rsa), 0,
+          "VerifyECPreamble() minor--");
+
+  /* Check signature */
+  Memcpy(h, hdr, hsize);
+  h->preamble_signature.sig_offset = hsize;
+  ReSignECPreamble(h, private_key);
+  TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
+           "VerifyECPreamble() sig off end");
+
+  Memcpy(h, hdr, hsize);
+  h->preamble_signature.sig_size--;
+  ReSignECPreamble(h, private_key);
+  TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
+           "VerifyECPreamble() sig too small");
+
+  Memcpy(h, hdr, hsize);
+  GetSignatureData(&h->body_digest)[0] ^= 0x34;
+  TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
+           "VerifyECPreamble() sig mismatch");
+
+  /* Check that we signed header and body sig */
+  Memcpy(h, hdr, hsize);
+  h->preamble_signature.data_size = 4;
+  h->body_digest.sig_offset = 0;
+  h->body_digest.sig_size = 0;
+  ReSignECPreamble(h, private_key);
+  TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
+           "VerifyECPreamble() didn't sign header");
+
+  Memcpy(h, hdr, hsize);
+  h->body_digest.sig_offset = hsize;
+  ReSignECPreamble(h, private_key);
+  TEST_NEQ(VerifyECPreamble(h, hsize, rsa), 0,
+           "VerifyECPreamble() body sig off end");
+
+  /* TODO: verify with extra padding at end of header. */
+
+  free(h);
+  RSAPublicKeyFree(rsa);
+  free(hdr);
+}
+
+
+int main(int argc, char* argv[]) {
+  VbPrivateKey* signing_private_key = NULL;
+  VbPublicKey* signing_public_key = NULL;
+
+  int error_code = 0;
+
+  if(argc != 3) {
+    fprintf(stderr, "Usage: %s <signing privkey> <signing pubkey>", argv[0]);
+    return -1;
+  }
+
+  signing_private_key = PrivateKeyRead(argv[1]);
+  if (!signing_private_key) {
+    fprintf(stderr, "Error reading signing_private_key\n");
+    return 1;
+  }
+
+  signing_public_key = PublicKeyRead(argv[2]);
+  if (!signing_public_key) {
+    fprintf(stderr, "Error reading signing_public_key\n");
+    return 1;
+  }
+
+  VerifyECPreambleTest(signing_public_key, signing_private_key);
+
+
+  if (signing_public_key)
+    free(signing_public_key);
+  if (signing_private_key)
+    free(signing_private_key);
+
+  return error_code;
+}
diff --git a/utility/Makefile b/utility/Makefile
index 59d624a..7f1e15e 100644
--- a/utility/Makefile
+++ b/utility/Makefile
@@ -27,6 +27,7 @@
 		tlcl_generator \
 		tpm_init_temp_fix \
 		tpmc \
+		vbutil_ec \
 		vbutil_firmware \
 		vbutil_kernel \
 		vbutil_key \
@@ -120,6 +121,9 @@
 ${BUILD_ROOT}/tlcl_generator: tlcl_generator.c
 	$(HOSTCC) $(CFLAGS) -fpack-struct $< -o $@
 
+${BUILD_ROOT}/vbutil_ec: vbutil_ec.c $(LIBS)
+	$(CC) $(CFLAGS) $< -o $@ $(LIBS) -lcrypto
+
 ${BUILD_ROOT}/vbutil_firmware: vbutil_firmware.c $(LIBS)
 	$(CC) $(CFLAGS) $< -o $@ $(LIBS) -lcrypto
 
diff --git a/utility/vbutil_ec.c b/utility/vbutil_ec.c
new file mode 100644
index 0000000..86747c0
--- /dev/null
+++ b/utility/vbutil_ec.c
@@ -0,0 +1,327 @@
+/* Copyright (c) 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 utility for EC firmware
+ */
+
+#include <getopt.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "cryptolib.h"
+#include "host_common.h"
+#include "vboot_common.h"
+
+
+/* Command line options */
+enum {
+  OPT_MODE_VBLOCK = 1000,
+  OPT_MODE_VERIFY,
+  OPT_KEYBLOCK,
+  OPT_SIGNPUBKEY,
+  OPT_SIGNPRIVATE,
+  OPT_VERSION,
+  OPT_FV,
+  OPT_KERNELKEY,
+  OPT_FLAGS,
+  OPT_NAME,
+};
+
+static struct option long_opts[] = {
+  {"vblock", 1, 0,                    OPT_MODE_VBLOCK             },
+  {"verify", 1, 0,                    OPT_MODE_VERIFY             },
+  {"keyblock", 1, 0,                  OPT_KEYBLOCK                },
+  {"signpubkey", 1, 0,                OPT_SIGNPUBKEY              },
+  {"signprivate", 1, 0,               OPT_SIGNPRIVATE             },
+  {"version", 1, 0,                   OPT_VERSION                 },
+  {"fv", 1, 0,                        OPT_FV                      },
+  {"flags", 1, 0,                     OPT_FLAGS                   },
+  {"name", 1, 0,                      OPT_NAME                    },
+  {NULL, 0, 0, 0}
+};
+
+
+/* Print help and return error */
+static int PrintHelp(void) {
+
+  puts("vbutil_ec - Verified boot signing utility for EC firmware\n"
+       "\n"
+       "Usage:  vbutil_ec <--vblock|--verify> <file> [OPTIONS]\n"
+       "\n"
+       "For '--vblock <file>', required OPTIONS are:\n"
+       "  --keyblock <file>           Key block in .keyblock format\n"
+       "  --signprivate <file>        Signing private key in .vbprivk format\n"
+       "  --version <number>          Firmware version\n"
+       "  --fv <file>                 Firmware volume to sign\n"
+       "optional OPTIONS are:\n"
+       "  --flags <number>            Preamble flags (defaults to 0)\n"
+       "  --name <string>             Human-readable description\n"
+       "\n"
+       "For '--verify <file>', required OPTIONS are:\n"
+       "  --fv <file>                 Firmware volume to verify\n"
+       "optional OPTIONS are:\n"
+       "  --signpubkey <file>         Signing public key in .vbpubk format\n"
+       "\n");
+  return 1;
+}
+
+
+/* Create an EC firmware .vblock */
+static int Vblock(const char* outfile, const char* keyblock_file,
+                  const char* signprivate, uint64_t version,
+                  const char* fv_file, uint32_t preamble_flags,
+                  const char* name) {
+  VbPrivateKey* signing_key;
+  VbSignature* body_digest;
+  VbECPreambleHeader* preamble;
+  VbKeyBlockHeader* key_block;
+  uint64_t key_block_size;
+  uint8_t* fv_data;
+  uint64_t fv_size;
+  FILE* f;
+  uint64_t i;
+
+  if (!outfile)
+    VbExError("Must specify output filename\n");
+
+  if (!keyblock_file || !signprivate)
+    VbExError("Must specify all keys\n");
+
+  if (!fv_file)
+    VbExError("Must specify firmware volume\n");
+
+  /* Read the key block and keys */
+  key_block = (VbKeyBlockHeader*)ReadFile(keyblock_file, &key_block_size);
+  if (!key_block)
+    VbExError("Error reading key block.\n");
+
+  signing_key = PrivateKeyRead(signprivate);
+  if (!signing_key)
+    VbExError("Error reading signing key.\n");
+
+  /* Read and sign the firmware volume */
+  fv_data = ReadFile(fv_file, &fv_size);
+  if (!fv_data)
+    return 1;
+  if (!fv_size)
+    VbExError("Empty firmware volume file\n");
+
+  if (name && strlen(name)+1 > sizeof(preamble->name))
+    VbExError("Name string is too long\n");
+
+  body_digest = CalculateHash(fv_data, fv_size, signing_key);
+  if (!body_digest)
+    VbExError("Error calculating body digest\n");
+  free(fv_data);
+
+  /* Create preamble */
+  preamble = CreateECPreamble(version, body_digest, signing_key,
+                              preamble_flags, name);
+  if (!preamble)
+    VbExError("Error creating preamble.\n");
+
+  /* Write the output file */
+  f = fopen(outfile, "wb");
+  if (!f)
+    VbExError("Can't open output file %s\n", outfile);
+
+  i = ((1 != fwrite(key_block, key_block_size, 1, f)) ||
+       (1 != fwrite(preamble, preamble->preamble_size, 1, f)));
+  fclose(f);
+  if (i) {
+    unlink(outfile);
+    VbExError("Can't write output file %s\n", outfile);
+  }
+
+  /* Success */
+  return 0;
+}
+
+static int Verify(const char* infile,
+                  const char* signpubkey,
+                  const char* fv_file) {
+  VbKeyBlockHeader* key_block;
+  VbECPreambleHeader* preamble;
+  VbPublicKey* data_key;
+  VbPublicKey* sign_key = 0;
+  RSAPublicKey* rsa;
+  uint8_t* blob;
+  uint64_t blob_size;
+  uint8_t* fv_data;
+  uint64_t fv_size;
+  uint64_t now = 0;
+
+  if (!infile || !fv_file) {
+    VbExError("Must specify filename and fv\n");
+    return 1;
+  }
+
+  /* Read public signing key */
+  if (signpubkey) {
+    sign_key = PublicKeyRead(signpubkey);
+    if (!sign_key)
+      VbExError("Error reading signpubkey.\n");
+  } else {
+    printf("WARNING:  No public key given - signature is not checked\n");
+  }
+
+  /* Read blob */
+  blob = ReadFile(infile, &blob_size);
+  if (!blob)
+    VbExError("Error reading input file\n");
+
+  /* Read firmware volume */
+  fv_data = ReadFile(fv_file, &fv_size);
+  if (!fv_data)
+    VbExError("Error reading firmware volume\n");
+
+  /* Verify key block */
+  key_block = (VbKeyBlockHeader*)blob;
+  if (0 != KeyBlockVerify(key_block, blob_size, sign_key, !signpubkey))
+    VbExError("Error verifying key block.\n");
+
+  if (sign_key)
+    free(sign_key);
+  now += key_block->key_block_size;
+
+  printf("Key block:\n");
+  data_key = &key_block->data_key;
+  printf("  Size:                %" PRIu64 "\n", key_block->key_block_size);
+  printf("  Flags:               %" PRIu64 " (ignored)\n",
+         key_block->key_block_flags);
+  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");
+
+  rsa = PublicKeyToRSA(&key_block->data_key);
+  if (!rsa)
+    VbExError("Error parsing data key.\n");
+
+  /* Verify preamble */
+  preamble = (VbECPreambleHeader*)(blob + now);
+  if (0 != VerifyECPreamble(preamble, blob_size - now, rsa))
+    VbExError("Error verifying preamble.\n");
+
+  now += preamble->preamble_size;
+
+  printf("Preamble:\n");
+  printf("  Size:                  %" PRIu64 "\n", preamble->preamble_size);
+  printf("  Header version:        %" PRIu32 ".%" PRIu32"\n",
+         preamble->header_version_major, preamble->header_version_minor);
+  printf("  Firmware version:      %" PRIu64 "\n", preamble->firmware_version);
+  printf("  Firmware body size:    %" PRIu64 "\n",
+         preamble->body_digest.data_size);
+  printf("  Preamble flags:        %" PRIu32 "\n", preamble->flags);
+  printf("  Preamble name:         %s\n", preamble->name);
+
+  /* TODO: verify body size same as signature size */
+
+  /* Verify body */
+  if (preamble->flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) {
+    printf("Preamble requests USE_RO_NORMAL; skipping body verification.\n");
+  } else {
+    if (0 != EqualData(fv_data, fv_size, &preamble->body_digest, rsa))
+      VbExError("Error verifying firmware body.\n");
+    printf("Body verification succeeded.\n");
+  }
+
+  return 0;
+}
+
+
+int main(int argc, char* argv[]) {
+
+  char* filename = NULL;
+  char* key_block_file = NULL;
+  char* signpubkey = NULL;
+  char* signprivate = NULL;
+  uint64_t version = 0;
+  int got_version = 0;
+  char* fv_file = NULL;
+  uint32_t preamble_flags = 0;
+  char *name = NULL;
+  int mode = 0;
+  int parse_error = 0;
+  char* e;
+  int i;
+
+  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_VBLOCK:
+      case OPT_MODE_VERIFY:
+        mode = i;
+        filename = optarg;
+        break;
+
+      case OPT_KEYBLOCK:
+        key_block_file = optarg;
+        break;
+
+      case OPT_SIGNPUBKEY:
+        signpubkey = optarg;
+        break;
+
+      case OPT_SIGNPRIVATE:
+        signprivate = optarg;
+        break;
+
+      case OPT_FV:
+        fv_file = optarg;
+        break;
+
+      case OPT_VERSION:
+        version = strtoul(optarg, &e, 0);
+        if (!*optarg || (e && *e)) {
+          printf("Invalid --version\n");
+          parse_error = 1;
+        }
+        got_version = 1;
+        break;
+
+      case OPT_FLAGS:
+        preamble_flags = strtoul(optarg, &e, 0);
+        if (!*optarg || (e && *e)) {
+          printf("Invalid --flags\n");
+          parse_error = 1;
+        }
+        break;
+
+    case OPT_NAME:
+      name = optarg;
+      break;
+    }
+  }
+
+  if (parse_error)
+    return PrintHelp();
+
+  switch(mode) {
+    case OPT_MODE_VBLOCK:
+      if (!got_version) {
+        printf("Must specify a version\n");
+        return PrintHelp();
+      }
+      return Vblock(filename, key_block_file, signprivate, version,
+                    fv_file, preamble_flags, name);
+    case OPT_MODE_VERIFY:
+      return Verify(filename, signpubkey, fv_file);
+    default:
+      printf("Must specify a mode.\n");
+      return PrintHelp();
+  }
+}