Files
OpenCellular/tests/vb21_api_tests.c
Randall Spangler 1a5e02c7a9 firmware: Align workbuf used size
Previously, workbuf used was not rounded up to a multiple of
VB2_WORKBUF_ALIGN.  The next allocation would be aligned, but not
until it was made.

Change this to round up used size when more workbuf is used.  This
provides better predictability of where the next allocation will be
placed.

Uncovered this problem when I added a new member to vb2_shared_data
which changed its size so it wasn't a multiple of VB2_WORKBUF_ALIGN,
and the vb20 and vb21 unit tests which tried to simulate not enough
buffer broke in strange ways.

BUG=chromium:611535
BRANCH=none
TEST=make -j runtests; build bob firmware and boot it

Change-Id: I0157a1c96326f7fce6be6efbd74d90c3d2942268
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/852488
Reviewed-by: Shelley Chen <shchen@chromium.org>
2018-01-05 21:14:12 -08:00

382 lines
10 KiB
C

/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* Tests for api library, new style structs
*/
#include <stdio.h>
#include "2sysincludes.h"
#include "2api.h"
#include "2common.h"
#include "2misc.h"
#include "2nvstorage.h"
#include "2rsa.h"
#include "2secdata.h"
#include "vb21_common.h"
#include "host_key2.h"
#include "host_signature2.h"
#include "test_common.h"
/* Common context for tests */
static uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE]
__attribute__ ((aligned (VB2_WORKBUF_ALIGN)));
static struct vb2_context ctx;
static struct vb2_shared_data *sd;
static const uint8_t mock_body[320] = "Mock body";
static const int mock_body_size = sizeof(mock_body);
static const int mock_hash_alg = VB2_HASH_SHA256;
static int mock_sig_size;
static const struct vb2_id test_id[4] = {
{.raw = {0x11}},
{.raw = {0x22}},
{.raw = {0x33}},
{.raw = {0x44}},
};
/* Mocked function data */
static enum {
HWCRYPTO_DISABLED,
HWCRYPTO_ENABLED,
HWCRYPTO_FORBIDDEN,
} hwcrypto_state;
static struct vb2_digest_context hwcrypto_emulation_dc;
static int retval_hwcrypto;
static int retval_vb21_load_fw_keyblock;
static int retval_vb21_load_fw_preamble;
/* Type of test to reset for */
enum reset_type {
FOR_MISC,
FOR_EXTEND_HASH,
FOR_CHECK_HASH,
};
static void reset_common_data(enum reset_type t)
{
const struct vb2_private_key *hash_key;
struct vb21_fw_preamble *pre;
struct vb21_signature *sig;
uint32_t sig_offset;
int i;
memset(workbuf, 0xaa, sizeof(workbuf));
memset(&ctx, 0, sizeof(ctx));
ctx.workbuf = workbuf;
ctx.workbuf_size = sizeof(workbuf);
vb2_init_context(&ctx);
sd = vb2_get_sd(&ctx);
vb2_nv_init(&ctx);
vb2_secdata_create(&ctx);
vb2_secdata_init(&ctx);
memset(&hwcrypto_emulation_dc, 0, sizeof(hwcrypto_emulation_dc));
retval_hwcrypto = VB2_SUCCESS;
retval_vb21_load_fw_keyblock = VB2_SUCCESS;
retval_vb21_load_fw_preamble = VB2_SUCCESS;
vb2_private_key_hash(&hash_key, mock_hash_alg);
sd->workbuf_preamble_offset = ctx.workbuf_used;
pre = (struct vb21_fw_preamble *)
(ctx.workbuf + sd->workbuf_preamble_offset);
pre->hash_count = 3;
pre->hash_offset = sig_offset = sizeof(*pre);
if (hwcrypto_state == HWCRYPTO_FORBIDDEN)
pre->flags = VB21_FIRMWARE_PREAMBLE_DISALLOW_HWCRYPTO;
else
pre->flags = 0;
for (i = 0; i < 3; i++) {
vb21_sign_data(&sig, mock_body, mock_body_size - 16 * i,
hash_key, NULL);
memcpy(&sig->id, test_id + i, sizeof(sig->id));
memcpy((uint8_t *)pre + sig_offset, sig, sig->c.total_size);
sig_offset += sig->c.total_size;
mock_sig_size = sig->c.total_size;
free(sig);
}
sd->workbuf_preamble_size = sig_offset;
ctx.workbuf_used = vb2_wb_round_up(sd->workbuf_preamble_offset +
sd->workbuf_preamble_size);
if (t == FOR_EXTEND_HASH || t == FOR_CHECK_HASH)
vb21api_init_hash(&ctx, test_id, NULL);
if (t == FOR_CHECK_HASH)
vb2api_extend_hash(&ctx, mock_body, mock_body_size);
};
/* Mocked functions */
int vb21_load_fw_keyblock(struct vb2_context *ctx)
{
return retval_vb21_load_fw_keyblock;
}
int vb21_load_fw_preamble(struct vb2_context *ctx)
{
return retval_vb21_load_fw_preamble;
}
int vb2ex_hwcrypto_digest_init(enum vb2_hash_algorithm hash_alg,
uint32_t data_size)
{
vb2_digest_init(&hwcrypto_emulation_dc, hash_alg);
switch (hwcrypto_state) {
case HWCRYPTO_DISABLED:
return VB2_ERROR_EX_HWCRYPTO_UNSUPPORTED;
case HWCRYPTO_ENABLED:
if (hash_alg != mock_hash_alg)
return VB2_ERROR_SHA_INIT_ALGORITHM;
else
return retval_hwcrypto;
case HWCRYPTO_FORBIDDEN:
default:
return VB2_ERROR_UNKNOWN;
}
}
int vb2ex_hwcrypto_digest_extend(const uint8_t *buf,
uint32_t size)
{
vb2_digest_extend(&hwcrypto_emulation_dc, buf, size);
if (hwcrypto_state != HWCRYPTO_ENABLED)
return VB2_ERROR_UNKNOWN;
return retval_hwcrypto;
}
int vb2ex_hwcrypto_digest_finalize(uint8_t *digest,
uint32_t digest_size)
{
vb2_digest_finalize(&hwcrypto_emulation_dc, digest, digest_size);
if (hwcrypto_state != HWCRYPTO_ENABLED)
return VB2_ERROR_UNKNOWN;
return retval_hwcrypto;
}
/* Tests */
static void phase3_tests(void)
{
reset_common_data(FOR_MISC);
TEST_SUCC(vb21api_fw_phase3(&ctx), "phase3 good");
reset_common_data(FOR_MISC);
retval_vb21_load_fw_keyblock = VB2_ERROR_MOCK;
TEST_EQ(vb21api_fw_phase3(&ctx), VB2_ERROR_MOCK, "phase3 keyblock");
TEST_EQ(vb2_nv_get(&ctx, VB2_NV_RECOVERY_REQUEST),
VB2_RECOVERY_RO_INVALID_RW, " recovery reason");
reset_common_data(FOR_MISC);
retval_vb21_load_fw_preamble = VB2_ERROR_MOCK;
TEST_EQ(vb21api_fw_phase3(&ctx), VB2_ERROR_MOCK, "phase3 keyblock");
TEST_EQ(vb2_nv_get(&ctx, VB2_NV_RECOVERY_REQUEST),
VB2_RECOVERY_RO_INVALID_RW, " recovery reason");
}
static void init_hash_tests(void)
{
struct vb21_fw_preamble *pre;
struct vb21_signature *sig;
int wb_used_before;
uint32_t size;
reset_common_data(FOR_MISC);
pre = (struct vb21_fw_preamble *)
(ctx.workbuf + sd->workbuf_preamble_offset);
sig = (struct vb21_signature *)((uint8_t *)pre + pre->hash_offset);
wb_used_before = ctx.workbuf_used;
TEST_SUCC(vb21api_init_hash(&ctx, test_id, &size),
"init hash good");
TEST_EQ(sd->workbuf_hash_offset, wb_used_before,
"hash context offset");
TEST_EQ(sd->workbuf_hash_size, sizeof(struct vb2_digest_context),
"hash context size");
TEST_EQ(ctx.workbuf_used,
vb2_wb_round_up(sd->workbuf_hash_offset +
sd->workbuf_hash_size),
"hash uses workbuf");
TEST_EQ(sd->hash_tag,
sd->workbuf_preamble_offset + pre->hash_offset,
"hash signature offset");
TEST_EQ(sd->hash_remaining_size, mock_body_size, "hash remaining");
wb_used_before = ctx.workbuf_used;
TEST_SUCC(vb21api_init_hash(&ctx, test_id + 2, NULL),
"init hash again");
TEST_EQ(ctx.workbuf_used, wb_used_before, "init hash reuses context");
TEST_EQ(sd->hash_tag,
sd->workbuf_preamble_offset + pre->hash_offset +
2 * mock_sig_size,
"hash signature offset 2");
reset_common_data(FOR_MISC);
TEST_EQ(vb21api_init_hash(&ctx, test_id + 3, &size),
VB2_ERROR_API_INIT_HASH_ID, "init hash invalid id");
reset_common_data(FOR_MISC);
sd->workbuf_preamble_size = 0;
TEST_EQ(vb21api_init_hash(&ctx, test_id, &size),
VB2_ERROR_API_INIT_HASH_PREAMBLE, "init hash preamble");
reset_common_data(FOR_MISC);
ctx.workbuf_used = ctx.workbuf_size + VB2_WORKBUF_ALIGN -
vb2_wb_round_up(sizeof(struct vb2_digest_context));
TEST_EQ(vb21api_init_hash(&ctx, test_id, &size),
VB2_ERROR_API_INIT_HASH_WORKBUF, "init hash workbuf");
reset_common_data(FOR_MISC);
sig->hash_alg = VB2_HASH_INVALID;
TEST_EQ(vb21api_init_hash(&ctx, test_id, &size),
VB2_ERROR_SHA_INIT_ALGORITHM, "init hash algorithm");
if (hwcrypto_state == HWCRYPTO_ENABLED) {
reset_common_data(FOR_MISC);
retval_hwcrypto = VB2_ERROR_MOCK;
TEST_EQ(vb21api_init_hash(&ctx, test_id, &size),
VB2_ERROR_MOCK, "init hash use hwcrypto");
}
}
static void extend_hash_tests(void)
{
struct vb2_digest_context *dc;
reset_common_data(FOR_EXTEND_HASH);
TEST_SUCC(vb2api_extend_hash(&ctx, mock_body, 32),
"hash extend good");
TEST_EQ(sd->hash_remaining_size, mock_body_size - 32,
"hash extend remaining");
TEST_SUCC(vb2api_extend_hash(&ctx, mock_body, mock_body_size - 32),
"hash extend again");
TEST_EQ(sd->hash_remaining_size, 0, "hash extend remaining 2");
reset_common_data(FOR_EXTEND_HASH);
sd->workbuf_hash_size = 0;
TEST_EQ(vb2api_extend_hash(&ctx, mock_body, mock_body_size),
VB2_ERROR_API_EXTEND_HASH_WORKBUF, "hash extend no workbuf");
reset_common_data(FOR_EXTEND_HASH);
TEST_EQ(vb2api_extend_hash(&ctx, mock_body, mock_body_size + 1),
VB2_ERROR_API_EXTEND_HASH_SIZE, "hash extend too much");
reset_common_data(FOR_EXTEND_HASH);
TEST_EQ(vb2api_extend_hash(&ctx, mock_body, 0),
VB2_ERROR_API_EXTEND_HASH_SIZE, "hash extend empty");
if (hwcrypto_state == HWCRYPTO_ENABLED) {
reset_common_data(FOR_EXTEND_HASH);
retval_hwcrypto = VB2_ERROR_MOCK;
TEST_EQ(vb2api_extend_hash(&ctx, mock_body, mock_body_size),
VB2_ERROR_MOCK, "hash extend use hwcrypto");
} else {
reset_common_data(FOR_EXTEND_HASH);
dc = (struct vb2_digest_context *)
(ctx.workbuf + sd->workbuf_hash_offset);
dc->hash_alg = VB2_HASH_INVALID;
TEST_EQ(vb2api_extend_hash(&ctx, mock_body, mock_body_size),
VB2_ERROR_SHA_EXTEND_ALGORITHM, "hash extend fail");
}
}
static void check_hash_tests(void)
{
struct vb21_fw_preamble *pre;
struct vb21_signature *sig;
struct vb2_digest_context *dc;
reset_common_data(FOR_CHECK_HASH);
pre = (struct vb21_fw_preamble *)
(ctx.workbuf + sd->workbuf_preamble_offset);
sig = (struct vb21_signature *)((uint8_t *)pre + pre->hash_offset);
dc = (struct vb2_digest_context *)
(ctx.workbuf + sd->workbuf_hash_offset);
TEST_SUCC(vb21api_check_hash(&ctx), "check hash good");
reset_common_data(FOR_CHECK_HASH);
sd->hash_tag = 0;
TEST_EQ(vb21api_check_hash(&ctx),
VB2_ERROR_API_CHECK_HASH_TAG, "check hash tag");
reset_common_data(FOR_CHECK_HASH);
sd->workbuf_hash_size = 0;
TEST_EQ(vb21api_check_hash(&ctx),
VB2_ERROR_API_CHECK_HASH_WORKBUF, "check hash no workbuf");
reset_common_data(FOR_CHECK_HASH);
sd->hash_remaining_size = 1;
TEST_EQ(vb21api_check_hash(&ctx),
VB2_ERROR_API_CHECK_HASH_SIZE, "check hash size");
reset_common_data(FOR_CHECK_HASH);
ctx.workbuf_used = ctx.workbuf_size;
TEST_EQ(vb21api_check_hash(&ctx),
VB2_ERROR_API_CHECK_HASH_WORKBUF_DIGEST, "check hash workbuf");
reset_common_data(FOR_CHECK_HASH);
*((uint8_t *)sig + sig->sig_offset) ^= 0x55;
TEST_EQ(vb21api_check_hash(&ctx),
VB2_ERROR_API_CHECK_HASH_SIG, "check hash sig");
if (hwcrypto_state == HWCRYPTO_ENABLED) {
reset_common_data(FOR_CHECK_HASH);
retval_hwcrypto = VB2_ERROR_MOCK;
TEST_EQ(vb21api_check_hash(&ctx),
VB2_ERROR_MOCK, "check hash use hwcrypto");
} else {
reset_common_data(FOR_CHECK_HASH);
dc->hash_alg = VB2_HASH_INVALID;
*((uint8_t *)sig + sig->sig_offset) ^= 0x55;
TEST_EQ(vb21api_check_hash(&ctx),
VB2_ERROR_SHA_FINALIZE_ALGORITHM, "check hash finaliz");
}
}
int main(int argc, char* argv[])
{
phase3_tests();
fprintf(stderr, "Running hash API tests without hwcrypto support...\n");
hwcrypto_state = HWCRYPTO_DISABLED;
init_hash_tests();
extend_hash_tests();
check_hash_tests();
fprintf(stderr, "Running hash API tests with hwcrypto support...\n");
hwcrypto_state = HWCRYPTO_ENABLED;
init_hash_tests();
extend_hash_tests();
check_hash_tests();
fprintf(stderr, "Running hash API tests with forbidden hwcrypto...\n");
hwcrypto_state = HWCRYPTO_FORBIDDEN;
init_hash_tests();
extend_hash_tests();
check_hash_tests();
return gTestSuccess ? 0 : 255;
}