mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
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:
@@ -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
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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].
|
||||
*
|
||||
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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].
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -158,7 +158,8 @@ static void VerifyFirmwarePreambleTest(const VbPublicKey* public_key,
|
||||
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);
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user