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>
This commit is contained in:
Randall Spangler
2011-07-13 09:48:41 -07:00
parent d70241f37d
commit a712e01ae7
11 changed files with 125 additions and 26 deletions

View File

@@ -138,9 +138,13 @@ typedef struct VbInitParams {
* VbSelectFirmwareParams.selected_firmware. Note that we store these * VbSelectFirmwareParams.selected_firmware. Note that we store these
* in a uint32_t because enum maps to int, which isn't fixed-size. */ * in a uint32_t because enum maps to int, which isn't fixed-size. */
enum VbSelectFirmware_t { enum VbSelectFirmware_t {
/* Recovery mode */
VB_SELECT_FIRMWARE_RECOVERY = 0, VB_SELECT_FIRMWARE_RECOVERY = 0,
/* Rewritable firmware A/B for normal or developer path */
VB_SELECT_FIRMWARE_A = 1, 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
}; };

View File

@@ -78,9 +78,33 @@ typedef struct VbKeyBlockHeader {
#define FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR 2 #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 { typedef struct VbFirmwarePreambleHeader {
uint64_t preamble_size; /* Size of this preamble, including keys, uint64_t preamble_size; /* Size of this preamble, including keys,
* signatures, and padding, in bytes */ * signatures, and padding, in bytes */
@@ -93,16 +117,23 @@ typedef struct VbFirmwarePreambleHeader {
uint64_t firmware_version; /* Firmware version */ uint64_t firmware_version; /* Firmware version */
VbPublicKey kernel_subkey; /* Key to verify kernel key block */ VbPublicKey kernel_subkey; /* Key to verify kernel key block */
VbSignature body_signature; /* Signature for the firmware body */ 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; } __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. * 1) The kernel_subkey key data, pointed to by kernel_subkey.key_offset.
* 2) The signature data for the firmware body, pointed to by * 2) The signature data for the firmware body, pointed to by
* body_signature.sig_offset. * body_signature.sig_offset.
* 3) The signature data for (VBFirmwarePreambleHeader + kernel_subkey data * 3) The signature data for (header + kernel_subkey data + body signature
* + body signature data), pointed to by * data), pointed to by preamble_signature.sig_offset. */
* preamble_signature.sig_offset. */
#define EXPECTED_VBFIRMWAREPREAMBLEHEADER_SIZE 104
#define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2 #define KERNEL_PREAMBLE_HEADER_VERSION_MAJOR 2
#define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 0 #define KERNEL_PREAMBLE_HEADER_VERSION_MINOR 0

View File

@@ -102,6 +102,14 @@ int VerifyFirmwarePreamble(const VbFirmwarePreambleHeader* preamble,
uint64_t size, const RSAPublicKey* key); 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, /* Checks the sanity of a kernel preamble of size [size] bytes,
* using public key [key]. * using public key [key].
* *

View File

@@ -297,8 +297,8 @@ int VerifyFirmwarePreamble(const VbFirmwarePreambleHeader* preamble,
const VbSignature* sig = &preamble->preamble_signature; const VbSignature* sig = &preamble->preamble_signature;
/* Sanity checks before attempting signature of data */ /* Sanity checks before attempting signature of data */
if(size < sizeof(VbFirmwarePreambleHeader)) { if(size < EXPECTED_VBFIRMWAREPREAMBLEHEADER2_0_SIZE) {
VBDEBUG(("Not enough data for preamble header.\n")); VBDEBUG(("Not enough data for preamble header 2.0.\n"));
return VBOOT_PREAMBLE_INVALID; return VBOOT_PREAMBLE_INVALID;
} }
if (preamble->header_version_major != if (preamble->header_version_major !=
@@ -348,11 +348,32 @@ int VerifyFirmwarePreamble(const VbFirmwarePreambleHeader* preamble,
return VBOOT_PREAMBLE_INVALID; 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 */ /* Success */
return VBOOT_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, int VerifyKernelPreamble(const VbKernelPreambleHeader* preamble,
uint64_t size, const RSAPublicKey* key) { uint64_t size, const RSAPublicKey* key) {

View File

@@ -86,6 +86,7 @@ int main(void)
VerifyDigest(0, 0, 0); VerifyDigest(0, 0, 0);
KeyBlockVerify(0, 0, 0, 0); KeyBlockVerify(0, 0, 0, 0);
VerifyFirmwarePreamble(0, 0, 0); VerifyFirmwarePreamble(0, 0, 0);
VbGetFirmwarePreambleFlags(0);
VerifyKernelPreamble(0, 0, 0); VerifyKernelPreamble(0, 0, 0);
VbSharedDataInit(0, 0); VbSharedDataInit(0, 0);
VbSharedDataReserve(0, 0); VbSharedDataReserve(0, 0);

View File

@@ -30,7 +30,8 @@ VbFirmwarePreambleHeader* CreateFirmwarePreamble(
uint64_t firmware_version, uint64_t firmware_version,
const VbPublicKey* kernel_subkey, const VbPublicKey* kernel_subkey,
const VbSignature* body_signature, const VbSignature* body_signature,
const VbPrivateKey* signing_key); const VbPrivateKey* signing_key,
uint32_t flags);
/* Creates a kernel preamble, signed with [signing_key]. /* Creates a kernel preamble, signed with [signing_key].

View File

@@ -18,7 +18,8 @@ VbFirmwarePreambleHeader* CreateFirmwarePreamble(
uint64_t firmware_version, uint64_t firmware_version,
const VbPublicKey* kernel_subkey, const VbPublicKey* kernel_subkey,
const VbSignature* body_signature, const VbSignature* body_signature,
const VbPrivateKey* signing_key) { const VbPrivateKey* signing_key,
uint32_t flags) {
VbFirmwarePreambleHeader* h; VbFirmwarePreambleHeader* h;
uint64_t signed_size = (sizeof(VbFirmwarePreambleHeader) + uint64_t signed_size = (sizeof(VbFirmwarePreambleHeader) +
@@ -34,6 +35,7 @@ VbFirmwarePreambleHeader* CreateFirmwarePreamble(
h = (VbFirmwarePreambleHeader*)malloc(block_size); h = (VbFirmwarePreambleHeader*)malloc(block_size);
if (!h) if (!h)
return NULL; return NULL;
Memset(h, 0, block_size);
kernel_subkey_dest = (uint8_t*)(h + 1); kernel_subkey_dest = (uint8_t*)(h + 1);
body_sig_dest = kernel_subkey_dest + kernel_subkey->key_size; body_sig_dest = kernel_subkey_dest + kernel_subkey->key_size;
block_sig_dest = body_sig_dest + body_signature->sig_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->header_version_minor = FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR;
h->preamble_size = block_size; h->preamble_size = block_size;
h->firmware_version = firmware_version; h->firmware_version = firmware_version;
h->flags = flags;
/* Copy data key */ /* Copy data key */
PublicKeyInit(&h->kernel_subkey, kernel_subkey_dest, PublicKeyInit(&h->kernel_subkey, kernel_subkey_dest,

View File

@@ -35,7 +35,7 @@ int main(void)
CalculateSignature(0, 0, 0); CalculateSignature(0, 0, 0);
/* host_common.h */ /* host_common.h */
CreateFirmwarePreamble(0, 0, 0, 0); CreateFirmwarePreamble(0, 0, 0, 0, 0);
CreateKernelPreamble(0, 0, 0, 0, 0, 0, 0); CreateKernelPreamble(0, 0, 0, 0, 0, 0, 0);
/* file_keys.h */ /* file_keys.h */

View File

@@ -158,7 +158,8 @@ static void VerifyFirmwarePreambleTest(const VbPublicKey* public_key,
VbSignature* body_sig = SignatureAlloc(56, 78); VbSignature* body_sig = SignatureAlloc(56, 78);
rsa = PublicKeyToRSA(public_key); 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"); TEST_NEQ(hdr && rsa, 0, "VerifyFirmwarePreamble() prerequisites");
if (!hdr) if (!hdr)
return; return;
@@ -238,7 +239,15 @@ static void VerifyFirmwarePreambleTest(const VbPublicKey* public_key,
TEST_NEQ(VerifyFirmwarePreamble(h, hsize, rsa), 0, TEST_NEQ(VerifyFirmwarePreamble(h, hsize, rsa), 0,
"VerifyFirmwarePreamble() body sig off end"); "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); free(h);
RSAPublicKeyFree(rsa); RSAPublicKeyFree(rsa);

View File

@@ -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 * Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. * found in the LICENSE file.
* *
@@ -19,8 +19,12 @@ static void StructPackingTest(void) {
"sizeof(VbSignature)"); "sizeof(VbSignature)");
TEST_EQ(EXPECTED_VBKEYBLOCKHEADER_SIZE, sizeof(VbKeyBlockHeader), TEST_EQ(EXPECTED_VBKEYBLOCKHEADER_SIZE, sizeof(VbKeyBlockHeader),
"sizeof(VbKeyBlockHeader)"); "sizeof(VbKeyBlockHeader)");
TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER_SIZE, TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_0_SIZE,
sizeof(VbFirmwarePreambleHeader), "sizeof(VbFirmwarePreambleHeader)"); sizeof(VbFirmwarePreambleHeader2_0),
"sizeof(VbFirmwarePreambleHeader)");
TEST_EQ(EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
sizeof(VbFirmwarePreambleHeader),
"sizeof(VbFirmwarePreambleHeader)");
TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER_SIZE, TEST_EQ(EXPECTED_VBKERNELPREAMBLEHEADER_SIZE,
sizeof(VbKernelPreambleHeader), "sizeof(VbKernelPreambleHeader)"); sizeof(VbKernelPreambleHeader), "sizeof(VbKernelPreambleHeader)");
} }

View File

@@ -28,6 +28,7 @@ enum {
OPT_VERSION, OPT_VERSION,
OPT_FV, OPT_FV,
OPT_KERNELKEY, OPT_KERNELKEY,
OPT_FLAGS,
}; };
static struct option long_opts[] = { static struct option long_opts[] = {
@@ -39,6 +40,7 @@ static struct option long_opts[] = {
{"version", 1, 0, OPT_VERSION }, {"version", 1, 0, OPT_VERSION },
{"fv", 1, 0, OPT_FV }, {"fv", 1, 0, OPT_FV },
{"kernelkey", 1, 0, OPT_KERNELKEY }, {"kernelkey", 1, 0, OPT_KERNELKEY },
{"flags", 1, 0, OPT_FLAGS },
{NULL, 0, 0, 0} {NULL, 0, 0, 0}
}; };
@@ -56,6 +58,8 @@ static int PrintHelp(void) {
" --version <number> Firmware version\n" " --version <number> Firmware version\n"
" --fv <file> Firmware volume to sign\n" " --fv <file> Firmware volume to sign\n"
" --kernelkey <file> Kernel subkey in .vbpubk format\n" " --kernelkey <file> Kernel subkey in .vbpubk format\n"
"optional OPTIONS are:\n"
" --flags <number> Preamble flags (defaults to 0)\n"
"\n" "\n"
"For '--verify <file>', required OPTIONS are:\n" "For '--verify <file>', required OPTIONS are:\n"
" --signpubkey <file> Signing public key in .vbpubk format\n" " --signpubkey <file> Signing public key in .vbpubk format\n"
@@ -71,7 +75,8 @@ static int PrintHelp(void) {
/* Create a firmware .vblock */ /* Create a firmware .vblock */
static int Vblock(const char* outfile, const char* keyblock_file, static int Vblock(const char* outfile, const char* keyblock_file,
const char* signprivate, uint64_t version, 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; VbPrivateKey* signing_key;
VbPublicKey* kernel_subkey; VbPublicKey* kernel_subkey;
@@ -135,7 +140,8 @@ static int Vblock(const char* outfile, const char* keyblock_file,
preamble = CreateFirmwarePreamble(version, preamble = CreateFirmwarePreamble(version,
kernel_subkey, kernel_subkey,
body_sig, body_sig,
signing_key); signing_key,
preamble_flags);
if (!preamble) { if (!preamble) {
VbExError("Error creating preamble.\n"); VbExError("Error creating preamble.\n");
return 1; return 1;
@@ -254,6 +260,8 @@ static int Verify(const char* infile, const char* signpubkey,
printf("\n"); printf("\n");
printf(" Firmware body size: %" PRIu64 "\n", printf(" Firmware body size: %" PRIu64 "\n",
preamble->body_signature.data_size); preamble->body_signature.data_size);
printf(" Preamble flags: %" PRIu32 "\n",
VbGetFirmwarePreambleFlags(preamble));
/* TODO: verify body size same as signature size */ /* TODO: verify body size same as signature size */
@@ -285,6 +293,7 @@ int main(int argc, char* argv[]) {
uint64_t version = 0; uint64_t version = 0;
char* fv_file = NULL; char* fv_file = NULL;
char* kernelkey_file = NULL; char* kernelkey_file = NULL;
uint32_t preamble_flags = 0;
int mode = 0; int mode = 0;
int parse_error = 0; int parse_error = 0;
char* e; char* e;
@@ -331,6 +340,14 @@ int main(int argc, char* argv[]) {
parse_error = 1; parse_error = 1;
} }
break; 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) { switch(mode) {
case OPT_MODE_VBLOCK: case OPT_MODE_VBLOCK:
return Vblock(filename, key_block_file, signprivate, version, fv_file, return Vblock(filename, key_block_file, signprivate, version, fv_file,
kernelkey_file); kernelkey_file, preamble_flags);
case OPT_MODE_VERIFY: case OPT_MODE_VERIFY:
return Verify(filename, signpubkey, fv_file, kernelkey_file); return Verify(filename, signpubkey, fv_file, kernelkey_file);
default: default: