summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kitching <kitching@google.com>2019-08-28 17:45:05 +0800
committerCommit Bot <commit-bot@chromium.org>2019-09-23 17:54:09 +0000
commit967ba853d88b7803c73f3adb94b8717d001a077b (patch)
tree2ce2dc70ead38a5f687f2c5b822a2d19d38469f2
parentaaf394335cc4e287a1ffb6332311559b2b29c41f (diff)
downloadvboot-967ba853d88b7803c73f3adb94b8717d001a077b.tar.gz
vboot/secdata: implement vboot2 FWMP support
Implement FWMP support in vboot2. Currently, the data structure is just accessed directly, checking to see whether its `flags` member contains particular flags. We'd like to change this to follow the same scheme as secdata_firmware and secdata_kernel. This CL also updates some functions, comments, and tests related to secdata_firmware and secdata_kernel to ensure consistency between code for the secdata spaces. BUG=b:124141368, chromium:972956 TEST=make clean && make runtests BRANCH=none Change-Id: Ia0d67532cc6e077e170ffb25d0bc587b1d53edf3 Signed-off-by: Joel Kitching <kitching@google.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/1773088 Reviewed-by: Joel Kitching <kitching@chromium.org> Tested-by: Joel Kitching <kitching@chromium.org> Commit-Queue: Joel Kitching <kitching@chromium.org>
-rw-r--r--Makefile3
-rw-r--r--firmware/2lib/2api.c2
-rw-r--r--firmware/2lib/2misc.c6
-rw-r--r--firmware/2lib/2secdata_firmware.c8
-rw-r--r--firmware/2lib/2secdata_fwmp.c130
-rw-r--r--firmware/2lib/2secdata_kernel.c6
-rw-r--r--firmware/2lib/include/2api.h70
-rw-r--r--firmware/2lib/include/2constants.h2
-rw-r--r--firmware/2lib/include/2misc.h2
-rw-r--r--firmware/2lib/include/2return_codes.h12
-rw-r--r--firmware/2lib/include/2secdata.h85
-rw-r--r--firmware/2lib/include/2struct.h3
-rw-r--r--firmware/lib/mocked_secdata_tpm.c2
-rw-r--r--tests/vb20_verify_fw.c8
-rw-r--r--tests/vb2_api_tests.c12
-rw-r--r--tests/vb2_misc_tests.c23
-rw-r--r--tests/vb2_secdata_firmware_tests.c117
-rw-r--r--tests/vb2_secdata_fwmp_tests.c242
-rw-r--r--tests/vb2_secdata_kernel_tests.c100
19 files changed, 692 insertions, 141 deletions
diff --git a/Makefile b/Makefile
index fa63773b..515d27e9 100644
--- a/Makefile
+++ b/Makefile
@@ -359,6 +359,7 @@ FWLIB2X_SRCS = \
firmware/2lib/2packed_key.c \
firmware/2lib/2rsa.c \
firmware/2lib/2secdata_firmware.c \
+ firmware/2lib/2secdata_fwmp.c \
firmware/2lib/2secdata_kernel.c \
firmware/2lib/2sha1.c \
firmware/2lib/2sha256.c \
@@ -712,6 +713,7 @@ TEST2X_NAMES = \
tests/vb2_nvstorage_tests \
tests/vb2_rsa_utility_tests \
tests/vb2_secdata_firmware_tests \
+ tests/vb2_secdata_fwmp_tests \
tests/vb2_secdata_kernel_tests \
tests/vb2_sha_tests \
tests/hmac_test
@@ -1279,6 +1281,7 @@ run2tests: test_setup
${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_firmware_tests
+ ${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_fwmp_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_kernel_tests
${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_tests
${RUNTEST} ${BUILD_RUN}/tests/vb20_api_tests
diff --git a/firmware/2lib/2api.c b/firmware/2lib/2api.c
index e93894d7..7e168cb0 100644
--- a/firmware/2lib/2api.c
+++ b/firmware/2lib/2api.c
@@ -63,7 +63,7 @@ vb2_error_t vb2api_fw_phase1(struct vb2_context *ctx)
vb2_fail(ctx, VB2_RECOVERY_SECDATA_FIRMWARE_INIT, rv);
/* Load and parse the GBB header */
- rv = vb2_fw_parse_gbb(ctx);
+ rv = vb2_fw_init_gbb(ctx);
if (rv)
vb2_fail(ctx, VB2_RECOVERY_GBB_HEADER, rv);
diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c
index 98b5c33a..c3cae7c2 100644
--- a/firmware/2lib/2misc.c
+++ b/firmware/2lib/2misc.c
@@ -209,7 +209,7 @@ void vb2_check_recovery(struct vb2_context *ctx)
}
}
-vb2_error_t vb2_fw_parse_gbb(struct vb2_context *ctx)
+vb2_error_t vb2_fw_init_gbb(struct vb2_context *ctx)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
struct vb2_gbb_header *gbb;
@@ -231,6 +231,10 @@ vb2_error_t vb2_fw_parse_gbb(struct vb2_context *ctx)
sd->gbb_offset = vb2_offset_of(sd, gbb);
ctx->workbuf_used = vb2_offset_of(ctx->workbuf, wb.buf);
+ /* Set any context flags based on GBB flags */
+ if (gbb->flags & VB2_GBB_FLAG_DISABLE_FWMP)
+ ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP;
+
return VB2_SUCCESS;
}
diff --git a/firmware/2lib/2secdata_firmware.c b/firmware/2lib/2secdata_firmware.c
index 1ce5b29b..74b7ff1f 100644
--- a/firmware/2lib/2secdata_firmware.c
+++ b/firmware/2lib/2secdata_firmware.c
@@ -32,7 +32,7 @@ vb2_error_t vb2api_secdata_firmware_check(struct vb2_context *ctx)
return VB2_SUCCESS;
}
-vb2_error_t vb2api_secdata_firmware_create(struct vb2_context *ctx)
+uint32_t vb2api_secdata_firmware_create(struct vb2_context *ctx)
{
struct vb2_secdata_firmware *sec =
(struct vb2_secdata_firmware *)ctx->secdata_firmware;
@@ -49,7 +49,7 @@ vb2_error_t vb2api_secdata_firmware_create(struct vb2_context *ctx)
/* Mark as changed */
ctx->flags |= VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
- return VB2_SUCCESS;
+ return sizeof(*sec);
}
vb2_error_t vb2_secdata_firmware_init(struct vb2_context *ctx)
@@ -64,7 +64,7 @@ vb2_error_t vb2_secdata_firmware_init(struct vb2_context *ctx)
/* Set status flag */
sd->status |= VB2_SD_STATUS_SECDATA_FIRMWARE_INIT;
- /* Read this now to make sure crossystem has it even in rec mode. */
+ /* Read this now to make sure crossystem has it even in rec mode */
rv = vb2_secdata_firmware_get(ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
&sd->fw_version_secdata);
if (rv)
@@ -109,7 +109,7 @@ vb2_error_t vb2_secdata_firmware_set(struct vb2_context *ctx,
if (!(vb2_get_sd(ctx)->status & VB2_SD_STATUS_SECDATA_FIRMWARE_INIT))
return VB2_ERROR_SECDATA_FIRMWARE_SET_UNINITIALIZED;
- /* If not changing the value, don't regenerate the CRC. */
+ /* If not changing the value, don't regenerate the CRC */
if (vb2_secdata_firmware_get(ctx, param, &now) == VB2_SUCCESS &&
now == value)
return VB2_SUCCESS;
diff --git a/firmware/2lib/2secdata_fwmp.c b/firmware/2lib/2secdata_fwmp.c
new file mode 100644
index 00000000..774a7fa8
--- /dev/null
+++ b/firmware/2lib/2secdata_fwmp.c
@@ -0,0 +1,130 @@
+/* Copyright 2019 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.
+ *
+ * Firmware management parameters (FWMP) APIs
+ */
+
+#include "2crc8.h"
+#include "2common.h"
+#include "2misc.h"
+#include "2secdata.h"
+
+uint32_t vb2_secdata_fwmp_crc(struct vb2_secdata_fwmp *sec)
+{
+ int version_offset = offsetof(struct vb2_secdata_fwmp, struct_version);
+ return vb2_crc8((void *)sec + version_offset,
+ sec->struct_size - version_offset);
+}
+
+vb2_error_t vb2api_secdata_fwmp_check(struct vb2_context *ctx, uint8_t *size)
+{
+ struct vb2_secdata_fwmp *sec =
+ (struct vb2_secdata_fwmp *)&ctx->secdata_fwmp;
+
+ /* Verify that at least the minimum size has been read */
+ if (*size < VB2_SECDATA_FWMP_MIN_SIZE) {
+ VB2_DEBUG("FWMP: missing %d bytes for minimum size\n",
+ VB2_SECDATA_FWMP_MIN_SIZE - *size);
+ *size = VB2_SECDATA_FWMP_MIN_SIZE;
+ return VB2_ERROR_SECDATA_FWMP_INCOMPLETE;
+ }
+
+ /* Verify that struct_size is reasonable */
+ if (sec->struct_size < VB2_SECDATA_FWMP_MIN_SIZE ||
+ sec->struct_size > VB2_SECDATA_FWMP_MAX_SIZE) {
+ VB2_DEBUG("FWMP: invalid size: %d\n", sec->struct_size);
+ return VB2_ERROR_SECDATA_FWMP_SIZE;
+ }
+
+ /* Verify that we have read full structure */
+ if (*size < sec->struct_size) {
+ VB2_DEBUG("FWMP: missing %d bytes\n", sec->struct_size - *size);
+ *size = sec->struct_size;
+ return VB2_ERROR_SECDATA_FWMP_INCOMPLETE;
+ }
+ *size = sec->struct_size;
+
+ /* Verify CRC */
+ if (sec->crc8 != vb2_secdata_fwmp_crc(sec)) {
+ VB2_DEBUG("FWMP: bad CRC\n");
+ return VB2_ERROR_SECDATA_FWMP_CRC;
+ }
+
+ /* Verify major version is compatible */
+ if ((sec->struct_version >> 4) != (VB2_SECDATA_FWMP_VERSION >> 4)) {
+ VB2_DEBUG("FWMP: major version incompatible\n");
+ return VB2_ERROR_SECDATA_FWMP_VERSION;
+ }
+
+ /*
+ * If this were a 1.1+ reader and the source was a 1.0 struct,
+ * we would need to take care of initializing the extra fields
+ * added in 1.1+. But that's not an issue yet.
+ */
+ return VB2_SUCCESS;
+}
+
+vb2_error_t vb2_secdata_fwmp_init(struct vb2_context *ctx)
+{
+ struct vb2_shared_data *sd = vb2_get_sd(ctx);
+ struct vb2_secdata_fwmp *sec =
+ (struct vb2_secdata_fwmp *)&ctx->secdata_fwmp;
+ vb2_error_t rv;
+
+ /* Skip checking if NO_SECDATA_FWMP is set. */
+ if (!(ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP)) {
+ rv = vb2api_secdata_fwmp_check(ctx, &sec->struct_size);
+ if (rv)
+ return rv;
+ }
+
+ /* Mark as initialized */
+ sd->status |= VB2_SD_STATUS_SECDATA_FWMP_INIT;
+
+ return VB2_SUCCESS;
+}
+
+int vb2_secdata_fwmp_get_flag(struct vb2_context *ctx,
+ enum vb2_secdata_fwmp_flags flag)
+{
+ struct vb2_shared_data *sd = vb2_get_sd(ctx);
+ struct vb2_secdata_fwmp *sec =
+ (struct vb2_secdata_fwmp *)&ctx->secdata_fwmp;
+
+ if (!(sd->status & VB2_SD_STATUS_SECDATA_FWMP_INIT)) {
+ if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
+ VB2_DEBUG("Assuming broken FWMP flag %d as 0\n", flag);
+ return 0;
+ } else {
+ VB2_DIE("Must init FWMP before retrieving flag\n");
+ }
+ }
+
+ if (ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP)
+ return 0;
+
+ return !!(sec->flags & flag);
+}
+
+uint8_t *vb2_secdata_fwmp_get_dev_key_hash(struct vb2_context *ctx)
+{
+ struct vb2_shared_data *sd = vb2_get_sd(ctx);
+ struct vb2_secdata_fwmp *sec =
+ (struct vb2_secdata_fwmp *)&ctx->secdata_fwmp;
+
+ if (!(sd->status & VB2_SD_STATUS_SECDATA_FWMP_INIT)) {
+ if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) {
+ VB2_DEBUG("Assuming broken FWMP dev_key_hash "
+ "as empty\n");
+ return NULL;
+ } else {
+ VB2_DIE("Must init FWMP before getting dev key hash\n");
+ }
+ }
+
+ if (ctx->flags & VB2_CONTEXT_NO_SECDATA_FWMP)
+ return NULL;
+
+ return sec->dev_key_hash;
+}
diff --git a/firmware/2lib/2secdata_kernel.c b/firmware/2lib/2secdata_kernel.c
index 47c7100f..fb9f0b95 100644
--- a/firmware/2lib/2secdata_kernel.c
+++ b/firmware/2lib/2secdata_kernel.c
@@ -38,7 +38,7 @@ vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx)
return VB2_SUCCESS;
}
-vb2_error_t vb2api_secdata_kernel_create(struct vb2_context *ctx)
+uint32_t vb2api_secdata_kernel_create(struct vb2_context *ctx)
{
struct vb2_secdata_kernel *sec =
(struct vb2_secdata_kernel *)ctx->secdata_kernel;
@@ -58,7 +58,7 @@ vb2_error_t vb2api_secdata_kernel_create(struct vb2_context *ctx)
/* Mark as changed */
ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
- return VB2_SUCCESS;
+ return sizeof(*sec);
}
vb2_error_t vb2_secdata_kernel_init(struct vb2_context *ctx)
@@ -109,7 +109,7 @@ vb2_error_t vb2_secdata_kernel_set(struct vb2_context *ctx,
if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT))
return VB2_ERROR_SECDATA_KERNEL_SET_UNINITIALIZED;
- /* If not changing the value, don't regenerate the CRC. */
+ /* If not changing the value, don't regenerate the CRC */
if (vb2_secdata_kernel_get(ctx, param, &now) == VB2_SUCCESS &&
now == value)
return VB2_SUCCESS;
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index 24d85da0..9a8a2228 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -185,6 +185,15 @@ enum vb2_context_flags {
* support.
*/
VB2_CONTEXT_DISPLAY_INIT = (1 << 20),
+
+ /*
+ * Caller may set this before running vb2api_kernel_phase1. It means
+ * that there is no FWMP on this system, and thus default values should
+ * be used instead.
+ *
+ * Caller should *not* set this when FWMP is available but invalid.
+ */
+ VB2_CONTEXT_NO_SECDATA_FWMP = (1 << 21),
};
/*
@@ -213,18 +222,19 @@ struct vb2_context {
/*
* Non-volatile data. Caller must fill this from some non-volatile
- * location. If the VB2_CONTEXT_NVDATA_CHANGED flag is set when a
- * vb2api function returns, caller must save the data back to the
- * non-volatile location and then clear the flag.
+ * location before calling vb2api_fw_phase1. If the
+ * VB2_CONTEXT_NVDATA_CHANGED flag is set when a vb2api function
+ * returns, caller must save the data back to the non-volatile location
+ * and then clear the flag.
*/
uint8_t nvdata[VB2_NVDATA_SIZE_V2];
/*
* Secure data for firmware verification stage. Caller must fill this
- * from some secure non-volatile location. If the
- * VB2_CONTEXT_SECDATA_CHANGED flag is set when a function returns,
- * caller must save the data back to the secure non-volatile location
- * and then clear the flag.
+ * from some secure non-volatile location before calling
+ * vb2api_fw_phase1. If the VB2_CONTEXT_SECDATA_CHANGED flag is set
+ * when a function returns, caller must save the data back to the
+ * secure non-volatile location and then clear the flag.
*/
uint8_t secdata_firmware[VB2_SECDATA_FIRMWARE_SIZE];
@@ -254,12 +264,24 @@ struct vb2_context {
/*
* Secure data for kernel verification stage. Caller must fill this
- * from some secure non-volatile location. If the
- * VB2_CONTEXT_SECDATA_KERNEL_CHANGED flag is set when a function
+ * from some secure non-volatile location before calling
+ * vb2api_kernel_phase1. If the VB2_CONTEXT_SECDATA_KERNEL_CHANGED
+ * flag is set when a function returns, caller must save the data back
+ * to the secure non-volatile location and then clear the flag.
+ */
+ uint8_t secdata_kernel[VB2_SECDATA_KERNEL_SIZE];
+
+ /*
+ * Firmware management parameters (FWMP) secure data. Caller must fill
+ * this from some secure non-volatile location before calling
+ * vb2api_kernel_phase1. Since FWMP is a variable-size space, caller
+ * should initially fill in VB2_SECDATA_FWMP_MIN_SIZE bytes, and call
+ * vb2_secdata_fwmp_check() to see whether more should be read. If the
+ * VB2_CONTEXT_SECDATA_FWMP_CHANGED flag is set when a function
* returns, caller must save the data back to the secure non-volatile
* location and then clear the flag.
*/
- uint8_t secdata_kernel[VB2_SECDATA_KERNEL_SIZE];
+ uint8_t secdata_fwmp[VB2_SECDATA_FWMP_MAX_SIZE];
};
/* Resource index for vb2ex_read_resource() */
@@ -404,7 +426,7 @@ enum vb2_pcr_digest {
*/
/**
- * Check the validity of the firmware secure storage context.
+ * Check the validity of firmware secure storage context.
*
* Checks version and CRC.
*
@@ -414,7 +436,7 @@ enum vb2_pcr_digest {
vb2_error_t vb2api_secdata_firmware_check(struct vb2_context *ctx);
/**
- * Create fresh data in the firmware secure storage context.
+ * Create fresh data in firmware secure storage context.
*
* Use this only when initializing the secure storage context on a new machine
* the first time it boots. Do NOT simply use this if
@@ -422,12 +444,12 @@ vb2_error_t vb2api_secdata_firmware_check(struct vb2_context *ctx);
* that could allow the secure data to be rolled back to an insecure state.
*
* @param ctx Context pointer
- * @return VB2_SUCCESS, or non-zero error code if error.
+ * @return size of created firmware secure storage data in bytes
*/
-vb2_error_t vb2api_secdata_firmware_create(struct vb2_context *ctx);
+uint32_t vb2api_secdata_firmware_create(struct vb2_context *ctx);
/**
- * Check the validity of the kernel secure storage context.
+ * Check the validity of kernel secure storage context.
*
* Checks version, UID, and CRC.
*
@@ -437,7 +459,7 @@ vb2_error_t vb2api_secdata_firmware_create(struct vb2_context *ctx);
vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx);
/**
- * Create fresh data in the kernel secure storage context.
+ * Create fresh data in kernel secure storage context.
*
* Use this only when initializing the secure storage context on a new machine
* the first time it boots. Do NOT simply use this if
@@ -445,9 +467,23 @@ vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx);
* could allow the secure data to be rolled back to an insecure state.
*
* @param ctx Context pointer
+ * @return size of created kernel secure storage data in bytes
+ */
+uint32_t vb2api_secdata_kernel_create(struct vb2_context *ctx);
+
+/**
+ * Check the validity of firmware management parameters (FWMP) space.
+ *
+ * Checks size, version, and CRC. If the struct size is larger than the size
+ * passed in, the size pointer is set to the expected full size of the struct,
+ * and VB2_ERROR_SECDATA_FWMP_INCOMPLETE is returned. The caller should
+ * re-read the returned number of bytes, and call this function again.
+ *
+ * @param ctx Context pointer
+ * @param size Amount of struct which has been read
* @return VB2_SUCCESS, or non-zero error code if error.
*/
-vb2_error_t vb2api_secdata_kernel_create(struct vb2_context *ctx);
+vb2_error_t vb2api_secdata_fwmp_check(struct vb2_context *ctx, uint8_t *size);
/**
* Report firmware failure to vboot.
diff --git a/firmware/2lib/include/2constants.h b/firmware/2lib/include/2constants.h
index f8d0d317..3f80b9ae 100644
--- a/firmware/2lib/include/2constants.h
+++ b/firmware/2lib/include/2constants.h
@@ -24,6 +24,8 @@
/* Size of secure data spaces used by vboot */
#define VB2_SECDATA_FIRMWARE_SIZE 10
#define VB2_SECDATA_KERNEL_SIZE 13
+#define VB2_SECDATA_FWMP_MIN_SIZE 40
+#define VB2_SECDATA_FWMP_MAX_SIZE 64
/* TODO(chromium:972956): Remove once coreboot is using updated names */
#define VB2_SECDATA_SIZE 10
diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h
index c7970d68..b03df5f3 100644
--- a/firmware/2lib/include/2misc.h
+++ b/firmware/2lib/include/2misc.h
@@ -117,7 +117,7 @@ void vb2_check_recovery(struct vb2_context *ctx);
* @param ctx Vboot context
* @return VB2_SUCCESS, or error code on error.
*/
-vb2_error_t vb2_fw_parse_gbb(struct vb2_context *ctx);
+vb2_error_t vb2_fw_init_gbb(struct vb2_context *ctx);
/**
* Check developer switch position.
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index 865ea7cf..bc612344 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -197,6 +197,18 @@ enum vb2_return_code {
/* Called vb2_secdata_kernel_set() with uninitialized secdata_kernel */
VB2_ERROR_SECDATA_KERNEL_SET_UNINITIALIZED,
+ /* Bad size in vb2api_secdata_fwmp_check() */
+ VB2_ERROR_SECDATA_FWMP_SIZE,
+
+ /* Incomplete structure in vb2api_secdata_fwmp_check() */
+ VB2_ERROR_SECDATA_FWMP_INCOMPLETE,
+
+ /* Bad CRC in vb2api_secdata_fwmp_check() */
+ VB2_ERROR_SECDATA_FWMP_CRC,
+
+ /* Bad struct version in vb2_secdata_fwmp_check() */
+ VB2_ERROR_SECDATA_FWMP_VERSION,
+
/**********************************************************************
* Common code errors
*/
diff --git a/firmware/2lib/include/2secdata.h b/firmware/2lib/include/2secdata.h
index 0bbce4f3..4e6fdda2 100644
--- a/firmware/2lib/include/2secdata.h
+++ b/firmware/2lib/include/2secdata.h
@@ -89,6 +89,44 @@ enum vb2_secdata_kernel_param {
};
/*****************************************************************************/
+/* Firmware management parameters (FWMP) space */
+
+#define VB2_SECDATA_FWMP_VERSION 0x10 /* 1.0 */
+#define VB2_SECDATA_FWMP_HASH_SIZE 32 /* enough for SHA-256 */
+
+/* Flags for FWMP space */
+enum vb2_secdata_fwmp_flags {
+ VB2_SECDATA_FWMP_DEV_DISABLE_BOOT = (1 << 0),
+ VB2_SECDATA_FWMP_DEV_DISABLE_RECOVERY = (1 << 1),
+ VB2_SECDATA_FWMP_DEV_ENABLE_USB = (1 << 2),
+ VB2_SECDATA_FWMP_DEV_ENABLE_LEGACY = (1 << 3),
+ VB2_SECDATA_FWMP_DEV_ENABLE_OFFICIAL_ONLY = (1 << 4),
+ VB2_SECDATA_FWMP_DEV_USE_KEY_HASH = (1 << 5),
+ /* CCD = case-closed debugging on cr50; flag implemented on cr50 */
+ VB2_SECDATA_FWMP_DEV_DISABLE_CCD_UNLOCK = (1 << 6),
+};
+
+struct vb2_secdata_fwmp {
+ /* CRC-8 of fields following struct_size */
+ uint8_t crc8;
+
+ /* Structure size in bytes */
+ uint8_t struct_size;
+
+ /* Structure version (4 bits major, 4 bits minor) */
+ uint8_t struct_version;
+
+ /* Reserved; ignored by current reader */
+ uint8_t reserved0;
+
+ /* Flags; see enum vb2_secdata_fwmp_flags */
+ uint32_t flags;
+
+ /* Hash of developer kernel key */
+ uint8_t dev_key_hash[VB2_SECDATA_FWMP_HASH_SIZE];
+};
+
+/*****************************************************************************/
/* Firmware secure storage space functions */
/**
@@ -166,4 +204,51 @@ vb2_error_t vb2_secdata_kernel_set(struct vb2_context *ctx,
enum vb2_secdata_kernel_param param,
uint32_t value);
+/*****************************************************************************/
+/* Firmware management parameters (FWMP) space functions */
+
+/**
+ * Generate CRC for FWMP secure storage space.
+ *
+ * Calculate CRC hash from struct_version onward. Should not be used;
+ * prototype only in header for use by unittests.
+ *
+ * In valid FWMP data, this CRC value should match the crc8 field.
+ *
+ * @param sec Pointer to FWMP struct
+ * @return 32-bit CRC hash of FWMP data
+ */
+uint32_t vb2_secdata_fwmp_crc(struct vb2_secdata_fwmp *sec);
+
+/**
+ * Initialize FWMP secure storage context and verify its CRC.
+ *
+ * This must be called before vb2_secdata_fwmp_get_flag/get_dev_key_hash().
+ *
+ * @param ctx Context pointer
+ * @return VB2_SUCCESS, or non-zero error code if error.
+ */
+vb2_error_t vb2_secdata_fwmp_init(struct vb2_context *ctx);
+
+/**
+ * Read a FWMP secure storage flag value.
+ *
+ * It is unsupported to call before successfully running vb2_secdata_fwmp_init.
+ * In this case, vboot will fail and exit.
+ *
+ * @param ctx Context pointer
+ * @param flag Flag to read
+ * @return current flag value (0 or 1)
+ */
+int vb2_secdata_fwmp_get_flag(struct vb2_context *ctx,
+ enum vb2_secdata_fwmp_flags flag);
+
+/**
+ * Return a pointer to FWMP dev key hash.
+ *
+ * @param ctx Context pointer
+ * @return uint8_t pointer to dev_key_hash field
+ */
+uint8_t *vb2_secdata_fwmp_get_dev_key_hash(struct vb2_context *ctx);
+
#endif /* VBOOT_REFERENCE_2SECDATA_H_ */
diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h
index 4aff7ca7..52d905ae 100644
--- a/firmware/2lib/include/2struct.h
+++ b/firmware/2lib/include/2struct.h
@@ -79,6 +79,9 @@ enum vb2_shared_data_status {
/* Secure data kernel version space initialized */
VB2_SD_STATUS_SECDATA_KERNEL_INIT = (1 << 4),
+
+ /* FWMP secure data initialized */
+ VB2_SD_STATUS_SECDATA_FWMP_INIT = (1 << 5),
};
/* "V2SD" = vb2_shared_data.magic */
diff --git a/firmware/lib/mocked_secdata_tpm.c b/firmware/lib/mocked_secdata_tpm.c
index 4271f768..b2f0670f 100644
--- a/firmware/lib/mocked_secdata_tpm.c
+++ b/firmware/lib/mocked_secdata_tpm.c
@@ -33,6 +33,6 @@ uint32_t RollbackKernelLock(int recovery_mode)
uint32_t RollbackFwmpRead(struct RollbackSpaceFwmp *fwmp)
{
- memset(fwmp, 0, sizeof(*fwmp));
+ ctx->flags |= VB2_CONTEXT_NO_SECDATA_FWMP;
return TPM_SUCCESS;
}
diff --git a/tests/vb20_verify_fw.c b/tests/vb20_verify_fw.c
index 5cf2b765..1fe662c2 100644
--- a/tests/vb20_verify_fw.c
+++ b/tests/vb20_verify_fw.c
@@ -164,13 +164,7 @@ int main(int argc, char *argv[])
ctx.workbuf_size = sizeof(workbuf);
/* Initialize secure context */
- rv = vb2api_secdata_firmware_create(&ctx);
- if (rv) {
- fprintf(stderr,
- "error: vb2api_secdata_firmware_create() failed (%d)\n",
- rv);
- return 1;
- }
+ vb2api_secdata_firmware_create(&ctx);
// TODO: optional args to set contents for nvdata, secdata?
diff --git a/tests/vb2_api_tests.c b/tests/vb2_api_tests.c
index 6429ca31..4ce5798e 100644
--- a/tests/vb2_api_tests.c
+++ b/tests/vb2_api_tests.c
@@ -36,7 +36,7 @@ static const uint8_t mock_hwid_digest[VB2_GBB_HWID_DIGEST_SIZE] = {
/* Mocked function data */
static int force_dev_mode;
-static vb2_error_t retval_vb2_fw_parse_gbb;
+static vb2_error_t retval_vb2_fw_init_gbb;
static vb2_error_t retval_vb2_check_dev_switch;
static vb2_error_t retval_vb2_check_tpm_clear;
static vb2_error_t retval_vb2_select_fw_slot;
@@ -63,7 +63,7 @@ static void reset_common_data(enum reset_type t)
vb2_secdata_firmware_init(&ctx);
force_dev_mode = 0;
- retval_vb2_fw_parse_gbb = VB2_SUCCESS;
+ retval_vb2_fw_init_gbb = VB2_SUCCESS;
retval_vb2_check_dev_switch = VB2_SUCCESS;
retval_vb2_check_tpm_clear = VB2_SUCCESS;
retval_vb2_select_fw_slot = VB2_SUCCESS;
@@ -78,9 +78,9 @@ struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c)
return &gbb;
}
-vb2_error_t vb2_fw_parse_gbb(struct vb2_context *c)
+vb2_error_t vb2_fw_init_gbb(struct vb2_context *c)
{
- return retval_vb2_fw_parse_gbb;
+ return retval_vb2_fw_init_gbb;
}
vb2_error_t vb2_check_dev_switch(struct vb2_context *c)
@@ -111,7 +111,7 @@ static void misc_tests(void)
TEST_EQ(vb2api_secdata_firmware_check(&ctx),
VB2_ERROR_SECDATA_FIRMWARE_CRC,
"secdata_firmware check");
- TEST_SUCC(vb2api_secdata_firmware_create(&ctx),
+ TEST_EQ(vb2api_secdata_firmware_create(&ctx), VB2_SECDATA_FIRMWARE_SIZE,
"secdata_firmware create");
TEST_SUCC(vb2api_secdata_firmware_check(&ctx),
"secdata_firmware check 2");
@@ -138,7 +138,7 @@ static void phase1_tests(void)
0, " display available SD flag");
reset_common_data(FOR_MISC);
- retval_vb2_fw_parse_gbb = VB2_ERROR_GBB_MAGIC;
+ retval_vb2_fw_init_gbb = VB2_ERROR_GBB_MAGIC;
TEST_EQ(vb2api_fw_phase1(&ctx), VB2_ERROR_API_PHASE1_RECOVERY,
"phase1 gbb");
TEST_EQ(sd->recovery_reason, VB2_RECOVERY_GBB_HEADER,
diff --git a/tests/vb2_misc_tests.c b/tests/vb2_misc_tests.c
index 43c97e4e..ee73da4f 100644
--- a/tests/vb2_misc_tests.c
+++ b/tests/vb2_misc_tests.c
@@ -219,13 +219,13 @@ static void gbb_tests(void)
gbbsrc.header_size--;
TEST_EQ(vb2_read_gbb_header(&ctx, &gbbdest),
VB2_ERROR_GBB_HEADER_SIZE, "read gbb header size");
- TEST_EQ(vb2_fw_parse_gbb(&ctx),
- VB2_ERROR_GBB_HEADER_SIZE, "parse gbb failure");
+ TEST_EQ(vb2_fw_init_gbb(&ctx),
+ VB2_ERROR_GBB_HEADER_SIZE, "init gbb failure");
gbbsrc.header_size++;
- /* Parse GBB */
+ /* Init GBB */
int used_before = ctx.workbuf_used;
- TEST_SUCC(vb2_fw_parse_gbb(&ctx), "parse gbb");
+ TEST_SUCC(vb2_fw_init_gbb(&ctx), "init gbb");
/* Manually calculate the location of GBB since we have mocked out the
original definition of vb2_get_gbb. */
struct vb2_gbb_header *current_gbb = vb2_member_of(sd, sd->gbb_offset);
@@ -237,8 +237,19 @@ static void gbb_tests(void)
/* Workbuf failure */
reset_common_data();
ctx.workbuf_used = ctx.workbuf_size - 4;
- TEST_EQ(vb2_fw_parse_gbb(&ctx),
- VB2_ERROR_GBB_WORKBUF, "parse gbb no workbuf");
+ TEST_EQ(vb2_fw_init_gbb(&ctx),
+ VB2_ERROR_GBB_WORKBUF, "init gbb no workbuf");
+
+ /* Check for setting NO_SECDATA_FWMP context flag */
+ reset_common_data();
+ TEST_SUCC(vb2_fw_init_gbb(&ctx), "init gbb");
+ TEST_EQ(ctx.flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0,
+ "without DISABLE_FWMP: NO_SECDATA_FWMP shouldn't be set");
+ reset_common_data();
+ gbbsrc.flags |= VB2_GBB_FLAG_DISABLE_FWMP;
+ TEST_SUCC(vb2_fw_init_gbb(&ctx), "init gbb");
+ TEST_NEQ(ctx.flags & VB2_CONTEXT_NO_SECDATA_FWMP, 0,
+ "with DISABLE_FWMP: NO_SECDATA_FWMP should be set");
}
static void fail_tests(void)
diff --git a/tests/vb2_secdata_firmware_tests.c b/tests/vb2_secdata_firmware_tests.c
index 3564cfa5..d20ee709 100644
--- a/tests/vb2_secdata_firmware_tests.c
+++ b/tests/vb2_secdata_firmware_tests.c
@@ -14,6 +14,26 @@
#include "test_common.h"
#include "vboot_common.h"
+static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
+ __attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
+static struct vb2_context ctx;
+static struct vb2_shared_data *sd;
+static struct vb2_secdata_firmware *sec;
+
+static void reset_common_data(void)
+{
+ 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);
+
+ sec = (struct vb2_secdata_firmware *)ctx.secdata_firmware;
+}
+
static void test_changed(struct vb2_context *c, int changed, const char *why)
{
if (changed)
@@ -28,118 +48,115 @@ static void test_changed(struct vb2_context *c, int changed, const char *why)
static void secdata_firmware_test(void)
{
- uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
- __attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
- struct vb2_context c = {
- .flags = 0,
- .workbuf = workbuf,
- .workbuf_size = sizeof(workbuf),
- };
- struct vb2_secdata_firmware *sec =
- (struct vb2_secdata_firmware *)c.secdata_firmware;
- struct vb2_shared_data *sd = vb2_get_sd(&c);
uint32_t v = 1;
+ reset_common_data();
/* Check size constant */
TEST_EQ(VB2_SECDATA_FIRMWARE_SIZE, sizeof(struct vb2_secdata_firmware),
"Struct size constant");
/* Blank data is invalid */
- memset(c.secdata_firmware, 0xa6, sizeof(c.secdata_firmware));
- TEST_EQ(vb2api_secdata_firmware_check(&c),
+ memset(ctx.secdata_firmware, 0xa6, sizeof(ctx.secdata_firmware));
+ TEST_EQ(vb2api_secdata_firmware_check(&ctx),
VB2_ERROR_SECDATA_FIRMWARE_CRC, "Check blank CRC");
- TEST_EQ(vb2_secdata_firmware_init(&c),
+ TEST_EQ(vb2_secdata_firmware_init(&ctx),
VB2_ERROR_SECDATA_FIRMWARE_CRC, "Init blank CRC");
/* Ensure zeroed buffers are invalid (coreboot relies on this) */
- memset(c.secdata_firmware, 0, sizeof(c.secdata_firmware));
- TEST_EQ(vb2_secdata_firmware_init(&c),
+ memset(ctx.secdata_firmware, 0, sizeof(ctx.secdata_firmware));
+ TEST_EQ(vb2_secdata_firmware_init(&ctx),
VB2_ERROR_SECDATA_FIRMWARE_VERSION,
"Zeroed buffer (invalid version)");
/* Try with bad version */
- TEST_SUCC(vb2api_secdata_firmware_create(&c), "Create");
+ TEST_EQ(vb2api_secdata_firmware_create(&ctx), VB2_SECDATA_FIRMWARE_SIZE,
+ "Create");
sec->struct_version -= 1;
sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata_firmware, crc8));
- TEST_EQ(vb2api_secdata_firmware_check(&c),
+ TEST_EQ(vb2api_secdata_firmware_check(&ctx),
VB2_ERROR_SECDATA_FIRMWARE_VERSION, "Check invalid version");
- TEST_EQ(vb2_secdata_firmware_init(&c),
+ TEST_EQ(vb2_secdata_firmware_init(&ctx),
VB2_ERROR_SECDATA_FIRMWARE_VERSION, "Init invalid version");
/* Create good data */
- TEST_SUCC(vb2api_secdata_firmware_create(&c), "Create");
- TEST_SUCC(vb2api_secdata_firmware_check(&c), "Check created CRC");
- TEST_SUCC(vb2_secdata_firmware_init(&c), "Init created CRC");
+ vb2api_secdata_firmware_create(&ctx);
+ TEST_SUCC(vb2api_secdata_firmware_check(&ctx), "Check created CRC");
+ TEST_SUCC(vb2_secdata_firmware_init(&ctx), "Init created CRC");
TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_FIRMWARE_INIT, 0,
"Init set SD status");
sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT;
- test_changed(&c, 1, "Create changes data");
+ test_changed(&ctx, 1, "Create changes data");
/* Now corrupt it */
- c.secdata_firmware[2]++;
- TEST_EQ(vb2api_secdata_firmware_check(&c),
+ ctx.secdata_firmware[2]++;
+ TEST_EQ(vb2api_secdata_firmware_check(&ctx),
VB2_ERROR_SECDATA_FIRMWARE_CRC, "Check invalid CRC");
- TEST_EQ(vb2_secdata_firmware_init(&c),
+ TEST_EQ(vb2_secdata_firmware_init(&ctx),
VB2_ERROR_SECDATA_FIRMWARE_CRC, "Init invalid CRC");
/* Read/write flags */
- vb2api_secdata_firmware_create(&c);
- vb2_secdata_firmware_init(&c);
- c.flags = 0;
- TEST_SUCC(vb2_secdata_firmware_get(&c, VB2_SECDATA_FIRMWARE_FLAGS, &v),
+ vb2api_secdata_firmware_create(&ctx);
+ vb2_secdata_firmware_init(&ctx);
+ ctx.flags = 0;
+ TEST_SUCC(vb2_secdata_firmware_get(&ctx, VB2_SECDATA_FIRMWARE_FLAGS,
+ &v),
"Get flags");
TEST_EQ(v, 0, "Flags created 0");
- test_changed(&c, 0, "Get doesn't change data");
- TEST_SUCC(vb2_secdata_firmware_set(&c, VB2_SECDATA_FIRMWARE_FLAGS,
+ test_changed(&ctx, 0, "Get doesn't change data");
+ TEST_SUCC(vb2_secdata_firmware_set(&ctx, VB2_SECDATA_FIRMWARE_FLAGS,
0x12),
"Set flags");
- test_changed(&c, 1, "Set changes data");
- TEST_SUCC(vb2_secdata_firmware_set(&c, VB2_SECDATA_FIRMWARE_FLAGS,
+ test_changed(&ctx, 1, "Set changes data");
+ TEST_SUCC(vb2_secdata_firmware_set(&ctx, VB2_SECDATA_FIRMWARE_FLAGS,
0x12),
"Set flags 2");
- test_changed(&c, 0, "Set again doesn't change data");
- TEST_SUCC(vb2_secdata_firmware_get(&c, VB2_SECDATA_FIRMWARE_FLAGS, &v),
+ test_changed(&ctx, 0, "Set again doesn't change data");
+ TEST_SUCC(vb2_secdata_firmware_get(&ctx, VB2_SECDATA_FIRMWARE_FLAGS,
+ &v),
"Get flags 2");
TEST_EQ(v, 0x12, "Flags changed");
- TEST_EQ(vb2_secdata_firmware_set(&c, VB2_SECDATA_FIRMWARE_FLAGS, 0x100),
+ TEST_EQ(vb2_secdata_firmware_set(&ctx, VB2_SECDATA_FIRMWARE_FLAGS,
+ 0x100),
VB2_ERROR_SECDATA_FIRMWARE_SET_FLAGS, "Bad flags");
/* Read/write versions */
- TEST_SUCC(vb2_secdata_firmware_get(&c, VB2_SECDATA_FIRMWARE_VERSIONS,
+ TEST_SUCC(vb2_secdata_firmware_get(&ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
&v),
"Get versions");
TEST_EQ(v, 0, "Versions created 0");
- test_changed(&c, 0, "Get doesn't change data");
- TEST_SUCC(vb2_secdata_firmware_set(&c, VB2_SECDATA_FIRMWARE_VERSIONS,
+ test_changed(&ctx, 0, "Get doesn't change data");
+ TEST_SUCC(vb2_secdata_firmware_set(&ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
0x123456ff),
"Set versions");
- test_changed(&c, 1, "Set changes data");
- TEST_SUCC(vb2_secdata_firmware_set(&c, VB2_SECDATA_FIRMWARE_VERSIONS,
+ test_changed(&ctx, 1, "Set changes data");
+ TEST_SUCC(vb2_secdata_firmware_set(&ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
0x123456ff),
"Set versions 2");
- test_changed(&c, 0, "Set again doesn't change data");
- TEST_SUCC(vb2_secdata_firmware_get(&c, VB2_SECDATA_FIRMWARE_VERSIONS, &v),
+ test_changed(&ctx, 0, "Set again doesn't change data");
+ TEST_SUCC(vb2_secdata_firmware_get(&ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
+ &v),
"Get versions 2");
TEST_EQ(v, 0x123456ff, "Versions changed");
/* Invalid field fails */
- TEST_EQ(vb2_secdata_firmware_get(&c, -1, &v),
+ TEST_EQ(vb2_secdata_firmware_get(&ctx, -1, &v),
VB2_ERROR_SECDATA_FIRMWARE_GET_PARAM, "Get invalid");
- TEST_EQ(vb2_secdata_firmware_set(&c, -1, 456),
+ TEST_EQ(vb2_secdata_firmware_set(&ctx, -1, 456),
VB2_ERROR_SECDATA_FIRMWARE_SET_PARAM, "Set invalid");
- test_changed(&c, 0, "Set invalid field doesn't change data");
+ test_changed(&ctx, 0, "Set invalid field doesn't change data");
/* Read/write uninitialized data fails */
sd->status &= ~VB2_SD_STATUS_SECDATA_FIRMWARE_INIT;
- TEST_EQ(vb2_secdata_firmware_get(&c, VB2_SECDATA_FIRMWARE_VERSIONS, &v),
+ TEST_EQ(vb2_secdata_firmware_get(&ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
+ &v),
VB2_ERROR_SECDATA_FIRMWARE_GET_UNINITIALIZED,
"Get uninitialized");
- test_changed(&c, 0, "Get uninitialized doesn't change data");
- TEST_EQ(vb2_secdata_firmware_set(&c, VB2_SECDATA_FIRMWARE_VERSIONS,
+ test_changed(&ctx, 0, "Get uninitialized doesn't change data");
+ TEST_EQ(vb2_secdata_firmware_set(&ctx, VB2_SECDATA_FIRMWARE_VERSIONS,
0x123456ff),
VB2_ERROR_SECDATA_FIRMWARE_SET_UNINITIALIZED,
"Set uninitialized");
- test_changed(&c, 0, "Set uninitialized doesn't change data");
+ test_changed(&ctx, 0, "Set uninitialized doesn't change data");
}
int main(int argc, char* argv[])
diff --git a/tests/vb2_secdata_fwmp_tests.c b/tests/vb2_secdata_fwmp_tests.c
new file mode 100644
index 00000000..06a89fdf
--- /dev/null
+++ b/tests/vb2_secdata_fwmp_tests.c
@@ -0,0 +1,242 @@
+/* Copyright 2019 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 firmware management parameters (FWMP) library.
+ */
+
+#include "2common.h"
+#include "2misc.h"
+#include "2secdata.h"
+#include "2struct.h"
+#include "test_common.h"
+
+static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
+ __attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
+static struct vb2_context ctx;
+static struct vb2_gbb_header gbb;
+static struct vb2_shared_data *sd;
+static struct vb2_secdata_fwmp *sec;
+
+static void reset_common_data(void)
+{
+ memset(workbuf, 0xaa, sizeof(workbuf));
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.workbuf = workbuf;
+ ctx.workbuf_size = sizeof(workbuf);
+ ctx.flags = 0;
+
+ vb2_init_context(&ctx);
+ sd = vb2_get_sd(&ctx);
+ sd->status = VB2_SD_STATUS_SECDATA_FWMP_INIT;
+
+ memset(&gbb, 0, sizeof(gbb));
+
+ sec = (struct vb2_secdata_fwmp *)ctx.secdata_fwmp;
+ sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE;
+ sec->struct_version = VB2_SECDATA_FWMP_VERSION;
+ sec->flags = 0;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+}
+
+/* Mocked functions */
+
+struct vb2_gbb_header *vb2_get_gbb(struct vb2_context *c)
+{
+ return &gbb;
+}
+
+static void check_init_test(void)
+{
+ uint8_t size;
+
+ /* Check size constants */
+ TEST_TRUE(sizeof(struct vb2_secdata_fwmp) >= VB2_SECDATA_FWMP_MIN_SIZE,
+ "Struct min size constant");
+ TEST_TRUE(sizeof(struct vb2_secdata_fwmp) <= VB2_SECDATA_FWMP_MAX_SIZE,
+ "Struct max size constant");
+
+ /* struct_size too large */
+ reset_common_data();
+ sec->struct_size = VB2_SECDATA_FWMP_MAX_SIZE + 1;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ size = sec->struct_size;
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_SIZE, "Check struct_size too large");
+ TEST_EQ(vb2_secdata_fwmp_init(&ctx),
+ VB2_ERROR_SECDATA_FWMP_SIZE, "Init struct_size too large");
+
+ /* struct_size too small */
+ reset_common_data();
+ sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE - 1;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ size = VB2_SECDATA_FWMP_MIN_SIZE;
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_SIZE, "Check struct_size too small");
+
+ /* Need more data to reach minimum size */
+ reset_common_data();
+ sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE - 1;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ size = 0;
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_INCOMPLETE, "Check more to reach MIN");
+ TEST_EQ(vb2_secdata_fwmp_init(&ctx),
+ VB2_ERROR_SECDATA_FWMP_INCOMPLETE, "Init more to reach MIN");
+
+ /* Need more data to reach full size */
+ reset_common_data();
+ sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE + 1;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ size = VB2_SECDATA_FWMP_MIN_SIZE;
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_INCOMPLETE, "Check more for full size");
+
+ /* Bad data is invalid */
+ reset_common_data();
+ memset(ctx.secdata_fwmp, 0xa6, sizeof(ctx.secdata_fwmp));
+ sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE;
+ size = sec->struct_size;
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_CRC, "Check bad data CRC");
+ TEST_EQ(vb2_secdata_fwmp_init(&ctx),
+ VB2_ERROR_SECDATA_FWMP_CRC, "Init bad data CRC");
+
+ /* Bad CRC with corruption past minimum size */
+ reset_common_data();
+ sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE + 1;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ size = sec->struct_size;
+ *((uint8_t *)sec + sec->struct_size - 1) += 1;
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_CRC, "Check corruption CRC");
+ TEST_EQ(vb2_secdata_fwmp_init(&ctx),
+ VB2_ERROR_SECDATA_FWMP_CRC, "Init corruption CRC");
+
+ /* Zeroed data is invalid */
+ reset_common_data();
+ memset(ctx.secdata_fwmp, 0, sizeof(ctx.secdata_fwmp));
+ sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE;
+ size = sec->struct_size;
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_VERSION, "Check zeroed data CRC");
+ TEST_EQ(vb2_secdata_fwmp_init(&ctx),
+ VB2_ERROR_SECDATA_FWMP_VERSION, "Init zeroed data CRC");
+
+ /* Major version too high */
+ reset_common_data();
+ sec->struct_version = ((VB2_SECDATA_FWMP_VERSION >> 4) + 1) << 4;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_VERSION, "Check major too high");
+ TEST_EQ(vb2_secdata_fwmp_init(&ctx),
+ VB2_ERROR_SECDATA_FWMP_VERSION, "Init major too high");
+
+ /* Major version too low */
+ reset_common_data();
+ sec->struct_version = ((VB2_SECDATA_FWMP_VERSION >> 4) - 1) << 4;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ TEST_EQ(vb2api_secdata_fwmp_check(&ctx, &size),
+ VB2_ERROR_SECDATA_FWMP_VERSION, "Check major too low");
+ TEST_EQ(vb2_secdata_fwmp_init(&ctx),
+ VB2_ERROR_SECDATA_FWMP_VERSION, "Init major too low");
+
+ /* Minor version difference okay */
+ reset_common_data();
+ sec->struct_version += 1;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ TEST_SUCC(vb2api_secdata_fwmp_check(&ctx, &size), "Check minor okay");
+ TEST_SUCC(vb2_secdata_fwmp_init(&ctx), "Init minor okay");
+
+ /* Good FWMP data at minimum size */
+ reset_common_data();
+ TEST_SUCC(vb2api_secdata_fwmp_check(&ctx, &size), "Check good (min)");
+ TEST_SUCC(vb2_secdata_fwmp_init(&ctx), "Init good (min)");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_FWMP_INIT, 0,
+ "Init flag set");
+
+ /* Good FWMP data at minimum + N size */
+ reset_common_data();
+ sec->struct_size = VB2_SECDATA_FWMP_MIN_SIZE + 1;
+ sec->crc8 = vb2_secdata_fwmp_crc(sec);
+ size = sec->struct_size;
+ TEST_SUCC(vb2api_secdata_fwmp_check(&ctx, &size), "Check good (min+N)");
+ TEST_SUCC(vb2_secdata_fwmp_init(&ctx), "Init good (min+N)");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_FWMP_INIT, 0,
+ "Init flag set");
+
+ /* Skip data check when NO_SECDATA_FWMP set */
+ reset_common_data();
+ memset(ctx.secdata_fwmp, 0xa6, sizeof(ctx.secdata_fwmp));
+ ctx.flags |= VB2_CONTEXT_NO_SECDATA_FWMP;
+ TEST_EQ(vb2_secdata_fwmp_init(&ctx), 0,
+ "Init skip data check when NO_SECDATA_FWMP set");
+ TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_FWMP_INIT, 0,
+ "Init flag set");
+}
+
+static void get_flag_test(void)
+{
+ /* Successfully returns value */
+ reset_common_data();
+ sec->flags |= 1;
+ TEST_EQ(vb2_secdata_fwmp_get_flag(&ctx, 1), 1,
+ "Successfully returns flag value");
+
+ /* NO_SECDATA_FWMP */
+ reset_common_data();
+ sec->flags |= 1;
+ ctx.flags |= VB2_CONTEXT_NO_SECDATA_FWMP;
+ TEST_EQ(vb2_secdata_fwmp_get_flag(&ctx, 1), 0,
+ "NO_SECDATA_FWMP forces default flag value");
+
+ /* FWMP hasn't been initialized (recovery mode) */
+ reset_common_data();
+ sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ ctx.flags |= VB2_CONTEXT_RECOVERY_MODE;
+ TEST_EQ(vb2_secdata_fwmp_get_flag(&ctx, 0), 0,
+ "non-init in recovery mode forces default flag value");
+
+ /* FWMP hasn't been initialized (normal mode) */
+ reset_common_data();
+ sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ TEST_ABORT(vb2_secdata_fwmp_get_flag(&ctx, 0),
+ "non-init in normal mode triggers abort");
+}
+
+static void get_dev_key_hash_test(void)
+{
+ /* CONTEXT_NO_SECDATA_FWMP */
+ reset_common_data();
+ ctx.flags |= VB2_CONTEXT_NO_SECDATA_FWMP;
+ TEST_TRUE(vb2_secdata_fwmp_get_dev_key_hash(&ctx) == NULL,
+ "NO_SECDATA_FWMP forces NULL pointer");
+
+ /* FWMP hasn't been initialized (recovery mode) */
+ reset_common_data();
+ sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ ctx.flags |= VB2_CONTEXT_RECOVERY_MODE;
+ TEST_TRUE(vb2_secdata_fwmp_get_dev_key_hash(&ctx) == NULL,
+ "non-init in recovery mode forces NULL pointer");
+
+ /* FWMP hasn't been initialized (normal mode) */
+ reset_common_data();
+ sd->status &= ~VB2_SD_STATUS_SECDATA_FWMP_INIT;
+ TEST_ABORT(vb2_secdata_fwmp_get_dev_key_hash(&ctx),
+ "non-init in normal mode triggers abort");
+
+ /* Success case */
+ reset_common_data();
+ TEST_TRUE(vb2_secdata_fwmp_get_dev_key_hash(&ctx) ==
+ sec->dev_key_hash, "proper dev_key_hash pointer returned");
+}
+
+int main(int argc, char* argv[])
+{
+ check_init_test();
+ get_flag_test();
+ get_dev_key_hash_test();
+
+ return gTestSuccess ? 0 : 255;
+}
diff --git a/tests/vb2_secdata_kernel_tests.c b/tests/vb2_secdata_kernel_tests.c
index c1ae2e16..e278b86e 100644
--- a/tests/vb2_secdata_kernel_tests.c
+++ b/tests/vb2_secdata_kernel_tests.c
@@ -14,6 +14,26 @@
#include "test_common.h"
#include "vboot_common.h"
+static uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
+ __attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
+static struct vb2_context ctx;
+static struct vb2_shared_data *sd;
+static struct vb2_secdata_kernel *sec;
+
+static void reset_common_data(void)
+{
+ 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);
+
+ sec = (struct vb2_secdata_kernel *)ctx.secdata_kernel;
+}
+
static void test_changed(struct vb2_context *c, int changed, const char *why)
{
if (changed)
@@ -26,105 +46,97 @@ static void test_changed(struct vb2_context *c, int changed, const char *why)
static void secdata_kernel_test(void)
{
- uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
- __attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
- struct vb2_context c = {
- .flags = 0,
- .workbuf = workbuf,
- .workbuf_size = sizeof(workbuf),
- };
- struct vb2_secdata_kernel *sec =
- (struct vb2_secdata_kernel *)c.secdata_kernel;
- struct vb2_shared_data *sd = vb2_get_sd(&c);
uint32_t v = 1;
+ reset_common_data();
/* Check size constant */
TEST_EQ(VB2_SECDATA_KERNEL_SIZE, sizeof(struct vb2_secdata_kernel),
"Struct size constant");
/* Blank data is invalid */
- memset(c.secdata_kernel, 0xa6, sizeof(c.secdata_kernel));
- TEST_EQ(vb2api_secdata_kernel_check(&c),
+ memset(ctx.secdata_kernel, 0xa6, sizeof(ctx.secdata_kernel));
+ TEST_EQ(vb2api_secdata_kernel_check(&ctx),
VB2_ERROR_SECDATA_KERNEL_CRC, "Check blank CRC");
- TEST_EQ(vb2_secdata_kernel_init(&c),
+ TEST_EQ(vb2_secdata_kernel_init(&ctx),
VB2_ERROR_SECDATA_KERNEL_CRC, "Init blank CRC");
/* Ensure zeroed buffers are invalid */
- memset(c.secdata_kernel, 0, sizeof(c.secdata_kernel));
- TEST_EQ(vb2_secdata_kernel_init(&c), VB2_ERROR_SECDATA_KERNEL_VERSION,
+ memset(ctx.secdata_kernel, 0, sizeof(ctx.secdata_kernel));
+ TEST_EQ(vb2_secdata_kernel_init(&ctx), VB2_ERROR_SECDATA_KERNEL_VERSION,
"Zeroed buffer (invalid version)");
/* Try with bad version */
- TEST_SUCC(vb2api_secdata_kernel_create(&c), "Create");
+ TEST_EQ(vb2api_secdata_kernel_create(&ctx), VB2_SECDATA_KERNEL_SIZE,
+ "Create");
sec->struct_version -= 1;
sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata_kernel, crc8));
- TEST_EQ(vb2api_secdata_kernel_check(&c),
+ TEST_EQ(vb2api_secdata_kernel_check(&ctx),
VB2_ERROR_SECDATA_KERNEL_VERSION, "Check invalid version");
- TEST_EQ(vb2_secdata_kernel_init(&c),
+ TEST_EQ(vb2_secdata_kernel_init(&ctx),
VB2_ERROR_SECDATA_KERNEL_VERSION, "Init invalid version");
/* Create good data */
- TEST_SUCC(vb2api_secdata_kernel_create(&c), "Create");
- TEST_SUCC(vb2api_secdata_kernel_check(&c), "Check created CRC");
- TEST_SUCC(vb2_secdata_kernel_init(&c), "Init created CRC");
+ vb2api_secdata_kernel_create(&ctx);
+ TEST_SUCC(vb2api_secdata_kernel_check(&ctx), "Check created CRC");
+ TEST_SUCC(vb2_secdata_kernel_init(&ctx), "Init created CRC");
TEST_NEQ(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT, 0,
"Init set SD status");
sd->status &= ~VB2_SD_STATUS_SECDATA_KERNEL_INIT;
- test_changed(&c, 1, "Create changes data");
+ test_changed(&ctx, 1, "Create changes data");
/* Now corrupt it */
- c.secdata_kernel[2]++;
- TEST_EQ(vb2api_secdata_kernel_check(&c),
+ ctx.secdata_kernel[2]++;
+ TEST_EQ(vb2api_secdata_kernel_check(&ctx),
VB2_ERROR_SECDATA_KERNEL_CRC, "Check invalid CRC");
- TEST_EQ(vb2_secdata_kernel_init(&c),
+ TEST_EQ(vb2_secdata_kernel_init(&ctx),
VB2_ERROR_SECDATA_KERNEL_CRC, "Init invalid CRC");
/* Make sure UID is checked */
- vb2api_secdata_kernel_create(&c);
+ vb2api_secdata_kernel_create(&ctx);
sec->uid++;
sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata_kernel, crc8));
- TEST_EQ(vb2_secdata_kernel_init(&c), VB2_ERROR_SECDATA_KERNEL_UID,
+ TEST_EQ(vb2_secdata_kernel_init(&ctx), VB2_ERROR_SECDATA_KERNEL_UID,
"Init invalid struct UID");
/* Read/write versions */
- vb2api_secdata_kernel_create(&c);
- vb2_secdata_kernel_init(&c);
- c.flags = 0;
- TEST_SUCC(vb2_secdata_kernel_get(&c, VB2_SECDATA_KERNEL_VERSIONS, &v),
+ vb2api_secdata_kernel_create(&ctx);
+ vb2_secdata_kernel_init(&ctx);
+ ctx.flags = 0;
+ TEST_SUCC(vb2_secdata_kernel_get(&ctx, VB2_SECDATA_KERNEL_VERSIONS, &v),
"Get versions");
TEST_EQ(v, 0, "Versions created 0");
- test_changed(&c, 0, "Get doesn't change data");
- TEST_SUCC(vb2_secdata_kernel_set(&c, VB2_SECDATA_KERNEL_VERSIONS,
+ test_changed(&ctx, 0, "Get doesn't change data");
+ TEST_SUCC(vb2_secdata_kernel_set(&ctx, VB2_SECDATA_KERNEL_VERSIONS,
0x123456ff),
"Set versions");
- test_changed(&c, 1, "Set changes data");
- TEST_SUCC(vb2_secdata_kernel_set(&c, VB2_SECDATA_KERNEL_VERSIONS,
+ test_changed(&ctx, 1, "Set changes data");
+ TEST_SUCC(vb2_secdata_kernel_set(&ctx, VB2_SECDATA_KERNEL_VERSIONS,
0x123456ff),
"Set versions 2");
- test_changed(&c, 0, "Set again doesn't change data");
- TEST_SUCC(vb2_secdata_kernel_get(&c, VB2_SECDATA_KERNEL_VERSIONS, &v),
+ test_changed(&ctx, 0, "Set again doesn't change data");
+ TEST_SUCC(vb2_secdata_kernel_get(&ctx, VB2_SECDATA_KERNEL_VERSIONS, &v),
"Get versions 2");
TEST_EQ(v, 0x123456ff, "Versions changed");
/* Invalid field fails */
- TEST_EQ(vb2_secdata_kernel_get(&c, -1, &v),
+ TEST_EQ(vb2_secdata_kernel_get(&ctx, -1, &v),
VB2_ERROR_SECDATA_KERNEL_GET_PARAM, "Get invalid");
- TEST_EQ(vb2_secdata_kernel_set(&c, -1, 456),
+ TEST_EQ(vb2_secdata_kernel_set(&ctx, -1, 456),
VB2_ERROR_SECDATA_KERNEL_SET_PARAM, "Set invalid");
- test_changed(&c, 0, "Set invalid field doesn't change data");
+ test_changed(&ctx, 0, "Set invalid field doesn't change data");
/* Read/write uninitialized data fails */
sd->status &= ~VB2_SD_STATUS_SECDATA_KERNEL_INIT;
- TEST_EQ(vb2_secdata_kernel_get(&c, VB2_SECDATA_KERNEL_VERSIONS, &v),
+ TEST_EQ(vb2_secdata_kernel_get(&ctx, VB2_SECDATA_KERNEL_VERSIONS, &v),
VB2_ERROR_SECDATA_KERNEL_GET_UNINITIALIZED,
"Get uninitialized");
- test_changed(&c, 0, "Get uninitialized doesn't change data");
- TEST_EQ(vb2_secdata_kernel_set(&c, VB2_SECDATA_KERNEL_VERSIONS,
+ test_changed(&ctx, 0, "Get uninitialized doesn't change data");
+ TEST_EQ(vb2_secdata_kernel_set(&ctx, VB2_SECDATA_KERNEL_VERSIONS,
0x123456ff),
VB2_ERROR_SECDATA_KERNEL_SET_UNINITIALIZED,
"Set uninitialized");
- test_changed(&c, 0, "Set uninitialized doesn't change data");
+ test_changed(&ctx, 0, "Set uninitialized doesn't change data");
}
int main(int argc, char* argv[])