summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordnojiri <dnojiri@chromium.org>2020-02-06 11:50:46 -0800
committerCommit Bot <commit-bot@chromium.org>2020-03-05 02:40:38 +0000
commit1b4affa3650261efa2684a6e551030291fe00590 (patch)
treed521bc60a7a8c212957ecbf473666ad399a2d4e3
parent3f544bd4898383dcd4d7f44517a4e159f8924024 (diff)
downloadvboot-1b4affa3650261efa2684a6e551030291fe00590.tar.gz
Add vb2_secdata_kernel_v10
This patch adds vb2_secdata_kernel_v10. It has ec_hash field to support EFS2. The secdata kernel APIs continue to support v0.2. BUG=chromium:1045217 TEST=emerge-hatch depthcharge TEST=make runtests Change-Id: I18d5097ed799e790a2742d54c25c89a7559cbcb2 Signed-off-by: dnojiri <dnojiri@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2041695
-rw-r--r--firmware/2lib/2secdata_kernel.c204
-rw-r--r--firmware/2lib/include/2api.h19
-rw-r--r--firmware/2lib/include/2constants.h8
-rw-r--r--firmware/2lib/include/2return_codes.h9
-rw-r--r--firmware/2lib/include/2secdata.h17
-rw-r--r--firmware/2lib/include/2secdata_struct.h56
-rw-r--r--firmware/lib/include/vboot_test.h11
-rw-r--r--tests/vb20_api_kernel_tests.c2
-rw-r--r--tests/vb2_secdata_kernel_tests.c252
9 files changed, 504 insertions, 74 deletions
diff --git a/firmware/2lib/2secdata_kernel.c b/firmware/2lib/2secdata_kernel.c
index ca122ab5..f4d1b825 100644
--- a/firmware/2lib/2secdata_kernel.c
+++ b/firmware/2lib/2secdata_kernel.c
@@ -11,25 +11,54 @@
#include "2secdata.h"
#include "2secdata_struct.h"
#include "2sysincludes.h"
+#include "vboot_test.h"
-vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx)
+#define MAJOR_VER(x) (((x) & 0xf0) >> 4)
+#define MINOR_VER(x) ((x) & 0x0f)
+
+static inline int is_v0(struct vb2_context *ctx)
{
- struct vb2_secdata_kernel *sec =
- (struct vb2_secdata_kernel *)ctx->secdata_kernel;
+ struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
+ return MAJOR_VER(sec->struct_version) == 0;
+}
- /* Verify CRC */
- if (sec->crc8 != vb2_crc8(sec, offsetof(struct vb2_secdata_kernel,
- crc8))) {
- VB2_DEBUG("secdata_kernel: bad CRC\n");
- return VB2_ERROR_SECDATA_KERNEL_CRC;
+uint8_t vb2_secdata_kernel_crc(struct vb2_context *ctx)
+{
+ size_t offset, size;
+
+ if (is_v0(ctx)) {
+ offset = 0;
+ size = offsetof(struct vb2_secdata_kernel_v0, crc8);
+ } else {
+ struct vb2_secdata_kernel_v1 *sec
+ = (void *)ctx->secdata_kernel;
+ offset = offsetof(struct vb2_secdata_kernel_v1, reserved0);
+ size = sec->struct_size - offset;
}
- /* Verify version */
- if (sec->struct_version < VB2_SECDATA_KERNEL_VERSION) {
- VB2_DEBUG("secdata_firmware: version incompatible\n");
+ return vb2_crc8(ctx->secdata_kernel + offset, size);
+}
+
+static vb2_error_t secdata_kernel_check_v0(struct vb2_context *ctx,
+ uint8_t *size)
+{
+ struct vb2_secdata_kernel_v0 *sec = (void *)ctx->secdata_kernel;
+ uint8_t ver = sec->struct_version;
+
+ if (MINOR_VER(ver) != MINOR_VER(VB2_SECDATA_KERNEL_VERSION_V02)) {
+ VB2_DEBUG("secdata_kernel: bad struct_version (%d.%d)\n",
+ MAJOR_VER(ver), MINOR_VER(ver));
return VB2_ERROR_SECDATA_KERNEL_VERSION;
}
+ *size = VB2_SECDATA_KERNEL_SIZE_V02;
+
+ /* Verify CRC */
+ if (sec->crc8 != vb2_secdata_kernel_crc(ctx)) {
+ VB2_DEBUG("secdata_kernel: bad CRC\n");
+ return VB2_ERROR_SECDATA_KERNEL_CRC;
+ }
+
/* Verify UID */
if (sec->uid != VB2_SECDATA_KERNEL_UID) {
VB2_DEBUG("secdata_kernel: bad UID\n");
@@ -39,22 +68,93 @@ vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx)
return VB2_SUCCESS;
}
+static vb2_error_t secdata_kernel_check_v1(struct vb2_context *ctx,
+ uint8_t *size)
+{
+ struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
+ uint8_t ver = sec->struct_version;
+
+ if (MAJOR_VER(ver) != MAJOR_VER(VB2_SECDATA_KERNEL_VERSION_V10)) {
+ VB2_DEBUG("secdata_kernel: bad struct_version (%d.%d)\n",
+ MAJOR_VER(ver), MINOR_VER(ver));
+ return VB2_ERROR_SECDATA_KERNEL_VERSION;
+ }
+
+ if (sec->struct_size < VB2_SECDATA_KERNEL_SIZE_V10 ||
+ VB2_SECDATA_KERNEL_MAX_SIZE < sec->struct_size) {
+ VB2_DEBUG("secdata_kernel: bad struct_size (%d)\n",
+ sec->struct_size);
+ return VB2_ERROR_SECDATA_KERNEL_STRUCT_SIZE;
+ }
+
+ if (*size < sec->struct_size) {
+ *size = sec->struct_size;
+ VB2_DEBUG("secdata_kernel: incomplete data (missing %d bytes)",
+ sec->struct_size - *size);
+ return VB2_ERROR_SECDATA_KERNEL_INCOMPLETE;
+ }
+
+ /*
+ * In case larger data should be passed, kindly let the caller know
+ * the right size.
+ */
+ *size = sec->struct_size;
+
+ /* Verify CRC */
+ if (sec->crc8 != vb2_secdata_kernel_crc(ctx)) {
+ VB2_DEBUG("secdata_kernel: bad CRC\n");
+ return VB2_ERROR_SECDATA_KERNEL_CRC;
+ }
+
+ return VB2_SUCCESS;
+}
+
+vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx, uint8_t *size)
+{
+ if (*size < VB2_SECDATA_KERNEL_MIN_SIZE) {
+ VB2_DEBUG("secdata_kernel: data size too small!");
+ *size = VB2_SECDATA_KERNEL_MIN_SIZE;
+ return VB2_ERROR_SECDATA_KERNEL_INCOMPLETE;
+ }
+
+ if (is_v0(ctx))
+ return secdata_kernel_check_v0(ctx, size);
+ else
+ return secdata_kernel_check_v1(ctx, size);
+}
+
uint32_t vb2api_secdata_kernel_create(struct vb2_context *ctx)
{
- struct vb2_secdata_kernel *sec =
- (struct vb2_secdata_kernel *)ctx->secdata_kernel;
+ struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
+
+ /* Populate the struct */
+ memset(sec, 0, sizeof(*sec));
+ sec->struct_version = VB2_SECDATA_KERNEL_VERSION_LATEST;
+ sec->struct_size = sizeof(*sec);
+ sec->crc8 = vb2_secdata_kernel_crc(ctx);
+
+ /* Mark as changed */
+ ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
+
+ return sizeof(*sec);
+}
+
+/* For TPM 1.2 */
+uint32_t vb2api_secdata_kernel_create_v0(struct vb2_context *ctx)
+{
+ struct vb2_secdata_kernel_v0 *sec = (void *)ctx->secdata_kernel;
/* Clear the entire struct */
memset(sec, 0, sizeof(*sec));
/* Set to current version */
- sec->struct_version = VB2_SECDATA_KERNEL_VERSION;
+ sec->struct_version = VB2_SECDATA_KERNEL_VERSION_V02;
/* Set UID */
sec->uid = VB2_SECDATA_KERNEL_UID;
/* Calculate initial CRC */
- sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata_kernel, crc8));
+ sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata_kernel_v0, crc8));
/* Mark as changed */
ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
@@ -65,9 +165,10 @@ uint32_t vb2api_secdata_kernel_create(struct vb2_context *ctx)
vb2_error_t vb2_secdata_kernel_init(struct vb2_context *ctx)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
+ uint8_t size = VB2_SECDATA_KERNEL_MAX_SIZE;
vb2_error_t rv;
- rv = vb2api_secdata_kernel_check(ctx);
+ rv = vb2api_secdata_kernel_check(ctx, &size);
if (rv)
return rv;
@@ -81,8 +182,6 @@ uint32_t vb2_secdata_kernel_get(struct vb2_context *ctx,
enum vb2_secdata_kernel_param param)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
- struct vb2_secdata_kernel *sec =
- (struct vb2_secdata_kernel *)ctx->secdata_kernel;
const char *msg;
if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT)) {
@@ -92,8 +191,15 @@ uint32_t vb2_secdata_kernel_get(struct vb2_context *ctx,
switch (param) {
case VB2_SECDATA_KERNEL_VERSIONS:
- return sec->kernel_versions;
-
+ if (is_v0(ctx)) {
+ struct vb2_secdata_kernel_v0 *sec =
+ (void *)ctx->secdata_kernel;
+ return sec->kernel_versions;
+ } else {
+ struct vb2_secdata_kernel_v1 *sec =
+ (void *)ctx->secdata_kernel;
+ return sec->kernel_versions;
+ }
default:
msg = "invalid param";
}
@@ -108,9 +214,10 @@ void vb2_secdata_kernel_set(struct vb2_context *ctx,
uint32_t value)
{
struct vb2_shared_data *sd = vb2_get_sd(ctx);
- struct vb2_secdata_kernel *sec =
- (struct vb2_secdata_kernel *)ctx->secdata_kernel;
const char *msg;
+ struct vb2_secdata_kernel_v0 *v0 = (void *)ctx->secdata_kernel;
+ struct vb2_secdata_kernel_v1 *v1 = (void *)ctx->secdata_kernel;
+ uint32_t *ptr;
if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT)) {
msg = "set before init";
@@ -123,9 +230,9 @@ void vb2_secdata_kernel_set(struct vb2_context *ctx,
switch (param) {
case VB2_SECDATA_KERNEL_VERSIONS:
+ ptr = is_v0(ctx) ? &v0->kernel_versions : &v1->kernel_versions;
VB2_DEBUG("secdata_kernel versions updated from %#x to %#x\n",
- sec->kernel_versions, value);
- sec->kernel_versions = value;
+ *ptr, value);
break;
default:
@@ -133,11 +240,56 @@ void vb2_secdata_kernel_set(struct vb2_context *ctx,
goto fail;
}
- /* Regenerate CRC */
- sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata_kernel, crc8));
+ *ptr = value;
+
+ if (is_v0(ctx))
+ v0->crc8 = vb2_secdata_kernel_crc(ctx);
+ else
+ v1->crc8 = vb2_secdata_kernel_crc(ctx);
+
ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
return;
fail:
VB2_REC_OR_DIE(ctx, "%s\n", msg);
}
+
+const uint8_t *vb2_secdata_kernel_get_ec_hash(struct vb2_context *ctx)
+{
+ struct vb2_shared_data *sd = vb2_get_sd(ctx);
+ struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
+
+ if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT)) {
+ VB2_REC_OR_DIE(ctx, "Get kernel secdata before init\n");
+ return NULL;
+ }
+ if (is_v0(ctx)) {
+ VB2_DEBUG("kernel secdata v.0* doesn't support EC hash\n");
+ return NULL;
+ }
+
+ return sec->ec_hash;
+}
+
+void vb2_secdata_kernel_set_ec_hash(struct vb2_context *ctx,
+ const uint8_t *sha256)
+{
+ struct vb2_shared_data *sd = vb2_get_sd(ctx);
+ struct vb2_secdata_kernel_v1 *sec = (void *)ctx->secdata_kernel;
+
+ if (!(sd->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT)) {
+ VB2_REC_OR_DIE(ctx, "Get kernel secdata before init\n");
+ return;
+ }
+ if (is_v0(ctx)) {
+ VB2_REC_OR_DIE(ctx, "Invalid version of kernel secdata\n");
+ return;
+ }
+
+ memcpy(sec->ec_hash, sha256, sizeof(sec->ec_hash));
+ sec->crc8 = vb2_secdata_kernel_crc(ctx);
+
+ ctx->flags |= VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
+
+ return;
+}
diff --git a/firmware/2lib/include/2api.h b/firmware/2lib/include/2api.h
index af504584..9bd07297 100644
--- a/firmware/2lib/include/2api.h
+++ b/firmware/2lib/include/2api.h
@@ -26,6 +26,7 @@
#include "2id.h"
#include "2recovery_reasons.h"
#include "2return_codes.h"
+#include "2secdata_struct.h"
/* Modes for vb2ex_tpm_set_mode. */
enum vb2_tpm_mode {
@@ -252,8 +253,8 @@ struct vb2_context {
* 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];
- VB2_PAD_STRUCT(VB2_SECDATA_KERNEL_SIZE, 8);
+ uint8_t secdata_kernel[VB2_SECDATA_KERNEL_MAX_SIZE];
+ VB2_PAD_STRUCT(VB2_SECDATA_KERNEL_MAX_SIZE, 8);
/*
* Firmware management parameters (FWMP) secure data. Caller must fill
@@ -506,14 +507,18 @@ vb2_error_t vb2api_secdata_firmware_check(struct vb2_context *ctx);
uint32_t vb2api_secdata_firmware_create(struct vb2_context *ctx);
/**
- * Check the validity of kernel secure storage context.
+ * Check the validity of kernel secure storage context (ctx->secdata_kernel).
*
* Checks version, UID, and CRC.
*
* @param ctx Context pointer
- * @return VB2_SUCCESS, or non-zero error code if error.
+ * @param size (IN) Size of data to be checked
+ * (OUT) Expected size of data
+ * @return VB2_SUCCESS, or non-zero error code if error. If data is missing,
+ * it returns VB2_ERROR_SECDATA_KERNEL_INCOMPLETE and informs the caller
+ * of the expected size.
*/
-vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx);
+vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx, uint8_t *size);
/**
* Create fresh data in kernel secure storage context.
@@ -523,10 +528,14 @@ vb2_error_t vb2api_secdata_kernel_check(struct vb2_context *ctx);
* vb2api_secdata_kernel_check() (or any other API in this library) fails; that
* could allow the secure data to be rolled back to an insecure state.
*
+ * vb2api_secdata_kernel_create always creates secdata kernel using the latest
+ * revision.
+ *
* @param ctx Context pointer
* @return size of created kernel secure storage data in bytes
*/
uint32_t vb2api_secdata_kernel_create(struct vb2_context *ctx);
+uint32_t vb2api_secdata_kernel_create_v0(struct vb2_context *ctx);
/**
* Check the validity of firmware management parameters (FWMP) space.
diff --git a/firmware/2lib/include/2constants.h b/firmware/2lib/include/2constants.h
index 47e121a0..96dc9995 100644
--- a/firmware/2lib/include/2constants.h
+++ b/firmware/2lib/include/2constants.h
@@ -23,10 +23,16 @@
/* Size of secure data spaces used by vboot */
#define VB2_SECDATA_FIRMWARE_SIZE 10
-#define VB2_SECDATA_KERNEL_SIZE 13
+#define VB2_SECDATA_KERNEL_SIZE_V02 13
+#define VB2_SECDATA_KERNEL_SIZE_V10 40
+#define VB2_SECDATA_KERNEL_MIN_SIZE 13
+#define VB2_SECDATA_KERNEL_MAX_SIZE 64
#define VB2_SECDATA_FWMP_MIN_SIZE 40
#define VB2_SECDATA_FWMP_MAX_SIZE 64
+/* Size of current secdata_kernel revision. Referenced by external projects. */
+#define VB2_SECDATA_KERNEL_SIZE VB2_SECDATA_KERNEL_SIZE_V10
+
/*
* Recommended size of work buffer for firmware verification stage.
*
diff --git a/firmware/2lib/include/2return_codes.h b/firmware/2lib/include/2return_codes.h
index 9f42205b..5e5e5266 100644
--- a/firmware/2lib/include/2return_codes.h
+++ b/firmware/2lib/include/2return_codes.h
@@ -244,6 +244,15 @@ enum vb2_return_code {
/* Error reading secdata_fwmp from storage backend */
VB2_ERROR_SECDATA_FWMP_READ,
+ /* Bad buffer size to read vb2_secdata_kernel */
+ VB2_ERROR_SECDATA_KERNEL_BUFFER_SIZE,
+
+ /* Incomplete structure in vb2api_secdata_kernel_check() */
+ VB2_ERROR_SECDATA_KERNEL_INCOMPLETE,
+
+ /* Bad struct size in vb2_secdata_kernel */
+ VB2_ERROR_SECDATA_KERNEL_STRUCT_SIZE,
+
/**********************************************************************
* Common code errors
*/
diff --git a/firmware/2lib/include/2secdata.h b/firmware/2lib/include/2secdata.h
index 6f9b2816..96e21f76 100644
--- a/firmware/2lib/include/2secdata.h
+++ b/firmware/2lib/include/2secdata.h
@@ -114,6 +114,23 @@ void vb2_secdata_kernel_set(struct vb2_context *ctx,
enum vb2_secdata_kernel_param param,
uint32_t value);
+/**
+ * Get ec_hash from kernel secure storage.
+ *
+ * @param ctx Context pointer
+ * @return Buffer where hash is stored or NULL on error.
+ */
+const uint8_t *vb2_secdata_kernel_get_ec_hash(struct vb2_context *ctx);
+
+/**
+ * Set ec_hash in kernel secure storage.
+ *
+ * @param ctx Context pointer
+ * @param sha256 Hash to be set. 32 bytes.
+ */
+void vb2_secdata_kernel_set_ec_hash(struct vb2_context *ctx,
+ const uint8_t *sha256);
+
/*****************************************************************************/
/* Firmware management parameters (FWMP) space */
diff --git a/firmware/2lib/include/2secdata_struct.h b/firmware/2lib/include/2secdata_struct.h
index 7a835dd7..d8b5340f 100644
--- a/firmware/2lib/include/2secdata_struct.h
+++ b/firmware/2lib/include/2secdata_struct.h
@@ -8,7 +8,9 @@
#ifndef VBOOT_REFERENCE_2SECDATA_STRUCT_H_
#define VBOOT_REFERENCE_2SECDATA_STRUCT_H_
+#include "2constants.h"
#include "2crc8.h"
+#include "2sha.h"
#include "2sysincludes.h"
/*****************************************************************************/
@@ -34,15 +36,26 @@ struct vb2_secdata_firmware {
} __attribute__((packed));
/*****************************************************************************/
-/* Kernel secure storage space */
+/* Kernel secure storage space
+ *
+ * We'll never convert v0.2 to v1.* or the other way. v0.2 or v1.* data will be
+ * passed around between AP and TPM without upgrade or downgrade.
+ *
+ * 1. Old BIOS on old device will read/write v0.2 data from/to TPM.
+ * 2. New BIOS on old device will read/write v0.2 data from/to TPM.
+ * 3. Old BIOS on new device will read/write v0.2 data from/to TPM.
+ * 4. New BIOS on new device will read/write v1.0 data from/to TPM.
+ */
/* Kernel space - KERNEL_NV_INDEX, locked with physical presence. */
-#define VB2_SECDATA_KERNEL_VERSION 2
+#define VB2_SECDATA_KERNEL_VERSION_V02 (0 << 4 | 2 << 0) /* 0.2 */
+#define VB2_SECDATA_KERNEL_VERSION_V10 (1 << 4 | 0 << 0) /* 1.0 */
+#define VB2_SECDATA_KERNEL_VERSION_LATEST VB2_SECDATA_KERNEL_VERSION_V10
#define VB2_SECDATA_KERNEL_UID 0x4752574c /* 'LWRG' */
-struct vb2_secdata_kernel {
+struct vb2_secdata_kernel_v0 {
/* Struct version, for backwards compatibility */
- uint8_t struct_version;
+ uint8_t struct_version; /* 0.2 (or 0x02 in v0 format) */
/* Unique ID to detect space redefinition */
uint32_t uid;
@@ -56,6 +69,41 @@ struct vb2_secdata_kernel {
/* CRC; must be last field in struct */
uint8_t crc8;
} __attribute__((packed));
+_Static_assert(sizeof(struct vb2_secdata_kernel_v0)
+ == VB2_SECDATA_KERNEL_SIZE_V02,
+ "VB2_SECDATA_KERNEL_SIZE_V02 incorrect");
+_Static_assert(sizeof(struct vb2_secdata_kernel_v0)
+ < VB2_SECDATA_KERNEL_MAX_SIZE,
+ "VB2_SECDATA_KERNEL_SIZE_V02 exceeds max size");
+
+/*
+ * Secdata kernel v1.* series.
+ */
+struct vb2_secdata_kernel_v1 {
+ /* Struct version, for backwards compatibility */
+ uint8_t struct_version; /* 1.0 (or 0x10 in v0 format) */
+
+ /* Size of the struct */
+ uint8_t struct_size;
+
+ /* 8-bit CRC for everything below */
+ uint8_t crc8;
+
+ /* Reserved for future expansion */
+ uint8_t reserved0;
+
+ /* Kernel versions */
+ uint32_t kernel_versions;
+
+ /* EC hash used for EFS2 */
+ uint8_t ec_hash[VB2_SHA256_DIGEST_SIZE];
+};
+_Static_assert(sizeof(struct vb2_secdata_kernel_v1)
+ == VB2_SECDATA_KERNEL_SIZE_V10,
+ "VB2_SECDATA_KERNEL_SIZE_V10 incorrect");
+_Static_assert(sizeof(struct vb2_secdata_kernel_v1)
+ < VB2_SECDATA_KERNEL_MAX_SIZE,
+ "VB2_SECDATA_KERNEL_SIZE_V10 exceeds max size");
/*****************************************************************************/
/* Firmware management parameters (FWMP) space */
diff --git a/firmware/lib/include/vboot_test.h b/firmware/lib/include/vboot_test.h
index 1f0a6629..35a3451a 100644
--- a/firmware/lib/include/vboot_test.h
+++ b/firmware/lib/include/vboot_test.h
@@ -29,4 +29,15 @@ vb2_error_t vb2_check_padding(const uint8_t *sig,
struct LoadKernelParams;
struct LoadKernelParams *VbApiKernelGetParams(void);
+/****************************************************************************
+ * 2secdata_kernel.c */
+
+/**
+ * Calculate crc8 of kernel secure storage.
+ *
+ * @param ctx Context pointer
+ * @return Calculated crc8 value.
+ */
+uint8_t vb2_secdata_kernel_crc(struct vb2_context *ctx);
+
#endif /* VBOOT_REFERENCE_TEST_API_H_ */
diff --git a/tests/vb20_api_kernel_tests.c b/tests/vb20_api_kernel_tests.c
index 11f58817..dad612f0 100644
--- a/tests/vb20_api_kernel_tests.c
+++ b/tests/vb20_api_kernel_tests.c
@@ -277,7 +277,7 @@ static void phase1_tests(void)
/* Bad secdata_kernel causes failure in normal mode only */
reset_common_data(FOR_PHASE1);
- ctx->secdata_kernel[0] ^= 0x33;
+ ctx->secdata_kernel[2] ^= 0x33; /* 3rd byte is CRC */
TEST_EQ(vb2api_kernel_phase1(ctx), VB2_ERROR_SECDATA_KERNEL_CRC,
"phase1 bad secdata_kernel");
TEST_EQ(vb2_nv_get(ctx, VB2_NV_RECOVERY_REQUEST),
diff --git a/tests/vb2_secdata_kernel_tests.c b/tests/vb2_secdata_kernel_tests.c
index d141c876..06f8474b 100644
--- a/tests/vb2_secdata_kernel_tests.c
+++ b/tests/vb2_secdata_kernel_tests.c
@@ -13,12 +13,14 @@
#include "2secdata_struct.h"
#include "2sysincludes.h"
#include "test_common.h"
+#include "vboot_test.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 struct vb2_secdata_kernel_v0 *sec02;
+static struct vb2_secdata_kernel_v1 *sec10;
static void reset_common_data(void)
{
@@ -28,7 +30,16 @@ static void reset_common_data(void)
sd = vb2_get_sd(ctx);
- sec = (struct vb2_secdata_kernel *)ctx->secdata_kernel;
+ sec02 = (struct vb2_secdata_kernel_v0 *)ctx->secdata_kernel;
+ sec10 = (struct vb2_secdata_kernel_v1 *)ctx->secdata_kernel;
+}
+
+static void test_init(struct vb2_shared_data *s, int init, const char *why)
+{
+ if (init)
+ TEST_NEQ(s->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT, 0, why);
+ else
+ TEST_EQ(s->status & VB2_SD_STATUS_SECDATA_KERNEL_INIT, 0, why);
}
static void test_changed(struct vb2_context *c, int changed, const char *why)
@@ -39,62 +50,155 @@ static void test_changed(struct vb2_context *c, int changed, const char *why)
TEST_EQ(c->flags & VB2_CONTEXT_SECDATA_KERNEL_CHANGED, 0, why);
c->flags &= ~VB2_CONTEXT_SECDATA_KERNEL_CHANGED;
-};
+}
+/*
+ * Version-independent tests
+ */
static void secdata_kernel_test(void)
{
- uint32_t v = 1;
- reset_common_data();
+ uint8_t size;
- /* Check size constant */
- TEST_EQ(VB2_SECDATA_KERNEL_SIZE, sizeof(struct vb2_secdata_kernel),
- "Struct size constant");
+ reset_common_data();
/* Blank data is invalid */
- memset(&ctx->secdata_kernel, 0xa6, sizeof(ctx->secdata_kernel));
- TEST_EQ(vb2api_secdata_kernel_check(ctx),
- VB2_ERROR_SECDATA_KERNEL_CRC, "Check blank CRC");
+ size = VB2_SECDATA_KERNEL_MIN_SIZE;
+ memset(&ctx->secdata_kernel, 0xa6, size);
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
+ VB2_ERROR_SECDATA_KERNEL_VERSION, "Check blank bad version");
TEST_EQ(vb2_secdata_kernel_init(ctx),
- VB2_ERROR_SECDATA_KERNEL_CRC, "Init blank CRC");
+ VB2_ERROR_SECDATA_KERNEL_VERSION, "Init blank bad version");
+ test_init(sd, 0, "Init set SD status");
/* Ensure zeroed buffers are invalid */
- 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_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(ctx),
+ size = VB2_SECDATA_KERNEL_MIN_SIZE;
+ memset(&ctx->secdata_kernel, 0, size);
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
+ VB2_ERROR_SECDATA_KERNEL_VERSION, "Check zero bad version");
+ TEST_EQ(vb2_secdata_kernel_init(ctx),
+ VB2_ERROR_SECDATA_KERNEL_VERSION, "Init zero incomplete");
+ test_init(sd, 0, "Init set SD status");
+
+ /* Read data less than minimum size */
+ size = VB2_SECDATA_KERNEL_MIN_SIZE - 1;
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
+ VB2_ERROR_SECDATA_KERNEL_INCOMPLETE, "Check incomplete");
+ TEST_EQ(size, VB2_SECDATA_KERNEL_MIN_SIZE, "Return minimum size");
+}
+
+static void secdata_kernel_test_v10(void)
+{
+ uint8_t size;
+
+ reset_common_data();
+
+ /* Create good data */
+ size = VB2_SECDATA_KERNEL_SIZE_V10;
+ TEST_EQ(vb2api_secdata_kernel_create(ctx),
+ VB2_SECDATA_KERNEL_SIZE_V10, "Create v1.0");
+ TEST_SUCC(vb2api_secdata_kernel_check(ctx, &size), "Check created CRC");
+ TEST_SUCC(vb2_secdata_kernel_init(ctx), "Init created CRC");
+ test_init(sd, 1, "Init set SD status");
+ test_changed(ctx, 1, "Create changes data");
+
+ /* Check excessive data */
+ size = VB2_SECDATA_KERNEL_SIZE_V10 + 1;
+ TEST_SUCC(vb2api_secdata_kernel_check(ctx, &size),
+ "Check large v1.0 data");
+ TEST_EQ(size, VB2_SECDATA_KERNEL_SIZE_V10, "Return expected size");
+
+ /* Check incomplete data */
+ size = VB2_SECDATA_KERNEL_SIZE_V10 - 1;
+ vb2api_secdata_kernel_create(ctx);
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
+ VB2_ERROR_SECDATA_KERNEL_INCOMPLETE, "Check incomplete");
+ TEST_EQ(size, VB2_SECDATA_KERNEL_SIZE_V10, "Return expected size");
+
+ reset_common_data();
+
+ /* Bad version */
+ size = VB2_SECDATA_KERNEL_SIZE_V10;
+ vb2api_secdata_kernel_create(ctx);
+ sec10->struct_version -= 1;
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
VB2_ERROR_SECDATA_KERNEL_VERSION, "Check invalid version");
TEST_EQ(vb2_secdata_kernel_init(ctx),
VB2_ERROR_SECDATA_KERNEL_VERSION, "Init invalid version");
+ test_init(sd, 0, "Init set SD status");
- /* Create good data */
+ /* Higher minor version */
+ vb2api_secdata_kernel_create(ctx);
+ sec10->struct_version += 1;
+ TEST_SUCC(vb2api_secdata_kernel_check(ctx, &size), "Check v1.1 data");
+ TEST_SUCC(vb2_secdata_kernel_init(ctx), "Init v1.1 data");
+ test_init(sd, 1, "Init set SD status");
+
+ reset_common_data();
+
+ /* Higher major version */
vb2api_secdata_kernel_create(ctx);
- TEST_SUCC(vb2api_secdata_kernel_check(ctx), "Check created CRC");
+ sec10->struct_version += 0x10;
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
+ VB2_ERROR_SECDATA_KERNEL_VERSION, "Check v2.0 data");
+ TEST_EQ(vb2_secdata_kernel_init(ctx),
+ VB2_ERROR_SECDATA_KERNEL_VERSION, "Init v2.0 data");
+ test_init(sd, 0, "Init set SD status");
+
+ reset_common_data();
+
+ /* Corrupt data */
+ size = VB2_SECDATA_KERNEL_SIZE_V10;
+ vb2api_secdata_kernel_create(ctx);
+ sec10->kernel_versions++;
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
+ VB2_ERROR_SECDATA_KERNEL_CRC, "Check invalid CRC");
+ TEST_EQ(vb2_secdata_kernel_init(ctx),
+ VB2_ERROR_SECDATA_KERNEL_CRC, "Init invalid CRC");
+ test_init(sd, 0, "Init set SD status");
+}
+
+static void secdata_kernel_test_v02(void)
+{
+ uint8_t size;
+
+ reset_common_data();
+
+ /* Create good data */
+ size = VB2_SECDATA_KERNEL_SIZE_V02;
+ TEST_EQ(vb2api_secdata_kernel_create_v0(ctx), size, "Create v0.2");
+ TEST_SUCC(vb2api_secdata_kernel_check(ctx, &size), "Check v0.2");
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(ctx, 1, "Create changes data");
+ test_init(sd, 1, "Init set SD status");
+
+ /* Check excessive data */
+ size = VB2_SECDATA_KERNEL_SIZE_V02 + 1;
+ TEST_SUCC(vb2api_secdata_kernel_check(ctx, &size),
+ "Check large v0.2 data");
+ TEST_EQ(size, VB2_SECDATA_KERNEL_SIZE_V02, "Return expected size");
- /* Now corrupt it */
- ctx->secdata_kernel[2]++;
- TEST_EQ(vb2api_secdata_kernel_check(ctx),
+ /* Check incomplete data */
+ size = VB2_SECDATA_KERNEL_SIZE_V02 - 1;
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
+ VB2_ERROR_SECDATA_KERNEL_INCOMPLETE, "Check small v0.2 data");
+ TEST_EQ(size, VB2_SECDATA_KERNEL_SIZE_V02, "Return expected size");
+ reset_common_data();
+
+ /* Corrupt data */
+ vb2api_secdata_kernel_create_v0(ctx);
+ sec02->kernel_versions++;
+ TEST_EQ(vb2api_secdata_kernel_check(ctx, &size),
VB2_ERROR_SECDATA_KERNEL_CRC, "Check invalid CRC");
TEST_EQ(vb2_secdata_kernel_init(ctx),
VB2_ERROR_SECDATA_KERNEL_CRC, "Init invalid CRC");
+}
- /* Make sure UID is checked */
+static void secdata_kernel_access_test_v10(void)
+{
+ uint32_t v = 1;
+ const uint8_t *p;
+ uint8_t ec_hash[VB2_SHA256_DIGEST_SIZE];
- vb2api_secdata_kernel_create(ctx);
- sec->uid++;
- sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata_kernel, crc8));
- TEST_EQ(vb2_secdata_kernel_init(ctx), VB2_ERROR_SECDATA_KERNEL_UID,
- "Init invalid struct UID");
+ reset_common_data();
/* Read/write versions */
vb2api_secdata_kernel_create(ctx);
@@ -124,11 +228,85 @@ static void secdata_kernel_test(void)
0x123456ff),
"Set uninitialized");
test_changed(ctx, 0, "Set uninitialized doesn't change data");
+
+ /* Test EC hash set */
+ vb2api_secdata_kernel_create(ctx);
+ vb2_secdata_kernel_init(ctx);
+ memset(ec_hash, 0xaa, sizeof(ec_hash));
+ vb2_secdata_kernel_set_ec_hash(ctx, ec_hash);
+ TEST_EQ(memcmp(ec_hash, sec10->ec_hash, sizeof(ec_hash)), 0,
+ "Check EC hash");
+ test_changed(ctx, 1, "Set EC hash changes data");
+
+ sec10->struct_version = VB2_SECDATA_KERNEL_VERSION_V02;
+ TEST_ABORT(vb2_secdata_kernel_set_ec_hash(ctx, ec_hash),
+ "Can't set EC hash for v0.2");
+ test_changed(ctx, 0, "Failing to set EC hash doesn't change data");
+ sec10->struct_version = VB2_SECDATA_KERNEL_VERSION_V10;
+
+ sd->status &= ~VB2_SD_STATUS_SECDATA_KERNEL_INIT;
+ TEST_ABORT(vb2_secdata_kernel_set_ec_hash(ctx, ec_hash),
+ "Can't set EC hash before init");
+ sd->status |= VB2_SD_STATUS_SECDATA_KERNEL_INIT;
+
+ /* Test EC hash get */
+ p = vb2_secdata_kernel_get_ec_hash(ctx);
+ TEST_PTR_EQ(p, sec10->ec_hash, "Get EC hash returns pointer");
+ test_changed(ctx, 0, "Get EC hash doesn't change data");
+
+ sec10->struct_version = VB2_SECDATA_KERNEL_VERSION_V02;
+ TEST_PTR_EQ(vb2_secdata_kernel_get_ec_hash(ctx), NULL,
+ "Can't get EC hash for v0.2");
+ sec10->struct_version = VB2_SECDATA_KERNEL_VERSION_V10;
+
+ sd->status &= ~VB2_SD_STATUS_SECDATA_KERNEL_INIT;
+ TEST_ABORT(vb2_secdata_kernel_get_ec_hash(ctx),
+ "Can't get EC hash before init");
+ sd->status |= VB2_SD_STATUS_SECDATA_KERNEL_INIT;
+}
+
+static void secdata_kernel_access_test_v02(void)
+{
+ uint32_t v = 1;
+ reset_common_data();
+
+ /* Read/write versions */
+ vb2api_secdata_kernel_create_v0(ctx);
+ vb2_secdata_kernel_init(ctx);
+ ctx->flags = 0;
+ v = vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS);
+ TEST_EQ(v, 0, "Versions created 0");
+ test_changed(ctx, 0, "Get doesn't change data");
+ vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, 0x123456ff);
+ test_changed(ctx, 1, "Set changes data");
+ vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS, 0x123456ff);
+ test_changed(ctx, 0, "Set again doesn't change data");
+ v = vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS);
+ TEST_EQ(v, 0x123456ff, "Versions changed");
+
+ /* Invalid field fails */
+ TEST_ABORT(vb2_secdata_kernel_get(ctx, -1), "Get invalid");
+ TEST_ABORT(vb2_secdata_kernel_set(ctx, -1, 456), "Set invalid");
+ 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_ABORT(vb2_secdata_kernel_get(ctx, VB2_SECDATA_KERNEL_VERSIONS),
+ "Get uninitialized");
+ test_changed(ctx, 0, "Get uninitialized doesn't change data");
+ TEST_ABORT(vb2_secdata_kernel_set(ctx, VB2_SECDATA_KERNEL_VERSIONS,
+ 0x123456ff),
+ "Set uninitialized");
+ test_changed(ctx, 0, "Set uninitialized doesn't change data");
}
int main(int argc, char* argv[])
{
secdata_kernel_test();
+ secdata_kernel_test_v10();
+ secdata_kernel_test_v02();
+ secdata_kernel_access_test_v10();
+ secdata_kernel_access_test_v02();
return gTestSuccess ? 0 : 255;
}