diff options
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | firmware/2lib/2misc2.c | 238 | ||||
-rw-r--r-- | firmware/2lib/include/2misc.h | 10 | ||||
-rw-r--r-- | firmware/2lib/include/2return_codes.h | 3 | ||||
-rw-r--r-- | tests/vb2_misc3_tests.c | 384 |
5 files changed, 638 insertions, 0 deletions
@@ -286,6 +286,7 @@ FWLIB2_SRCS = \ firmware/2lib/2common2.c \ firmware/2lib/2crc8.c \ firmware/2lib/2misc.c \ + firmware/2lib/2misc2.c \ firmware/2lib/2nvstorage.c \ firmware/2lib/2packed_key.c \ firmware/2lib/2packed_key2.c \ @@ -641,6 +642,7 @@ TEST_NAMES += \ tests/vb2_common3_tests \ tests/vb2_misc_tests \ tests/vb2_misc2_tests \ + tests/vb2_misc3_tests \ tests/vb2_nvstorage_tests \ tests/vb2_rsa_padding_tests \ tests/vb2_rsa_utility_tests \ @@ -1177,6 +1179,7 @@ run2tests: test_setup ${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_misc3_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/2misc2.c b/firmware/2lib/2misc2.c new file mode 100644 index 00000000..dbdf95c0 --- /dev/null +++ b/firmware/2lib/2misc2.c @@ -0,0 +1,238 @@ +/* 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. + * + * Misc functions which need access to vb2_context but are not public APIs + */ + +#include "2sysincludes.h" +#include "2api.h" +#include "2common.h" +#include "2misc.h" +#include "2nvstorage.h" +#include "2secdata.h" +#include "2sha.h" +#include "2rsa.h" + +/** + * Read an object with a common struct header from a verified boot resource. + * + * On success, an object buffer will be allocated in the work buffer, the + * object will be stored into the buffer, and *buf_ptr will point to the + * object. + * + * @param ctx Vboot context + * @param index Resource index to read + * @param offset Byte offset within resource to start at + * @param buf_ptr Destination for object pointer + * @return VB2_SUCCESS, or error code on error. + */ +int vb2_read_resource_object(struct vb2_context *ctx, + enum vb2_resource_index index, + uint32_t offset, + struct vb2_workbuf *wb, + void **buf_ptr) +{ + struct vb2_struct_common c; + void *buf; + int rv; + + *buf_ptr = NULL; + + /* Read the common header */ + rv = vb2ex_read_resource(ctx, index, offset, &c, sizeof(c)); + if (rv) + return rv; + + /* Allocate a buffer for the object, now that we know how big it is */ + buf = vb2_workbuf_alloc(wb, c.total_size); + if (!buf) + return VB2_ERROR_READ_RESOURCE_OBJECT_BUF; + + /* Read the object */ + rv = vb2ex_read_resource(ctx, index, offset, buf, c.total_size); + if (rv) { + vb2_workbuf_free(wb, c.total_size); + return rv; + } + + /* Save the pointer */ + *buf_ptr = buf; + return VB2_SUCCESS; +} + +int vb2_load_fw_keyblock2(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_key2 *packed_key; + struct vb2_public_key root_key; + struct vb2_keyblock2 *kb; + + 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_key2(&root_key, key_data, key_size); + if (rv) + return rv; + + /* + * Load the firmware keyblock common header into the work buffer after + * the root key. + */ + rv = vb2_read_resource_object(ctx, VB2_RES_FW_VBLOCK, 0, &wb, + (void **)&kb); + if (rv) + return rv; + + /* Verify the keyblock */ + rv = vb2_verify_keyblock2(kb, kb->c.total_size, &root_key, &wb); + if (rv) + return rv; + + /* Preamble follows the keyblock in the vblock */ + sd->vblock_preamble_offset = kb->c.total_size; + + /* Read the secure key version */ + rv = vb2_secdata_get(ctx, VB2_SECDATA_VERSIONS, &sec_version); + if (rv) + return rv; + + packed_key = (struct vb2_packed_key2 *)((uint8_t *)kb + kb->key_offset); + + /* Key version is the upper 16 bits of the composite firmware version */ + if (packed_key->key_version > 0xffff) + return VB2_ERROR_FW_KEYBLOCK_VERSION_RANGE; + if (packed_key->key_version < (sec_version >> 16)) + return VB2_ERROR_FW_KEYBLOCK_VERSION_ROLLBACK; + + sd->fw_version = packed_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. + * + * Use memmove() instead of memcpy(). In theory, the destination will + * never overlap 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, packed_key->c.total_size); + packed_key = (struct vb2_packed_key2 *)key_data; + + /* 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->c.total_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; +} + +int vb2_load_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_preamble2 *pre; + + 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_key2(&data_key, key_data, key_size); + if (rv) + return rv; + + /* Load the firmware preamble */ + rv = vb2_read_resource_object(ctx, VB2_RES_FW_VBLOCK, + sd->vblock_preamble_offset, &wb, + (void **)&pre); + if (rv) + return rv; + + /* Work buffer now contains the data subkey data and the preamble */ + + /* Verify the preamble */ + rv = vb2_verify_fw_preamble2(pre, pre->c.total_size, &data_key, &wb); + if (rv) + return rv; + + /* Move the preamble down now that the data key is no longer used */ + memmove(key_data, pre, pre->c.total_size); + pre = (struct vb2_fw_preamble2 *)key_data; + + /* Data key is now gone */ + sd->workbuf_data_key_offset = sd->workbuf_data_key_size = 0; + + /* 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_load_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->c.total_size; + + /* Preamble will persist in work buffer after we return */ + ctx->workbuf_used = sd->workbuf_preamble_offset + + sd->workbuf_preamble_size; + + return VB2_SUCCESS; +} diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h index d50ed319..24b32db7 100644 --- a/firmware/2lib/include/2misc.h +++ b/firmware/2lib/include/2misc.h @@ -131,6 +131,11 @@ int vb2_select_fw_slot(struct vb2_context *ctx); int vb2_load_fw_keyblock(struct vb2_context *ctx); /** + * (same, for new-style structs) + */ +int vb2_load_fw_keyblock2(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. @@ -140,4 +145,9 @@ int vb2_load_fw_keyblock(struct vb2_context *ctx); */ int vb2_load_fw_preamble(struct vb2_context *ctx); +/** + * (same, for new-style structs) + */ +int vb2_load_fw_preamble2(struct vb2_context *ctx); + #endif /* VBOOT_REFERENCE_VBOOT_2MISC_H_ */ diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h index 4ff84468..259726d1 100644 --- a/firmware/2lib/include/2return_codes.h +++ b/firmware/2lib/include/2return_codes.h @@ -364,6 +364,9 @@ enum vb2_return_code { /* Firmware version rollback in vb2_load_fw_preamble() */ VB2_ERROR_FW_PREAMBLE2_VERSION_ROLLBACK, + /* Not enough space in work buffer for resource object */ + VB2_ERROR_READ_RESOURCE_OBJECT_BUF, + /********************************************************************** * API-level errors */ diff --git a/tests/vb2_misc3_tests.c b/tests/vb2_misc3_tests.c new file mode 100644 index 00000000..c607d248 --- /dev/null +++ b/tests/vb2_misc3_tests.c @@ -0,0 +1,384 @@ +/* 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, new-style structs + */ + +#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 ctx; +static struct vb2_shared_data *sd; + +/* Mocked function data */ + +static struct { + struct vb2_gbb_header h; + struct vb2_packed_key2 rootkey; + char rootkey_data[32]; +} mock_gbb; + +static struct { + /* Keyblock */ + struct { + struct vb2_keyblock2 kb; + struct vb2_packed_key2 data_key; + char data_key_data[16]; + uint8_t kbdata[128]; + } k; + /* Preamble follows keyblock */ + struct { + struct vb2_fw_preamble2 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_keyblock2 *kb = &mock_vblock.k.kb; + struct vb2_packed_key2 *dk = &mock_vblock.k.data_key; + struct vb2_fw_preamble2 *pre = &mock_vblock.p.pre; + + memset(workbuf, 0xaa, sizeof(workbuf)); + + memset(&ctx, 0, sizeof(ctx)); + ctx.workbuf = workbuf; + ctx.workbuf_size = sizeof(workbuf); + + vb2_init_context(&ctx); + sd = vb2_get_sd(&ctx); + + vb2_nv_init(&ctx); + + vb2_secdata_create(&ctx); + vb2_secdata_init(&ctx); + + 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(&ctx, 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.sig_alg = VB2_SIG_RSA8192; + 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->c.total_size = sizeof(mock_vblock.k); + kb->key_offset = vb2_offset_of(&mock_vblock.k.kb, + &mock_vblock.k.data_key); + + dk->c.fixed_size = sizeof(mock_vblock.k.data_key); + dk->sig_alg = VB2_SIG_RSA4096; + dk->key_version = 2; + dk->key_offset = dk->c.fixed_size; + dk->key_size = sizeof(mock_vblock.k.data_key_data); + dk->c.total_size = dk->key_offset + dk->key_size; + strcpy(mock_vblock.k.data_key_data, "data key data!!"); + + pre->c.total_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_load_fw_keyblock2(&ctx); +}; + +/* 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_key2(struct vb2_public_key *key, + const uint8_t *buf, + uint32_t size) +{ + return mock_unpack_key_retval; +} + +int vb2_verify_keyblock2(struct vb2_keyblock2 *block, + uint32_t size, + const struct vb2_public_key *key, + const struct vb2_workbuf *wb) +{ + return mock_verify_keyblock_retval; +} + +int vb2_verify_fw_preamble2(struct vb2_fw_preamble2 *preamble, + uint32_t size, + const struct vb2_public_key *key, + const struct vb2_workbuf *wb) +{ + return mock_verify_preamble_retval; +} + +/* Tests */ + +static void load_keyblock_tests(void) +{ + struct vb2_keyblock2 *kb = &mock_vblock.k.kb; + struct vb2_packed_key2 *dk = &mock_vblock.k.data_key; + struct vb2_packed_key2 *k; + int wb_used_before; + + /* Test successful call */ + reset_common_data(FOR_KEYBLOCK); + wb_used_before = ctx.workbuf_used; + TEST_SUCC(vb2_load_fw_keyblock2(&ctx), "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(ctx.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_key2 *)(ctx.workbuf + + sd->workbuf_data_key_offset); + TEST_EQ(k->sig_alg, VB2_SIG_RSA4096, "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(ctx.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(ctx.workbuf_used, + sd->workbuf_data_key_offset + sd->workbuf_data_key_size, + "workbuf used after"); + + /* Test failures */ + reset_common_data(FOR_KEYBLOCK); + ctx.workbuf_used = ctx.workbuf_size - sd->gbb_rootkey_size + 8; + TEST_EQ(vb2_load_fw_keyblock2(&ctx), + 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_load_fw_keyblock2(&ctx), + VB2_ERROR_EX_READ_RESOURCE_SIZE, + "keyblock read root key"); + + reset_common_data(FOR_KEYBLOCK); + mock_unpack_key_retval = VB2_ERROR_UNPACK_KEY_SIG_ALGORITHM; + TEST_EQ(vb2_load_fw_keyblock2(&ctx), + VB2_ERROR_UNPACK_KEY_SIG_ALGORITHM, + "keyblock unpack root key"); + + reset_common_data(FOR_KEYBLOCK); + ctx.workbuf_used = ctx.workbuf_size - sd->gbb_rootkey_size - 8; + TEST_EQ(vb2_load_fw_keyblock2(&ctx), + VB2_ERROR_READ_RESOURCE_OBJECT_BUF, + "keyblock not enough workbuf for header"); + + reset_common_data(FOR_KEYBLOCK); + mock_read_res_fail_on_call = 2; + TEST_EQ(vb2_load_fw_keyblock2(&ctx), + VB2_ERROR_EX_READ_RESOURCE_INDEX, + "keyblock read keyblock header"); + + reset_common_data(FOR_KEYBLOCK); + ctx.workbuf_used = ctx.workbuf_size - sd->gbb_rootkey_size + - sizeof(struct vb2_keyblock); + TEST_EQ(vb2_load_fw_keyblock2(&ctx), + VB2_ERROR_READ_RESOURCE_OBJECT_BUF, + "keyblock not enough workbuf for entire keyblock"); + + reset_common_data(FOR_KEYBLOCK); + kb->c.total_size = sizeof(mock_vblock) + 1; + TEST_EQ(vb2_load_fw_keyblock2(&ctx), + 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_load_fw_keyblock2(&ctx), + VB2_ERROR_KEYBLOCK_MAGIC, + "keyblock verify keyblock"); + + reset_common_data(FOR_KEYBLOCK); + dk->key_version = 0x10000; + TEST_EQ(vb2_load_fw_keyblock2(&ctx), + VB2_ERROR_FW_KEYBLOCK_VERSION_RANGE, + "keyblock version range"); + + reset_common_data(FOR_KEYBLOCK); + dk->key_version = 1; + TEST_EQ(vb2_load_fw_keyblock2(&ctx), + VB2_ERROR_FW_KEYBLOCK_VERSION_ROLLBACK, + "keyblock rollback"); +} + +static void load_preamble_tests(void) +{ + struct vb2_fw_preamble2 *pre = &mock_vblock.p.pre; + int data_key_offset_before; + uint32_t v; + + /* Test successful call */ + reset_common_data(FOR_PREAMBLE); + data_key_offset_before = sd->workbuf_data_key_offset; + TEST_SUCC(vb2_load_fw_preamble2(&ctx), "preamble good"); + TEST_EQ(sd->fw_version, 0x20002, "combined version"); + TEST_EQ(sd->workbuf_preamble_offset, data_key_offset_before, + "preamble offset"); + TEST_EQ(sd->workbuf_preamble_size, pre->c.total_size, "preamble size"); + TEST_EQ(ctx.workbuf_used, + sd->workbuf_preamble_offset + sd->workbuf_preamble_size, + "workbuf used"); + TEST_EQ(sd->workbuf_data_key_offset, 0, "data key offset gone"); + TEST_EQ(sd->workbuf_data_key_size, 0, "data key size gone"); + + /* Expected failures */ + reset_common_data(FOR_PREAMBLE); + sd->workbuf_data_key_size = 0; + TEST_EQ(vb2_load_fw_preamble2(&ctx), + VB2_ERROR_FW_PREAMBLE2_DATA_KEY, + "preamble no data key"); + + reset_common_data(FOR_PREAMBLE); + mock_unpack_key_retval = VB2_ERROR_UNPACK_KEY_HASH_ALGORITHM; + TEST_EQ(vb2_load_fw_preamble2(&ctx), + VB2_ERROR_UNPACK_KEY_HASH_ALGORITHM, + "preamble unpack data key"); + + reset_common_data(FOR_PREAMBLE); + ctx.workbuf_used = ctx.workbuf_size + - sizeof(struct vb2_fw_preamble) + 8; + TEST_EQ(vb2_load_fw_preamble2(&ctx), + VB2_ERROR_READ_RESOURCE_OBJECT_BUF, + "preamble not enough workbuf for header"); + + reset_common_data(FOR_PREAMBLE); + sd->vblock_preamble_offset = sizeof(mock_vblock); + TEST_EQ(vb2_load_fw_preamble2(&ctx), + VB2_ERROR_EX_READ_RESOURCE_SIZE, + "preamble read header"); + + reset_common_data(FOR_PREAMBLE); + ctx.workbuf_used = ctx.workbuf_size - sizeof(mock_vblock.p) + 8; + TEST_EQ(vb2_load_fw_preamble2(&ctx), + VB2_ERROR_READ_RESOURCE_OBJECT_BUF, + "preamble not enough workbuf"); + + reset_common_data(FOR_PREAMBLE); + pre->c.total_size = sizeof(mock_vblock); + TEST_EQ(vb2_load_fw_preamble2(&ctx), + 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_load_fw_preamble2(&ctx), + VB2_ERROR_PREAMBLE_SIG_INVALID, + "preamble verify"); + + reset_common_data(FOR_PREAMBLE); + pre->firmware_version = 0x10000; + TEST_EQ(vb2_load_fw_preamble2(&ctx), + VB2_ERROR_FW_PREAMBLE2_VERSION_RANGE, + "preamble version range"); + + reset_common_data(FOR_PREAMBLE); + pre->firmware_version = 1; + TEST_EQ(vb2_load_fw_preamble2(&ctx), + VB2_ERROR_FW_PREAMBLE2_VERSION_ROLLBACK, + "preamble version rollback"); + + reset_common_data(FOR_PREAMBLE); + pre->firmware_version = 3; + TEST_SUCC(vb2_load_fw_preamble2(&ctx), + "preamble version roll forward"); + vb2_secdata_get(&ctx, 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_load_fw_preamble2(&ctx), + "preamble version no roll forward 1"); + vb2_secdata_get(&ctx, 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_load_fw_preamble2(&ctx), + "preamble version no roll forward 2"); + vb2_secdata_get(&ctx, VB2_SECDATA_VERSIONS, &v); + TEST_EQ(v, 0x20002, "no roll forward"); +} + +int main(int argc, char* argv[]) +{ + load_keyblock_tests(); + load_preamble_tests(); + + return gTestSuccess ? 0 : 255; +} |