From a712e01ae783351e921031aab59ff1b7583d683d Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Wed, 13 Jul 2011 09:48:41 -0700 Subject: 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 Tested-by: Randall Spangler --- firmware/include/vboot_api.h | 6 ++++- firmware/include/vboot_struct.h | 45 +++++++++++++++++++++++++++++++------ firmware/lib/include/vboot_common.h | 8 +++++++ firmware/lib/vboot_common.c | 25 +++++++++++++++++++-- firmware/linktest/main.c | 1 + host/include/host_common.h | 3 ++- host/lib/host_common.c | 5 ++++- host/linktest/main.c | 2 +- tests/vboot_common3_tests.c | 23 +++++++++++++------ tests/vboot_common_tests.c | 10 ++++++--- utility/vbutil_firmware.c | 23 ++++++++++++++++--- 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 Firmware version\n" " --fv Firmware volume to sign\n" " --kernelkey Kernel subkey in .vbpubk format\n" + "optional OPTIONS are:\n" + " --flags Preamble flags (defaults to 0)\n" "\n" "For '--verify ', required OPTIONS are:\n" " --signpubkey 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: -- cgit v1.2.1