diff options
author | Randall Spangler <rspangler@chromium.org> | 2014-06-11 16:01:08 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-06-19 03:23:28 +0000 |
commit | 1803068173a625efd83d1cee8dd90843feb0d972 (patch) | |
tree | d60b7678f832fd2e4875e4cbfb8de1fcd30a059e | |
parent | da2b49cf08a27551fd910626f669910a636378d4 (diff) | |
download | vboot-1803068173a625efd83d1cee8dd90843feb0d972.tar.gz |
vboot2: misc higher-level routines, part 2
I'm breaking the last chunk of vboot2 into smaller pieces as I add
tests. This has the higher-level routines for verifying keyblock and
preamble.
BUG=chromium:370082
BRANCH=none
TEST=make clean && VBOOT2=1 COV=1 make
Change-Id: I82da9542c8857a3f89a85f206c9f5aecadf94a79
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/203501
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | firmware/2lib/2misc.c | 213 | ||||
-rw-r--r-- | firmware/2lib/include/2misc.h | 20 | ||||
-rw-r--r-- | tests/vb2_misc2_tests.c | 377 |
4 files changed, 612 insertions, 0 deletions
@@ -575,6 +575,7 @@ TEST_NAMES += \ tests/vb2_common2_tests \ tests/vb2_common3_tests \ tests/vb2_misc_tests \ + tests/vb2_misc2_tests \ tests/vb2_nvstorage_tests \ tests/vb2_rsa_padding_tests \ tests/vb2_rsa_utility_tests \ @@ -1106,6 +1107,7 @@ run2tests: test_setup ${RUNTEST} ${BUILD_RUN}/tests/vb2_common2_tests ${TEST_KEYS} ${RUNTEST} ${BUILD_RUN}/tests/vb2_common3_tests ${TEST_KEYS} ${RUNTEST} ${BUILD_RUN}/tests/vb2_misc_tests + ${RUNTEST} ${BUILD_RUN}/tests/vb2_misc2_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_tests diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index c0692c53..685cf07d 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -342,3 +342,216 @@ int vb2_select_fw_slot(struct vb2_context *ctx) return VB2_SUCCESS; } + +int vb2_verify_fw_keyblock(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + struct vb2_workbuf wb; + + uint8_t *key_data; + uint32_t key_size; + struct vb2_packed_key *packed_key; + struct vb2_public_key root_key; + + struct vb2_keyblock *kb; + uint32_t block_size; + + uint32_t sec_version; + int rv; + + vb2_workbuf_from_ctx(ctx, &wb); + + /* Read the root key */ + key_size = sd->gbb_rootkey_size; + key_data = vb2_workbuf_alloc(&wb, key_size); + if (!key_data) + return VB2_ERROR_FW_KEYBLOCK_WORKBUF_ROOT_KEY; + + rv = vb2ex_read_resource(ctx, VB2_RES_GBB, sd->gbb_rootkey_offset, + key_data, key_size); + if (rv) + return rv; + + /* Unpack the root key */ + rv = vb2_unpack_key(&root_key, key_data, key_size); + if (rv) + return rv; + + /* Load the firmware keyblock header after the root key */ + kb = vb2_workbuf_alloc(&wb, sizeof(*kb)); + if (!kb) + return VB2_ERROR_FW_KEYBLOCK_WORKBUF_HEADER; + + rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK, 0, kb, sizeof(*kb)); + if (rv) + return rv; + + block_size = kb->keyblock_size; + + /* + * Load the entire keyblock, now that we know how big it is. Note that + * we're loading the entire keyblock instead of just the piece after + * the header. That means we re-read the header. But that's a tiny + * amount of data, and it makes the code much more straightforward. + */ + kb = vb2_workbuf_realloc(&wb, sizeof(*kb), block_size); + if (!kb) + return VB2_ERROR_FW_KEYBLOCK_WORKBUF; + + rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK, 0, kb, block_size); + if (rv) + return rv; + + /* Verify the keyblock */ + rv = vb2_verify_keyblock(kb, block_size, &root_key, &wb); + if (rv) + return rv; + + /* Read the secure key version */ + rv = vb2_secdata_get(ctx, VB2_SECDATA_VERSIONS, &sec_version); + if (rv) + return rv; + + /* Key version is the upper 16 bits of the composite firmware version */ + if (kb->data_key.key_version > 0xffff) + return VB2_ERROR_FW_KEYBLOCK_VERSION_RANGE; + if (kb->data_key.key_version < (sec_version >> 16)) + return VB2_ERROR_FW_KEYBLOCK_VERSION_ROLLBACK; + + sd->fw_version = kb->data_key.key_version << 16; + + /* + * Save the data key in the work buffer. This overwrites the root key + * we read above. That's ok, because now that we have the data key we + * no longer need the root key. + */ + packed_key = (struct vb2_packed_key *)key_data; + + packed_key->algorithm = kb->data_key.algorithm; + packed_key->key_version = kb->data_key.key_version; + packed_key->key_size = kb->data_key.key_size; + + /* + * Use memmove() instead of memcpy(). In theory, the destination will + * never overlap because with the source because the root key is likely + * to be at least as large as the data key, but there's no harm here in + * being paranoid. + */ + memmove(key_data + packed_key->key_offset, + (uint8_t*)&kb->data_key + kb->data_key.key_offset, + packed_key->key_size); + + /* Save the packed key offset and size */ + sd->workbuf_data_key_offset = vb2_offset_of(ctx->workbuf, key_data); + sd->workbuf_data_key_size = + packed_key->key_offset + packed_key->key_size; + + /* Preamble follows the keyblock in the vblock */ + sd->vblock_preamble_offset = kb->keyblock_size; + + /* Data key will persist in the workbuf after we return */ + ctx->workbuf_used = sd->workbuf_data_key_offset + + sd->workbuf_data_key_size; + + return VB2_SUCCESS; +} + +// TODO: Terrible that this and the low-level verification want to have the +// same function name. Pick a better name... +int vb2_verify_fw_preamble2(struct vb2_context *ctx) +{ + struct vb2_shared_data *sd = vb2_get_sd(ctx); + struct vb2_workbuf wb; + + uint8_t *key_data = ctx->workbuf + sd->workbuf_data_key_offset; + uint32_t key_size = sd->workbuf_data_key_size; + struct vb2_public_key data_key; + + /* Preamble goes in the next unused chunk of work buffer */ + struct vb2_fw_preamble *pre; + uint32_t pre_size; + + uint32_t sec_version; + int rv; + + vb2_workbuf_from_ctx(ctx, &wb); + + /* Unpack the firmware data key */ + if (!sd->workbuf_data_key_size) + return VB2_ERROR_FW_PREAMBLE2_DATA_KEY; + + rv = vb2_unpack_key(&data_key, key_data, key_size); + if (rv) + return rv; + + /* Load the firmware preamble header */ + pre = vb2_workbuf_alloc(&wb, sizeof(*pre)); + if (!pre) + return VB2_ERROR_FW_PREAMBLE2_WORKBUF_HEADER; + + rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK, + sd->vblock_preamble_offset, + pre, sizeof(*pre)); + if (rv) + return rv; + + pre_size = pre->preamble_size; + + /* Load the entire firmware preamble, now that we know how big it is */ + pre = vb2_workbuf_realloc(&wb, sizeof(*pre), pre_size); + if (!pre) + return VB2_ERROR_FW_PREAMBLE2_WORKBUF; + + rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK, + sd->vblock_preamble_offset, + pre, pre_size); + if (rv) + return rv; + + /* Work buffer now contains the data subkey data and the preamble */ + + /* Verify the preamble */ + rv = vb2_verify_fw_preamble(pre, pre_size, &data_key, &wb); + if (rv) + return rv; + + /* Read the secure key version */ + rv = vb2_secdata_get(ctx, VB2_SECDATA_VERSIONS, &sec_version); + if (rv) + return rv; + + /* + * Firmware version is the lower 16 bits of the composite firmware + * version. + */ + if (pre->firmware_version > 0xffff) + return VB2_ERROR_FW_PREAMBLE2_VERSION_RANGE; + + /* Combine with the key version from vb2_verify_fw_keyblock() */ + sd->fw_version |= pre->firmware_version; + if (sd->fw_version < sec_version) + return VB2_ERROR_FW_PREAMBLE2_VERSION_ROLLBACK; + + /* + * If this is a newer version than in secure storage, and we + * successfully booted the same slot last boot, roll forward the + * version in secure storage. + */ + if (sd->fw_version > sec_version && + sd->last_fw_slot == sd->fw_slot && + sd->last_fw_result == VB2_FW_RESULT_SUCCESS) { + + rv = vb2_secdata_set(ctx, VB2_SECDATA_VERSIONS, sd->fw_version); + if (rv) + return rv; + } + + /* Keep track of where we put the preamble */ + sd->workbuf_preamble_offset = vb2_offset_of(ctx->workbuf, pre); + sd->workbuf_preamble_size = pre_size; + + /* Preamble will persist in work buffer after we return */ + ctx->workbuf_used = sd->workbuf_preamble_offset + pre_size; + + return VB2_SUCCESS; +} diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h index f2e259e4..d90399a4 100644 --- a/firmware/2lib/include/2misc.h +++ b/firmware/2lib/include/2misc.h @@ -112,4 +112,24 @@ int vb2_check_tpm_clear(struct vb2_context *ctx); */ int vb2_select_fw_slot(struct vb2_context *ctx); +/** + * Verify the firmware keyblock using the root key. + * + * After this call, the data key is stored in the work buffer. + * + * @param ctx Vboot context + * @return VB2_SUCCESS, or error code on error. + */ +int vb2_verify_fw_keyblock(struct vb2_context *ctx); + +/** + * Verify the firmware preamble using the data subkey from the keyblock. + * + * After this call, the preamble is stored in the work buffer. + * + * @param ctx Vboot context + * @return VB2_SUCCESS, or error code on error. + */ +int vb2_verify_fw_preamble2(struct vb2_context *ctx); + #endif /* VBOOT_REFERENCE_VBOOT_2MISC_H_ */ diff --git a/tests/vb2_misc2_tests.c b/tests/vb2_misc2_tests.c new file mode 100644 index 00000000..14526f70 --- /dev/null +++ b/tests/vb2_misc2_tests.c @@ -0,0 +1,377 @@ +/* Copyright (c) 2014 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. + * + * Tests for misc library + */ + +#include <stdio.h> + +#include "2sysincludes.h" +#include "2api.h" +#include "2common.h" +#include "2misc.h" +#include "2nvstorage.h" +#include "2secdata.h" + +#include "test_common.h" + +/* Common context for tests */ +static uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE] + __attribute__ ((aligned (16))); +static struct vb2_context cc; +static struct vb2_shared_data *sd; + +/* Mocked function data */ + +static struct { + struct vb2_gbb_header h; + struct vb2_packed_key rootkey; + char rootkey_data[32]; +} mock_gbb; + +static struct { + /* Keyblock */ + struct { + struct vb2_keyblock kb; + char data_key_data[16]; + uint8_t kbdata[128]; + } k; + /* Preamble follows keyblock */ + struct { + struct vb2_fw_preamble pre; + uint8_t predata[128]; + } p; + +} mock_vblock; + +static int mock_read_res_fail_on_call; +static int mock_unpack_key_retval; +static int mock_verify_keyblock_retval; +static int mock_verify_preamble_retval; + +/* Type of test to reset for */ +enum reset_type { + FOR_KEYBLOCK, + FOR_PREAMBLE +}; + +static void reset_common_data(enum reset_type t) +{ + struct vb2_keyblock *kb = &mock_vblock.k.kb; + struct vb2_fw_preamble *pre = &mock_vblock.p.pre; + + memset(workbuf, 0xaa, sizeof(workbuf)); + + memset(&cc, 0, sizeof(cc)); + cc.workbuf = workbuf; + cc.workbuf_size = sizeof(workbuf); + + vb2_init_context(&cc); + sd = vb2_get_sd(&cc); + + vb2_nv_init(&cc); + + vb2_secdata_create(&cc); + vb2_secdata_init(&cc); + + mock_read_res_fail_on_call = 0; + mock_unpack_key_retval = VB2_SUCCESS; + mock_verify_keyblock_retval = VB2_SUCCESS; + mock_verify_preamble_retval = VB2_SUCCESS; + + /* Set up mock data for verifying keyblock */ + vb2_secdata_set(&cc, VB2_SECDATA_VERSIONS, 0x20002); + + sd->gbb_rootkey_offset = vb2_offset_of(&mock_gbb, &mock_gbb.rootkey); + sd->gbb_rootkey_size = sizeof(mock_gbb.rootkey_data); + sd->last_fw_result = VB2_FW_RESULT_SUCCESS; + + mock_gbb.rootkey.algorithm = 11; + mock_gbb.rootkey.key_offset = + vb2_offset_of(&mock_gbb.rootkey, + &mock_gbb.rootkey_data); + mock_gbb.rootkey.key_size = sizeof(mock_gbb.rootkey_data); + + kb->keyblock_size = sizeof(mock_vblock.k); + kb->data_key.algorithm = 7; + kb->data_key.key_version = 2; + kb->data_key.key_offset = + vb2_offset_of(&mock_vblock.k, &mock_vblock.k.data_key_data) - + vb2_offset_of(&mock_vblock.k, &kb->data_key); + kb->data_key.key_size = sizeof(mock_vblock.k.data_key_data); + strcpy(mock_vblock.k.data_key_data, "data key data!!"); + + pre->preamble_size = sizeof(mock_vblock.p); + pre->firmware_version = 2; + + /* If verifying preamble, verify keyblock first to set up data key */ + if (t == FOR_PREAMBLE) + vb2_verify_fw_keyblock(&cc); +}; + +/* Mocked functions */ + +int vb2ex_read_resource(struct vb2_context *ctx, + enum vb2_resource_index index, + uint32_t offset, + void *buf, + uint32_t size) +{ + uint8_t *rptr; + uint32_t rsize; + + if (--mock_read_res_fail_on_call == 0) + return VB2_ERROR_EX_READ_RESOURCE_INDEX; + + switch(index) { + case VB2_RES_GBB: + rptr = (uint8_t *)&mock_gbb; + rsize = sizeof(mock_gbb); + break; + case VB2_RES_FW_VBLOCK: + rptr = (uint8_t *)&mock_vblock; + rsize = sizeof(mock_vblock); + break; + default: + return VB2_ERROR_EX_READ_RESOURCE_INDEX; + } + + if (offset > rsize || offset + size > rsize) + return VB2_ERROR_EX_READ_RESOURCE_SIZE; + + memcpy(buf, rptr + offset, size); + return VB2_SUCCESS; +} + +int vb2_unpack_key(struct vb2_public_key *key, + const uint8_t *buf, + uint32_t size) +{ + return mock_unpack_key_retval; +} + +int vb2_verify_keyblock(struct vb2_keyblock *block, + uint32_t size, + const struct vb2_public_key *key, + struct vb2_workbuf *wb) +{ + return mock_verify_keyblock_retval; +} + +int vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble, + uint32_t size, + const struct vb2_public_key *key, + struct vb2_workbuf *wb) +{ + return mock_verify_preamble_retval; +} + +/* Tests */ + +static void verify_keyblock_tests(void) +{ + struct vb2_keyblock *kb = &mock_vblock.k.kb; + struct vb2_packed_key *k; + int wb_used_before; + + /* Test successful call */ + reset_common_data(FOR_KEYBLOCK); + wb_used_before = cc.workbuf_used; + TEST_SUCC(vb2_verify_fw_keyblock(&cc), "keyblock verify"); + TEST_EQ(sd->fw_version, 0x20000, "keyblock version"); + TEST_EQ(sd->vblock_preamble_offset, sizeof(mock_vblock.k), + "preamble offset"); + TEST_EQ(sd->workbuf_data_key_offset, + (wb_used_before + (VB2_WORKBUF_ALIGN - 1)) & + ~(VB2_WORKBUF_ALIGN - 1), + "keyblock data key offset"); + TEST_EQ(cc.workbuf_used, + sd->workbuf_data_key_offset + sd->workbuf_data_key_size, + "workbuf used"); + + /* Make sure data key was properly saved */ + k = (struct vb2_packed_key *)(cc.workbuf + sd->workbuf_data_key_offset); + TEST_EQ(k->algorithm, 7, "data key algorithm"); + TEST_EQ(k->key_version, 2, "data key version"); + TEST_EQ(k->key_size, sizeof(mock_vblock.k.data_key_data), + "data key size"); + TEST_EQ(memcmp(cc.workbuf + sd->workbuf_data_key_offset + + k->key_offset, mock_vblock.k.data_key_data, + sizeof(mock_vblock.k.data_key_data)), + 0, "data key data"); + TEST_EQ(cc.workbuf_used, + sd->workbuf_data_key_offset + sd->workbuf_data_key_size, + "workbuf used after"); + + /* Test failures */ + reset_common_data(FOR_KEYBLOCK); + cc.workbuf_used = cc.workbuf_size - sd->gbb_rootkey_size + 8; + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_FW_KEYBLOCK_WORKBUF_ROOT_KEY, + "keyblock not enough workbuf for root key"); + + reset_common_data(FOR_KEYBLOCK); + sd->gbb_rootkey_size = sizeof(mock_gbb); + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_EX_READ_RESOURCE_SIZE, + "keyblock read root key"); + + reset_common_data(FOR_KEYBLOCK); + mock_unpack_key_retval = VB2_ERROR_UNPACK_KEY_ALGORITHM; + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_UNPACK_KEY_ALGORITHM, + "keyblock unpack root key"); + + reset_common_data(FOR_KEYBLOCK); + cc.workbuf_used = cc.workbuf_size - sd->gbb_rootkey_size - 8; + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_FW_KEYBLOCK_WORKBUF_HEADER, + "keyblock not enough workbuf for header"); + + reset_common_data(FOR_KEYBLOCK); + mock_read_res_fail_on_call = 2; + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_EX_READ_RESOURCE_INDEX, + "keyblock read keyblock header"); + + reset_common_data(FOR_KEYBLOCK); + cc.workbuf_used = cc.workbuf_size - sd->gbb_rootkey_size + - sizeof(struct vb2_keyblock); + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_FW_KEYBLOCK_WORKBUF, + "keyblock not enough workbuf for entire keyblock"); + + reset_common_data(FOR_KEYBLOCK); + kb->keyblock_size = sizeof(mock_vblock) + 1; + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_EX_READ_RESOURCE_SIZE, + "keyblock read keyblock"); + + reset_common_data(FOR_KEYBLOCK); + mock_verify_keyblock_retval = VB2_ERROR_KEYBLOCK_MAGIC; + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_KEYBLOCK_MAGIC, + "keyblock verify keyblock"); + + reset_common_data(FOR_KEYBLOCK); + kb->data_key.key_version = 0x10000; + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_FW_KEYBLOCK_VERSION_RANGE, + "keyblock version range"); + + reset_common_data(FOR_KEYBLOCK); + kb->data_key.key_version = 1; + TEST_EQ(vb2_verify_fw_keyblock(&cc), + VB2_ERROR_FW_KEYBLOCK_VERSION_ROLLBACK, + "keyblock rollback"); +} + +static void verify_preamble_tests(void) +{ + struct vb2_fw_preamble *pre = &mock_vblock.p.pre; + int wb_used_before; + uint32_t v; + + /* Test successful call */ + reset_common_data(FOR_PREAMBLE); + wb_used_before = cc.workbuf_used; + TEST_SUCC(vb2_verify_fw_preamble2(&cc), "preamble good"); + TEST_EQ(sd->fw_version, 0x20002, "combined version"); + TEST_EQ(sd->workbuf_preamble_offset, + (wb_used_before + (VB2_WORKBUF_ALIGN - 1)) & + ~(VB2_WORKBUF_ALIGN - 1), + "preamble offset"); + TEST_EQ(sd->workbuf_preamble_size, pre->preamble_size, "preamble size"); + TEST_EQ(cc.workbuf_used, + sd->workbuf_preamble_offset + sd->workbuf_preamble_size, + "workbuf used"); + + /* Expected failures */ + reset_common_data(FOR_PREAMBLE); + sd->workbuf_data_key_size = 0; + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_FW_PREAMBLE2_DATA_KEY, + "preamble no data key"); + + reset_common_data(FOR_PREAMBLE); + mock_unpack_key_retval = VB2_ERROR_UNPACK_KEY_ALGORITHM; + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_UNPACK_KEY_ALGORITHM, + "preamble unpack data key"); + + reset_common_data(FOR_PREAMBLE); + cc.workbuf_used = cc.workbuf_size - sizeof(struct vb2_fw_preamble) + 8; + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_FW_PREAMBLE2_WORKBUF_HEADER, + "preamble not enough workbuf for header"); + + reset_common_data(FOR_PREAMBLE); + sd->vblock_preamble_offset = sizeof(mock_vblock); + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_EX_READ_RESOURCE_SIZE, + "preamble read header"); + + reset_common_data(FOR_PREAMBLE); + cc.workbuf_used = cc.workbuf_size - sizeof(mock_vblock.p) + 8; + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_FW_PREAMBLE2_WORKBUF, + "preamble not enough workbuf"); + + reset_common_data(FOR_PREAMBLE); + pre->preamble_size = sizeof(mock_vblock); + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_EX_READ_RESOURCE_SIZE, + "preamble read full"); + + reset_common_data(FOR_PREAMBLE); + mock_verify_preamble_retval = VB2_ERROR_PREAMBLE_SIG_INVALID; + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_PREAMBLE_SIG_INVALID, + "preamble verify"); + + reset_common_data(FOR_PREAMBLE); + pre->firmware_version = 0x10000; + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_FW_PREAMBLE2_VERSION_RANGE, + "preamble version range"); + + reset_common_data(FOR_PREAMBLE); + pre->firmware_version = 1; + TEST_EQ(vb2_verify_fw_preamble2(&cc), + VB2_ERROR_FW_PREAMBLE2_VERSION_ROLLBACK, + "preamble version rollback"); + + reset_common_data(FOR_PREAMBLE); + pre->firmware_version = 3; + TEST_SUCC(vb2_verify_fw_preamble2(&cc), + "preamble version roll forward"); + vb2_secdata_get(&cc, VB2_SECDATA_VERSIONS, &v); + TEST_EQ(v, 0x20003, "roll forward"); + + /* Newer version without result success doesn't roll forward */ + reset_common_data(FOR_PREAMBLE); + pre->firmware_version = 3; + sd->last_fw_result = VB2_FW_RESULT_UNKNOWN; + TEST_SUCC(vb2_verify_fw_preamble2(&cc), + "preamble version no roll forward 1"); + vb2_secdata_get(&cc, VB2_SECDATA_VERSIONS, &v); + TEST_EQ(v, 0x20002, "no roll forward"); + + /* Newer version with success but for other slot doesn't roll forward */ + reset_common_data(FOR_PREAMBLE); + pre->firmware_version = 3; + sd->last_fw_slot = 1; + TEST_SUCC(vb2_verify_fw_preamble2(&cc), + "preamble version no roll forward 2"); + vb2_secdata_get(&cc, VB2_SECDATA_VERSIONS, &v); + TEST_EQ(v, 0x20002, "no roll forward"); +} + +int main(int argc, char* argv[]) +{ + verify_keyblock_tests(); + verify_preamble_tests(); + + return gTestSuccess ? 0 : 255; +} |