diff options
author | dnojiri <dnojiri@chromium.org> | 2020-02-06 11:50:46 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-03-05 02:40:38 +0000 |
commit | 1b4affa3650261efa2684a6e551030291fe00590 (patch) | |
tree | d521bc60a7a8c212957ecbf473666ad399a2d4e3 | |
parent | 3f544bd4898383dcd4d7f44517a4e159f8924024 (diff) | |
download | vboot-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.c | 204 | ||||
-rw-r--r-- | firmware/2lib/include/2api.h | 19 | ||||
-rw-r--r-- | firmware/2lib/include/2constants.h | 8 | ||||
-rw-r--r-- | firmware/2lib/include/2return_codes.h | 9 | ||||
-rw-r--r-- | firmware/2lib/include/2secdata.h | 17 | ||||
-rw-r--r-- | firmware/2lib/include/2secdata_struct.h | 56 | ||||
-rw-r--r-- | firmware/lib/include/vboot_test.h | 11 | ||||
-rw-r--r-- | tests/vb20_api_kernel_tests.c | 2 | ||||
-rw-r--r-- | tests/vb2_secdata_kernel_tests.c | 252 |
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; } |