summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2011-07-13 09:48:41 -0700
committerRandall Spangler <rspangler@chromium.org>2011-07-13 10:13:12 -0700
commita712e01ae783351e921031aab59ff1b7583d683d (patch)
tree81b255e45fd41e2ca5ef7405d19e044234500f07
parentd70241f37d87bd7758fc6c5bbb7d5870098ecdfc (diff)
downloadvboot-a712e01ae783351e921031aab59ff1b7583d683d.tar.gz
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>
-rw-r--r--firmware/include/vboot_api.h6
-rw-r--r--firmware/include/vboot_struct.h45
-rw-r--r--firmware/lib/include/vboot_common.h8
-rw-r--r--firmware/lib/vboot_common.c25
-rw-r--r--firmware/linktest/main.c1
-rw-r--r--host/include/host_common.h3
-rw-r--r--host/lib/host_common.c5
-rw-r--r--host/linktest/main.c2
-rw-r--r--tests/vboot_common3_tests.c23
-rw-r--r--tests/vboot_common_tests.c10
-rw-r--r--utility/vbutil_firmware.c23
11 files changed, 125 insertions, 26 deletions
diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h
index 48859e06..a97f0e8f 100644
--- a/firmware/include/vboot_api.h
+++ b/firmware/include/vboot_api.h
@@ -138,9 +138,13 @@ typedef struct VbInitParams {
* 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 0271979c..dd6a4155 100644
--- a/firmware/include/vboot_struct.h
+++ b/firmware/include/vboot_struct.h
@@ -78,9 +78,33 @@ typedef struct VbKeyBlockHeader {
#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 @@ typedef struct VbFirmwarePreambleHeader {
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 88bf9ac6..32031068 100644
--- a/firmware/lib/include/vboot_common.h
+++ b/firmware/lib/include/vboot_common.h
@@ -102,6 +102,14 @@ int VerifyFirmwarePreamble(const VbFirmwarePreambleHeader* preamble,
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 81e2597b..5622d13b 100644
--- a/firmware/lib/vboot_common.c
+++ b/firmware/lib/vboot_common.c
@@ -297,8 +297,8 @@ int VerifyFirmwarePreamble(const VbFirmwarePreambleHeader* preamble,
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 @@ int VerifyFirmwarePreamble(const VbFirmwarePreambleHeader* preamble,
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 4aae27d9..16ba3ab3 100644
--- a/firmware/linktest/main.c
+++ b/firmware/linktest/main.c
@@ -86,6 +86,7 @@ int main(void)
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 007c9d91..5d206301 100644
--- a/host/include/host_common.h
+++ b/host/include/host_common.h
@@ -30,7 +30,8 @@ VbFirmwarePreambleHeader* CreateFirmwarePreamble(
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 9e0a5d9f..cb513922 100644
--- a/host/lib/host_common.c
+++ b/host/lib/host_common.c
@@ -18,7 +18,8 @@ VbFirmwarePreambleHeader* CreateFirmwarePreamble(
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 @@ VbFirmwarePreambleHeader* CreateFirmwarePreamble(
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 @@ VbFirmwarePreambleHeader* CreateFirmwarePreamble(
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 45fb0bcf..1f3dfecc 100644
--- a/host/linktest/main.c
+++ b/host/linktest/main.c
@@ -35,7 +35,7 @@ int main(void)
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 313078c9..a63e477c 100644
--- a/tests/vboot_common3_tests.c
+++ b/tests/vboot_common3_tests.c
@@ -135,8 +135,8 @@ static void KeyBlockVerifyTest(const VbPublicKey* public_key,
}
-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 @@ static void VerifyFirmwarePreambleTest(const VbPublicKey* public_key,
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 @@ static void VerifyFirmwarePreambleTest(const VbPublicKey* public_key,
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 aecf90cf..adb57084 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 @@ static void StructPackingTest(void) {
"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 fb8e102c..76d46c6b 100644
--- a/utility/vbutil_firmware.c
+++ b/utility/vbutil_firmware.c
@@ -28,6 +28,7 @@ enum {
OPT_VERSION,
OPT_FV,
OPT_KERNELKEY,
+ OPT_FLAGS,
};
static struct option long_opts[] = {
@@ -39,6 +40,7 @@ static struct option long_opts[] = {
{"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 @@ static int PrintHelp(void) {
" --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 @@ static int PrintHelp(void) {
/* 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 @@ static int Vblock(const char* outfile, const char* keyblock_file,
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 @@ static int Verify(const char* infile, const char* signpubkey,
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 @@ int main(int argc, char* argv[]) {
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 @@ int main(int argc, char* argv[]) {
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 @@ int main(int argc, char* argv[]) {
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: