VBoot Reference: Refactor Pass 1: Split {firmware|kernel}_image

This CL refactors verified boot firmware and kernel image functions into firmware and userland portions. Data Types and Functions that need to be a part of the final firmware implementation reside in files with "_fw" suffix - firmware_image_fw.{c|h} and kernel_image_fw.{c|h}.

Also some Makefile cleanups.

Review URL: http://codereview.chromium.org/1599001
diff --git a/common/utility_stub.c b/common/utility_stub.c
index 2d01226..d2244c7 100644
--- a/common/utility_stub.c
+++ b/common/utility_stub.c
@@ -8,9 +8,27 @@
 
 #include "utility.h"
 
+#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 
+void error(const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  fprintf(stderr, "ERROR: ");
+  vfprintf(stderr, format, ap);
+  va_end(ap);
+  exit(1);
+}
+
+void debug(const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  fprintf(stderr, "WARNING: ");
+  vfprintf(stderr, format, ap);
+  va_end(ap);
+}
+
 void* Malloc(size_t size) {
   void* p = malloc(size);
   if (!p) {
diff --git a/include/firmware_image.h b/include/firmware_image.h
index 810e3a0..19a87d9 100644
--- a/include/firmware_image.h
+++ b/include/firmware_image.h
@@ -2,53 +2,14 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  *
- * Data structure and API definitions for a verified boot firmware image.
+ * API definitions for a verified boot firmware image.
+ * (Userland Portion)
  */
 
 #ifndef VBOOT_REFERENCE_FIRMWARE_IMAGE_H_
 #define VBOOT_REFERENCE_FIRMWARE_IMAGE_H_
 
-#include <inttypes.h>
-
-#include "rsa.h"
-#include "sha.h"
-
-#define FIRMWARE_MAGIC "CHROMEOS"
-#define FIRMWARE_MAGIC_SIZE 8
-#define FIRMWARE_PREAMBLE_SIZE 8
-
-/* RSA 8192 and SHA-512. */
-#define ROOT_SIGNATURE_ALGORITHM 11
-#define ROOT_SIGNATURE_ALGORITHM_STRING "11"
-
-typedef struct FirmwareImage {
-  uint8_t magic[FIRMWARE_MAGIC_SIZE];
-  /* Key Header */
-  uint16_t header_len;  /* Length of the header. */
-  uint16_t firmware_sign_algorithm;  /* Signature algorithm used by the signing
-                                      * key. */
-  uint16_t firmware_key_version;  /* Key Version# for preventing rollbacks. */
-  uint8_t* firmware_sign_key;  /* Pre-processed public half of signing key. */
-  uint8_t header_checksum[SHA512_DIGEST_SIZE];  /* SHA-512 hash of the header.*/
-
-  uint8_t firmware_key_signature[RSA8192NUMBYTES];  /* Signature of the header
-                                                     * above. */
-
-  /* Firmware Preamble. */
-  uint16_t firmware_version;  /* Firmware Version# for preventing rollbacks.*/
-  uint64_t firmware_len;  /* Length of the rest of the R/W firmware data. */
-  uint8_t preamble[FIRMWARE_PREAMBLE_SIZE];  /* Remaining preamble data.*/
-
-  uint8_t* preamble_signature;  /* Signature over the preamble. */
-
-  /* The firmware signature comes first as it may allow us to parallelize
-   * the firmware data fetch and RSA public operation.
-   */
-  uint8_t* firmware_signature;  /* Signature on the Preamble +
-                                   [firmware_data]. */
-  uint8_t* firmware_data;  /* Rest of firmware data */
-
-} FirmwareImage;
+#include "firmware_image_fw.h"
 
 /* Allocate and return a new FirmwareImage structure. */
 FirmwareImage* FirmwareImageNew(void);
@@ -100,77 +61,11 @@
 int WriteFirmwareImage(const char* input_file,
                        const FirmwareImage* image);
 
-
 /* Pretty print the contents of [image]. Only headers and metadata information
  * is printed.
  */
 void PrintFirmwareImage(const FirmwareImage* image);
 
-/* Error Codes for VerifyFirmware* family of functions. */
-#define VERIFY_FIRMWARE_SUCCESS 0
-#define VERIFY_FIRMWARE_INVALID_IMAGE 1
-#define VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED 2
-#define VERIFY_FIRMWARE_INVALID_ALGORITHM 3
-#define VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED 4
-#define VERIFY_FIRMWARE_SIGNATURE_FAILED 5
-#define VERIFY_FIRMWARE_WRONG_MAGIC 6
-#define VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM 7
-#define VERIFY_FIRMWARE_KEY_ROLLBACK 8
-#define VERIFY_FIRMWARE_VERSION_ROLLBACK 9
-#define VERIFY_FIRMWARE_MAX 10  /* Total number of error codes. */
-
-extern char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX];
-
-/* Checks for the sanity of the firmware header pointed by [header_blob].
- *
- * On success, put signature algorithm in [algorithm], header length
- * in [header_len], and return 0.
- * Else, return error code on failure.
- */
-int VerifyFirmwareHeader(const uint8_t* root_key_blob,
-                         const uint8_t* header_blob,
-                         int* algorithm,
-                         int* header_len);
-
-/* Checks the preamble signature on firmware preamble pointed by
- * [preamble_blob] using the signing key [sign_key].
- *
- * On success, put firmware length into [firmware_len], and return 0.
- * Else, return error code on failure.
- */
-int VerifyFirmwarePreamble(RSAPublicKey* sign_key,
-                           const uint8_t* preamble_blob,
-                           int algorithm,
-                           uint64_t* firmware_len);
-
-/* Checks the signature on the preamble + firmware data at
- * [preamble_start] and [firmware_data_start].
- * The length of the actual firmware data is firmware_len and it is assumed to
- * be prepended with the signature whose size depends on the signature_algorithm
- * [algorithm]. This signature also covers the preamble data (but not the
- * preamble signature itself).
- *
- * Return 0 on success, error code on failure.
- */
-int VerifyFirmwareData(RSAPublicKey* sign_key,
-                       const uint8_t* preamble_start,
-                       const uint8_t* firmware_data_start,
-                       uint64_t firmware_len,
-                       int algorithm);
-
-/* Performs a chained verify of the firmware blob [firmware_blob].
- *
- * Returns 0 on success, error code on failure.
- *
- * NOTE: The length of the firmware blob is derived from reading the fields
- * in the first few bytes of the buffer. This might look risky but in firmware
- * land, the start address of the firmware_blob will always be fixed depending
- * on the memory map on the particular platform. In addition, the signature on
- * length itself is checked early in the verification process for extra safety.
- */
-int VerifyFirmware(const uint8_t* root_key_blob,
-                   const uint8_t* firmware_blob);
-
 /* Performs a chained verify of the firmware [image].
  *
  * Returns 0 on success, error code on failure.
@@ -195,26 +90,4 @@
  */
 int AddFirmwareSignature(FirmwareImage* image, const char* signing_key_file);
 
-/* Returns the logical version of a firmware blob which is calculated as
- * (firmware_key_version << 16 | firmware_version). */
-uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob);
-
-#define  BOOT_FIRMWARE_A_CONTINUE 1
-#define  BOOT_FIRMWARE_B_CONTINUE 2
-#define  BOOT_FIRMWARE_RECOVERY_CONTINUE 3
-
-/* This function is the driver used by the RO firmware to
- * determine which copy of the firmware to boot from. It performs
- * the requisite rollback index checking, including updating them,
- * if required.
- *
- * Returns the code path to follow. It is one of:
- * BOOT_FIRMWARE_A_CONTINUE          Boot from Firmware A
- * BOOT_FIRMWARE_B_CONTINUE          Boot from Firmware B
- * BOOT_FIRMWARE_RECOVERY_CONTINUE   Jump to recovery mode
- */
-int VerifyFirmwareDriver_f(uint8_t* root_key_blob,
-                           uint8_t* firmwareA,
-                           uint8_t* firmwareB);
-
 #endif  /* VBOOT_REFERENCE_FIRMWARE_IMAGE_H_ */
diff --git a/include/firmware_image_fw.h b/include/firmware_image_fw.h
new file mode 100644
index 0000000..53b558a
--- /dev/null
+++ b/include/firmware_image_fw.h
@@ -0,0 +1,142 @@
+/* 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.
+ *
+ * Data structure and API definitions for a verified boot firmware image.
+ * (Firmware Portion)
+ */
+
+#ifndef VBOOT_REFERENCE_FIRMWARE_IMAGE_FW_H_
+#define VBOOT_REFERENCE_FIRMWARE_IMAGE_FW_H_
+
+#include <stdint.h>
+#include "rsa.h"
+#include "sha.h"
+
+#define FIRMWARE_MAGIC "CHROMEOS"
+#define FIRMWARE_MAGIC_SIZE 8
+#define FIRMWARE_PREAMBLE_SIZE 8
+
+/* RSA 8192 and SHA-512. */
+#define ROOT_SIGNATURE_ALGORITHM 11
+#define ROOT_SIGNATURE_ALGORITHM_STRING "11"
+
+typedef struct FirmwareImage {
+  uint8_t magic[FIRMWARE_MAGIC_SIZE];
+  /* Key Header */
+  uint16_t header_len;  /* Length of the header. */
+  uint16_t firmware_sign_algorithm;  /* Signature algorithm used by the signing
+                                      * key. */
+  uint16_t firmware_key_version;  /* Key Version# for preventing rollbacks. */
+  uint8_t* firmware_sign_key;  /* Pre-processed public half of signing key. */
+  uint8_t header_checksum[SHA512_DIGEST_SIZE];  /* SHA-512 hash of the header.*/
+
+  uint8_t firmware_key_signature[RSA8192NUMBYTES];  /* Signature of the header
+                                                     * above. */
+
+  /* Firmware Preamble. */
+  uint16_t firmware_version;  /* Firmware Version# for preventing rollbacks.*/
+  uint64_t firmware_len;  /* Length of the rest of the R/W firmware data. */
+  uint8_t preamble[FIRMWARE_PREAMBLE_SIZE];  /* Remaining preamble data.*/
+
+  uint8_t* preamble_signature;  /* Signature over the preamble. */
+
+  /* The firmware signature comes first as it may allow us to parallelize
+   * the firmware data fetch and RSA public operation.
+   */
+  uint8_t* firmware_signature;  /* Signature on the Preamble +
+                                   [firmware_data]. */
+  uint8_t* firmware_data;  /* Rest of firmware data */
+
+} FirmwareImage;
+
+
+/* Error Codes for VerifyFirmware* family of functions. */
+#define VERIFY_FIRMWARE_SUCCESS 0
+#define VERIFY_FIRMWARE_INVALID_IMAGE 1
+#define VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED 2
+#define VERIFY_FIRMWARE_INVALID_ALGORITHM 3
+#define VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED 4
+#define VERIFY_FIRMWARE_SIGNATURE_FAILED 5
+#define VERIFY_FIRMWARE_WRONG_MAGIC 6
+#define VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM 7
+#define VERIFY_FIRMWARE_KEY_ROLLBACK 8
+#define VERIFY_FIRMWARE_VERSION_ROLLBACK 9
+#define VERIFY_FIRMWARE_MAX 10  /* Total number of error codes. */
+
+extern char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX];
+
+/* Checks for the sanity of the firmware header pointed by [header_blob].
+ *
+ * On success, put signature algorithm in [algorithm], header length
+ * in [header_len], and return 0.
+ * Else, return error code on failure.
+ */
+int VerifyFirmwareHeader(const uint8_t* root_key_blob,
+                         const uint8_t* header_blob,
+                         int* algorithm,
+                         int* header_len);
+
+/* Checks the preamble signature on firmware preamble pointed by
+ * [preamble_blob] using the signing key [sign_key].
+ *
+ * On success, put firmware length into [firmware_len], and return 0.
+ * Else, return error code on failure.
+ */
+int VerifyFirmwarePreamble(RSAPublicKey* sign_key,
+                           const uint8_t* preamble_blob,
+                           int algorithm,
+                           uint64_t* firmware_len);
+
+/* Checks the signature on the preamble + firmware data at
+ * [preamble_start] and [firmware_data_start].
+ * The length of the actual firmware data is firmware_len and it is assumed to
+ * be prepended with the signature whose size depends on the signature_algorithm
+ * [algorithm]. This signature also covers the preamble data (but not the
+ * preamble signature itself).
+ *
+ * Return 0 on success, error code on failure.
+ */
+int VerifyFirmwareData(RSAPublicKey* sign_key,
+                       const uint8_t* preamble_start,
+                       const uint8_t* firmware_data_start,
+                       uint64_t firmware_len,
+                       int algorithm);
+
+/* Performs a chained verify of the firmware blob [firmware_blob].
+ *
+ * Returns 0 on success, error code on failure.
+ *
+ * NOTE: The length of the firmware blob is derived from reading the fields
+ * in the first few bytes of the buffer. This might look risky but in firmware
+ * land, the start address of the firmware_blob will always be fixed depending
+ * on the memory map on the particular platform. In addition, the signature on
+ * length itself is checked early in the verification process for extra safety.
+ */
+int VerifyFirmware(const uint8_t* root_key_blob,
+                   const uint8_t* firmware_blob);
+
+/* Returns the logical version of a firmware blob which is calculated as
+ * (firmware_key_version << 16 | firmware_version). */
+uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob);
+
+#define  BOOT_FIRMWARE_A_CONTINUE 1
+#define  BOOT_FIRMWARE_B_CONTINUE 2
+#define  BOOT_FIRMWARE_RECOVERY_CONTINUE 3
+
+/* This function is the driver used by the RO firmware to
+ * determine which copy of the firmware to boot from. It performs
+ * the requisite rollback index checking, including updating them,
+ * if required.
+ *
+ * Returns the code path to follow. It is one of:
+ * BOOT_FIRMWARE_A_CONTINUE          Boot from Firmware A
+ * BOOT_FIRMWARE_B_CONTINUE          Boot from Firmware B
+ * BOOT_FIRMWARE_RECOVERY_CONTINUE   Jump to recovery mode
+ */
+int VerifyFirmwareDriver_f(uint8_t* root_key_blob,
+                           uint8_t* firmwareA,
+                           uint8_t* firmwareB);
+
+
+#endif  /* VBOOT_REFERENCE_FIRMWARE_IMAGE_FW_H_ */
diff --git a/include/kernel_image.h b/include/kernel_image.h
index 3718624..0ea8adb 100644
--- a/include/kernel_image.h
+++ b/include/kernel_image.h
@@ -2,73 +2,14 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  *
- * Data structure and API definitions for a verified boot kernel image.
+ * API definitions for a generating and manipulating verified boot kernel images.
+ * (Userland portion.)
  */
 
 #ifndef VBOOT_REFERENCE_KERNEL_IMAGE_H_
 #define VBOOT_REFERENCE_KERNEL_IMAGE_H_
 
-#include <inttypes.h>
-
-#include "rsa.h"
-#include "sha.h"
-
-#define KERNEL_MAGIC "CHROMEOS"
-#define KERNEL_MAGIC_SIZE 8
-#define KERNEL_CMD_LINE_SIZE 4096
-
-#define DEV_MODE_ENABLED 1
-#define DEV_MODE_DISABLED 0
-
-/* Kernel config file options according to the Chrome OS drive map design. */
-typedef struct kconfig_options {
-  uint32_t version[2];  /* Configuration file version. */
-  uint8_t cmd_line[KERNEL_CMD_LINE_SIZE];  /* Kernel command line option string
-                                            * terminated by a NULL character. */
-  uint64_t kernel_len;  /* Size of the kernel. */
-  uint64_t kernel_load_addr;  /* Load address in memory for the kernel image */
-  uint64_t kernel_entry_addr;  /* Address to jump to after kernel is loaded. */
-} kconfig_options;
-
-
-typedef struct KernelImage {
-  uint8_t magic[KERNEL_MAGIC_SIZE];
-  /* Key header */
-  uint16_t header_version;  /* Header version. */
-  uint16_t header_len;  /* Length of the header. */
-  uint16_t firmware_sign_algorithm;  /* Signature algorithm used by the firmware
-                                      * signing key (used to sign this kernel
-                                      * header. */
-  uint16_t kernel_sign_algorithm;  /* Signature algorithm used by the kernel
-                                    * signing key. */
-  uint16_t kernel_key_version;  /* Key Version# for preventing rollbacks. */
-  uint8_t* kernel_sign_key;  /* Pre-processed public half of signing key. */
-  /* TODO(gauravsh): Do we need a choice of digest algorithms for the header
-   * checksum? */
-  uint8_t header_checksum[SHA512_DIGEST_SIZE];  /* SHA-512 Crytographic hash of
-                                                 * the concatenation of the
-                                                 * header fields, i.e.
-                                                 * [header_len,
-                                                 * firmware_sign_algorithm,
-                                                 * sign_algorithm, sign_key,
-                                                 * key_version] */
-
-  uint8_t* kernel_key_signature;   /* Signature of the header above. */
-
-  uint16_t kernel_version;  /* Kernel Version# for preventing rollbacks. */
-  kconfig_options options;  /* Other kernel/bootloader options. */
-
-  uint8_t* config_signature;  /* Signature of the kernel config file. */
-
-  /* The kernel signature comes first as it may allow us to parallelize
-   * the kernel data fetch and RSA public key operation.
-   */
-  uint8_t* kernel_signature;  /* Signature on the concatenation of
-                               * [kernel_version], [options] and
-                               * [kernel_data]. */
-  uint8_t* kernel_data;  /* Actual kernel data. */
-
-} KernelImage;
+#include "kernel_image_fw.h"
 
 /* Allocate and return a new KernelImage structure. */
 KernelImage* KernelImageNew(void);
@@ -125,79 +66,6 @@
  */
 void PrintKernelImage(const KernelImage* image);
 
-/* Error Codes for VerifyFirmware. */
-#define VERIFY_KERNEL_SUCCESS 0
-#define VERIFY_KERNEL_INVALID_IMAGE 1
-#define VERIFY_KERNEL_KEY_SIGNATURE_FAILED 2
-#define VERIFY_KERNEL_INVALID_ALGORITHM 3
-#define VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED 4
-#define VERIFY_KERNEL_SIGNATURE_FAILED 5
-#define VERIFY_KERNEL_WRONG_MAGIC 6
-#define VERIFY_KERNEL_MAX 7  /* Generic catch-all. */
-
-extern char* kVerifyKernelErrors[VERIFY_KERNEL_MAX];
-
-/* Checks for the sanity of the kernel header pointed by [kernel_header_blob].
- * If [dev_mode] is enabled, also checks the firmware key signature using the
- * pre-processed public firmware signing  key [firmware_sign_key_blob].
- *
- * On success, put firmware signature algorithm in [firmware_algorithm],
- * kernel signature algorithm in [kernel_algorithm], kernel header
- * length in [header_len], and return 0.
- * Else, return error code on failure.
- */
-int VerifyKernelHeader(const uint8_t* firmware_sign_key_blob,
-                       const uint8_t* kernel_header_blob,
-                       const int dev_mode,
-                       int* firmware_algorithm,
-                       int* kernel_algorithm,
-                       int* header_len);
-
-/* Checks the kernel config (analogous to preamble for firmware) signature on
- * kernel config pointed by [kernel_config_blob] using the signing key
- * [kernel_sign_key].
- *
- * On success, put kernel length into [kernel_len], and return 0.
- * Else, return error code on failure.
- */
-int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
-                       const uint8_t* kernel_config_blob,
-                       int algorithm,
-                       uint64_t* kernel_len);
-
-/* Checks the signature on the kernel data at location [kernel_data_start].
- * The length of the actual kernel data is kernel _len and it is assumed to
- * be prepended with the signature whose size depends on the signature_algorithm
- * [algorithm].
- *
- * Return 0 on success, error code on failure.
- */
-int VerifyKernelData(RSAPublicKey* kernel_sign_key,
-                     const uint8_t* kernel_config_start,
-                     const uint8_t* kernel_data_start,
-                     uint64_t kernel_len,
-                     int algorithm);
-
-/* Performs a chained verify of the kernel blob [kernel_blob]. If
- * [dev_mode] is 0 [inactive], then the pre-processed public signing key
- * [root_key_blob] is used to verify the signature of the signing key,
- * else the check is skipped.
- *
- * TODO(gauravsh): Does the dev mode only effect the R/W firmware verification,
- * or kernel verification, or both?
- *
- * Returns 0 on success, error code on failure.
- *
- * NOTE: The length of the kernel blob is derived from reading the fields
- * in the first few bytes of the buffer. This might look risky but in firmware
- * land, the start address of the kernel_blob will always be fixed depending
- * on the memory map on the particular platform. In addition, the signature on
- * length itself is checked early in the verification process for extra safety.
- */
-int VerifyKernel(const uint8_t* signing_key_blob,
-                 const uint8_t* kernel_blob,
-                 const int dev_mode);
-
 /* Performs a chained verify of the kernel [image]. If [dev_mode] is
  * 0 (inactive), then the [firmware_signing_key] is used to verify the signature
  * of the signing key, else the check is skipped.
@@ -227,44 +95,6 @@
 int AddKernelSignature(KernelImage* image,
                        const char* kernel_sigining_key_file);
 
-/* Returns the logical version of a kernel blob which is calculated as
- * (kernel_key_version << 16 | kernel_version). */
-uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob);
-
-#define  BOOT_KERNEL_A_CONTINUE 1
-#define  BOOT_KERNEL_B_CONTINUE 2
-#define  BOOT_KERNEL_RECOVERY_CONTINUE 3
-
-/* Contains information about the kernel paritition
- * gleaned from the GPT partition table.
- *
- * Based on the Chromium OS Drive Map design document by
- * rspangler@chromium.org.
- *
-*/
-typedef struct kernel_entry {
-  uint8_t* kernel_blob;  /* Pointer to actual kernel. */
-  uint8_t boot_priority;  /* 15 = highest, 1 = lowest, 0 = not bootable. */
-  uint8_t boot_tries_remaining;  /* Used when boot_priority = 0. */
-  uint8_t boot_success_flag;  /* Set to 1 on successful boot by AU. */
-} kernel_entry;
-
 void PrintKernelEntry(kernel_entry* entry);
 
-/* This function is the driver used by the RW firmware to
- * determine which copy of the kernel to boot from. It performs
- * the requisite priority and remaining tries checking for a specific
- * kernel partition, does rollback index checking, including updating
- * if required.
- *
- * Returns the code path to follow. It is one of:
- * BOOT_KERNEL_A_CONTINUE          Boot from Kenrel A
- * BOOT_KERNEL_B_CONTINUE          Boot from Kernel B
- * BOOT_KERNEL_RECOVERY_CONTINUE   Jump to recovery mode
- */
-int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
-                         kernel_entry* kernelA,
-                         kernel_entry* kernelB,
-                         int dev_mode);
-
 #endif  /* VBOOT_REFERENCE_KERNEL_IMAGE_H_ */
diff --git a/include/kernel_image_fw.h b/include/kernel_image_fw.h
new file mode 100644
index 0000000..d299b5a
--- /dev/null
+++ b/include/kernel_image_fw.h
@@ -0,0 +1,183 @@
+/* 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.
+ *
+ * Data structure and API definitions for a verified boot kernel image.
+ * (Firmware Portion)
+ */
+
+#ifndef VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_
+#define VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_
+
+#include <stdint.h>
+#include "rsa.h"
+#include "sha.h"
+
+#define KERNEL_MAGIC "CHROMEOS"
+#define KERNEL_MAGIC_SIZE 8
+#define KERNEL_CMD_LINE_SIZE 4096
+
+#define DEV_MODE_ENABLED 1
+#define DEV_MODE_DISABLED 0
+
+/* Kernel config file options according to the Chrome OS drive map design. */
+typedef struct kconfig_options {
+  uint32_t version[2];  /* Configuration file version. */
+  uint8_t cmd_line[KERNEL_CMD_LINE_SIZE];  /* Kernel command line option string
+                                            * terminated by a NULL character. */
+  uint64_t kernel_len;  /* Size of the kernel. */
+  uint64_t kernel_load_addr;  /* Load address in memory for the kernel image */
+  uint64_t kernel_entry_addr;  /* Address to jump to after kernel is loaded. */
+} kconfig_options;
+
+typedef struct KernelImage {
+  uint8_t magic[KERNEL_MAGIC_SIZE];
+  /* Key header */
+  uint16_t header_version;  /* Header version. */
+  uint16_t header_len;  /* Length of the header. */
+  uint16_t firmware_sign_algorithm;  /* Signature algorithm used by the firmware
+                                      * signing key (used to sign this kernel
+                                      * header. */
+  uint16_t kernel_sign_algorithm;  /* Signature algorithm used by the kernel
+                                    * signing key. */
+  uint16_t kernel_key_version;  /* Key Version# for preventing rollbacks. */
+  uint8_t* kernel_sign_key;  /* Pre-processed public half of signing key. */
+  /* TODO(gauravsh): Do we need a choice of digest algorithms for the header
+   * checksum? */
+  uint8_t header_checksum[SHA512_DIGEST_SIZE];  /* SHA-512 Crytographic hash of
+                                                 * the concatenation of the
+                                                 * header fields, i.e.
+                                                 * [header_len,
+                                                 * firmware_sign_algorithm,
+                                                 * sign_algorithm, sign_key,
+                                                 * key_version] */
+
+  uint8_t* kernel_key_signature;   /* Signature of the header above. */
+
+  uint16_t kernel_version;  /* Kernel Version# for preventing rollbacks. */
+  kconfig_options options;  /* Other kernel/bootloader options. */
+
+  uint8_t* config_signature;  /* Signature of the kernel config file. */
+
+  /* The kernel signature comes first as it may allow us to parallelize
+   * the kernel data fetch and RSA public key operation.
+   */
+  uint8_t* kernel_signature;  /* Signature on the concatenation of
+                               * [kernel_version], [options] and
+                               * [kernel_data]. */
+  uint8_t* kernel_data;  /* Actual kernel data. */
+
+} KernelImage;
+
+/* Error Codes for VerifyFirmware. */
+#define VERIFY_KERNEL_SUCCESS 0
+#define VERIFY_KERNEL_INVALID_IMAGE 1
+#define VERIFY_KERNEL_KEY_SIGNATURE_FAILED 2
+#define VERIFY_KERNEL_INVALID_ALGORITHM 3
+#define VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED 4
+#define VERIFY_KERNEL_SIGNATURE_FAILED 5
+#define VERIFY_KERNEL_WRONG_MAGIC 6
+#define VERIFY_KERNEL_MAX 7  /* Generic catch-all. */
+
+extern char* kVerifyKernelErrors[VERIFY_KERNEL_MAX];
+
+/* Checks for the sanity of the kernel header pointed by [kernel_header_blob].
+ * If [dev_mode] is enabled, also checks the firmware key signature using the
+ * pre-processed public firmware signing  key [firmware_sign_key_blob].
+ *
+ * On success, put firmware signature algorithm in [firmware_algorithm],
+ * kernel signature algorithm in [kernel_algorithm], kernel header
+ * length in [header_len], and return 0.
+ * Else, return error code on failure.
+ */
+int VerifyKernelHeader(const uint8_t* firmware_sign_key_blob,
+                       const uint8_t* kernel_header_blob,
+                       const int dev_mode,
+                       int* firmware_algorithm,
+                       int* kernel_algorithm,
+                       int* header_len);
+
+/* Checks the kernel config (analogous to preamble for firmware) signature on
+ * kernel config pointed by [kernel_config_blob] using the signing key
+ * [kernel_sign_key].
+ *
+ * On success, put kernel length into [kernel_len], and return 0.
+ * Else, return error code on failure.
+ */
+int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
+                       const uint8_t* kernel_config_blob,
+                       int algorithm,
+                       uint64_t* kernel_len);
+
+/* Checks the signature on the kernel data at location [kernel_data_start].
+ * The length of the actual kernel data is kernel _len and it is assumed to
+ * be prepended with the signature whose size depends on the signature_algorithm
+ * [algorithm].
+ *
+ * Return 0 on success, error code on failure.
+ */
+int VerifyKernelData(RSAPublicKey* kernel_sign_key,
+                     const uint8_t* kernel_config_start,
+                     const uint8_t* kernel_data_start,
+                     uint64_t kernel_len,
+                     int algorithm);
+
+/* Performs a chained verify of the kernel blob [kernel_blob]. If
+ * [dev_mode] is 0 [inactive], then the pre-processed public signing key
+ * [root_key_blob] is used to verify the signature of the signing key,
+ * else the check is skipped.
+ *
+ * TODO(gauravsh): Does the dev mode only effect the R/W firmware verification,
+ * or kernel verification, or both?
+ *
+ * Returns 0 on success, error code on failure.
+ *
+ * NOTE: The length of the kernel blob is derived from reading the fields
+ * in the first few bytes of the buffer. This might look risky but in firmware
+ * land, the start address of the kernel_blob will always be fixed depending
+ * on the memory map on the particular platform. In addition, the signature on
+ * length itself is checked early in the verification process for extra safety.
+ */
+int VerifyKernel(const uint8_t* signing_key_blob,
+                 const uint8_t* kernel_blob,
+                 const int dev_mode);
+
+/* Returns the logical version of a kernel blob which is calculated as
+ * (kernel_key_version << 16 | kernel_version). */
+uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob);
+
+#define  BOOT_KERNEL_A_CONTINUE 1
+#define  BOOT_KERNEL_B_CONTINUE 2
+#define  BOOT_KERNEL_RECOVERY_CONTINUE 3
+
+/* Contains information about the kernel paritition
+ * gleaned from the GPT partition table.
+ *
+ * Based on the Chromium OS Drive Map design document by
+ * rspangler@chromium.org.
+ *
+*/
+typedef struct kernel_entry {
+  uint8_t* kernel_blob;  /* Pointer to actual kernel. */
+  uint8_t boot_priority;  /* 15 = highest, 1 = lowest, 0 = not bootable. */
+  uint8_t boot_tries_remaining;  /* Used when boot_priority = 0. */
+  uint8_t boot_success_flag;  /* Set to 1 on successful boot by AU. */
+} kernel_entry;
+
+/* This function is the driver used by the RW firmware to
+ * determine which copy of the kernel to boot from. It performs
+ * the requisite priority and remaining tries checking for a specific
+ * kernel partition, does rollback index checking, including updating
+ * if required.
+ *
+ * Returns the code path to follow. It is one of:
+ * BOOT_KERNEL_A_CONTINUE          Boot from Kenrel A
+ * BOOT_KERNEL_B_CONTINUE          Boot from Kernel B
+ * BOOT_KERNEL_RECOVERY_CONTINUE   Jump to recovery mode
+ */
+int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
+                         kernel_entry* kernelA,
+                         kernel_entry* kernelB,
+                         int dev_mode);
+
+#endif  /* VBOOT_REFERENCE_KERNEL_IMAGE_FW_H_ */
diff --git a/include/tlcl.h b/include/tlcl.h
index e0b5626..2e6d3fd 100644
--- a/include/tlcl.h
+++ b/include/tlcl.h
@@ -16,41 +16,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-#define POSSIBLY_UNUSED __attribute__((unused))
-
-#ifdef __STRICT_ANSI__
-#define INLINE
-#else
-#define INLINE inline
-#endif
-
-/* Outputs an error message and quits the program.
- */
-POSSIBLY_UNUSED
-static void error(const char *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  fprintf(stderr, "ERROR: ");
-  vfprintf(stderr, format, ap);
-  va_end(ap);
-  exit(1);
-}
-
-/* Outputs a warning and continues.
- */
-POSSIBLY_UNUSED
-static void warning(const char *format, ...) {
-  va_list ap;
-  va_start(ap, format);
-  fprintf(stderr, "WARNING: ");
-  vfprintf(stderr, format, ap);
-  va_end(ap);
-}
-
-#define assert(expr) do { if (!(expr)) { \
-      error("assert fail: %s at %s:%d\n", \
-            #expr, __FILE__, __LINE__); }} while(0)
-
 /* Call this first.
  */
 void TlclLibinit(void);
diff --git a/include/utility.h b/include/utility.h
index 429223c..8619cd2 100644
--- a/include/utility.h
+++ b/include/utility.h
@@ -10,9 +10,20 @@
 #ifndef VBOOT_REFERENCE_UTILITY_H_
 #define VBOOT_REFERENCE_UTILITY_H_
 
-#include <inttypes.h>
+#include <stdint.h>
 #include <string.h>
 
+/* Outputs an error message and quits. */
+void error(const char *format, ...);
+
+/* Outputs debug/warning messages. */
+void debug(const char *format, ...);
+
+
+#define assert(expr) do { if (!(expr)) { \
+      error("assert fail: %s at %s:%d\n", \
+            #expr, __FILE__, __LINE__); }} while(0)
+
 /* Combine [msw] and [lsw] uint16s to a uint32_t with its [msw] and
  * [lsw] forming the most and least signficant 16-bit words.
  */
diff --git a/tests/Makefile b/tests/Makefile
index 3645e7d..99e2d3a 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -8,26 +8,31 @@
 TOP ?= ../
 
 BASE_LIBS = $(TOP)/crypto/libcrypto.a $(TOP)/common/libcommon.a
-IMAGE_LIBS = $(TOP)/utils/firmware_image.o $(TOP)/utils/kernel_image.o
+IMAGE_LIBS = $(TOP)/utils/firmware_image.o \
+		$(TOP)/utils/firmware_image_fw.o \
+		$(TOP)/utils/kernel_image.o \
+		$(TOP)/utils/kernel_image_fw.o
 UTIL_LIBS = $(TOP)/utils/file_keys.o $(TOP)/utils/signature_digest.o
 LIBS = $(IMAGE_LIBS) $(UTIL_LIBS) -lcrypto $(BASE_LIBS)
 
-tests: big_firmware_tests \
-	big_kernel_tests \
-	firmware_image_tests \
-	firmware_rollback_tests \
-	firmware_splicing_tests \
-	firmware_verify_benchmark \
-	kernel_image_tests \
-	kernel_rollback_tests \
-	kernel_splicing_tests \
-	kernel_verify_benchmark \
-	rsa_padding_test \
-	rsa_verify_benchmark \
-	sha_benchmark \
-	sha_tests \
-	verify_firmware_fuzz_driver \
-	verify_kernel_fuzz_driver
+TEST_BINS = big_firmware_tests \
+		big_kernel_tests \
+		firmware_image_tests \
+		firmware_rollback_tests \
+		firmware_splicing_tests \
+		firmware_verify_benchmark \
+		kernel_image_tests \
+		kernel_rollback_tests \
+		kernel_splicing_tests \
+		kernel_verify_benchmark \
+		rsa_padding_test \
+		rsa_verify_benchmark \
+		sha_benchmark \
+		sha_tests \
+		verify_firmware_fuzz_driver \
+		verify_kernel_fuzz_driver
+
+all: $(TEST_BINS)
 
 big_firmware_tests: big_firmware_tests.c rollback_index_mock.c test_common.c
 	$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
@@ -87,19 +92,4 @@
 	$(CC) $(CFLAGS) $(INCLUDES) $^ -o $@ $(LIBS)
 
 clean:
-	rm -f big_firmware_tests \
-		big_kernel_tests \
-		firmware_image_tests \
-		firmware_rollback_tests \
-		firmware_splicing_tests \
-		firmware_verify_benchmark \
-		kernel_image_tests \
-		kernel_rollback_tests \
-		kernel_splicing_tests \
-		kernel_verify_benchmark \
-		rsa_padding_test \
-		rsa_verify_benchmark \
-		sha_benchmark \
-		sha_tests \
-		verify_firmware_fuzz_driver \
-		verify_kernel_fuzz_driver
+	rm -f $(TEST_BINS)
diff --git a/utils/Makefile b/utils/Makefile
index 597638e..81de74f 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -8,43 +8,53 @@
 INCLUDES ?= -I../include/
 TOP ?= ../
 
-LIBS =  firmware_image.o kernel_image.o signature_digest.o file_keys.o \
-	rollback_index.o
+LIBS = file_keys.o \
+	firmware_image.o \
+	firmware_image_fw.o \
+	kernel_image.o \
+	kernel_image_fw.o \
+	rollback_index.o \
+	signature_digest.o 
 
 FIRMWARELIBS = $(TOP)/crypto/libcrypto.a $(TOP)/common/libcommon.a
 
-all: dumpRSAPublicKey verify_data file_keys.o signature_digest.o \
-	firmware_image.o kernel_image.o signature_digest.o \
-	signature_digest_utility firmware_utility kernel_utility \
-	rollback_index.o
+TARGET_BINS = $(LIBS) \
+		dumpRSAPublicKey \
+		firmware_utility \
+		kernel_utility \
+		signature_digest_utility \
+		verify_data
+
+all: $(TARGET_BINS)
+
+.c.o:
+	$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
 
 dumpRSAPublicKey: dumpRSAPublicKey.c
 	$(CC) $(CFLAGS) $< -o $@ -lcrypto
 
-verify_data: verify_data.c $(LIBS) $(FIRMWARELIBS)
-	$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARELIBS) -lcrypto
-
-signature_digest_utility: signature_digest_utility.c $(LIBS) $(FIRMWARELIBS)
-	$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARELIBS) -lcrypto
+firmware_image_fw.o: firmware_image_fw.c
+	$(CC) $(CFLAGS) -ansi $(INCLUDES) -c $^ -o $@
 
 firmware_utility: firmware_utility.cc $(LIBS) $(FIRMWARELIBS)
 	$(CXX) $(CFLAGS) $(INCLUDES) -ggdb -D__STDC_LIMIT_MACROS $< \
 	-o $@ $(FIRMWARELIBS) $(LIBS) $(TOP)/common/libcommon.a \
 	-lcrypto
 
+kernel_image_fw.o: kernel_image_fw.c
+	$(CC) $(CFLAGS) -ansi $(INCLUDES) -c $< -o $@
+
 kernel_utility: kernel_utility.cc $(LIBS) $(FIRMWARELIBS)
 	$(CXX) $(CFLAGS) $(INCLUDES) -ggdb -D__STDC_LIMIT_MACROS $< \
 	-o $@ $(FIRMWARELIBS) $(LIBS) $(TOP)/common/libcommon.a \
 	-lcrypto
 
-.c.o:
-	$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@
+signature_digest_utility: signature_digest_utility.c $(LIBS) $(FIRMWARELIBS)
+	$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARELIBS) -lcrypto
 
-firmware_image.o: firmware_image.c
-	$(CC) -ansi $(CFLAGS) $(INCLUDES) -c $< -o $@
+verify_data: verify_data.c $(LIBS) $(FIRMWARELIBS)
+	$(CC) $(CFLAGS) $(INCLUDES) $< -o $@ $(LIBS) $(FIRMWARELIBS) -lcrypto
 
-kernel_image.o: kernel_image.c
-	$(CC) -ansi $(CFLAGS) $(INCLUDES) -c $< -o $@
 clean:
-	rm -f dumpRSAPublicKey verify_data signature_digest firmware_utility \
-	kernel_utility signature_digest_utility $(LIBS)
+	rm -f $(TARGET_BINS) $(LIBS)
+
diff --git a/utils/dumpRSAPublicKey.c b/utils/dumpRSAPublicKey.c
index b6a5190..837303c 100644
--- a/utils/dumpRSAPublicKey.c
+++ b/utils/dumpRSAPublicKey.c
@@ -8,7 +8,7 @@
  * /tools/DumpPublicKey.java). Uses the OpenSSL X509 and BIGNUM library.
  */
 
-#include <inttypes.h>
+#include <stdint.h>
 #include <openssl/bn.h>
 #include <openssl/evp.h>
 #include <openssl/pem.h>
diff --git a/utils/firmware_image.c b/utils/firmware_image.c
index 2e3f924..803ef89 100644
--- a/utils/firmware_image.c
+++ b/utils/firmware_image.c
@@ -9,14 +9,12 @@
 
 #include <fcntl.h>
 #include <limits.h>
-#include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
 #include "file_keys.h"
 #include "padding.h"
-#include "rollback_index.h"
 #include "rsa_utility.h"
 #include "sha_utility.h"
 #include "signature_digest.h"
@@ -71,7 +69,7 @@
   /* Read and compare magic bytes. */
   StatefulMemcpy(&st, &image->magic, FIRMWARE_MAGIC_SIZE);
   if (SafeMemcmp(image->magic, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE)) {
-    fprintf(stderr, "Wrong Firmware Magic.\n");
+    debug("Wrong Firmware Magic.\n");
     Free(firmware_buf);
     return NULL;
   }
@@ -92,8 +90,8 @@
   /* Check whether the header length is correct. */
   header_len = GetFirmwareHeaderLen(image);
   if (header_len != image->header_len) {
-    fprintf(stderr, "Header length mismatch. Got: %d Expected: %d\n",
-            image->header_len, header_len);
+    debug("Header length mismatch. Got: %d Expected: %d\n",
+          image->header_len, header_len);
     Free(firmware_buf);
     return NULL;
   }
@@ -109,7 +107,7 @@
   CalculateFirmwareHeaderChecksum(image, header_checksum);
   if (SafeMemcmp(header_checksum, image->header_checksum,
                  FIELD_LEN(header_checksum))) {
-    fprintf(stderr, "Invalid firmware header checksum!\n");
+    debug("Invalid firmware header checksum!\n");
     Free(firmware_buf);
     return NULL;
   }
@@ -271,17 +269,17 @@
   if (!image)
     return 0;
   if (-1 == (fd = creat(input_file, S_IRWXU))) {
-    fprintf(stderr, "Couldn't open file for writing.\n");
+    debug("Couldn't open file for writing.\n");
     return 0;
   }
 
   firmware_blob = GetFirmwareBlob(image, &blob_len);
   if (!firmware_blob) {
-    fprintf(stderr, "Couldn't create firmware blob from FirmwareImage.\n");
+    debug("Couldn't create firmware blob from FirmwareImage.\n");
     return 0;
   }
   if (blob_len != write(fd, firmware_blob, blob_len)) {
-    fprintf(stderr, "Couldn't write Firmware Image to file: %s\n", input_file);
+    debug("Couldn't write Firmware Image to file: %s\n", input_file);
     Free(firmware_blob);
     close(fd);
     return 0;
@@ -296,7 +294,7 @@
     return;
 
   /* Print header. */
-  printf("Header Length = %d\n"
+  debug("Header Length = %d\n"
          "Firmware Signature Algorithm = %s\n"
          "Firmware Key Version = %d\n\n",
          image->header_len,
@@ -304,201 +302,13 @@
          image->firmware_key_version);
   /* TODO(gauravsh): Output hash and key signature here? */
   /* Print preamble. */
-  printf("Firmware Version = %d\n"
+  debug("Firmware Version = %d\n"
          "Firmware Length = %" PRIu64 "\n\n",
          image->firmware_version,
          image->firmware_len);
   /* Output key signature here? */
 }
 
-char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX] = {
-  "Success.",
-  "Invalid Image.",
-  "Root Key Signature Failed.",
-  "Invalid Verification Algorithm.",
-  "Preamble Signature Failed.",
-  "Firmware Signature Failed.",
-  "Wrong Firmware Magic.",
-  "Invalid Firmware Header Checksum.",
-  "Firmware Signing Key Rollback.",
-  "Firmware Version Rollback."
-};
-
-int VerifyFirmwareHeader(const uint8_t* root_key_blob,
-                         const uint8_t* header_blob,
-                         int* algorithm,
-                         int* header_len) {
-  int firmware_sign_key_len;
-  int root_key_len;
-  uint16_t hlen, algo;
-  uint8_t* header_checksum = NULL;
-
-  /* Base Offset for the header_checksum field. Actual offset is
-   * this + firmware_sign_key_len. */
-  int base_header_checksum_offset = (FIELD_LEN(header_len) +
-                                     FIELD_LEN(firmware_sign_algorithm) +
-                                     FIELD_LEN(firmware_key_version));
-
-
-  root_key_len = RSAProcessedKeySize(ROOT_SIGNATURE_ALGORITHM);
-  Memcpy(&hlen, header_blob, sizeof(hlen));
-  Memcpy(&algo,
-         header_blob + FIELD_LEN(firmware_sign_algorithm),
-         sizeof(algo));
-  if (algo >= kNumAlgorithms)
-    return VERIFY_FIRMWARE_INVALID_ALGORITHM;
-  *algorithm = (int) algo;
-  firmware_sign_key_len = RSAProcessedKeySize(*algorithm);
-
-  /* Verify that header len is correct. */
-  if (hlen != (base_header_checksum_offset +
-               firmware_sign_key_len +
-               FIELD_LEN(header_checksum)))
-    return VERIFY_FIRMWARE_INVALID_IMAGE;
-
-  *header_len = (int) hlen;
-
-  /* Verify if the hash of the header is correct. */
-  header_checksum = DigestBuf(header_blob,
-                              *header_len - FIELD_LEN(header_checksum),
-                              SHA512_DIGEST_ALGORITHM);
-  if (SafeMemcmp(header_checksum,
-                  header_blob + (base_header_checksum_offset +
-                                 firmware_sign_key_len),
-                  FIELD_LEN(header_checksum))) {
-    Free(header_checksum);
-    return VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM;
-  }
-  Free(header_checksum);
-
-  /* Root key signature on the firmware signing key is always checked
-   * irrespective of dev mode. */
-  if (!RSAVerifyBinary_f(root_key_blob, NULL,  /* Key to use */
-                         header_blob,  /* Data to verify */
-                         *header_len, /* Length of data */
-                         header_blob + *header_len,  /* Expected Signature */
-                         ROOT_SIGNATURE_ALGORITHM))
-    return VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED;
-  return 0;
-}
-
-int VerifyFirmwarePreamble(RSAPublicKey* firmware_sign_key,
-                           const uint8_t* preamble_blob,
-                           int algorithm,
-                           uint64_t* firmware_len) {
-  uint64_t len;
-  int preamble_len;
-  uint16_t firmware_version;
-
-  Memcpy(&firmware_version, preamble_blob, sizeof(firmware_version));
-
-  preamble_len = (FIELD_LEN(firmware_version) +
-                  FIELD_LEN(firmware_len) +
-                  FIELD_LEN(preamble));
-  if (!RSAVerifyBinary_f(NULL, firmware_sign_key,  /* Key to use */
-                         preamble_blob,  /* Data to verify */
-                         preamble_len,  /* Length of data */
-                         preamble_blob + preamble_len,  /* Expected Signature */
-                         algorithm))
-    return VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED;
-
-  Memcpy(&len, preamble_blob + FIELD_LEN(firmware_version),
-         sizeof(len));
-  *firmware_len = len;
-  return 0;
-}
-
-int VerifyFirmwareData(RSAPublicKey* firmware_sign_key,
-                       const uint8_t* preamble_start,
-                       const uint8_t* firmware_data_start,
-                       uint64_t firmware_len,
-                       int algorithm) {
-  int signature_len = siglen_map[algorithm];
-  uint8_t* digest;
-  DigestContext ctx;
-
-  /* Since the firmware signature is over the preamble and the firmware data,
-   * which does not form a contiguous region of memory, we calculate the
-   * message digest ourselves. */
-  DigestInit(&ctx, algorithm);
-  DigestUpdate(&ctx, preamble_start, GetFirmwarePreambleLen());
-  DigestUpdate(&ctx, firmware_data_start + signature_len, firmware_len);
-  digest = DigestFinal(&ctx);
-  if (!RSAVerifyBinaryWithDigest_f(
-          NULL, firmware_sign_key,  /* Key to use. */
-          digest,  /* Digest of the data to verify. */
-          firmware_data_start,  /* Expected Signature */
-          algorithm)) {
-    Free(digest);
-    return VERIFY_FIRMWARE_SIGNATURE_FAILED;
-  }
-  Free(digest);
-  return 0;
-}
-
-int VerifyFirmware(const uint8_t* root_key_blob,
-                   const uint8_t* firmware_blob) {
-  int error_code = 0;
-  int algorithm;  /* Signing key algorithm. */
-  RSAPublicKey* firmware_sign_key = NULL;
-  int firmware_sign_key_len, signature_len, header_len;
-  uint64_t firmware_len;
-  const uint8_t* header_ptr = NULL;  /* Pointer to header. */
-  const uint8_t* firmware_sign_key_ptr = NULL;  /* Pointer to signing key. */
-  const uint8_t* preamble_ptr = NULL;  /* Pointer to preamble block. */
-  const uint8_t* firmware_ptr = NULL;  /* Pointer to firmware signature/data. */
-
-  /* Note: All the offset calculations are based on struct FirmwareImage which
-   * is defined in include/firmware_image.h. */
-
-  /* Compare magic bytes. */
-  if (SafeMemcmp(firmware_blob, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE))
-    return VERIFY_FIRMWARE_WRONG_MAGIC;
-  header_ptr = firmware_blob + FIRMWARE_MAGIC_SIZE;
-
-  /* Only continue if header verification succeeds. */
-  if ((error_code = VerifyFirmwareHeader(root_key_blob, header_ptr,
-                                         &algorithm, &header_len)))
-    return error_code;  /* AKA jump to revovery. */
-
-  /* Parse signing key into RSAPublicKey structure since it is required multiple
-   * times. */
-  firmware_sign_key_len = RSAProcessedKeySize(algorithm);
-  firmware_sign_key_ptr = header_ptr + (FIELD_LEN(header_len) +
-                                        FIELD_LEN(firmware_sign_algorithm) +
-                                        FIELD_LEN(firmware_key_version));
-  firmware_sign_key = RSAPublicKeyFromBuf(firmware_sign_key_ptr,
-                                          firmware_sign_key_len);
-  signature_len = siglen_map[algorithm];
-
-  /* Only continue if preamble verification succeeds. */
-  preamble_ptr = (header_ptr + header_len +
-                  FIELD_LEN(firmware_key_signature));
-  if ((error_code = VerifyFirmwarePreamble(firmware_sign_key, preamble_ptr,
-                                           algorithm,
-                                           &firmware_len))) {
-    RSAPublicKeyFree(firmware_sign_key);
-    fprintf(stderr, "Couldn't verify Firmware preamble.\n");
-    return error_code;  /* AKA jump to recovery. */
-  }
-  /* Only continue if firmware data verification succeeds. */
-  firmware_ptr = (preamble_ptr +
-                  GetFirmwarePreambleLen() +
-                  signature_len);
-
-  if ((error_code = VerifyFirmwareData(firmware_sign_key, preamble_ptr,
-                                       firmware_ptr,
-                                       firmware_len,
-                                       algorithm))) {
-    RSAPublicKeyFree(firmware_sign_key);
-    fprintf(stderr, "Couldn't verify Firmware data.\n");
-    return error_code;  /* AKA jump to recovery. */
-  }
-
-  RSAPublicKeyFree(firmware_sign_key);
-  return 0;  /* Success! */
-}
-
 int VerifyFirmwareImage(const RSAPublicKey* root_key,
                         const FirmwareImage* image) {
   RSAPublicKey* firmware_sign_key = NULL;
@@ -662,114 +472,3 @@
   Free(preamble_blob);
   return 1;
 }
-
-uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob) {
-  uint16_t firmware_key_version;
-  uint16_t firmware_version;
-  uint16_t firmware_sign_algorithm;
-  int firmware_sign_key_len;
-  Memcpy(&firmware_sign_algorithm,
-         firmware_blob + (FIELD_LEN(magic) +  /* Offset to field. */
-                          FIELD_LEN(header_len)),
-         sizeof(firmware_sign_algorithm));
-  Memcpy(&firmware_key_version,
-         firmware_blob + (FIELD_LEN(magic) +  /* Offset to field. */
-                          FIELD_LEN(header_len) +
-                          FIELD_LEN(firmware_sign_algorithm)),
-         sizeof(firmware_key_version));
-  if (firmware_sign_algorithm >= kNumAlgorithms)
-    return 0;
-  firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
-  Memcpy(&firmware_version,
-         firmware_blob +  (FIELD_LEN(magic) +  /* Offset to field. */
-                           FIELD_LEN(header_len) +
-                           FIELD_LEN(firmware_key_version) +
-                           firmware_sign_key_len +
-                           FIELD_LEN(header_checksum) +
-                           FIELD_LEN(firmware_key_signature)),
-         sizeof(firmware_version));
-  return CombineUint16Pair(firmware_key_version, firmware_version);
-}
-
-int VerifyFirmwareDriver_f(uint8_t* root_key_blob,
-                           uint8_t* firmwareA,
-                           uint8_t* firmwareB) {
-  /* Contains the logical firmware version (32-bit) which is calculated as
-   * (firmware_key_version << 16 | firmware_version) where
-   * [firmware_key_version] [firmware_version] are both 16-bit.
-   */
-  uint32_t firmwareA_lversion, firmwareB_lversion;
-  uint8_t firmwareA_is_verified = 0;  /* Whether firmwareA verify succeeded. */
-  uint32_t min_lversion;  /* Minimum of firmware A and firmware lversion. */
-  uint32_t stored_lversion;  /* Stored logical version in the TPM. */
-
-  /* Initialize the TPM since we'll be reading the rollback indices. */
-  SetupTPM();
-
-  /* We get the key versions by reading directly from the image blobs without
-   * any additional (expensive) sanity checking on the blob since it's faster to
-   * outright reject a firmware with an older firmware key version. A malformed
-   * or corrupted firmware blob will still fail when VerifyFirmware() is called
-   * on it.
-   */
-  firmwareA_lversion = GetLogicalFirmwareVersion(firmwareA);
-  firmwareB_lversion = GetLogicalFirmwareVersion(firmwareB);
-  min_lversion  = Min(firmwareA_lversion, firmwareB_lversion);
-  stored_lversion = CombineUint16Pair(GetStoredVersion(FIRMWARE_KEY_VERSION),
-                                      GetStoredVersion(FIRMWARE_VERSION));
-  /* Always try FirmwareA first. */
-  if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareA))
-    firmwareA_is_verified = 1;
-  if (firmwareA_is_verified && (stored_lversion < firmwareA_lversion)) {
-    /* Stored version may need to be updated but only if FirmwareB
-     * is successfully verified and has a logical version greater than
-     * the stored logical version. */
-    if (stored_lversion < firmwareB_lversion) {
-      if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)) {
-        WriteStoredVersion(FIRMWARE_KEY_VERSION,
-                           (uint16_t) (min_lversion >> 16));
-        WriteStoredVersion(FIRMWARE_VERSION,
-                           (uint16_t) (min_lversion & 0x00FFFF));
-        stored_lversion = min_lversion;  /* Update stored version as it's used
-                                          * later. */
-      }
-    }
-  }
-  /* Lock Firmware TPM rollback indices from further writes. */
-  /* TODO(gauravsh): Figure out if these can be combined into one
-   * 32-bit location since we seem to always use them together. This can help
-   * us minimize the number of NVRAM writes/locks (which are limited over flash
-   * memory lifetimes.
-   */
-  LockStoredVersion(FIRMWARE_KEY_VERSION);
-  LockStoredVersion(FIRMWARE_VERSION);
-
-  /* Determine which firmware (if any) to jump to.
-   *
-   * We always attempt to jump to FirmwareA first. If verification of FirmwareA
-   * fails, we try FirmwareB. In all cases, if the firmware successfully
-   * verified but is a rollback, we jump to recovery.
-   *
-   * Note: This means that if FirmwareA verified successfully and is a
-   * rollback, then no attempt is made to check FirmwareB. We still jump to
-   * recovery. FirmwareB is only used as a backup in case FirmwareA gets
-   * corrupted. Since newer firmware updates are always written to A,
-   * the case where firmware A is verified but a rollback should not occur in
-   * normal operation.
-   */
-  if (firmwareA_is_verified) {
-    if (stored_lversion <= firmwareA_lversion)
-      return BOOT_FIRMWARE_A_CONTINUE;
-  } else {
-    /* If FirmwareA was not valid, then we skipped over the
-     * check to update the rollback indices and a Verify of FirmwareB wasn't
-     * attempted.
-     * If FirmwareB is not a rollback, then we attempt to do the verification.
-     */
-    if (stored_lversion <= firmwareB_lversion &&
-        (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)))
-        return BOOT_FIRMWARE_B_CONTINUE;
-  }
-  /* D'oh: No bootable firmware. */
-  return BOOT_FIRMWARE_RECOVERY_CONTINUE;
-}
diff --git a/utils/firmware_image_fw.c b/utils/firmware_image_fw.c
new file mode 100644
index 0000000..f5c7d89
--- /dev/null
+++ b/utils/firmware_image_fw.c
@@ -0,0 +1,323 @@
+/* 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.
+ *
+ * Functions for verifying a verified boot firmware image.
+ * (Firmware Portion)
+ */
+
+#include "firmware_image_fw.h"
+
+#include "padding.h"
+#include "rollback_index.h"
+#include "rsa_utility.h"
+#include "sha_utility.h"
+#include "utility.h"
+
+/* Macro to determine the size of a field structure in the FirmwareImage
+ * structure. */
+#define FIELD_LEN(field) (sizeof(((FirmwareImage*)0)->field))
+
+char* kVerifyFirmwareErrors[VERIFY_FIRMWARE_MAX] = {
+  "Success.",
+  "Invalid Image.",
+  "Root Key Signature Failed.",
+  "Invalid Verification Algorithm.",
+  "Preamble Signature Failed.",
+  "Firmware Signature Failed.",
+  "Wrong Firmware Magic.",
+  "Invalid Firmware Header Checksum.",
+  "Firmware Signing Key Rollback.",
+  "Firmware Version Rollback."
+};
+
+int VerifyFirmwareHeader(const uint8_t* root_key_blob,
+                         const uint8_t* header_blob,
+                         int* algorithm,
+                         int* header_len) {
+  int firmware_sign_key_len;
+  int root_key_len;
+  uint16_t hlen, algo;
+  uint8_t* header_checksum = NULL;
+
+  /* Base Offset for the header_checksum field. Actual offset is
+   * this + firmware_sign_key_len. */
+  int base_header_checksum_offset = (FIELD_LEN(header_len) +
+                                     FIELD_LEN(firmware_sign_algorithm) +
+                                     FIELD_LEN(firmware_key_version));
+
+
+  root_key_len = RSAProcessedKeySize(ROOT_SIGNATURE_ALGORITHM);
+  Memcpy(&hlen, header_blob, sizeof(hlen));
+  Memcpy(&algo,
+         header_blob + FIELD_LEN(firmware_sign_algorithm),
+         sizeof(algo));
+  if (algo >= kNumAlgorithms)
+    return VERIFY_FIRMWARE_INVALID_ALGORITHM;
+  *algorithm = (int) algo;
+  firmware_sign_key_len = RSAProcessedKeySize(*algorithm);
+
+  /* Verify that header len is correct. */
+  if (hlen != (base_header_checksum_offset +
+               firmware_sign_key_len +
+               FIELD_LEN(header_checksum)))
+    return VERIFY_FIRMWARE_INVALID_IMAGE;
+
+  *header_len = (int) hlen;
+
+  /* Verify if the hash of the header is correct. */
+  header_checksum = DigestBuf(header_blob,
+                              *header_len - FIELD_LEN(header_checksum),
+                              SHA512_DIGEST_ALGORITHM);
+  if (SafeMemcmp(header_checksum,
+                  header_blob + (base_header_checksum_offset +
+                                 firmware_sign_key_len),
+                  FIELD_LEN(header_checksum))) {
+    Free(header_checksum);
+    return VERIFY_FIRMWARE_WRONG_HEADER_CHECKSUM;
+  }
+  Free(header_checksum);
+
+  /* Root key signature on the firmware signing key is always checked
+   * irrespective of dev mode. */
+  if (!RSAVerifyBinary_f(root_key_blob, NULL,  /* Key to use */
+                         header_blob,  /* Data to verify */
+                         *header_len, /* Length of data */
+                         header_blob + *header_len,  /* Expected Signature */
+                         ROOT_SIGNATURE_ALGORITHM))
+    return VERIFY_FIRMWARE_ROOT_SIGNATURE_FAILED;
+  return 0;
+}
+
+int VerifyFirmwarePreamble(RSAPublicKey* firmware_sign_key,
+                           const uint8_t* preamble_blob,
+                           int algorithm,
+                           uint64_t* firmware_len) {
+  uint64_t len;
+  int preamble_len;
+  uint16_t firmware_version;
+
+  Memcpy(&firmware_version, preamble_blob, sizeof(firmware_version));
+
+  preamble_len = (FIELD_LEN(firmware_version) +
+                  FIELD_LEN(firmware_len) +
+                  FIELD_LEN(preamble));
+  if (!RSAVerifyBinary_f(NULL, firmware_sign_key,  /* Key to use */
+                         preamble_blob,  /* Data to verify */
+                         preamble_len,  /* Length of data */
+                         preamble_blob + preamble_len,  /* Expected Signature */
+                         algorithm))
+    return VERIFY_FIRMWARE_PREAMBLE_SIGNATURE_FAILED;
+
+  Memcpy(&len, preamble_blob + FIELD_LEN(firmware_version),
+         sizeof(len));
+  *firmware_len = len;
+  return 0;
+}
+
+int VerifyFirmwareData(RSAPublicKey* firmware_sign_key,
+                       const uint8_t* preamble_start,
+                       const uint8_t* firmware_data_start,
+                       uint64_t firmware_len,
+                       int algorithm) {
+  int signature_len = siglen_map[algorithm];
+  uint8_t* digest;
+  DigestContext ctx;
+
+  /* Since the firmware signature is over the preamble and the firmware data,
+   * which does not form a contiguous region of memory, we calculate the
+   * message digest ourselves. */
+  DigestInit(&ctx, algorithm);
+  DigestUpdate(&ctx, preamble_start,
+               (FIELD_LEN(firmware_version) +
+                FIELD_LEN(firmware_len) +
+                FIELD_LEN(preamble)));
+  DigestUpdate(&ctx, firmware_data_start + signature_len, firmware_len);
+  digest = DigestFinal(&ctx);
+  if (!RSAVerifyBinaryWithDigest_f(
+          NULL, firmware_sign_key,  /* Key to use. */
+          digest,  /* Digest of the data to verify. */
+          firmware_data_start,  /* Expected Signature */
+          algorithm)) {
+    Free(digest);
+    return VERIFY_FIRMWARE_SIGNATURE_FAILED;
+  }
+  Free(digest);
+  return 0;
+}
+
+int VerifyFirmware(const uint8_t* root_key_blob,
+                   const uint8_t* firmware_blob) {
+  int error_code = 0;
+  int algorithm;  /* Signing key algorithm. */
+  RSAPublicKey* firmware_sign_key = NULL;
+  int firmware_sign_key_len, signature_len, header_len;
+  uint64_t firmware_len;
+  const uint8_t* header_ptr = NULL;  /* Pointer to header. */
+  const uint8_t* firmware_sign_key_ptr = NULL;  /* Pointer to signing key. */
+  const uint8_t* preamble_ptr = NULL;  /* Pointer to preamble block. */
+  const uint8_t* firmware_ptr = NULL;  /* Pointer to firmware signature/data. */
+
+  /* Note: All the offset calculations are based on struct FirmwareImage which
+   * is defined in include/firmware_image.h. */
+
+  /* Compare magic bytes. */
+  if (SafeMemcmp(firmware_blob, FIRMWARE_MAGIC, FIRMWARE_MAGIC_SIZE))
+    return VERIFY_FIRMWARE_WRONG_MAGIC;
+  header_ptr = firmware_blob + FIRMWARE_MAGIC_SIZE;
+
+  /* Only continue if header verification succeeds. */
+  if ((error_code = VerifyFirmwareHeader(root_key_blob, header_ptr,
+                                         &algorithm, &header_len)))
+    return error_code;  /* AKA jump to revovery. */
+
+  /* Parse signing key into RSAPublicKey structure since it is required multiple
+   * times. */
+  firmware_sign_key_len = RSAProcessedKeySize(algorithm);
+  firmware_sign_key_ptr = header_ptr + (FIELD_LEN(header_len) +
+                                        FIELD_LEN(firmware_sign_algorithm) +
+                                        FIELD_LEN(firmware_key_version));
+  firmware_sign_key = RSAPublicKeyFromBuf(firmware_sign_key_ptr,
+                                          firmware_sign_key_len);
+  signature_len = siglen_map[algorithm];
+
+  /* Only continue if preamble verification succeeds. */
+  preamble_ptr = (header_ptr + header_len +
+                  FIELD_LEN(firmware_key_signature));
+  if ((error_code = VerifyFirmwarePreamble(firmware_sign_key, preamble_ptr,
+                                           algorithm,
+                                           &firmware_len))) {
+    RSAPublicKeyFree(firmware_sign_key);
+    debug("Couldn't verify Firmware preamble.\n");
+    return error_code;  /* AKA jump to recovery. */
+  }
+  /* Only continue if firmware data verification succeeds. */
+  firmware_ptr = (preamble_ptr +
+                  (FIELD_LEN(firmware_version) +  /* Skip the preamble. */
+                   FIELD_LEN(firmware_len) +
+                   FIELD_LEN(preamble)) +
+                  signature_len);
+
+  if ((error_code = VerifyFirmwareData(firmware_sign_key, preamble_ptr,
+                                       firmware_ptr,
+                                       firmware_len,
+                                       algorithm))) {
+    RSAPublicKeyFree(firmware_sign_key);
+    debug("Couldn't verify Firmware data.\n");
+    return error_code;  /* AKA jump to recovery. */
+  }
+
+  RSAPublicKeyFree(firmware_sign_key);
+  return 0;  /* Success! */
+}
+
+uint32_t GetLogicalFirmwareVersion(uint8_t* firmware_blob) {
+  uint16_t firmware_key_version;
+  uint16_t firmware_version;
+  uint16_t firmware_sign_algorithm;
+  int firmware_sign_key_len;
+  Memcpy(&firmware_sign_algorithm,
+         firmware_blob + (FIELD_LEN(magic) +  /* Offset to field. */
+                          FIELD_LEN(header_len)),
+         sizeof(firmware_sign_algorithm));
+  Memcpy(&firmware_key_version,
+         firmware_blob + (FIELD_LEN(magic) +  /* Offset to field. */
+                          FIELD_LEN(header_len) +
+                          FIELD_LEN(firmware_sign_algorithm)),
+         sizeof(firmware_key_version));
+  if (firmware_sign_algorithm >= kNumAlgorithms)
+    return 0;
+  firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
+  Memcpy(&firmware_version,
+         firmware_blob +  (FIELD_LEN(magic) +  /* Offset to field. */
+                           FIELD_LEN(header_len) +
+                           FIELD_LEN(firmware_key_version) +
+                           firmware_sign_key_len +
+                           FIELD_LEN(header_checksum) +
+                           FIELD_LEN(firmware_key_signature)),
+         sizeof(firmware_version));
+  return CombineUint16Pair(firmware_key_version, firmware_version);
+}
+
+int VerifyFirmwareDriver_f(uint8_t* root_key_blob,
+                           uint8_t* firmwareA,
+                           uint8_t* firmwareB) {
+  /* Contains the logical firmware version (32-bit) which is calculated as
+   * (firmware_key_version << 16 | firmware_version) where
+   * [firmware_key_version] [firmware_version] are both 16-bit.
+   */
+  uint32_t firmwareA_lversion, firmwareB_lversion;
+  uint8_t firmwareA_is_verified = 0;  /* Whether firmwareA verify succeeded. */
+  uint32_t min_lversion;  /* Minimum of firmware A and firmware lversion. */
+  uint32_t stored_lversion;  /* Stored logical version in the TPM. */
+
+  /* Initialize the TPM since we'll be reading the rollback indices. */
+  SetupTPM();
+
+  /* We get the key versions by reading directly from the image blobs without
+   * any additional (expensive) sanity checking on the blob since it's faster to
+   * outright reject a firmware with an older firmware key version. A malformed
+   * or corrupted firmware blob will still fail when VerifyFirmware() is called
+   * on it.
+   */
+  firmwareA_lversion = GetLogicalFirmwareVersion(firmwareA);
+  firmwareB_lversion = GetLogicalFirmwareVersion(firmwareB);
+  min_lversion  = Min(firmwareA_lversion, firmwareB_lversion);
+  stored_lversion = CombineUint16Pair(GetStoredVersion(FIRMWARE_KEY_VERSION),
+                                      GetStoredVersion(FIRMWARE_VERSION));
+  /* Always try FirmwareA first. */
+  if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareA))
+    firmwareA_is_verified = 1;
+  if (firmwareA_is_verified && (stored_lversion < firmwareA_lversion)) {
+    /* Stored version may need to be updated but only if FirmwareB
+     * is successfully verified and has a logical version greater than
+     * the stored logical version. */
+    if (stored_lversion < firmwareB_lversion) {
+      if (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)) {
+        WriteStoredVersion(FIRMWARE_KEY_VERSION,
+                           (uint16_t) (min_lversion >> 16));
+        WriteStoredVersion(FIRMWARE_VERSION,
+                           (uint16_t) (min_lversion & 0x00FFFF));
+        stored_lversion = min_lversion;  /* Update stored version as it's used
+                                          * later. */
+      }
+    }
+  }
+  /* Lock Firmware TPM rollback indices from further writes. */
+  /* TODO(gauravsh): Figure out if these can be combined into one
+   * 32-bit location since we seem to always use them together. This can help
+   * us minimize the number of NVRAM writes/locks (which are limited over flash
+   * memory lifetimes.
+   */
+  LockStoredVersion(FIRMWARE_KEY_VERSION);
+  LockStoredVersion(FIRMWARE_VERSION);
+
+  /* Determine which firmware (if any) to jump to.
+   *
+   * We always attempt to jump to FirmwareA first. If verification of FirmwareA
+   * fails, we try FirmwareB. In all cases, if the firmware successfully
+   * verified but is a rollback, we jump to recovery.
+   *
+   * Note: This means that if FirmwareA verified successfully and is a
+   * rollback, then no attempt is made to check FirmwareB. We still jump to
+   * recovery. FirmwareB is only used as a backup in case FirmwareA gets
+   * corrupted. Since newer firmware updates are always written to A,
+   * the case where firmware A is verified but a rollback should not occur in
+   * normal operation.
+   */
+  if (firmwareA_is_verified) {
+    if (stored_lversion <= firmwareA_lversion)
+      return BOOT_FIRMWARE_A_CONTINUE;
+  } else {
+    /* If FirmwareA was not valid, then we skipped over the
+     * check to update the rollback indices and a Verify of FirmwareB wasn't
+     * attempted.
+     * If FirmwareB is not a rollback, then we attempt to do the verification.
+     */
+    if (stored_lversion <= firmwareB_lversion &&
+        (VERIFY_FIRMWARE_SUCCESS == VerifyFirmware(root_key_blob, firmwareB)))
+        return BOOT_FIRMWARE_B_CONTINUE;
+  }
+  /* D'oh: No bootable firmware. */
+  return BOOT_FIRMWARE_RECOVERY_CONTINUE;
+}
diff --git a/utils/kernel_image.c b/utils/kernel_image.c
index 32e12a8..e66ce38 100644
--- a/utils/kernel_image.c
+++ b/utils/kernel_image.c
@@ -3,6 +3,7 @@
  * found in the LICENSE file.
  *
  * Functions for generating and manipulating a verified boot kernel image.
+ * (Userland portion)
  */
 
 #include "kernel_image.h"
@@ -75,7 +76,7 @@
   StatefulMemcpy(&st, &image->magic, KERNEL_MAGIC_SIZE);
 
   if (SafeMemcmp(image->magic, KERNEL_MAGIC, KERNEL_MAGIC_SIZE)) {
-    fprintf(stderr, "Wrong Kernel Magic.\n");
+    debug("Wrong Kernel Magic.\n");
     Free(kernel_buf);
     return NULL;
   }
@@ -107,7 +108,7 @@
   /* Check whether key header length is correct. */
   header_len = GetKernelHeaderLen(image);
   if (header_len != image->header_len) {
-    fprintf(stderr, "Header length mismatch. Got: %d, Expected: %d\n",
+    debug("Header length mismatch. Got: %d, Expected: %d\n",
             image->header_len, header_len);
     Free(kernel_buf);
     return NULL;
@@ -124,7 +125,7 @@
   CalculateKernelHeaderChecksum(image, header_checksum);
   if (SafeMemcmp(header_checksum, image->header_checksum,
                  FIELD_LEN(header_checksum))) {
-    fprintf(stderr, "Invalid kernel header checksum!\n");
+    debug("Invalid kernel header checksum!\n");
     Free(kernel_buf);
     return NULL;
   }
@@ -307,17 +308,17 @@
   if (!image)
     return 0;
   if (-1 == (fd = creat(input_file, S_IRWXU))) {
-    fprintf(stderr, "Couldn't open file for writing kernel image: %s\n",
+    debug("Couldn't open file for writing kernel image: %s\n",
             input_file);
     return 0;
   }
   kernel_blob = GetKernelBlob(image, &blob_len);
   if (!kernel_blob) {
-    fprintf(stderr, "Couldn't create kernel blob from KernelImage.\n");
+    debug("Couldn't create kernel blob from KernelImage.\n");
     return 0;
   }
   if (blob_len != write(fd, kernel_blob, blob_len)) {
-    fprintf(stderr, "Couldn't write Kernel Image to file: %s\n",
+    debug("Couldn't write Kernel Image to file: %s\n",
             input_file);
 
     Free(kernel_blob);
@@ -361,212 +362,6 @@
   /* TODO(gauravsh): Output kernel signature here? */
 }
 
-char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
-  "Success.",
-  "Invalid Image.",
-  "Kernel Key Signature Failed.",
-  "Invalid Kernel Verification Algorithm.",
-  "Config Signature Failed.",
-  "Kernel Signature Failed.",
-  "Wrong Kernel Magic.",
-};
-
-int VerifyKernelHeader(const uint8_t* firmware_key_blob,
-                       const uint8_t* header_blob,
-                       const int dev_mode,
-                       int* firmware_algorithm,
-                       int* kernel_algorithm,
-                       int* kernel_header_len) {
-  int kernel_sign_key_len;
-  int firmware_sign_key_len;
-  uint16_t header_version, header_len;
-  uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
-  uint8_t* header_checksum = NULL;
-
-  /* Base Offset for the header_checksum field. Actual offset is
-   * this + kernel_sign_key_len. */
-  int base_header_checksum_offset = (FIELD_LEN(header_version) +
-                                     FIELD_LEN(header_len) +
-                                     FIELD_LEN(firmware_sign_algorithm) +
-                                     FIELD_LEN(kernel_sign_algorithm) +
-                                     FIELD_LEN(kernel_key_version));
-
-  Memcpy(&header_version, header_blob, sizeof(header_version));
-  Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
-         sizeof(header_len));
-  Memcpy(&firmware_sign_algorithm,
-         header_blob + (FIELD_LEN(header_version) +
-                        FIELD_LEN(header_len)),
-         sizeof(firmware_sign_algorithm));
-  Memcpy(&kernel_sign_algorithm,
-         header_blob + (FIELD_LEN(header_version) +
-                        FIELD_LEN(header_len) +
-                        FIELD_LEN(firmware_sign_algorithm)),
-         sizeof(kernel_sign_algorithm));
-
-  /* TODO(gauravsh): Make this return two different error types depending
-   * on whether the firmware or kernel signing algorithm is invalid. */
-  if (firmware_sign_algorithm >= kNumAlgorithms)
-    return VERIFY_KERNEL_INVALID_ALGORITHM;
-  if (kernel_sign_algorithm >= kNumAlgorithms)
-    return VERIFY_KERNEL_INVALID_ALGORITHM;
-
-  *firmware_algorithm = (int) firmware_sign_algorithm;
-  *kernel_algorithm = (int) kernel_sign_algorithm;
-  kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
-  firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
-
-
-  /* Verify if header len is correct? */
-  if (header_len != (base_header_checksum_offset +
-                     kernel_sign_key_len +
-                     FIELD_LEN(header_checksum))) {
-    fprintf(stderr, "VerifyKernelHeader: Header length mismatch\n");
-    return VERIFY_KERNEL_INVALID_IMAGE;
-  }
-  *kernel_header_len = (int) header_len;
-
-  /* Verify if the hash of the header is correct. */
-  header_checksum = DigestBuf(header_blob,
-                              header_len - FIELD_LEN(header_checksum),
-                              SHA512_DIGEST_ALGORITHM);
-  if (SafeMemcmp(header_checksum,
-                 header_blob + (base_header_checksum_offset +
-                                kernel_sign_key_len),
-                 FIELD_LEN(header_checksum))) {
-    Free(header_checksum);
-    fprintf(stderr, "VerifyKernelHeader: Invalid header hash\n");
-    return VERIFY_KERNEL_INVALID_IMAGE;
-  }
-  Free(header_checksum);
-
-  /* Verify kernel key signature unless we are in dev mode. */
-  if (!dev_mode) {
-    if (!RSAVerifyBinary_f(firmware_key_blob, NULL,  /* Key to use */
-                           header_blob,  /* Data to verify */
-                           header_len, /* Length of data */
-                           header_blob + header_len,  /* Expected Signature */
-                           firmware_sign_algorithm))
-      return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
-  }
-  return 0;
-}
-
-int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
-                       const uint8_t* config_blob,
-                       int algorithm,
-                       uint64_t* kernel_len) {
-  uint64_t len;
-  int config_len;
-  config_len = GetKernelConfigLen(NULL);
-  if (!RSAVerifyBinary_f(NULL, kernel_sign_key,  /* Key to use */
-                         config_blob,  /* Data to verify */
-                         config_len,  /* Length of data */
-                         config_blob + config_len,  /* Expected Signature */
-                         algorithm))
-    return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
-
-  Memcpy(&len,
-         config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
-                              FIELD_LEN(options.cmd_line)),
-         sizeof(len));
-  *kernel_len = len;
-  return 0;
-}
-
-int VerifyKernelData(RSAPublicKey* kernel_sign_key,
-                     const uint8_t* kernel_config_start,
-                     const uint8_t* kernel_data_start,
-                     uint64_t kernel_len,
-                     int algorithm) {
-  int signature_len = siglen_map[algorithm];
-  uint8_t* digest;
-  DigestContext ctx;
-
-  /* Since the kernel signature is computed over the kernel version, options
-   * and data, which does not form a contiguous region of memory, we calculate
-   * the message digest ourselves. */
-  DigestInit(&ctx, algorithm);
-  DigestUpdate(&ctx, kernel_config_start, GetKernelConfigLen());
-  DigestUpdate(&ctx, kernel_data_start + signature_len, kernel_len);
-  digest = DigestFinal(&ctx);
-  if (!RSAVerifyBinaryWithDigest_f(
-          NULL, kernel_sign_key,  /* Key to use. */
-          digest, /* Digest of the data to verify. */
-          kernel_data_start,  /* Expected Signature */
-          algorithm)) {
-    Free(digest);
-    return VERIFY_KERNEL_SIGNATURE_FAILED;
-  }
-  Free(digest);
-  return 0;
-}
-
-int VerifyKernel(const uint8_t* firmware_key_blob,
-                 const uint8_t* kernel_blob,
-                 const int dev_mode) {
-  int error_code;
-  int firmware_sign_algorithm;  /* Firmware signing key algorithm. */
-  int kernel_sign_algorithm;  /* Kernel Signing key algorithm. */
-  RSAPublicKey* kernel_sign_key;
-  int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
-      header_len;
-  uint64_t kernel_len;
-  const uint8_t* header_ptr;  /* Pointer to header. */
-  const uint8_t* kernel_sign_key_ptr;  /* Pointer to signing key. */
-  const uint8_t* config_ptr;  /* Pointer to kernel config block. */
-  const uint8_t* kernel_ptr;  /* Pointer to kernel signature/data. */
-
-  /* Note: All the offset calculations are based on struct FirmwareImage which
-   * is defined in include/firmware_image.h. */
-
-  /* Compare magic bytes. */
-  if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
-    return VERIFY_KERNEL_WRONG_MAGIC;
-  header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
-
-  /* Only continue if header verification succeeds. */
-  if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
-                                       &firmware_sign_algorithm,
-                                       &kernel_sign_algorithm, &header_len))) {
-    fprintf(stderr, "VerifyKernel: Kernel header verification failed.\n");
-    return error_code;  /* AKA jump to recovery. */
-  }
-  /* Parse signing key into RSAPublicKey structure since it is required multiple
-   * times. */
-  kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
-  kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
-                                      FIELD_LEN(header_len) +
-                                      FIELD_LEN(firmware_sign_algorithm) +
-                                      FIELD_LEN(kernel_sign_algorithm) +
-                                      FIELD_LEN(kernel_key_version));
-  kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
-                                        kernel_sign_key_len);
-  kernel_signature_len = siglen_map[kernel_sign_algorithm];
-  kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
-
-  /* Only continue if config verification succeeds. */
-  config_ptr = (header_ptr + header_len + kernel_key_signature_len);
-  if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
-                                       kernel_sign_algorithm,
-                                       &kernel_len))) {
-    RSAPublicKeyFree(kernel_sign_key);
-    return error_code;  /* AKA jump to recovery. */
-  }
-  /* Only continue if kernel data verification succeeds. */
-  kernel_ptr = (config_ptr +
-                GetKernelConfigLen() +  /* Skip config block/signature. */
-                kernel_signature_len);
-
-  if ((error_code = VerifyKernelData(kernel_sign_key, config_ptr, kernel_ptr,
-                                     kernel_len,
-                                     kernel_sign_algorithm))) {
-    RSAPublicKeyFree(kernel_sign_key);
-    return error_code;  /* AKA jump to recovery. */
-  }
-  RSAPublicKeyFree(kernel_sign_key);
-  return 0;  /* Success! */
-}
 
 int VerifyKernelImage(const RSAPublicKey* firmware_key,
                       const KernelImage* image,
@@ -617,7 +412,7 @@
                     siglen_map[image->firmware_sign_algorithm],
                     image->firmware_sign_algorithm,
                     header_digest)) {
-      fprintf(stderr, "VerifyKernelImage(): Key signature check failed.\n");
+      debug("VerifyKernelImage(): Key signature check failed.\n");
       error_code =  VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
       goto verify_failure;
     }
@@ -723,7 +518,7 @@
                                         GetKernelConfigLen(),
                                         kernel_signing_key_file,
                                         image->kernel_sign_algorithm))) {
-    fprintf(stderr, "Could not compute signature on the kernel config.\n");
+    debug("Could not compute signature on the kernel config.\n");
     Free(config_blob);
     return 0;
   }
@@ -745,7 +540,7 @@
                                         image->kernel_sign_algorithm))) {
     Free(config_blob);
     Free(kernel_buf);
-    fprintf(stderr, "Could not compute signature on the kernel.\n");
+    debug("Could not compute signature on the kernel.\n");
     return 0;
   }
   image->kernel_signature = (uint8_t*) Malloc(signature_len);
@@ -756,146 +551,8 @@
   return 1;
 }
 
-uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) {
-  uint8_t* kernel_ptr;
-  uint16_t kernel_key_version;
-  uint16_t kernel_version;
-  uint16_t firmware_sign_algorithm;
-  uint16_t kernel_sign_algorithm;
-  int kernel_key_signature_len;
-  int kernel_sign_key_len;
-  kernel_ptr = kernel_blob + (FIELD_LEN(magic) +
-                              FIELD_LEN(header_version) +
-                              FIELD_LEN(header_len));
-  Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm));
-  kernel_ptr += FIELD_LEN(firmware_sign_algorithm);
-  Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm));
-  kernel_ptr += FIELD_LEN(kernel_sign_algorithm);
-  Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version));
-
-  if (firmware_sign_algorithm >= kNumAlgorithms)
-    return 0;
-  if (kernel_sign_algorithm >= kNumAlgorithms)
-    return 0;
-  kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
-  kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
-  kernel_ptr += (FIELD_LEN(kernel_key_version) +
-                 kernel_sign_key_len +
-                 FIELD_LEN(header_checksum) +
-                 kernel_key_signature_len);
-  Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version));
-  return CombineUint16Pair(kernel_key_version, kernel_version);
-}
-
 void PrintKernelEntry(kernel_entry* entry) {
-  fprintf(stderr, "Boot Priority = %d\n", entry->boot_priority);
-  fprintf(stderr, "Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
-  fprintf(stderr, "Boot Success Flag = %d\n", entry->boot_success_flag);
-}
-
-int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
-                         kernel_entry* kernelA,
-                         kernel_entry* kernelB,
-                         int dev_mode) {
-  int i;
-  /* Contains the logical kernel version (32-bit) which is calculated as
-   * (kernel_key_version << 16 | kernel_version) where
-   * [kernel_key_version], [firmware_version] are both 16-bit.
-   */
-  uint32_t kernelA_lversion, kernelB_lversion;
-  uint32_t min_lversion;  /* Minimum of kernel A and kernel B lversion. */
-  uint32_t stored_lversion;  /* Stored logical version in the TPM. */
-  kernel_entry* try_kernel[2];  /* Kernel in try order. */
-  int try_kernel_which[2];  /* Which corresponding kernel in the try order */
-  uint32_t try_kernel_lversion[2];  /* Their logical versions. */
-
-  /* [kernel_to_boot] will eventually contain the boot path to follow
-   * and is returned to the caller. Initially, we set it to recovery. If
-   * a valid bootable kernel is found, it will be set to that. */
-  int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE;
-
-
-  /* The TPM must already have be initialized, so no need to call SetupTPM(). */
-
-  /* We get the key versions by reading directly from the image blobs without
-   * any additional (expensive) sanity checking on the blob since it's faster to
-   * outright reject a kernel with an older kernel key version. A malformed
-   * or corrupted kernel blob will still fail when VerifyKernel() is called
-   * on it.
-   */
-  kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob);
-  kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob);
-  min_lversion  = Min(kernelA_lversion, kernelB_lversion);
-  stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION),
-                                      GetStoredVersion(KERNEL_VERSION));
-
-  /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the
-   * partition table - verify its signature/checksum before proceeding
-   * further. */
-
-  /* The logic for deciding which kernel to boot from is taken from the
-   * the Chromium OS Drive Map design document.
-   *
-   * We went to consider the kernels in their according to their boot
-   * priority attribute value.
-   */
-
-  if (kernelA->boot_priority >= kernelB->boot_priority) {
-    try_kernel[0] = kernelA;
-    try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE;
-    try_kernel_lversion[0] = kernelA_lversion;
-    try_kernel[1] = kernelB;
-    try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE;
-    try_kernel_lversion[1] = kernelB_lversion;
-  } else {
-    try_kernel[0] = kernelB;
-    try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE;
-    try_kernel_lversion[0] = kernelB_lversion;
-    try_kernel[1] = kernelA;
-    try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE;
-    try_kernel_lversion[1] = kernelA_lversion;
-  }
-
-  /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority
-   * below should be propagated to partition table. This will be added
-   * once the firmware parition table parsing code is in. */
-  for (i = 0; i < 2; i++) {
-    if ((try_kernel[i]->boot_success_flag ||
-         try_kernel[i]->boot_tries_remaining) &&
-        (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
-                                               try_kernel[i]->kernel_blob,
-                                               dev_mode))) {
-      if (try_kernel[i]->boot_tries_remaining > 0)
-        try_kernel[i]->boot_tries_remaining--;
-      if (stored_lversion > try_kernel_lversion[i])
-        continue;  /* Rollback: I am afraid I can't let you do that Dave. */
-      if (i == 0 && (stored_lversion < try_kernel_lversion[1])) {
-        /* The higher priority kernel is valid and bootable, See if we
-         * need to update the stored version for rollback prevention. */
-        if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
-                                                  try_kernel[1]->kernel_blob,
-                                                  dev_mode)) {
-          WriteStoredVersion(KERNEL_KEY_VERSION,
-                             (uint16_t) (min_lversion >> 16));
-          WriteStoredVersion(KERNEL_VERSION,
-                             (uint16_t) (min_lversion & 0xFFFF));
-          stored_lversion = min_lversion;  /* Update stored version as it's
-                                            * used later. */
-        }
-      }
-      kernel_to_boot = try_kernel_which[i];
-      break;  /* We found a valid kernel. */
-    }
-    try_kernel[i]->boot_priority = 0;
-    }  /* for loop. */
-
-  /* Lock Kernel TPM rollback indices from further writes.
-   * TODO(gauravsh): Figure out if these can be combined into one
-   * 32-bit location since we seem to always use them together. This can help
-   * us minimize the number of NVRAM writes/locks (which are limited over flash
-   * memory lifetimes.
-   */
-  LockStoredVersion(KERNEL_KEY_VERSION);
-  LockStoredVersion(KERNEL_VERSION);
-  return kernel_to_boot;
+  debug("Boot Priority = %d\n", entry->boot_priority);
+  debug("Boot Tries Remaining = %d\n", entry->boot_tries_remaining);
+  debug("Boot Success Flag = %d\n", entry->boot_success_flag);
 }
diff --git a/utils/kernel_image_fw.c b/utils/kernel_image_fw.c
new file mode 100644
index 0000000..466d34a
--- /dev/null
+++ b/utils/kernel_image_fw.c
@@ -0,0 +1,368 @@
+/* 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.
+ *
+ * Functions for verifying a verified boot kernel image.
+ * (Firmware portion)
+ */
+
+#include "kernel_image_fw.h"
+
+#include "padding.h"
+#include "rollback_index.h"
+#include "rsa_utility.h"
+#include "sha_utility.h"
+#include "utility.h"
+
+/* Macro to determine the size of a field structure in the KernelImage
+ * structure. */
+#define FIELD_LEN(field) (sizeof(((KernelImage*)0)->field))
+#define KERNEL_CONFIG_FIELD_LEN (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) + \
+                                 FIELD_LEN(options.cmd_line) + \
+                                 FIELD_LEN(options.kernel_len) + \
+                                 FIELD_LEN(options.kernel_load_addr) + \
+                                 FIELD_LEN(options.kernel_entry_addr))
+
+char* kVerifyKernelErrors[VERIFY_KERNEL_MAX] = {
+  "Success.",
+  "Invalid Image.",
+  "Kernel Key Signature Failed.",
+  "Invalid Kernel Verification Algorithm.",
+  "Config Signature Failed.",
+  "Kernel Signature Failed.",
+  "Wrong Kernel Magic.",
+};
+
+int VerifyKernelHeader(const uint8_t* firmware_key_blob,
+                       const uint8_t* header_blob,
+                       const int dev_mode,
+                       int* firmware_algorithm,
+                       int* kernel_algorithm,
+                       int* kernel_header_len) {
+  int kernel_sign_key_len;
+  int firmware_sign_key_len;
+  uint16_t header_version, header_len;
+  uint16_t firmware_sign_algorithm, kernel_sign_algorithm;
+  uint8_t* header_checksum = NULL;
+
+  /* Base Offset for the header_checksum field. Actual offset is
+   * this + kernel_sign_key_len. */
+  int base_header_checksum_offset = (FIELD_LEN(header_version) +
+                                     FIELD_LEN(header_len) +
+                                     FIELD_LEN(firmware_sign_algorithm) +
+                                     FIELD_LEN(kernel_sign_algorithm) +
+                                     FIELD_LEN(kernel_key_version));
+
+  Memcpy(&header_version, header_blob, sizeof(header_version));
+  Memcpy(&header_len, header_blob + FIELD_LEN(header_version),
+         sizeof(header_len));
+  Memcpy(&firmware_sign_algorithm,
+         header_blob + (FIELD_LEN(header_version) +
+                        FIELD_LEN(header_len)),
+         sizeof(firmware_sign_algorithm));
+  Memcpy(&kernel_sign_algorithm,
+         header_blob + (FIELD_LEN(header_version) +
+                        FIELD_LEN(header_len) +
+                        FIELD_LEN(firmware_sign_algorithm)),
+         sizeof(kernel_sign_algorithm));
+
+  /* TODO(gauravsh): Make this return two different error types depending
+   * on whether the firmware or kernel signing algorithm is invalid. */
+  if (firmware_sign_algorithm >= kNumAlgorithms)
+    return VERIFY_KERNEL_INVALID_ALGORITHM;
+  if (kernel_sign_algorithm >= kNumAlgorithms)
+    return VERIFY_KERNEL_INVALID_ALGORITHM;
+
+  *firmware_algorithm = (int) firmware_sign_algorithm;
+  *kernel_algorithm = (int) kernel_sign_algorithm;
+  kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
+  firmware_sign_key_len = RSAProcessedKeySize(firmware_sign_algorithm);
+
+
+  /* Verify if header len is correct? */
+  if (header_len != (base_header_checksum_offset +
+                     kernel_sign_key_len +
+                     FIELD_LEN(header_checksum))) {
+    debug("VerifyKernelHeader: Header length mismatch\n");
+    return VERIFY_KERNEL_INVALID_IMAGE;
+  }
+  *kernel_header_len = (int) header_len;
+
+  /* Verify if the hash of the header is correct. */
+  header_checksum = DigestBuf(header_blob,
+                              header_len - FIELD_LEN(header_checksum),
+                              SHA512_DIGEST_ALGORITHM);
+  if (SafeMemcmp(header_checksum,
+                 header_blob + (base_header_checksum_offset +
+                                kernel_sign_key_len),
+                 FIELD_LEN(header_checksum))) {
+    Free(header_checksum);
+    debug("VerifyKernelHeader: Invalid header hash\n");
+    return VERIFY_KERNEL_INVALID_IMAGE;
+  }
+  Free(header_checksum);
+
+  /* Verify kernel key signature unless we are in dev mode. */
+  if (!dev_mode) {
+    if (!RSAVerifyBinary_f(firmware_key_blob, NULL,  /* Key to use */
+                           header_blob,  /* Data to verify */
+                           header_len, /* Length of data */
+                           header_blob + header_len,  /* Expected Signature */
+                           firmware_sign_algorithm))
+      return VERIFY_KERNEL_KEY_SIGNATURE_FAILED;
+  }
+  return 0;
+}
+
+int VerifyKernelConfig(RSAPublicKey* kernel_sign_key,
+                       const uint8_t* config_blob,
+                       int algorithm,
+                       uint64_t* kernel_len) {
+  uint64_t len;
+  if (!RSAVerifyBinary_f(NULL, kernel_sign_key,  /* Key to use */
+                         config_blob,  /* Data to verify */
+                         KERNEL_CONFIG_FIELD_LEN,  /* Length of data */
+                         config_blob + KERNEL_CONFIG_FIELD_LEN,  /* Expected
+                                                                  * Signature */
+                         algorithm))
+    return VERIFY_KERNEL_CONFIG_SIGNATURE_FAILED;
+
+  Memcpy(&len,
+         config_blob + (FIELD_LEN(kernel_version) + FIELD_LEN(options.version) +
+                              FIELD_LEN(options.cmd_line)),
+         sizeof(len));
+  *kernel_len = len;
+  return 0;
+}
+
+int VerifyKernelData(RSAPublicKey* kernel_sign_key,
+                     const uint8_t* kernel_config_start,
+                     const uint8_t* kernel_data_start,
+                     uint64_t kernel_len,
+                     int algorithm) {
+  int signature_len = siglen_map[algorithm];
+  uint8_t* digest;
+  DigestContext ctx;
+
+  /* Since the kernel signature is computed over the kernel version, options
+   * and data, which does not form a contiguous region of memory, we calculate
+   * the message digest ourselves. */
+  DigestInit(&ctx, algorithm);
+  DigestUpdate(&ctx, kernel_config_start, KERNEL_CONFIG_FIELD_LEN);
+  DigestUpdate(&ctx, kernel_data_start + signature_len, kernel_len);
+  digest = DigestFinal(&ctx);
+  if (!RSAVerifyBinaryWithDigest_f(
+          NULL, kernel_sign_key,  /* Key to use. */
+          digest, /* Digest of the data to verify. */
+          kernel_data_start,  /* Expected Signature */
+          algorithm)) {
+    Free(digest);
+    return VERIFY_KERNEL_SIGNATURE_FAILED;
+  }
+  Free(digest);
+  return 0;
+}
+
+int VerifyKernel(const uint8_t* firmware_key_blob,
+                 const uint8_t* kernel_blob,
+                 const int dev_mode) {
+  int error_code;
+  int firmware_sign_algorithm;  /* Firmware signing key algorithm. */
+  int kernel_sign_algorithm;  /* Kernel Signing key algorithm. */
+  RSAPublicKey* kernel_sign_key;
+  int kernel_sign_key_len, kernel_key_signature_len, kernel_signature_len,
+      header_len;
+  uint64_t kernel_len;
+  const uint8_t* header_ptr;  /* Pointer to header. */
+  const uint8_t* kernel_sign_key_ptr;  /* Pointer to signing key. */
+  const uint8_t* config_ptr;  /* Pointer to kernel config block. */
+  const uint8_t* kernel_ptr;  /* Pointer to kernel signature/data. */
+
+  /* Note: All the offset calculations are based on struct FirmwareImage which
+   * is defined in include/firmware_image.h. */
+
+  /* Compare magic bytes. */
+  if (SafeMemcmp(kernel_blob, KERNEL_MAGIC, KERNEL_MAGIC_SIZE))
+    return VERIFY_KERNEL_WRONG_MAGIC;
+  header_ptr = kernel_blob + KERNEL_MAGIC_SIZE;
+
+  /* Only continue if header verification succeeds. */
+  if ((error_code = VerifyKernelHeader(firmware_key_blob, header_ptr, dev_mode,
+                                       &firmware_sign_algorithm,
+                                       &kernel_sign_algorithm, &header_len))) {
+    debug("VerifyKernel: Kernel header verification failed.\n");
+    return error_code;  /* AKA jump to recovery. */
+  }
+  /* Parse signing key into RSAPublicKey structure since it is required multiple
+   * times. */
+  kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
+  kernel_sign_key_ptr = header_ptr + (FIELD_LEN(header_version) +
+                                      FIELD_LEN(header_len) +
+                                      FIELD_LEN(firmware_sign_algorithm) +
+                                      FIELD_LEN(kernel_sign_algorithm) +
+                                      FIELD_LEN(kernel_key_version));
+  kernel_sign_key = RSAPublicKeyFromBuf(kernel_sign_key_ptr,
+                                        kernel_sign_key_len);
+  kernel_signature_len = siglen_map[kernel_sign_algorithm];
+  kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
+
+  /* Only continue if config verification succeeds. */
+  config_ptr = (header_ptr + header_len + kernel_key_signature_len);
+  if ((error_code = VerifyKernelConfig(kernel_sign_key, config_ptr,
+                                       kernel_sign_algorithm,
+                                       &kernel_len))) {
+    RSAPublicKeyFree(kernel_sign_key);
+    return error_code;  /* AKA jump to recovery. */
+  }
+  /* Only continue if kernel data verification succeeds. */
+  kernel_ptr = (config_ptr +
+                KERNEL_CONFIG_FIELD_LEN +  /* Skip config block/signature. */
+                kernel_signature_len);
+
+  if ((error_code = VerifyKernelData(kernel_sign_key, config_ptr, kernel_ptr,
+                                     kernel_len,
+                                     kernel_sign_algorithm))) {
+    RSAPublicKeyFree(kernel_sign_key);
+    return error_code;  /* AKA jump to recovery. */
+  }
+  RSAPublicKeyFree(kernel_sign_key);
+  return 0;  /* Success! */
+}
+
+uint32_t GetLogicalKernelVersion(uint8_t* kernel_blob) {
+  uint8_t* kernel_ptr;
+  uint16_t kernel_key_version;
+  uint16_t kernel_version;
+  uint16_t firmware_sign_algorithm;
+  uint16_t kernel_sign_algorithm;
+  int kernel_key_signature_len;
+  int kernel_sign_key_len;
+  kernel_ptr = kernel_blob + (FIELD_LEN(magic) +
+                              FIELD_LEN(header_version) +
+                              FIELD_LEN(header_len));
+  Memcpy(&firmware_sign_algorithm, kernel_ptr, sizeof(firmware_sign_algorithm));
+  kernel_ptr += FIELD_LEN(firmware_sign_algorithm);
+  Memcpy(&kernel_sign_algorithm, kernel_ptr, sizeof(kernel_sign_algorithm));
+  kernel_ptr += FIELD_LEN(kernel_sign_algorithm);
+  Memcpy(&kernel_key_version, kernel_ptr, sizeof(kernel_key_version));
+
+  if (firmware_sign_algorithm >= kNumAlgorithms)
+    return 0;
+  if (kernel_sign_algorithm >= kNumAlgorithms)
+    return 0;
+  kernel_key_signature_len = siglen_map[firmware_sign_algorithm];
+  kernel_sign_key_len = RSAProcessedKeySize(kernel_sign_algorithm);
+  kernel_ptr += (FIELD_LEN(kernel_key_version) +
+                 kernel_sign_key_len +
+                 FIELD_LEN(header_checksum) +
+                 kernel_key_signature_len);
+  Memcpy(&kernel_version, kernel_ptr, sizeof(kernel_version));
+  return CombineUint16Pair(kernel_key_version, kernel_version);
+}
+
+int VerifyKernelDriver_f(uint8_t* firmware_key_blob,
+                         kernel_entry* kernelA,
+                         kernel_entry* kernelB,
+                         int dev_mode) {
+  int i;
+  /* Contains the logical kernel version (32-bit) which is calculated as
+   * (kernel_key_version << 16 | kernel_version) where
+   * [kernel_key_version], [firmware_version] are both 16-bit.
+   */
+  uint32_t kernelA_lversion, kernelB_lversion;
+  uint32_t min_lversion;  /* Minimum of kernel A and kernel B lversion. */
+  uint32_t stored_lversion;  /* Stored logical version in the TPM. */
+  kernel_entry* try_kernel[2];  /* Kernel in try order. */
+  int try_kernel_which[2];  /* Which corresponding kernel in the try order */
+  uint32_t try_kernel_lversion[2];  /* Their logical versions. */
+
+  /* [kernel_to_boot] will eventually contain the boot path to follow
+   * and is returned to the caller. Initially, we set it to recovery. If
+   * a valid bootable kernel is found, it will be set to that. */
+  int kernel_to_boot = BOOT_KERNEL_RECOVERY_CONTINUE;
+
+
+  /* The TPM must already have be initialized, so no need to call SetupTPM(). */
+
+  /* We get the key versions by reading directly from the image blobs without
+   * any additional (expensive) sanity checking on the blob since it's faster to
+   * outright reject a kernel with an older kernel key version. A malformed
+   * or corrupted kernel blob will still fail when VerifyKernel() is called
+   * on it.
+   */
+  kernelA_lversion = GetLogicalKernelVersion(kernelA->kernel_blob);
+  kernelB_lversion = GetLogicalKernelVersion(kernelB->kernel_blob);
+  min_lversion  = Min(kernelA_lversion, kernelB_lversion);
+  stored_lversion = CombineUint16Pair(GetStoredVersion(KERNEL_KEY_VERSION),
+                                      GetStoredVersion(KERNEL_VERSION));
+
+  /* TODO(gauravsh): The kernel entries kernelA and kernelB come from the
+   * partition table - verify its signature/checksum before proceeding
+   * further. */
+
+  /* The logic for deciding which kernel to boot from is taken from the
+   * the Chromium OS Drive Map design document.
+   *
+   * We went to consider the kernels in their according to their boot
+   * priority attribute value.
+   */
+
+  if (kernelA->boot_priority >= kernelB->boot_priority) {
+    try_kernel[0] = kernelA;
+    try_kernel_which[0] = BOOT_KERNEL_A_CONTINUE;
+    try_kernel_lversion[0] = kernelA_lversion;
+    try_kernel[1] = kernelB;
+    try_kernel_which[1] = BOOT_KERNEL_B_CONTINUE;
+    try_kernel_lversion[1] = kernelB_lversion;
+  } else {
+    try_kernel[0] = kernelB;
+    try_kernel_which[0] = BOOT_KERNEL_B_CONTINUE;
+    try_kernel_lversion[0] = kernelB_lversion;
+    try_kernel[1] = kernelA;
+    try_kernel_which[1] = BOOT_KERNEL_A_CONTINUE;
+    try_kernel_lversion[1] = kernelA_lversion;
+  }
+
+  /* TODO(gauravsh): Changes to boot_tries_remaining and boot_priority
+   * below should be propagated to partition table. This will be added
+   * once the firmware parition table parsing code is in. */
+  for (i = 0; i < 2; i++) {
+    if ((try_kernel[i]->boot_success_flag ||
+         try_kernel[i]->boot_tries_remaining) &&
+        (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
+                                               try_kernel[i]->kernel_blob,
+                                               dev_mode))) {
+      if (try_kernel[i]->boot_tries_remaining > 0)
+        try_kernel[i]->boot_tries_remaining--;
+      if (stored_lversion > try_kernel_lversion[i])
+        continue;  /* Rollback: I am afraid I can't let you do that Dave. */
+      if (i == 0 && (stored_lversion < try_kernel_lversion[1])) {
+        /* The higher priority kernel is valid and bootable, See if we
+         * need to update the stored version for rollback prevention. */
+        if (VERIFY_KERNEL_SUCCESS == VerifyKernel(firmware_key_blob,
+                                                  try_kernel[1]->kernel_blob,
+                                                  dev_mode)) {
+          WriteStoredVersion(KERNEL_KEY_VERSION,
+                             (uint16_t) (min_lversion >> 16));
+          WriteStoredVersion(KERNEL_VERSION,
+                             (uint16_t) (min_lversion & 0xFFFF));
+          stored_lversion = min_lversion;  /* Update stored version as it's
+                                            * used later. */
+        }
+      }
+      kernel_to_boot = try_kernel_which[i];
+      break;  /* We found a valid kernel. */
+    }
+    try_kernel[i]->boot_priority = 0;
+    }  /* for loop. */
+
+  /* Lock Kernel TPM rollback indices from further writes.
+   * TODO(gauravsh): Figure out if these can be combined into one
+   * 32-bit location since we seem to always use them together. This can help
+   * us minimize the number of NVRAM writes/locks (which are limited over flash
+   * memory lifetimes.
+   */
+  LockStoredVersion(KERNEL_KEY_VERSION);
+  LockStoredVersion(KERNEL_VERSION);
+  return kernel_to_boot;
+}