| /* 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 "2secdata_struct.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)); |
| TEST_SUCC(vb2api_init(workbuf, sizeof(workbuf), &ctx), |
| "vb2api_init failed"); |
| |
| 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; |
| } |