Add support for flags in the firmware preamble.

The old (v2.0) parser is compatible with new (v2.1) structs.  That is,
this won't break existing firmware or vbutil_firmware.

A new (v2.1) parser parsing an old (v2.0) struct will return 0 for the
flags.

This will be used to support the RO-normal code path in a subsequent CL.

BUG=chromium-os:17304
TEST=added unit tests; make && make runtests

Change-Id: I73bcd8acd3330b0d7d143061b5ef838e6d79cf1a
Reviewed-on: http://gerrit.chromium.org/gerrit/4030
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Tested-by: Randall Spangler <rspangler@chromium.org>
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index 48859e0..a97f0e8 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -138,9 +138,13 @@
  * VbSelectFirmwareParams.selected_firmware.  Note that we store these
  * in a uint32_t because enum maps to int, which isn't fixed-size. */
 enum VbSelectFirmware_t {
+  /* Recovery mode */
   VB_SELECT_FIRMWARE_RECOVERY = 0,
+  /* Rewritable firmware A/B for normal or developer path */
   VB_SELECT_FIRMWARE_A = 1,
-  VB_SELECT_FIRMWARE_B = 2
+  VB_SELECT_FIRMWARE_B = 2,
+  /* Read only firmware for normal or developer path */
+  VB_SELECT_FIRMWARE_READONLY = 3
 };
 
 
diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h
index 0271979..dd6a415 100644
--- a/firmware/include/vboot_struct.h
+++ b/firmware/include/vboot_struct.h
@@ -78,9 +78,33 @@
 
 
 #define FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR 2
-#define FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR 0
+#define FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR 1
 
-/* Preamble block for rewritable firmware */
+/* Preamble block for rewritable firmware, version 2.0.  All 2.x
+ * versions of this struct must start with the same data, to be
+ * compatible with version 2.0 readers. */
+typedef struct VbFirmwarePreambleHeader2_0 {
+  uint64_t preamble_size;            /* Size of this preamble, including keys,
+                                      * signatures, and padding, in bytes */
+  VbSignature preamble_signature;    /* Signature for this preamble
+                                      * (header + kernel subkey +
+                                      * body signature) */
+  uint32_t header_version_major;     /* Version of this header format (= 2) */
+  uint32_t header_version_minor;     /* Version of this header format (= 0) */
+
+  uint64_t firmware_version;         /* Firmware version */
+  VbPublicKey kernel_subkey;         /* Key to verify kernel key block */
+  VbSignature body_signature;        /* Signature for the firmware body */
+} __attribute__((packed)) VbFirmwarePreambleHeader2_0;
+
+#define EXPECTED_VBFIRMWAREPREAMBLEHEADER2_0_SIZE 104
+
+/* Flags for VbFirmwarePreambleHeader.flags */
+/* Use the normal/dev boot path from the read-only firmware, instead
+ * of verifying the body signature. */
+#define VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL 0x00000001
+
+/* Premable block for rewritable firmware, version 2.1 */
 typedef struct VbFirmwarePreambleHeader {
   uint64_t preamble_size;            /* Size of this preamble, including keys,
                                       * signatures, and padding, in bytes */
@@ -93,16 +117,23 @@
   uint64_t firmware_version;         /* Firmware version */
   VbPublicKey kernel_subkey;         /* Key to verify kernel key block */
   VbSignature body_signature;        /* Signature for the firmware body */
+
+  /* Fields added in header version 2.1.  You must verify the header version
+   * before reading these fields! */
+  uint32_t flags;                    /* Flags; see VB_FIRMWARE_PREAMBLE_*.
+                                      * Readers should return 0 for header
+                                      * version < 2.1. */
 } __attribute__((packed)) VbFirmwarePreambleHeader;
-/* This should be followed by:
+
+#define EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE 108
+
+/* The firmware preamble header should be followed by:
  *   1) The kernel_subkey key data, pointed to by kernel_subkey.key_offset.
  *   2) The signature data for the firmware body, pointed to by
  *      body_signature.sig_offset.
- *   3) The signature data for (VBFirmwarePreambleHeader + kernel_subkey data
- *      + body signature data), pointed to by
- *      preamble_signature.sig_offset. */
+ *   3) The signature data for (header + kernel_subkey data + body signature
+ *      data), pointed to by preamble_signature.sig_offset. */
 
-#define EXPECTED_VBFIRMWAREPREAMBLEHEADER_SIZE 104
 
 #define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2
 #define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 0
diff --git a/firmware/lib/include/vboot_common.h b/firmware/lib/include/vboot_common.h
index 88bf9ac..3203106 100644
--- a/firmware/lib/include/vboot_common.h
+++ b/firmware/lib/include/vboot_common.h
@@ -102,6 +102,14 @@
                            uint64_t size, const RSAPublicKey* key);
 
 
+/* Returns the flags from a firmware preamble, or a default value for
+ * older preamble versions which didn't contain flags.  Use this
+ * function to ensure compatibility with older preamble versions
+ * (2.0).  Assumes the preamble has already been verified via
+ * VerifyFirmwarePreamble(). */
+uint32_t VbGetFirmwarePreambleFlags(const VbFirmwarePreambleHeader* preamble);
+
+
 /* Checks the sanity of a kernel preamble of size [size] bytes,
  * using public key [key].
  *
diff --git a/firmware/lib/vboot_common.c b/firmware/lib/vboot_common.c
index 81e2597..5622d13 100644
--- a/firmware/lib/vboot_common.c
+++ b/firmware/lib/vboot_common.c
@@ -297,8 +297,8 @@
   const VbSignature* sig = &preamble->preamble_signature;
 
   /* Sanity checks before attempting signature of data */
-  if(size < sizeof(VbFirmwarePreambleHeader)) {
-    VBDEBUG(("Not enough data for preamble header.\n"));
+  if(size < EXPECTED_VBFIRMWAREPREAMBLEHEADER2_0_SIZE) {
+    VBDEBUG(("Not enough data for preamble header 2.0.\n"));
     return VBOOT_PREAMBLE_INVALID;
   }
   if (preamble->header_version_major !=
@@ -348,11 +348,32 @@
     return VBOOT_PREAMBLE_INVALID;
   }
 
+  /* If the preamble header version is at least 2.1, verify we have
+   * space for the added fields from 2.1. */
+  if (preamble->header_version_minor >= 1) {
+    if(size < EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE) {
+      VBDEBUG(("Not enough data for preamble header 2.1.\n"));
+      return VBOOT_PREAMBLE_INVALID;
+    }
+  }
+
   /* Success */
   return VBOOT_SUCCESS;
 }
 
 
+uint32_t VbGetFirmwarePreambleFlags(const VbFirmwarePreambleHeader* preamble) {
+  if (preamble->header_version_minor < 1) {
+    /* Old structure; return default flags.  (Note that we don't need
+     * to check header_version_major; if that's not 2 then
+     * VerifyFirmwarePreamble() would have already failed. */
+    return 0;
+  }
+
+  return preamble->flags;
+}
+
+
 int VerifyKernelPreamble(const VbKernelPreambleHeader* preamble,
                          uint64_t size, const RSAPublicKey* key) {
 
diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c
index 4aae27d..16ba3ab 100644
--- a/firmware/linktest/main.c
+++ b/firmware/linktest/main.c
@@ -86,6 +86,7 @@
   VerifyDigest(0, 0, 0);
   KeyBlockVerify(0, 0, 0, 0);
   VerifyFirmwarePreamble(0, 0, 0);
+  VbGetFirmwarePreambleFlags(0);
   VerifyKernelPreamble(0, 0, 0);
   VbSharedDataInit(0, 0);
   VbSharedDataReserve(0, 0);
diff --git a/host/include/host_common.h b/host/include/host_common.h
index 007c9d9..5d20630 100644
--- a/host/include/host_common.h
+++ b/host/include/host_common.h
@@ -30,7 +30,8 @@
     uint64_t firmware_version,
     const VbPublicKey* kernel_subkey,
     const VbSignature* body_signature,
-    const VbPrivateKey* signing_key);
+    const VbPrivateKey* signing_key,
+    uint32_t flags);
 
 
 /* Creates a kernel preamble, signed with [signing_key].
diff --git a/host/lib/host_common.c b/host/lib/host_common.c
index 9e0a5d9..cb51392 100644
--- a/host/lib/host_common.c
+++ b/host/lib/host_common.c
@@ -18,7 +18,8 @@
     uint64_t firmware_version,
     const VbPublicKey* kernel_subkey,
     const VbSignature* body_signature,
-    const VbPrivateKey* signing_key) {
+    const VbPrivateKey* signing_key,
+    uint32_t flags) {
 
   VbFirmwarePreambleHeader* h;
   uint64_t signed_size = (sizeof(VbFirmwarePreambleHeader) +
@@ -34,6 +35,7 @@
   h = (VbFirmwarePreambleHeader*)malloc(block_size);
   if (!h)
     return NULL;
+  Memset(h, 0, block_size);
   kernel_subkey_dest = (uint8_t*)(h + 1);
   body_sig_dest = kernel_subkey_dest + kernel_subkey->key_size;
   block_sig_dest = body_sig_dest + body_signature->sig_size;
@@ -42,6 +44,7 @@
   h->header_version_minor = FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR;
   h->preamble_size = block_size;
   h->firmware_version = firmware_version;
+  h->flags = flags;
 
   /* Copy data key */
   PublicKeyInit(&h->kernel_subkey, kernel_subkey_dest,
diff --git a/host/linktest/main.c b/host/linktest/main.c
index 45fb0bc..1f3dfec 100644
--- a/host/linktest/main.c
+++ b/host/linktest/main.c
@@ -35,7 +35,7 @@
   CalculateSignature(0, 0, 0);
 
   /* host_common.h */
-  CreateFirmwarePreamble(0, 0, 0, 0);
+  CreateFirmwarePreamble(0, 0, 0, 0, 0);
   CreateKernelPreamble(0, 0, 0, 0, 0, 0, 0);
 
   /* file_keys.h */
diff --git a/tests/vboot_common3_tests.c b/tests/vboot_common3_tests.c
index 313078c..a63e477 100644
--- a/tests/vboot_common3_tests.c
+++ b/tests/vboot_common3_tests.c
@@ -135,8 +135,8 @@
 }
 
 
-static void ReSignFirmwarePreamble(VbFirmwarePreambleHeader *h,
-                                   const VbPrivateKey *key) {
+static void ReSignFirmwarePreamble(VbFirmwarePreambleHeader* h,
+                                   const VbPrivateKey* key) {
   VbSignature *sig = CalculateSignature((const uint8_t*)h,
                                         h->preamble_signature.data_size, key);
 
@@ -149,16 +149,17 @@
                                        const VbPrivateKey* private_key,
                                        const VbPublicKey* kernel_subkey) {
 
-  VbFirmwarePreambleHeader *hdr;
-  VbFirmwarePreambleHeader *h;
+  VbFirmwarePreambleHeader* hdr;
+  VbFirmwarePreambleHeader* h;
   RSAPublicKey* rsa;
   unsigned hsize;
 
   /* Create a dummy signature */
-  VbSignature *body_sig = SignatureAlloc(56, 78);
+  VbSignature* body_sig = SignatureAlloc(56, 78);
 
   rsa = PublicKeyToRSA(public_key);
-  hdr = CreateFirmwarePreamble(0x1234, kernel_subkey, body_sig, private_key);
+  hdr = CreateFirmwarePreamble(0x1234, kernel_subkey, body_sig, private_key,
+                               0x5678);
   TEST_NEQ(hdr && rsa, 0, "VerifyFirmwarePreamble() prerequisites");
   if (!hdr)
     return;
@@ -238,7 +239,15 @@
   TEST_NEQ(VerifyFirmwarePreamble(h, hsize, rsa), 0,
            "VerifyFirmwarePreamble() body sig off end");
 
-  /* TODO: verify parser can support a bigger header. */
+  /* Check that we return flags properly for new and old structs */
+  Memcpy(h, hdr, hsize);
+  TEST_EQ(VbGetFirmwarePreambleFlags(h), 0x5678,
+          "VbGetFirmwarePreambleFlags() v2.1");
+  h->header_version_minor = 0;
+  TEST_EQ(VbGetFirmwarePreambleFlags(h), 0,
+          "VbGetFirmwarePreambleFlags() v2.0");
+
+  /* TODO: verify with extra padding at end of header. */
 
   free(h);
   RSAPublicKeyFree(rsa);
diff --git a/tests/vboot_common_tests.c b/tests/vboot_common_tests.c
index aecf90c..adb5708 100644
--- a/tests/vboot_common_tests.c
+++ b/tests/vboot_common_tests.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  *
@@ -19,8 +19,12 @@
           "sizeof(VbSignature)");
   TEST_EQ(EXPECTED_VBKEYBLOCKHEADER_SIZE, sizeof(VbKeyBlockHeader),
           "sizeof(VbKeyBlockHeader)");
-  TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER_SIZE,
-          sizeof(VbFirmwarePreambleHeader), "sizeof(VbFirmwarePreambleHeader)");
+  TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_0_SIZE,
+          sizeof(VbFirmwarePreambleHeader2_0),
+          "sizeof(VbFirmwarePreambleHeader)");
+  TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
+          sizeof(VbFirmwarePreambleHeader),
+          "sizeof(VbFirmwarePreambleHeader)");
   TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER_SIZE,
           sizeof(VbKernelPreambleHeader), "sizeof(VbKernelPreambleHeader)");
 }
diff --git a/utility/vbutil_firmware.c b/utility/vbutil_firmware.c
index fb8e102..76d46c6 100644
--- a/utility/vbutil_firmware.c
+++ b/utility/vbutil_firmware.c
@@ -28,6 +28,7 @@
   OPT_VERSION,
   OPT_FV,
   OPT_KERNELKEY,
+  OPT_FLAGS,
 };
 
 static struct option long_opts[] = {
@@ -39,6 +40,7 @@
   {"version", 1, 0,                   OPT_VERSION                 },
   {"fv", 1, 0,                        OPT_FV                      },
   {"kernelkey", 1, 0,                 OPT_KERNELKEY               },
+  {"flags", 1, 0,                     OPT_FLAGS                   },
   {NULL, 0, 0, 0}
 };
 
@@ -56,6 +58,8 @@
        "  --version <number>          Firmware version\n"
        "  --fv <file>                 Firmware volume to sign\n"
        "  --kernelkey <file>          Kernel subkey in .vbpubk format\n"
+       "optional OPTIONS are:\n"
+       "  --flags <number>            Preamble flags (defaults to 0)\n"
        "\n"
        "For '--verify <file>', required OPTIONS are:\n"
        "  --signpubkey <file>         Signing public key in .vbpubk format\n"
@@ -71,7 +75,8 @@
 /* Create a firmware .vblock */
 static int Vblock(const char* outfile, const char* keyblock_file,
                   const char* signprivate, uint64_t version,
-                  const char* fv_file, const char* kernelkey_file) {
+                  const char* fv_file, const char* kernelkey_file,
+                  uint32_t preamble_flags) {
 
   VbPrivateKey* signing_key;
   VbPublicKey* kernel_subkey;
@@ -135,7 +140,8 @@
   preamble = CreateFirmwarePreamble(version,
                                     kernel_subkey,
                                     body_sig,
-                                    signing_key);
+                                    signing_key,
+                                    preamble_flags);
   if (!preamble) {
     VbExError("Error creating preamble.\n");
     return 1;
@@ -254,6 +260,8 @@
   printf("\n");
   printf("  Firmware body size:    %" PRIu64 "\n",
          preamble->body_signature.data_size);
+  printf("  Preamble flags:        %" PRIu32 "\n",
+         VbGetFirmwarePreambleFlags(preamble));
 
   /* TODO: verify body size same as signature size */
 
@@ -285,6 +293,7 @@
   uint64_t version = 0;
   char* fv_file = NULL;
   char* kernelkey_file = NULL;
+  uint32_t preamble_flags = 0;
   int mode = 0;
   int parse_error = 0;
   char* e;
@@ -331,6 +340,14 @@
           parse_error = 1;
         }
         break;
+
+      case OPT_FLAGS:
+        preamble_flags = strtoul(optarg, &e, 0);
+        if (!*optarg || (e && *e)) {
+          printf("Invalid --flags\n");
+          parse_error = 1;
+        }
+        break;
     }
   }
 
@@ -340,7 +357,7 @@
   switch(mode) {
     case OPT_MODE_VBLOCK:
       return Vblock(filename, key_block_file, signprivate, version, fv_file,
-                    kernelkey_file);
+                    kernelkey_file, preamble_flags);
     case OPT_MODE_VERIFY:
       return Verify(filename, signpubkey, fv_file, kernelkey_file);
     default: