mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-27 03:33:50 +00:00
vboot2: Add nvstorage and secdata functions
This is the second of several CLs adding a more memory- and code-efficient firmware verification library. BUG=chromium:370082 BRANCH=none TEST=make clean && COV=1 make Change-Id: I1dd571e7511bff18469707d5a2e90068e68e0d6f Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/199841 Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
e166d04e79
commit
3333e57849
10
Makefile
10
Makefile
@@ -280,7 +280,11 @@ VBSLK_SRCS = \
|
||||
# Firmware library source needed for smaller library 2
|
||||
FWLIB2_SRCS = \
|
||||
firmware/2lib/2common.c \
|
||||
firmware/2lib/2crc8.c \
|
||||
firmware/2lib/2misc.c \
|
||||
firmware/2lib/2nvstorage.c \
|
||||
firmware/2lib/2rsa.c \
|
||||
firmware/2lib/2secdata.c \
|
||||
firmware/2lib/2sha1.c \
|
||||
firmware/2lib/2sha256.c \
|
||||
firmware/2lib/2sha512.c \
|
||||
@@ -564,8 +568,11 @@ endif
|
||||
ifneq (${VBOOT2},)
|
||||
TEST_NAMES += \
|
||||
tests/vb2_common_tests \
|
||||
tests/vb2_misc_tests \
|
||||
tests/vb2_nvstorage_tests \
|
||||
tests/vb2_rsa_padding_tests \
|
||||
tests/vb2_rsa_utility_tests \
|
||||
tests/vb2_secdata_tests \
|
||||
tests/vb2_sha_tests \
|
||||
|
||||
endif
|
||||
@@ -1088,7 +1095,10 @@ runmisctests: test_setup
|
||||
.PHONY: run2tests
|
||||
run2tests: test_setup
|
||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_common_tests
|
||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_misc_tests
|
||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests
|
||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests
|
||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_tests
|
||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_tests
|
||||
|
||||
.PHONY: runfutiltests
|
||||
|
||||
29
firmware/2lib/2crc8.c
Normal file
29
firmware/2lib/2crc8.c
Normal file
@@ -0,0 +1,29 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
#include "2sysincludes.h"
|
||||
#include "2crc8.h"
|
||||
|
||||
uint8_t vb2_crc8(const void *vptr, uint32_t size)
|
||||
{
|
||||
const uint8_t *data = vptr;
|
||||
unsigned crc = 0;
|
||||
uint32_t i, j;
|
||||
|
||||
/*
|
||||
* Calculate CRC-8 directly. A table-based algorithm would be faster,
|
||||
* but for only a few bytes it isn't worth the code size.
|
||||
*/
|
||||
for (j = size; j; j--, data++) {
|
||||
crc ^= (*data << 8);
|
||||
for(i = 8; i; i--) {
|
||||
if (crc & 0x8000)
|
||||
crc ^= (0x1070 << 3);
|
||||
crc <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return (uint8_t)(crc >> 8);
|
||||
}
|
||||
39
firmware/2lib/2misc.c
Normal file
39
firmware/2lib/2misc.c
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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.
|
||||
*
|
||||
* Misc functions which need access to vb2_context but are not public APIs
|
||||
*/
|
||||
|
||||
#include "2sysincludes.h"
|
||||
#include "2api.h"
|
||||
#include "2common.h"
|
||||
#include "2misc.h"
|
||||
#include "2nvstorage.h"
|
||||
#include "2secdata.h"
|
||||
#include "2sha.h"
|
||||
#include "2rsa.h"
|
||||
|
||||
int vb2_init_context(struct vb2_context *ctx)
|
||||
{
|
||||
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
||||
|
||||
/* Don't do anything if the context has already been initialized */
|
||||
if (ctx->workbuf_used)
|
||||
return VB2_SUCCESS;
|
||||
|
||||
/*
|
||||
* Workbuf had better be big enough for our shared data struct and
|
||||
* aligned. Not much we can do if it isn't; we'll die before we can
|
||||
* store a recovery reason.
|
||||
*/
|
||||
if (ctx->workbuf_size < sizeof(*sd))
|
||||
return VB2_ERROR_WORKBUF_TOO_SMALL;
|
||||
if (!vb_aligned(ctx->workbuf, sizeof(uint32_t)))
|
||||
return VB2_ERROR_BUFFER_UNALIGNED;
|
||||
|
||||
/* Initialize the shared data at the start of the work buffer */
|
||||
memset(sd, 0, sizeof(*sd));
|
||||
ctx->workbuf_used = sizeof(*sd);
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
323
firmware/2lib/2nvstorage.c
Normal file
323
firmware/2lib/2nvstorage.c
Normal file
@@ -0,0 +1,323 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* Non-volatile storage routines */
|
||||
|
||||
#include "2sysincludes.h"
|
||||
#include "2common.h"
|
||||
#include "2crc8.h"
|
||||
#include "2misc.h"
|
||||
#include "2nvstorage.h"
|
||||
|
||||
/*
|
||||
* Constants for NV storage. We use this rather than structs and bitfields so
|
||||
* the data format is consistent across platforms and compilers. Total NV
|
||||
* storage size is VB2_NVDATA_SIZE = 16 bytes.
|
||||
*/
|
||||
|
||||
enum vb2_nv_offset {
|
||||
VB2_NV_OFFS_HEADER = 0,
|
||||
VB2_NV_OFFS_BOOT = 1,
|
||||
VB2_NV_OFFS_RECOVERY = 2,
|
||||
VB2_NV_OFFS_LOCALIZATION = 3,
|
||||
VB2_NV_OFFS_DEV = 4,
|
||||
VB2_NV_OFFS_TPM = 5,
|
||||
VB2_NV_OFFS_RECOVERY_SUBCODE = 6,
|
||||
VB2_NV_OFFS_BOOT2 = 7,
|
||||
/* Offsets 7-10 are currently unused */
|
||||
VB2_NV_OFFS_KERNEL = 11, /* 11-14; field is 32 bits */
|
||||
/* CRC must be last field */
|
||||
VB2_NV_OFFS_CRC = 15
|
||||
};
|
||||
|
||||
/* Fields in VB2_NV_OFFS_HEADER (unused = 0x0f) */
|
||||
#define VB2_NV_HEADER_KERNEL_SETTINGS_RESET 0x10
|
||||
#define VB2_NV_HEADER_FW_SETTINGS_RESET 0x20
|
||||
#define VB2_NV_HEADER_SIGNATURE 0x40
|
||||
#define VB2_NV_HEADER_MASK 0xc0
|
||||
|
||||
/* Fields in VB2_NV_OFFS_BOOT */
|
||||
#define VB2_NV_BOOT_TRY_COUNT_MASK 0x0f
|
||||
#define VB2_NV_BOOT_TRY_NEXT 0x10
|
||||
#define VB2_NV_BOOT_OPROM_NEEDED 0x20
|
||||
#define VB2_NV_BOOT_DISABLE_DEV 0x40
|
||||
#define VB2_NV_BOOT_DEBUG_RESET 0x80
|
||||
|
||||
/* Fields in VB2_NV_OFFS_BOOT2 (unused = 0xf8) */
|
||||
#define VB2_NV_BOOT2_RESULT_MASK 0x03
|
||||
#define VB2_NV_BOOT2_TRIED 0x04
|
||||
|
||||
/* Fields in VB2_NV_OFFS_DEV (unused = 0xf8) */
|
||||
#define VB2_NV_DEV_FLAG_USB 0x01
|
||||
#define VB2_NV_DEV_FLAG_SIGNED_ONLY 0x02
|
||||
#define VB2_NV_DEV_FLAG_LEGACY 0x04
|
||||
|
||||
/* Fields in VB2_NV_OFFS_TPM (unused = 0xfc) */
|
||||
#define VB2_NV_TPM_CLEAR_OWNER_REQUEST 0x01
|
||||
#define VB2_NV_TPM_CLEAR_OWNER_DONE 0x02
|
||||
|
||||
static void vb2_nv_regen_crc(struct vb2_context *ctx)
|
||||
{
|
||||
ctx->nvdata[VB2_NV_OFFS_CRC] = vb2_crc8(ctx->nvdata, VB2_NV_OFFS_CRC);
|
||||
ctx->flags |= VB2_CONTEXT_NVDATA_CHANGED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the CRC of the non-volatile storage context.
|
||||
*
|
||||
* Use this if reading from non-volatile storage may be flaky, and you want to
|
||||
* retry reading it several times.
|
||||
*
|
||||
* This may be called before vb2_context_init().
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||
*/
|
||||
int vb2_nv_check_crc(const struct vb2_context *ctx)
|
||||
{
|
||||
const uint8_t *p = ctx->nvdata;
|
||||
|
||||
/* Check header */
|
||||
if (VB2_NV_HEADER_SIGNATURE !=
|
||||
(p[VB2_NV_OFFS_HEADER] & VB2_NV_HEADER_MASK))
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
/* Check CRC */
|
||||
if (vb2_crc8(p, VB2_NV_OFFS_CRC) != p[VB2_NV_OFFS_CRC])
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
void vb2_nv_init(struct vb2_context *ctx)
|
||||
{
|
||||
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
||||
uint8_t *p = ctx->nvdata;
|
||||
|
||||
/* Check data for consistency */
|
||||
if (vb2_nv_check_crc(ctx) != VB2_SUCCESS) {
|
||||
/* Data is inconsistent (bad CRC or header); reset defaults */
|
||||
memset(p, 0, VB2_NVDATA_SIZE);
|
||||
p[VB2_NV_OFFS_HEADER] = (VB2_NV_HEADER_SIGNATURE |
|
||||
VB2_NV_HEADER_FW_SETTINGS_RESET |
|
||||
VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
|
||||
|
||||
/* Regenerate CRC */
|
||||
vb2_nv_regen_crc(ctx);
|
||||
|
||||
/* Set status flag */
|
||||
sd->status |= VB2_SD_STATUS_NV_REINIT;
|
||||
// TODO: unit test for status flag being set
|
||||
}
|
||||
|
||||
sd->status |= VB2_SD_STATUS_NV_INIT;
|
||||
}
|
||||
|
||||
/* Macro for vb2_nv_get() single-bit settings to reduce duplicate code. */
|
||||
#define GETBIT(offs, mask) (p[offs] & mask ? 1 : 0)
|
||||
|
||||
uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param)
|
||||
{
|
||||
const uint8_t *p = ctx->nvdata;
|
||||
|
||||
/*
|
||||
* TODO: We could reduce the binary size for this code by #ifdef'ing
|
||||
* out the params not used by firmware verification.
|
||||
*/
|
||||
switch (param) {
|
||||
case VB2_NV_FIRMWARE_SETTINGS_RESET:
|
||||
return GETBIT(VB2_NV_OFFS_HEADER,
|
||||
VB2_NV_HEADER_FW_SETTINGS_RESET);
|
||||
|
||||
case VB2_NV_KERNEL_SETTINGS_RESET:
|
||||
return GETBIT(VB2_NV_OFFS_HEADER,
|
||||
VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
|
||||
|
||||
case VB2_NV_DEBUG_RESET_MODE:
|
||||
return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DEBUG_RESET);
|
||||
|
||||
case VB2_NV_TRY_NEXT:
|
||||
return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_TRY_NEXT);
|
||||
|
||||
case VB2_NV_TRY_COUNT:
|
||||
return p[VB2_NV_OFFS_BOOT] & VB2_NV_BOOT_TRY_COUNT_MASK;
|
||||
|
||||
case VB2_NV_FW_TRIED:
|
||||
return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRIED);
|
||||
|
||||
case VB2_NV_FW_RESULT:
|
||||
return p[VB2_NV_OFFS_BOOT2] & VB2_NV_BOOT2_RESULT_MASK;
|
||||
|
||||
case VB2_NV_RECOVERY_REQUEST:
|
||||
return p[VB2_NV_OFFS_RECOVERY];
|
||||
|
||||
case VB2_NV_RECOVERY_SUBCODE:
|
||||
return p[VB2_NV_OFFS_RECOVERY_SUBCODE];
|
||||
|
||||
case VB2_NV_LOCALIZATION_INDEX:
|
||||
return p[VB2_NV_OFFS_LOCALIZATION];
|
||||
|
||||
case VB2_NV_KERNEL_FIELD:
|
||||
return (p[VB2_NV_OFFS_KERNEL]
|
||||
| (p[VB2_NV_OFFS_KERNEL + 1] << 8)
|
||||
| (p[VB2_NV_OFFS_KERNEL + 2] << 16)
|
||||
| (p[VB2_NV_OFFS_KERNEL + 3] << 24));
|
||||
|
||||
case VB2_NV_DEV_BOOT_USB:
|
||||
return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB);
|
||||
|
||||
case VB2_NV_DEV_BOOT_LEGACY:
|
||||
return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY);
|
||||
|
||||
case VB2_NV_DEV_BOOT_SIGNED_ONLY:
|
||||
return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_SIGNED_ONLY);
|
||||
|
||||
case VB2_NV_DISABLE_DEV_REQUEST:
|
||||
return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DISABLE_DEV);
|
||||
|
||||
case VB2_NV_OPROM_NEEDED:
|
||||
return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_OPROM_NEEDED);
|
||||
|
||||
case VB2_NV_CLEAR_TPM_OWNER_REQUEST:
|
||||
return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_REQUEST);
|
||||
|
||||
case VB2_NV_CLEAR_TPM_OWNER_DONE:
|
||||
return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Put default return outside the switch() instead of in default:, so
|
||||
* that adding a new param will cause a compiler warning.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef GETBIT
|
||||
|
||||
/* Macro for vb2_nv_set() single-bit settings to reduce duplicate code. */
|
||||
#define SETBIT(offs, mask) \
|
||||
{ if (value) p[offs] |= mask; else p[offs] &= ~mask; }
|
||||
|
||||
void vb2_nv_set(struct vb2_context *ctx,
|
||||
enum vb2_nv_param param,
|
||||
uint32_t value)
|
||||
{
|
||||
uint8_t *p = ctx->nvdata;
|
||||
|
||||
/* If not changing the value, don't regenerate the CRC. */
|
||||
if (vb2_nv_get(ctx, param) == value)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: We could reduce the binary size for this code by #ifdef'ing
|
||||
* out the params not used by firmware verification.
|
||||
*/
|
||||
switch (param) {
|
||||
case VB2_NV_FIRMWARE_SETTINGS_RESET:
|
||||
SETBIT(VB2_NV_OFFS_HEADER, VB2_NV_HEADER_FW_SETTINGS_RESET);
|
||||
break;
|
||||
|
||||
case VB2_NV_KERNEL_SETTINGS_RESET:
|
||||
SETBIT(VB2_NV_OFFS_HEADER, VB2_NV_HEADER_KERNEL_SETTINGS_RESET);
|
||||
break;
|
||||
|
||||
case VB2_NV_DEBUG_RESET_MODE:
|
||||
SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DEBUG_RESET);
|
||||
break;
|
||||
|
||||
case VB2_NV_TRY_NEXT:
|
||||
SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_TRY_NEXT);
|
||||
break;
|
||||
|
||||
case VB2_NV_TRY_COUNT:
|
||||
/* Clip to valid range. */
|
||||
if (value > VB2_NV_BOOT_TRY_COUNT_MASK)
|
||||
value = VB2_NV_BOOT_TRY_COUNT_MASK;
|
||||
|
||||
p[VB2_NV_OFFS_BOOT] &= ~VB2_NV_BOOT_TRY_COUNT_MASK;
|
||||
p[VB2_NV_OFFS_BOOT] |= (uint8_t)value;
|
||||
break;
|
||||
|
||||
case VB2_NV_FW_TRIED:
|
||||
SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRIED);
|
||||
break;
|
||||
|
||||
case VB2_NV_FW_RESULT:
|
||||
/* Map out of range values to unknown */
|
||||
if (value > VB2_NV_BOOT2_RESULT_MASK)
|
||||
value = VB2_FW_RESULT_UNKNOWN;
|
||||
|
||||
p[VB2_NV_OFFS_BOOT2] &= ~VB2_NV_BOOT2_RESULT_MASK;
|
||||
p[VB2_NV_OFFS_BOOT2] |= (uint8_t)value;
|
||||
break;
|
||||
|
||||
case VB2_NV_RECOVERY_REQUEST:
|
||||
/*
|
||||
* Map values outside the valid range to the legacy reason,
|
||||
* since we can't determine if we're called from kernel or user
|
||||
* mode.
|
||||
*/
|
||||
if (value > 0xff)
|
||||
value = VB2_RECOVERY_LEGACY;
|
||||
p[VB2_NV_OFFS_RECOVERY] = (uint8_t)value;
|
||||
break;
|
||||
|
||||
case VB2_NV_RECOVERY_SUBCODE:
|
||||
p[VB2_NV_OFFS_RECOVERY_SUBCODE] = (uint8_t)value;
|
||||
break;
|
||||
|
||||
case VB2_NV_LOCALIZATION_INDEX:
|
||||
/* Map values outside the valid range to the default index. */
|
||||
if (value > 0xFF)
|
||||
value = 0;
|
||||
p[VB2_NV_OFFS_LOCALIZATION] = (uint8_t)value;
|
||||
break;
|
||||
|
||||
case VB2_NV_KERNEL_FIELD:
|
||||
p[VB2_NV_OFFS_KERNEL] = (uint8_t)(value);
|
||||
p[VB2_NV_OFFS_KERNEL + 1] = (uint8_t)(value >> 8);
|
||||
p[VB2_NV_OFFS_KERNEL + 2] = (uint8_t)(value >> 16);
|
||||
p[VB2_NV_OFFS_KERNEL + 3] = (uint8_t)(value >> 24);
|
||||
break;
|
||||
|
||||
case VB2_NV_DEV_BOOT_USB:
|
||||
SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB);
|
||||
break;
|
||||
|
||||
case VB2_NV_DEV_BOOT_LEGACY:
|
||||
SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY);
|
||||
break;
|
||||
|
||||
case VB2_NV_DEV_BOOT_SIGNED_ONLY:
|
||||
SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_SIGNED_ONLY);
|
||||
break;
|
||||
|
||||
case VB2_NV_DISABLE_DEV_REQUEST:
|
||||
SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DISABLE_DEV);
|
||||
break;
|
||||
|
||||
case VB2_NV_OPROM_NEEDED:
|
||||
SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_OPROM_NEEDED);
|
||||
break;
|
||||
|
||||
case VB2_NV_CLEAR_TPM_OWNER_REQUEST:
|
||||
SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_REQUEST);
|
||||
break;
|
||||
|
||||
case VB2_NV_CLEAR_TPM_OWNER_DONE:
|
||||
SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note there is no default case. This causes a compiler warning if
|
||||
* a new param is added to the enum without adding support here.
|
||||
*/
|
||||
|
||||
/* Need to regenerate CRC, since the value changed. */
|
||||
vb2_nv_regen_crc(ctx);
|
||||
}
|
||||
|
||||
#undef SETBIT
|
||||
115
firmware/2lib/2secdata.c
Normal file
115
firmware/2lib/2secdata.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/* 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.
|
||||
*
|
||||
* Secure storage APIs
|
||||
*/
|
||||
|
||||
#include "2sysincludes.h"
|
||||
#include "2common.h"
|
||||
#include "2crc8.h"
|
||||
#include "2misc.h"
|
||||
#include "2secdata.h"
|
||||
|
||||
int vb2_secdata_check_crc(const struct vb2_context *ctx)
|
||||
{
|
||||
const struct vb2_secdata *sec =
|
||||
(const struct vb2_secdata *)ctx->secdata;
|
||||
|
||||
/* Verify CRC */
|
||||
if (sec->crc8 != vb2_crc8(sec, offsetof(struct vb2_secdata, crc8)))
|
||||
return VB2_ERROR_BAD_SECDATA;
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
int vb2_secdata_create(struct vb2_context *ctx)
|
||||
{
|
||||
struct vb2_secdata *sec = (struct vb2_secdata *)ctx->secdata;
|
||||
|
||||
/* Clear the entire struct */
|
||||
memset(sec, 0, sizeof(*sec));
|
||||
|
||||
/* Set to current version */
|
||||
sec->struct_version = VB2_SECDATA_VERSION;
|
||||
|
||||
/* Calculate initial CRC */
|
||||
sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata, crc8));
|
||||
ctx->flags |= VB2_CONTEXT_SECDATA_CHANGED;
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
int vb2_secdata_init(struct vb2_context *ctx)
|
||||
{
|
||||
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
||||
struct vb2_secdata *sec = (struct vb2_secdata *)ctx->secdata;
|
||||
int rv;
|
||||
|
||||
/* Data must be new enough to have a CRC */
|
||||
if (sec->struct_version < 2)
|
||||
return VB2_ERROR_BAD_SECDATA;
|
||||
|
||||
rv = vb2_secdata_check_crc(ctx);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
/* Set status flag */
|
||||
sd->status |= VB2_SD_STATUS_SECDATA_INIT;
|
||||
// TODO: unit test for that
|
||||
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
|
||||
int vb2_secdata_get(struct vb2_context *ctx,
|
||||
enum vb2_secdata_param param,
|
||||
uint32_t *dest)
|
||||
{
|
||||
struct vb2_secdata *sec = (struct vb2_secdata *)ctx->secdata;
|
||||
|
||||
switch(param) {
|
||||
case VB2_SECDATA_FLAGS:
|
||||
*dest = sec->flags;
|
||||
return VB2_SUCCESS;
|
||||
|
||||
case VB2_SECDATA_VERSIONS:
|
||||
*dest = sec->fw_versions;
|
||||
return VB2_SUCCESS;
|
||||
|
||||
default:
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int vb2_secdata_set(struct vb2_context *ctx,
|
||||
enum vb2_secdata_param param,
|
||||
uint32_t value)
|
||||
{
|
||||
struct vb2_secdata *sec = (struct vb2_secdata *)ctx->secdata;
|
||||
uint32_t now;
|
||||
|
||||
/* If not changing the value, don't regenerate the CRC. */
|
||||
if (vb2_secdata_get(ctx, param, &now) == VB2_SUCCESS && now == value)
|
||||
return VB2_SUCCESS;
|
||||
|
||||
switch(param) {
|
||||
case VB2_SECDATA_FLAGS:
|
||||
/* Make sure flags is in valid range */
|
||||
if (value > 0xff)
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
|
||||
sec->flags = value;
|
||||
break;
|
||||
|
||||
case VB2_SECDATA_VERSIONS:
|
||||
sec->fw_versions = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
return VB2_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* Regenerate CRC */
|
||||
sec->crc8 = vb2_crc8(sec, offsetof(struct vb2_secdata, crc8));
|
||||
ctx->flags |= VB2_CONTEXT_SECDATA_CHANGED;
|
||||
return VB2_SUCCESS;
|
||||
}
|
||||
146
firmware/2lib/include/2api.h
Normal file
146
firmware/2lib/include/2api.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/* Copyright (c) 2013 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.
|
||||
*/
|
||||
|
||||
/* APIs between calling firmware and vboot_reference
|
||||
*
|
||||
* General notes:
|
||||
*
|
||||
* TODO: split this file into a vboot_entry_points.h file which contains the
|
||||
* entry points for the firmware to call vboot_reference, and a
|
||||
* vboot_firmware_exports.h which contains the APIs to be implemented by the
|
||||
* calling firmware and exported to vboot_reference.
|
||||
*
|
||||
* Notes:
|
||||
* * Assumes this code is never called in the S3 resume path. TPM resume
|
||||
* must be done elsewhere, and VB2_NV_DEBUG_RESET_MODE is ignored.
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_2_API_H_
|
||||
#define VBOOT_2_API_H_
|
||||
#include <stdint.h>
|
||||
|
||||
#include "2recovery_reasons.h"
|
||||
#include "2return_codes.h"
|
||||
|
||||
/* Size of non-volatile data used by vboot */
|
||||
#define VB2_NVDATA_SIZE 16
|
||||
|
||||
/* Size of secure data used by vboot */
|
||||
#define VB2_SECDATA_SIZE 10
|
||||
|
||||
/*
|
||||
* Recommended size of work buffer.
|
||||
*
|
||||
* TODO: The recommended size really depends on which key algorithms are
|
||||
* used. Should have a better / more accurate recommendation than this.
|
||||
*/
|
||||
#define VB2_WORKBUF_RECOMMENDED_SIZE (12 * 1024)
|
||||
|
||||
/* Flags for vb2_context.
|
||||
*
|
||||
* Unless otherwise noted, flags are set by verified boot and may be read (but
|
||||
* not set or cleared) by the caller.
|
||||
*/
|
||||
enum vb2_context_flags {
|
||||
|
||||
/*
|
||||
* Verified boot has changed nvdata[]. Caller must save nvdata[] back
|
||||
* to its underlying storage, then may clear this flag.
|
||||
*/
|
||||
VB2_CONTEXT_NVDATA_CHANGED = (1 << 0),
|
||||
|
||||
/*
|
||||
* Verified boot has changed secdata[]. Caller must save secdata[]
|
||||
* back to its underlying storage, then may clear this flag.
|
||||
*/
|
||||
VB2_CONTEXT_SECDATA_CHANGED = (1 << 1),
|
||||
|
||||
/* Recovery mode is requested this boot */
|
||||
VB2_CONTEXT_RECOVERY_MODE = (1 << 2),
|
||||
|
||||
/* Developer mode is requested this boot */
|
||||
VB2_CONTEXT_DEVELOPER_MODE = (1 << 3),
|
||||
|
||||
/*
|
||||
* Force recovery mode due to physical user request. Caller may set
|
||||
* this flag when initializing the context.
|
||||
*/
|
||||
VB2_CONTEXT_FORCE_RECOVERY_MODE = (1 << 4),
|
||||
|
||||
/*
|
||||
* Force developer mode enabled. Caller may set this flag when
|
||||
* initializing the context.
|
||||
*/
|
||||
VB2_CONTEXT_FORCE_DEVELOPER_MODE = (1 << 5),
|
||||
|
||||
/* Using firmware slot B. If this flag is clear, using slot A. */
|
||||
VB2_CONTEXT_FW_SLOT_B = (1 << 6),
|
||||
|
||||
/* RAM should be cleared by caller this boot */
|
||||
VB2_CONTEXT_CLEAR_RAM = (1 << 7),
|
||||
};
|
||||
|
||||
/*
|
||||
* Context for firmware verification. Pass this to all vboot APIs.
|
||||
*
|
||||
* Caller may relocate this between calls to vboot APIs.
|
||||
*/
|
||||
struct vb2_context {
|
||||
/**********************************************************************
|
||||
* Fields which must be initialized by caller.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Flags; see vb2_context_flags. Some flags may only be set by caller
|
||||
* prior to calling vboot functions.
|
||||
*/
|
||||
uint32_t flags;
|
||||
|
||||
/*
|
||||
* Work buffer, and length in bytes. Caller may relocate this between
|
||||
* calls to vboot APIs; it contains no internal pointers. Caller must
|
||||
* not examine the contents of this work buffer directly.
|
||||
*/
|
||||
uint8_t *workbuf;
|
||||
uint32_t workbuf_size;
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
uint8_t nvdata[VB2_NVDATA_SIZE];
|
||||
|
||||
/*
|
||||
* Secure data. 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.
|
||||
*/
|
||||
uint8_t secdata[VB2_SECDATA_SIZE];
|
||||
|
||||
/*
|
||||
* Context pointer for use by caller. Verified boot never looks at
|
||||
* this. Put context here if you need it for APIs that verified boot
|
||||
* may call (vb2ex_...() functions).
|
||||
*/
|
||||
void *non_vboot_context;
|
||||
|
||||
/**********************************************************************
|
||||
* Fields caller may examine after calling vb2api_fw_phase1(). Caller
|
||||
* must set these fields to 0 before calling any vboot functions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Amount of work buffer used so far. Verified boot sub-calls use
|
||||
* this to know where the unused work area starts. Caller may use
|
||||
* this between calls to vboot APIs to know how much data must be
|
||||
* copied when relocating the work buffer.
|
||||
*/
|
||||
uint32_t workbuf_used;
|
||||
};
|
||||
|
||||
#endif /* VBOOT_2_API_H_ */
|
||||
@@ -9,6 +9,7 @@
|
||||
#define VBOOT_REFERENCE_VBOOT_2COMMON_H_
|
||||
|
||||
#include "2return_codes.h"
|
||||
#include "2struct.h"
|
||||
|
||||
struct vb2_public_key;
|
||||
|
||||
@@ -92,7 +93,7 @@ void *vb2_workbuf_realloc(struct vb2_workbuf *wb,
|
||||
void vb2_workbuf_free(struct vb2_workbuf *wb, uint32_t size);
|
||||
|
||||
/* Check if a pointer is aligned on an align-byte boundary */
|
||||
#define vb_aligned(ptr, align) (!(((size_t)(ptr)) & ((align) - 1)))
|
||||
#define vb_aligned(ptr, align) (!(((uintptr_t)(ptr)) & ((align) - 1)))
|
||||
|
||||
/**
|
||||
* Align a buffer and check its size.
|
||||
|
||||
20
firmware/2lib/include/2crc8.h
Normal file
20
firmware/2lib/include/2crc8.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* 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.
|
||||
*
|
||||
* Very simple 8-bit CRC function.
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_REFERENCE_2_CRC8_H_
|
||||
#define VBOOT_REFERENCE_2_CRC8_H_
|
||||
|
||||
/**
|
||||
* Calculate CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial.
|
||||
*
|
||||
* @param data Data to CRC
|
||||
* @param size Size of data in bytes
|
||||
* @return CRC-8 of the data.
|
||||
*/
|
||||
uint8_t vb2_crc8(const void *data, uint32_t size);
|
||||
|
||||
#endif /* VBOOT_REFERENCE_2_CRC8_H_ */
|
||||
35
firmware/2lib/include/2misc.h
Normal file
35
firmware/2lib/include/2misc.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* 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.
|
||||
*
|
||||
* Misc functions which need access to vb2_context but are not public APIs
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_REFERENCE_VBOOT_2MISC_H_
|
||||
#define VBOOT_REFERENCE_VBOOT_2MISC_H_
|
||||
|
||||
#include "2api.h"
|
||||
|
||||
/**
|
||||
* Get the shared data pointer from the vboot context
|
||||
*
|
||||
* @param ctx Vboot context
|
||||
* @return The shared data pointer.
|
||||
*/
|
||||
static __inline struct vb2_shared_data *vb2_get_sd(struct vb2_context *ctx) {
|
||||
return (struct vb2_shared_data *)ctx->workbuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the verified boot context data, if not already set up.
|
||||
*
|
||||
* This uses ctx->workbuf_used=0 as a flag to indicate that the data has not
|
||||
* yet been set up. Caller must set that before calling any voot functions;
|
||||
* see 2api.h.
|
||||
*
|
||||
* @param ctx Vboot context to initialize
|
||||
* @return VB2_SUCCESS, or error code on error.
|
||||
*/
|
||||
int vb2_init_context(struct vb2_context *ctx);
|
||||
|
||||
#endif /* VBOOT_REFERENCE_VBOOT_2MISC_H_ */
|
||||
135
firmware/2lib/include/2nvstorage.h
Normal file
135
firmware/2lib/include/2nvstorage.h
Normal file
@@ -0,0 +1,135 @@
|
||||
/* 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.
|
||||
*
|
||||
* Non-volatile storage routines
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_REFERENCE_VBOOT_2NVSTORAGE_H_
|
||||
#define VBOOT_REFERENCE_VBOOT_2NVSTORAGE_H_
|
||||
|
||||
enum vb2_nv_param {
|
||||
/*
|
||||
* Parameter values have been reset to defaults (flag for firmware).
|
||||
* 0=clear; 1=set.
|
||||
*/
|
||||
VB2_NV_FIRMWARE_SETTINGS_RESET = 0,
|
||||
/*
|
||||
* Parameter values have been reset to defaults (flag for kernel).
|
||||
* 0=clear; 1=set.
|
||||
*/
|
||||
VB2_NV_KERNEL_SETTINGS_RESET,
|
||||
/* Request debug reset on next S3->S0 transition. 0=clear; 1=set. */
|
||||
VB2_NV_DEBUG_RESET_MODE,
|
||||
/* Firmware slot to try next. 0=A, 1=B */
|
||||
VB2_NV_TRY_NEXT,
|
||||
/*
|
||||
* Number of times to try booting RW firmware slot B before slot A.
|
||||
* Valid range: 0-15.
|
||||
*
|
||||
* For VB2, number of times to try booting the slot indicated by
|
||||
* VB2_NV_TRY_NEXT. On a 1->0 transition of try count, VB2_NV_TRY_NEXT
|
||||
* will be set to the other slot.
|
||||
*/
|
||||
VB2_NV_TRY_COUNT,
|
||||
/*
|
||||
* Request recovery mode on next boot; see 2recovery_reason.h for
|
||||
* currently defined reason codes. 8-bit value.
|
||||
*/
|
||||
VB2_NV_RECOVERY_REQUEST,
|
||||
/*
|
||||
* Localization index for screen bitmaps displayed by firmware.
|
||||
* 8-bit value.
|
||||
*/
|
||||
VB2_NV_LOCALIZATION_INDEX,
|
||||
/* Field reserved for kernel/user-mode use; 32-bit value. */
|
||||
VB2_NV_KERNEL_FIELD,
|
||||
/* Allow booting from USB in developer mode. 0=no, 1=yes. */
|
||||
VB2_NV_DEV_BOOT_USB,
|
||||
/* Allow booting of legacy OSes in developer mode. 0=no, 1=yes. */
|
||||
VB2_NV_DEV_BOOT_LEGACY,
|
||||
/* Only boot Google-signed images in developer mode. 0=no, 1=yes. */
|
||||
VB2_NV_DEV_BOOT_SIGNED_ONLY,
|
||||
/*
|
||||
* Set by userspace to request that RO firmware disable dev-mode on the
|
||||
* next boot. This is likely only possible if the dev-switch is
|
||||
* virtual.
|
||||
*/
|
||||
VB2_NV_DISABLE_DEV_REQUEST,
|
||||
/*
|
||||
* Set and cleared by vboot to request that the video Option ROM be
|
||||
* loaded at boot time, so that BIOS screens can be displayed. 0=no,
|
||||
* 1=yes.
|
||||
*/
|
||||
VB2_NV_OPROM_NEEDED,
|
||||
/* Request that the firmware clear the TPM owner on the next boot. */
|
||||
VB2_NV_CLEAR_TPM_OWNER_REQUEST,
|
||||
/* Flag that TPM owner was cleared on request. */
|
||||
VB2_NV_CLEAR_TPM_OWNER_DONE,
|
||||
/* More details on recovery reason */
|
||||
VB2_NV_RECOVERY_SUBCODE,
|
||||
/* Firmware slot tried this boot (0=A, 1=B) */
|
||||
VB2_NV_FW_TRIED,
|
||||
/* Result of trying that firmware (see vb2_fw_result) */
|
||||
VB2_NV_FW_RESULT,
|
||||
};
|
||||
|
||||
/* Result of trying the firmware in VB2_NV_FW_TRIED */
|
||||
enum vb2_fw_result {
|
||||
/* Unknown */
|
||||
VB2_FW_RESULT_UNKNOWN = 0,
|
||||
|
||||
/* Trying a new slot, but haven't reached success/failure */
|
||||
VB2_FW_RESULT_TRYING = 1,
|
||||
|
||||
/* Successfully booted to the OS */
|
||||
VB2_FW_RESULT_SUCCESS = 2,
|
||||
|
||||
/* Known failure */
|
||||
VB2_FW_RESULT_FAILURE = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* Check the CRC of the non-volatile storage context.
|
||||
*
|
||||
* Use this if reading from non-volatile storage may be flaky, and you want to
|
||||
* retry reading it several times.
|
||||
*
|
||||
* This may be called before vb2_context_init().
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||
*/
|
||||
int vb2_nv_check_crc(const struct vb2_context *ctx);
|
||||
|
||||
/**
|
||||
* Initialize the non-volatile storage context and verify its CRC.
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
*/
|
||||
void vb2_nv_init(struct vb2_context *ctx);
|
||||
|
||||
/**
|
||||
* Read a non-volatile value.
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
* @param param Parameter to read
|
||||
* @return The value of the parameter. If you somehow force an invalid
|
||||
* parameter number, returns 0.
|
||||
*/
|
||||
uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param);
|
||||
|
||||
/**
|
||||
* Write a non-volatile value.
|
||||
*
|
||||
* Ignores writes to unknown params.
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
* @param param Parameter to write
|
||||
* @param value New value
|
||||
*/
|
||||
void vb2_nv_set(struct vb2_context *ctx,
|
||||
enum vb2_nv_param param,
|
||||
uint32_t value);
|
||||
|
||||
#endif /* VBOOT_REFERENCE_VBOOT_2NVSTORAGE_H_ */
|
||||
204
firmware/2lib/include/2recovery_reasons.h
Normal file
204
firmware/2lib/include/2recovery_reasons.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/* 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.
|
||||
*
|
||||
* Recovery reasons
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_REFERENCE_VBOOT_2RECOVERY_REASONS_H_
|
||||
#define VBOOT_REFERENCE_VBOOT_2RECOVERY_REASONS_H_
|
||||
|
||||
/* Recovery reason codes */
|
||||
enum vb2_nv_recovery {
|
||||
/* Recovery not requested. */
|
||||
VB2_RECOVERY_NOT_REQUESTED = 0x00,
|
||||
|
||||
/*
|
||||
* Recovery requested from legacy utility. (Prior to the NV storage
|
||||
* spec, recovery mode was a single bitfield; this value is reserved so
|
||||
* that scripts which wrote 1 to the recovery field are distinguishable
|
||||
* from scripts whch use the recovery reasons listed here.
|
||||
*/
|
||||
VB2_RECOVERY_LEGACY = 0x01,
|
||||
|
||||
/* User manually requested recovery via recovery button */
|
||||
VB2_RECOVERY_RO_MANUAL = 0x02,
|
||||
|
||||
/*
|
||||
* RW firmware failed signature check (neither RW firmware slot was
|
||||
* valid)
|
||||
*/
|
||||
VB2_RECOVERY_RO_INVALID_RW = 0x03,
|
||||
|
||||
/* S3 resume failed */
|
||||
VB2_RECOVERY_RO_S3_RESUME = 0x04,
|
||||
|
||||
/* TPM error in read-only firmware (deprecated) */
|
||||
VB2_RECOVERY_DEP_RO_TPM_ERROR = 0x05,
|
||||
|
||||
/* Shared data error in read-only firmware */
|
||||
VB2_RECOVERY_RO_SHARED_DATA = 0x06,
|
||||
|
||||
/* Test error from S3Resume() */
|
||||
VB2_RECOVERY_RO_TEST_S3 = 0x07,
|
||||
|
||||
/* Test error from LoadFirmwareSetup() (deprecated) */
|
||||
VB2_RECOVERY_RO_TEST_LFS = 0x08,
|
||||
|
||||
/* Test error from LoadFirmware() (deprecated) */
|
||||
VB2_RECOVERY_RO_TEST_LF = 0x09,
|
||||
|
||||
/*
|
||||
* RW firmware failed signature check (neither RW firmware slot was
|
||||
* valid). Recovery reason is VB2_RECOVERY_RO_INVALID_RW_CHECK_MIN +
|
||||
* the check value for the slot which came closest to validating; see
|
||||
* VBSD_LF_CHECK_* in vboot_struct.h.
|
||||
*/
|
||||
// TODO: pass back those codes from vboot2?
|
||||
VB2_RECOVERY_RO_INVALID_RW_CHECK_MIN = 0x10,
|
||||
VB2_RECOVERY_RO_INVALID_RW_CHECK_MAX = 0x1F,
|
||||
|
||||
/*
|
||||
* Firmware boot failure outside of verified boot (RAM init, missing
|
||||
* SSD, etc.).
|
||||
*/
|
||||
VB2_RECOVERY_RO_FIRMWARE = 0x20,
|
||||
|
||||
/*
|
||||
* Recovery mode TPM initialization requires a system reboot. The
|
||||
* system was already in recovery mode for some other reason when this
|
||||
* happened.
|
||||
*/
|
||||
VB2_RECOVERY_RO_TPM_REBOOT = 0x21,
|
||||
|
||||
/* EC software sync - other error */
|
||||
VB2_RECOVERY_EC_SOFTWARE_SYNC = 0x22,
|
||||
|
||||
/* EC software sync - unable to determine active EC image */
|
||||
VB2_RECOVERY_EC_UNKNOWN_IMAGE = 0x23,
|
||||
|
||||
/* EC software sync - error obtaining EC image hash (deprecated) */
|
||||
VB2_RECOVERY_DEP_EC_HASH = 0x24,
|
||||
|
||||
/* EC software sync - error obtaining expected EC image */
|
||||
VB2_RECOVERY_EC_EXPECTED_IMAGE = 0x25,
|
||||
|
||||
/* EC software sync - error updating EC */
|
||||
VB2_RECOVERY_EC_UPDATE = 0x26,
|
||||
|
||||
/* EC software sync - unable to jump to EC-RW */
|
||||
VB2_RECOVERY_EC_JUMP_RW = 0x27,
|
||||
|
||||
/* EC software sync - unable to protect / unprotect EC-RW */
|
||||
VB2_RECOVERY_EC_PROTECT = 0x28,
|
||||
|
||||
/* EC software sync - error obtaining expected EC hash */
|
||||
VB2_RECOVERY_EC_EXPECTED_HASH = 0x29,
|
||||
|
||||
/* EC software sync - expected EC image doesn't match hash */
|
||||
VB2_RECOVERY_EC_HASH_MISMATCH = 0x2a,
|
||||
|
||||
/* New error codes from VB2 */
|
||||
// TODO: may need to add strings for these in the original fwlib
|
||||
|
||||
/* Secure data inititalization error */
|
||||
VB2_RECOVERY_SECDATA_INIT = 0x2b,
|
||||
|
||||
/* GBB header is bad */
|
||||
VB2_RECOVERY_GBB_HEADER = 0x2c,
|
||||
|
||||
/* Unable to clear TPM owner */
|
||||
VB2_RECOVERY_TPM_CLEAR_OWNER = 0x2d,
|
||||
|
||||
/* Error determining/updating virtual dev switch */
|
||||
VB2_RECOVERY_DEV_SWITCH = 0x2e,
|
||||
|
||||
/* Error determining firmware slot */
|
||||
VB2_RECOVERY_FW_SLOT = 0x2f,
|
||||
|
||||
/* Unspecified/unknown error in read-only firmware */
|
||||
VB2_RECOVERY_RO_UNSPECIFIED = 0x3f,
|
||||
|
||||
/*
|
||||
* User manually requested recovery by pressing a key at developer
|
||||
* warning screen
|
||||
*/
|
||||
VB2_RECOVERY_RW_DEV_SCREEN = 0x41,
|
||||
|
||||
/* No OS kernel detected */
|
||||
VB2_RECOVERY_RW_NO_OS = 0x42,
|
||||
|
||||
/* OS kernel failed signature check */
|
||||
VB2_RECOVERY_RW_INVALID_OS = 0x43,
|
||||
|
||||
/* TPM error in rewritable firmware (deprecated) */
|
||||
VB2_RECOVERY_DEP_RW_TPM_ERROR = 0x44,
|
||||
|
||||
/* RW firmware in dev mode, but dev switch is off */
|
||||
VB2_RECOVERY_RW_DEV_MISMATCH = 0x45,
|
||||
|
||||
/* Shared data error in rewritable firmware */
|
||||
VB2_RECOVERY_RW_SHARED_DATA = 0x46,
|
||||
|
||||
/* Test error from LoadKernel() */
|
||||
VB2_RECOVERY_RW_TEST_LK = 0x47,
|
||||
|
||||
/* No bootable disk found (deprecated)*/
|
||||
VB2_RECOVERY_DEP_RW_NO_DISK = 0x48,
|
||||
|
||||
/* Rebooting did not correct TPM_E_FAIL or TPM_E_FAILEDSELFTEST */
|
||||
VB2_RECOVERY_TPM_E_FAIL = 0x49,
|
||||
|
||||
/* TPM setup error in read-only firmware */
|
||||
VB2_RECOVERY_RO_TPM_S_ERROR = 0x50,
|
||||
|
||||
/* TPM write error in read-only firmware */
|
||||
VB2_RECOVERY_RO_TPM_W_ERROR = 0x51,
|
||||
|
||||
/* TPM lock error in read-only firmware */
|
||||
VB2_RECOVERY_RO_TPM_L_ERROR = 0x52,
|
||||
|
||||
/* TPM update error in read-only firmware */
|
||||
VB2_RECOVERY_RO_TPM_U_ERROR = 0x53,
|
||||
|
||||
/* TPM read error in rewritable firmware */
|
||||
VB2_RECOVERY_RW_TPM_R_ERROR = 0x54,
|
||||
|
||||
/* TPM write error in rewritable firmware */
|
||||
VB2_RECOVERY_RW_TPM_W_ERROR = 0x55,
|
||||
|
||||
/* TPM lock error in rewritable firmware */
|
||||
VB2_RECOVERY_RW_TPM_L_ERROR = 0x56,
|
||||
|
||||
/* EC software sync unable to get EC image hash */
|
||||
VB2_RECOVERY_EC_HASH_FAILED = 0x57,
|
||||
|
||||
/* EC software sync invalid image hash size */
|
||||
VB2_RECOVERY_EC_HASH_SIZE = 0x58,
|
||||
|
||||
/* Unspecified error while trying to load kernel */
|
||||
VB2_RECOVERY_LK_UNSPECIFIED = 0x59,
|
||||
|
||||
/* No bootable storage device in system */
|
||||
VB2_RECOVERY_RW_NO_DISK = 0x5a,
|
||||
|
||||
/* No bootable kernel found on disk */
|
||||
VB2_RECOVERY_RW_NO_KERNEL = 0x5b,
|
||||
|
||||
/* Unspecified/unknown error in rewritable firmware */
|
||||
VB2_RECOVERY_RW_UNSPECIFIED = 0x7f,
|
||||
|
||||
/* DM-verity error */
|
||||
VB2_RECOVERY_KE_DM_VERITY = 0x81,
|
||||
|
||||
/* Unspecified/unknown error in kernel */
|
||||
VB2_RECOVERY_KE_UNSPECIFIED = 0xbf,
|
||||
|
||||
/* Recovery mode test from user-mode */
|
||||
VB2_RECOVERY_US_TEST = 0xc1,
|
||||
|
||||
/* Unspecified/unknown error in user-mode */
|
||||
VB2_RECOVERY_US_UNSPECIFIED = 0xff,
|
||||
};
|
||||
|
||||
#endif /* VBOOT_REFERENCE_VBOOT_2RECOVERY_REASONS_H_ */
|
||||
117
firmware/2lib/include/2secdata.h
Normal file
117
firmware/2lib/include/2secdata.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/* 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.
|
||||
*
|
||||
* Secure non-volatile storage routines
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_REFERENCE_VBOOT_SECDATA_H_
|
||||
#define VBOOT_REFERENCE_VBOOT_SECDATA_H_
|
||||
|
||||
/* Expected value of vb2_secdata.version */
|
||||
#define VB2_SECDATA_VERSION 2
|
||||
|
||||
/* Flags for firmware space */
|
||||
enum vb2_secdata_flags {
|
||||
/*
|
||||
* Last boot was developer mode. TPM ownership is cleared when
|
||||
* transitioning to/from developer mode. Set/cleared by
|
||||
* vb2_check_dev_switch().
|
||||
*/
|
||||
VB2_SECDATA_FLAG_LAST_BOOT_DEVELOPER = (1 << 0),
|
||||
|
||||
/*
|
||||
* Virtual developer mode switch is on. Set/cleared by the
|
||||
* keyboard-controlled dev screens in recovery mode. Cleared by
|
||||
* vb2_check_dev_switch().
|
||||
*/
|
||||
VB2_SECDATA_FLAG_DEV_MODE = (1 << 1),
|
||||
};
|
||||
|
||||
/* Secure data area */
|
||||
struct vb2_secdata {
|
||||
/* Struct version, for backwards compatibility */
|
||||
uint8_t struct_version;
|
||||
|
||||
/* Flags; see vb2_secdata_flags */
|
||||
uint8_t flags;
|
||||
|
||||
/* Firmware versions */
|
||||
uint32_t fw_versions;
|
||||
|
||||
/* Reserved for future expansion */
|
||||
uint8_t reserved[3];
|
||||
|
||||
/* CRC; must be last field in struct */
|
||||
uint8_t crc8;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Which param to get/set for vb2_secdata_get() / vb2_secdata_set() */
|
||||
enum vb2_secdata_param {
|
||||
/* Flags; see vb2_secdata_flags */
|
||||
VB2_SECDATA_FLAGS = 0,
|
||||
|
||||
/* Firmware versions */
|
||||
VB2_SECDATA_VERSIONS,
|
||||
};
|
||||
|
||||
/**
|
||||
* Check the CRC of the secure storage context.
|
||||
*
|
||||
* Use this if reading from secure storage may be flaky, and you want to retry
|
||||
* reading it several times.
|
||||
*
|
||||
* This may be called before vb2_context_init().
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||
*/
|
||||
int vb2_secdata_check_crc(const struct vb2_context *ctx);
|
||||
|
||||
/**
|
||||
* Create fresh data in the 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 vb2_secdata_check_crc()
|
||||
* (or any other API in this library) fails; that could allow the secure data
|
||||
* to be rolled back to an insecure state.
|
||||
*
|
||||
* This may be called before vb2_context_init().
|
||||
*/
|
||||
int vb2_secdata_create(struct vb2_context *ctx);
|
||||
|
||||
/**
|
||||
* Initialize the secure storage context and verify its CRC.
|
||||
*
|
||||
* This must be called before vb2_secdata_get() or vb2_secdata_set().
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||
*/
|
||||
int vb2_secdata_init(struct vb2_context *ctx);
|
||||
|
||||
/**
|
||||
* Read a secure storage value.
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
* @param param Parameter to read
|
||||
* @param dest Destination for value
|
||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||
*/
|
||||
int vb2_secdata_get(struct vb2_context *ctx,
|
||||
enum vb2_secdata_param param,
|
||||
uint32_t *dest);
|
||||
|
||||
/**
|
||||
* Write a secure storage value.
|
||||
*
|
||||
* @param ctx Context pointer
|
||||
* @param param Parameter to write
|
||||
* @param value New value
|
||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||
*/
|
||||
int vb2_secdata_set(struct vb2_context *ctx,
|
||||
enum vb2_secdata_param param,
|
||||
uint32_t value);
|
||||
|
||||
#endif /* VBOOT_REFERENCE_VBOOT_2SECDATA_H_ */
|
||||
383
firmware/2lib/include/2struct.h
Normal file
383
firmware/2lib/include/2struct.h
Normal file
@@ -0,0 +1,383 @@
|
||||
/* 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.
|
||||
*
|
||||
* Data structure definitions for verified boot, for on-disk / in-eeprom
|
||||
* data.
|
||||
*/
|
||||
|
||||
#ifndef VBOOT_REFERENCE_VBOOT_2STRUCT_H_
|
||||
#define VBOOT_REFERENCE_VBOOT_2STRUCT_H_
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* Note: Many of the structs have pairs of 32-bit fields and reserved fields.
|
||||
* This is to be backwards-compatible with older verified boot data which used
|
||||
* 64-bit fields (when we thought that hey, UEFI is 64-bit so all our fields
|
||||
* should be too).
|
||||
*/
|
||||
|
||||
/* Packed public key data */
|
||||
struct vb2_packed_key {
|
||||
/* Offset of key data from start of this struct */
|
||||
uint32_t key_offset;
|
||||
uint32_t reserved0;
|
||||
|
||||
/* Size of key data in bytes (NOT strength of key in bits) */
|
||||
uint32_t key_size;
|
||||
uint32_t reserved1;
|
||||
|
||||
/* Signature algorithm used by the key */
|
||||
uint32_t algorithm;
|
||||
uint32_t reserved2;
|
||||
|
||||
/* Key version */
|
||||
uint32_t key_version;
|
||||
uint32_t reserved3;
|
||||
|
||||
/* TODO: when redoing this struct, add a text description of the key */
|
||||
} __attribute__((packed));
|
||||
|
||||
#define EXPECTED_VBPUBLICKEY_SIZE 32
|
||||
|
||||
/* Signature data (a secure hash, possibly signed) */
|
||||
struct vb2_signature {
|
||||
/* Offset of signature data from start of this struct */
|
||||
uint32_t sig_offset;
|
||||
uint32_t reserved0;
|
||||
|
||||
/* Size of signature data in bytes */
|
||||
uint32_t sig_size;
|
||||
uint32_t reserved1;
|
||||
|
||||
/* Size of the data block which was signed in bytes */
|
||||
uint32_t data_size;
|
||||
uint32_t reserved2;
|
||||
|
||||
/*
|
||||
* TODO: when redoing this struct, add a text description of the
|
||||
* signature (including what key was used) and an algorithm type field.
|
||||
*/
|
||||
} __attribute__((packed));
|
||||
|
||||
#define EXPECTED_VBSIGNATURE_SIZE 24
|
||||
|
||||
#define KEY_BLOCK_MAGIC "CHROMEOS"
|
||||
#define KEY_BLOCK_MAGIC_SIZE 8
|
||||
|
||||
#define KEY_BLOCK_HEADER_VERSION_MAJOR 2
|
||||
#define KEY_BLOCK_HEADER_VERSION_MINOR 1
|
||||
|
||||
/*
|
||||
* The following flags set where the key is valid. Not used by firmware
|
||||
* verification; only kernel verification.
|
||||
*/
|
||||
#define VB2_KEY_BLOCK_FLAG_DEVELOPER_0 0x01 /* Developer switch off */
|
||||
#define VB2_KEY_BLOCK_FLAG_DEVELOPER_1 0x02 /* Developer switch on */
|
||||
#define VB2_KEY_BLOCK_FLAG_RECOVERY_0 0x04 /* Not recovery mode */
|
||||
#define VB2_KEY_BLOCK_FLAG_RECOVERY_1 0x08 /* Recovery mode */
|
||||
|
||||
/*
|
||||
* Key block, containing the public key used to sign some other chunk of data.
|
||||
*
|
||||
* This should be followed by:
|
||||
* 1) The data_key key data, pointed to by data_key.key_offset.
|
||||
* 2) The checksum data for (vb2_keyblock + data_key data), pointed to
|
||||
* by keyblock_checksum.sig_offset.
|
||||
* 3) The signature data for (vb2_keyblock + data_key data), pointed to
|
||||
* by keyblock_signature.sig_offset.
|
||||
*/
|
||||
struct vb2_keyblock {
|
||||
/* Magic number */
|
||||
uint8_t magic[KEY_BLOCK_MAGIC_SIZE];
|
||||
|
||||
/* Version of this header format */
|
||||
uint32_t header_version_major;
|
||||
|
||||
/* Version of this header format */
|
||||
uint32_t header_version_minor;
|
||||
|
||||
/*
|
||||
* Length of this entire key block, including keys, signatures, and
|
||||
* padding, in bytes
|
||||
*/
|
||||
uint32_t keyblock_size;
|
||||
uint32_t reserved0;
|
||||
|
||||
/*
|
||||
* Signature for this key block (header + data pointed to by data_key)
|
||||
* For use with signed data keys
|
||||
*/
|
||||
struct vb2_signature keyblock_signature;
|
||||
|
||||
/*
|
||||
* SHA-512 checksum for this key block (header + data pointed to by
|
||||
* data_key) For use with unsigned data keys.
|
||||
*
|
||||
* Note that the vb2 lib currently only supports signed blocks.
|
||||
*/
|
||||
struct vb2_signature keyblock_checksum_unused;
|
||||
|
||||
/* Flags for key (VB2_KEY_BLOCK_FLAG_*) */
|
||||
uint32_t keyblock_flags;
|
||||
uint32_t reserved1;
|
||||
|
||||
/* Key to verify the chunk of data */
|
||||
struct vb2_packed_key data_key;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define EXPECTED_VB2KEYBLOCKHEADER_SIZE 112
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Firmware preamble header */
|
||||
#define FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR 2
|
||||
#define FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR 1
|
||||
|
||||
/* Flags for VbFirmwarePreambleHeader.flags */
|
||||
/* Reserved; do not use */
|
||||
#define VB2_FIRMWARE_PREAMBLE_RESERVED0 0x00000001
|
||||
|
||||
/* Premable block for rewritable firmware, version 2.1.
|
||||
*
|
||||
* The firmware preamble header should be followed by:
|
||||
* 1) The kernel_subkey key data, pointed to by kernel_subkey.key_offset.
|
||||
* 2) The signature data for the firmware body, pointed to by
|
||||
* body_signature.sig_offset.
|
||||
* 3) The signature data for (header + kernel_subkey data + body signature
|
||||
* data), pointed to by preamble_signature.sig_offset.
|
||||
*/
|
||||
struct vb2_fw_preamble {
|
||||
/*
|
||||
* Size of this preamble, including keys, signatures, and padding, in
|
||||
* bytes
|
||||
*/
|
||||
uint32_t preamble_size;
|
||||
uint32_t reserved0;
|
||||
|
||||
/*
|
||||
* Signature for this preamble (header + kernel subkey + body
|
||||
* signature)
|
||||
*/
|
||||
struct vb2_signature preamble_signature;
|
||||
|
||||
/* Version of this header format */
|
||||
uint32_t header_version_major;
|
||||
uint32_t header_version_minor;
|
||||
|
||||
/* Firmware version */
|
||||
uint32_t firmware_version;
|
||||
uint32_t reserved1;
|
||||
|
||||
/* Key to verify kernel key block */
|
||||
struct vb2_packed_key kernel_subkey;
|
||||
|
||||
/* Signature for the firmware body */
|
||||
struct vb2_signature body_signature;
|
||||
|
||||
/*
|
||||
* Fields added in header version 2.1. You must verify the header
|
||||
* version before reading these fields!
|
||||
*/
|
||||
|
||||
/*
|
||||
* Flags; see VB2_FIRMWARE_PREAMBLE_*. Readers should return 0 for
|
||||
* header version < 2.1.
|
||||
*/
|
||||
uint32_t flags;
|
||||
} __attribute__((packed));
|
||||
|
||||
#define EXPECTED_VB2FIRMWAREPREAMBLEHEADER2_1_SIZE 108
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Flags for vb2_shared_data.flags */
|
||||
enum vb2_shared_data_flags {
|
||||
/* User has explicitly and physically requested recovery */
|
||||
VB2_SD_FLAG_MANUAL_RECOVERY = (1 << 0),
|
||||
|
||||
/* Developer mode is enabled */
|
||||
VB2_SD_DEV_MODE_ENABLED = (1 << 1),
|
||||
|
||||
/*
|
||||
* TODO: might be nice to add flags for why dev mode is enabled - via
|
||||
* gbb, virtual dev switch, or forced on for testing.
|
||||
*/
|
||||
};
|
||||
|
||||
/* Flags for vb2_shared_data.status */
|
||||
enum vb2_shared_data_status {
|
||||
/* Reinitialized NV data due to invalid checksum */
|
||||
VB2_SD_STATUS_NV_REINIT = (1 << 0),
|
||||
|
||||
/* NV data has been initialized */
|
||||
VB2_SD_STATUS_NV_INIT = (1 << 1),
|
||||
|
||||
/* Secure data initialized */
|
||||
VB2_SD_STATUS_SECDATA_INIT = (1 << 2),
|
||||
|
||||
/* Chose a firmware slot */
|
||||
VB2_SD_STATUS_CHOSE_SLOT = (1 << 3),
|
||||
};
|
||||
|
||||
/*
|
||||
* Data shared between vboot API calls. Stored at the start of the work
|
||||
* buffer.
|
||||
*/
|
||||
struct vb2_shared_data {
|
||||
/* Flags; see enum vb2_shared_data_flags */
|
||||
uint32_t flags;
|
||||
|
||||
/* Flags from GBB header */
|
||||
uint32_t gbb_flags;
|
||||
|
||||
/* Reason we are in recovery mode this boot, or 0 if we aren't */
|
||||
uint32_t recovery_reason;
|
||||
|
||||
/* Firmware slot used last boot (0=A, 1=B) */
|
||||
uint32_t last_fw_slot;
|
||||
|
||||
/* Result of last boot (enum vb2_fw_result) */
|
||||
uint32_t last_fw_result;
|
||||
|
||||
/* Firmware slot used this boot */
|
||||
uint32_t fw_slot;
|
||||
|
||||
/*
|
||||
* Version for this slot (top 16 bits = key, lower 16 bits = firmware).
|
||||
*
|
||||
* TODO: Make this a union to allow getting/setting those versions
|
||||
* separately?
|
||||
*/
|
||||
uint32_t fw_version;
|
||||
|
||||
/*
|
||||
* Status flags for this boot; see enum vb2_shared_data_status. Status
|
||||
* is "what we've done"; flags above are "decisions we've made".
|
||||
*/
|
||||
uint32_t status;
|
||||
|
||||
/**********************************************************************
|
||||
* Temporary variables used during firmware verification. These don't
|
||||
* really need to persist through to the OS, but there's nowhere else
|
||||
* we can put them.
|
||||
*/
|
||||
|
||||
/* Root key offset and size from GBB header */
|
||||
uint32_t gbb_rootkey_offset;
|
||||
uint32_t gbb_rootkey_size;
|
||||
|
||||
/* Offset of preamble from start of vblock */
|
||||
uint32_t vblock_preamble_offset;
|
||||
|
||||
/*
|
||||
* Offset and size of packed data key in work buffer. Size is 0 if
|
||||
* data key is not stored in the work buffer.
|
||||
*/
|
||||
uint32_t workbuf_data_key_offset;
|
||||
uint32_t workbuf_data_key_size;
|
||||
|
||||
/*
|
||||
* Offset and size of firmware preamble in work buffer. Size if 0 if
|
||||
* preamble is not stored in the work buffer.
|
||||
*/
|
||||
uint32_t workbuf_preamble_offset;
|
||||
uint32_t workbuf_preamble_size;
|
||||
|
||||
/*
|
||||
* Offset and size of hash context in work buffer. Size if 0 if
|
||||
* hash context is not stored in the work buffer.
|
||||
*/
|
||||
uint32_t workbuf_hash_offset;
|
||||
uint32_t workbuf_hash_size;
|
||||
|
||||
/* Current tag we're hashing */
|
||||
uint32_t hash_tag;
|
||||
|
||||
/* Amount of data we still expect to hash */
|
||||
uint32_t hash_remaining_size;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/* Signature at start of the GBB */
|
||||
#define VB2_GBB_SIGNATURE "$GBB"
|
||||
#define VB2_GBB_SIGNATURE_SIZE 4
|
||||
|
||||
/* VB2 GBB struct version */
|
||||
#define VB2_GBB_MAJOR_VER 1
|
||||
#define VB2_GBB_MINOR_VER 1
|
||||
|
||||
/* Flags for vb2_gbb_header.flags */
|
||||
enum vb2_gbb_flag {
|
||||
/*
|
||||
* Reduce the dev screen delay to 2 sec from 30 sec to speed up
|
||||
* factory.
|
||||
*/
|
||||
VB2_GBB_FLAG_DEV_SCREEN_SHORT_DELAY = (1 << 0),
|
||||
|
||||
/*
|
||||
* BIOS should load option ROMs from arbitrary PCI devices. We'll never
|
||||
* enable this ourselves because it executes non-verified code, but if
|
||||
* a customer wants to void their warranty and set this flag in the
|
||||
* read-only flash, they should be able to do so.
|
||||
*/
|
||||
VB2_GBB_FLAG_LOAD_OPTION_ROMS = (1 << 1),
|
||||
|
||||
/*
|
||||
* The factory flow may need the BIOS to boot a non-ChromeOS kernel if
|
||||
* the dev-switch is on. This flag allows that.
|
||||
*/
|
||||
VB2_GBB_FLAG_ENABLE_ALTERNATE_OS = (1 << 2),
|
||||
|
||||
/*
|
||||
* Force dev switch on, regardless of physical/keyboard dev switch
|
||||
* position.
|
||||
*/
|
||||
VB2_GBB_FLAG_FORCE_DEV_SWITCH_ON = (1 << 3),
|
||||
|
||||
/* Allow booting from USB in dev mode even if dev_boot_usb=0. */
|
||||
VB2_GBB_FLAG_FORCE_DEV_BOOT_USB = (1 << 4),
|
||||
|
||||
/* Disable firmware rollback protection. */
|
||||
VB2_GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK = (1 << 5),
|
||||
|
||||
/* Allow Enter key to trigger dev->tonorm screen transition */
|
||||
VB2_GBB_FLAG_ENTER_TRIGGERS_TONORM = (1 << 6),
|
||||
|
||||
/* Allow booting Legacy OSes in dev mode even if dev_boot_legacy=0. */
|
||||
VB2_GBB_FLAG_FORCE_DEV_BOOT_LEGACY = (1 << 7),
|
||||
|
||||
/* Allow booting using alternate keys for FAFT servo testing */
|
||||
VB2_GBB_FLAG_FAFT_KEY_OVERIDE = (1 << 8),
|
||||
|
||||
/* Disable EC software sync */
|
||||
VB2_GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC = (1 << 9),
|
||||
|
||||
/* Default to booting legacy OS when dev screen times out */
|
||||
VB2_GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY = (1 << 10),
|
||||
};
|
||||
|
||||
struct vb2_gbb_header {
|
||||
/* Fields present in version 1.1 */
|
||||
uint8_t signature[VB2_GBB_SIGNATURE_SIZE]; /* VB2_GBB_SIGNATURE */
|
||||
uint16_t major_version; /* See VB2_GBB_MAJOR_VER */
|
||||
uint16_t minor_version; /* See VB2_GBB_MINOR_VER */
|
||||
uint32_t header_size; /* Size of GBB header in bytes */
|
||||
uint32_t flags; /* Flags (see enum vb2_gbb_flag) */
|
||||
|
||||
/* Offsets (from start of header) and sizes (in bytes) of components */
|
||||
uint32_t hwid_offset; /* HWID */
|
||||
uint32_t hwid_size;
|
||||
uint32_t rootkey_offset; /* Root key */
|
||||
uint32_t rootkey_size;
|
||||
uint32_t bmpfv_offset; /* BMP FV */
|
||||
uint32_t bmpfv_size;
|
||||
uint32_t recovery_key_offset; /* Recovery key */
|
||||
uint32_t recovery_key_size;
|
||||
|
||||
uint8_t pad[80]; /* To match GBB_HEADER_SIZE. Initialize to 0. */
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* VBOOT_REFERENCE_VBOOT_2STRUCT_H_ */
|
||||
54
tests/vb2_misc_tests.c
Normal file
54
tests/vb2_misc_tests.c
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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 misc library
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test_common.h"
|
||||
#include "vboot_common.h"
|
||||
|
||||
#include "2api.h"
|
||||
#include "2common.h"
|
||||
#include "2misc.h"
|
||||
|
||||
static void misc_test(void)
|
||||
{
|
||||
uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE];
|
||||
|
||||
struct vb2_context c = {
|
||||
.workbuf = workbuf,
|
||||
.workbuf_size = sizeof(workbuf),
|
||||
};
|
||||
|
||||
TEST_EQ(vb2_init_context(&c), 0, "Init context good");
|
||||
TEST_EQ(c.workbuf_used, sizeof(struct vb2_shared_data),
|
||||
"Init vbsd");
|
||||
|
||||
/* Don't re-init if used is non-zero */
|
||||
c.workbuf_used = 200;
|
||||
TEST_EQ(vb2_init_context(&c), 0, "Re-init context good");
|
||||
TEST_EQ(c.workbuf_used, 200, "Didn't re-init");
|
||||
|
||||
/* Handle workbuf errors */
|
||||
c.workbuf_used = 0;
|
||||
c.workbuf_size = sizeof(struct vb2_shared_data) - 1;
|
||||
TEST_NEQ(vb2_init_context(&c), 0, "Init too small");
|
||||
c.workbuf_size = sizeof(workbuf);
|
||||
|
||||
/* Handle workbuf unaligned */
|
||||
c.workbuf++;
|
||||
TEST_NEQ(vb2_init_context(&c), 0, "Init unaligned");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
misc_test();
|
||||
|
||||
return gTestSuccess ? 0 : 255;
|
||||
}
|
||||
192
tests/vb2_nvstorage_tests.c
Normal file
192
tests/vb2_nvstorage_tests.c
Normal file
@@ -0,0 +1,192 @@
|
||||
/* 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 firmware NV storage library.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test_common.h"
|
||||
#include "vboot_common.h"
|
||||
|
||||
#include "2api.h"
|
||||
#include "2common.h"
|
||||
#include "2misc.h"
|
||||
#include "2nvstorage.h"
|
||||
|
||||
/* Single NV storage field to test */
|
||||
struct nv_field {
|
||||
enum vb2_nv_param param; /* Parameter index */
|
||||
uint32_t default_value; /* Expected default value */
|
||||
uint32_t test_value; /* Value to test writing */
|
||||
uint32_t test_value2; /* Second value to test writing */
|
||||
char *desc; /* Field description */
|
||||
};
|
||||
|
||||
/* Array of fields to test, terminated with a field with desc==NULL. */
|
||||
static struct nv_field nvfields[] = {
|
||||
{VB2_NV_DEBUG_RESET_MODE, 0, 1, 0, "debug reset mode"},
|
||||
{VB2_NV_TRY_NEXT, 0, 1, 0, "try next"},
|
||||
{VB2_NV_TRY_COUNT, 0, 6, 15, "try B count"},
|
||||
{VB2_NV_FW_TRIED, 0, 1, 0, "firmware tried"},
|
||||
{VB2_NV_FW_RESULT, 0, 1, 2, "firmware result"},
|
||||
{VB2_NV_RECOVERY_REQUEST, 0, 0x42, 0xED, "recovery request"},
|
||||
{VB2_NV_RECOVERY_SUBCODE, 0, 0x56, 0xAC, "recovery subcode"},
|
||||
{VB2_NV_LOCALIZATION_INDEX, 0, 0x69, 0xB0, "localization index"},
|
||||
{VB2_NV_KERNEL_FIELD, 0, 0x12345678, 0xFEDCBA98, "kernel field"},
|
||||
{VB2_NV_DEV_BOOT_USB, 0, 1, 0, "dev boot usb"},
|
||||
{VB2_NV_DEV_BOOT_LEGACY, 0, 1, 0, "dev boot legacy"},
|
||||
{VB2_NV_DEV_BOOT_SIGNED_ONLY, 0, 1, 0, "dev boot custom"},
|
||||
{VB2_NV_DISABLE_DEV_REQUEST, 0, 1, 0, "disable dev request"},
|
||||
{VB2_NV_CLEAR_TPM_OWNER_REQUEST, 0, 1, 0, "clear tpm owner request"},
|
||||
{VB2_NV_CLEAR_TPM_OWNER_DONE, 0, 1, 0, "clear tpm owner done"},
|
||||
{VB2_NV_OPROM_NEEDED, 0, 1, 0, "oprom needed"},
|
||||
{0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
static void test_changed(struct vb2_context *ctx, int changed, const char *why)
|
||||
{
|
||||
if (changed)
|
||||
TEST_NEQ(ctx->flags & VB2_CONTEXT_NVDATA_CHANGED, 0, why);
|
||||
else
|
||||
TEST_EQ(ctx->flags & VB2_CONTEXT_NVDATA_CHANGED, 0, why);
|
||||
};
|
||||
|
||||
static void nv_storage_test(void)
|
||||
{
|
||||
struct nv_field *vnf;
|
||||
uint8_t goodcrc;
|
||||
uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE];
|
||||
struct vb2_context c = {
|
||||
.flags = 0,
|
||||
.workbuf = workbuf,
|
||||
.workbuf_size = sizeof(workbuf),
|
||||
};
|
||||
struct vb2_shared_data *sd = vb2_get_sd(&c);
|
||||
|
||||
memset(c.nvdata, 0xA6, sizeof(c.nvdata));
|
||||
vb2_init_context(&c);
|
||||
|
||||
/* Init with invalid data should set defaults and regenerate CRC */
|
||||
vb2_nv_init(&c);
|
||||
TEST_EQ(c.nvdata[0], 0x70, "vb2_nv_init() reset header byte");
|
||||
TEST_NEQ(c.nvdata[15], 0, "vb2_nv_init() CRC");
|
||||
TEST_EQ(sd->status, VB2_SD_STATUS_NV_INIT | VB2_SD_STATUS_NV_REINIT,
|
||||
"vb2_nv_init() status changed");
|
||||
test_changed(&c, 1, "vb2_nv_init() reset changed");
|
||||
goodcrc = c.nvdata[15];
|
||||
|
||||
/* Another init should not cause further changes */
|
||||
c.flags = 0;
|
||||
sd->status = 0;
|
||||
vb2_nv_init(&c);
|
||||
test_changed(&c, 0, "vb2_nv_init() didn't re-reset");
|
||||
TEST_EQ(c.nvdata[15], goodcrc, "vb2_nv_init() CRC same");
|
||||
TEST_EQ(sd->status, VB2_SD_STATUS_NV_INIT, "vb2_nv_init() status same");
|
||||
|
||||
/* Perturbing the header should force defaults */
|
||||
c.nvdata[0] ^= 0x40;
|
||||
vb2_nv_init(&c);
|
||||
TEST_EQ(c.nvdata[0], 0x70, "vb2_nv_init() reset header byte again");
|
||||
test_changed(&c, 1, "vb2_nv_init() corrupt changed");
|
||||
TEST_EQ(c.nvdata[15], goodcrc, "vb2_nv_init() CRC same again");
|
||||
|
||||
/* So should perturbing some other byte */
|
||||
TEST_EQ(c.nvdata[11], 0, "Kernel byte starts at 0");
|
||||
c.nvdata[11] = 12;
|
||||
vb2_nv_init(&c);
|
||||
TEST_EQ(c.nvdata[11], 0, "vb2_nv_init() reset kernel byte");
|
||||
test_changed(&c, 1, "vb2_nv_init() corrupt elsewhere changed");
|
||||
TEST_EQ(c.nvdata[15], goodcrc, "vb2_nv_init() CRC same again");
|
||||
|
||||
/* Clear the kernel and firmware flags */
|
||||
vb2_nv_init(&c);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_FIRMWARE_SETTINGS_RESET),
|
||||
1, "Firmware settings are reset");
|
||||
vb2_nv_set(&c, VB2_NV_FIRMWARE_SETTINGS_RESET, 0);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_FIRMWARE_SETTINGS_RESET),
|
||||
0, "Firmware settings are clear");
|
||||
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_KERNEL_SETTINGS_RESET),
|
||||
1, "Kernel settings are reset");
|
||||
vb2_nv_set(&c, VB2_NV_KERNEL_SETTINGS_RESET, 0);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_KERNEL_SETTINGS_RESET),
|
||||
0, "Kernel settings are clear");
|
||||
|
||||
TEST_EQ(c.nvdata[0], 0x40, "Header byte now just has the header bit");
|
||||
/* That should have changed the CRC */
|
||||
TEST_NEQ(c.nvdata[15], goodcrc,
|
||||
"vb2_nv_init() CRC changed due to flags clear");
|
||||
|
||||
/* Test explicitly setting the reset flags again */
|
||||
vb2_nv_init(&c);
|
||||
vb2_nv_set(&c, VB2_NV_FIRMWARE_SETTINGS_RESET, 1);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_FIRMWARE_SETTINGS_RESET),
|
||||
1, "Firmware settings forced reset");
|
||||
vb2_nv_set(&c, VB2_NV_FIRMWARE_SETTINGS_RESET, 0);
|
||||
|
||||
vb2_nv_set(&c, VB2_NV_KERNEL_SETTINGS_RESET, 1);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_KERNEL_SETTINGS_RESET),
|
||||
1, "Kernel settings forced reset");
|
||||
vb2_nv_set(&c, VB2_NV_KERNEL_SETTINGS_RESET, 0);
|
||||
|
||||
/* Get/set an invalid field */
|
||||
vb2_nv_init(&c);
|
||||
vb2_nv_set(&c, -1, 1);
|
||||
TEST_EQ(vb2_nv_get(&c, -1), 0, "Get invalid setting");
|
||||
|
||||
/* Test other fields */
|
||||
vb2_nv_init(&c);
|
||||
for (vnf = nvfields; vnf->desc; vnf++) {
|
||||
TEST_EQ(vb2_nv_get(&c, vnf->param), vnf->default_value,
|
||||
vnf->desc);
|
||||
vb2_nv_set(&c, vnf->param, vnf->test_value);
|
||||
TEST_EQ(vb2_nv_get(&c, vnf->param), vnf->test_value, vnf->desc);
|
||||
vb2_nv_set(&c, vnf->param, vnf->test_value2);
|
||||
TEST_EQ(vb2_nv_get(&c, vnf->param), vnf->test_value2,
|
||||
vnf->desc);
|
||||
}
|
||||
|
||||
/* None of those changes should have caused a reset to defaults */
|
||||
vb2_nv_init(&c);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_FIRMWARE_SETTINGS_RESET),
|
||||
0, "Firmware settings are still clear");
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_KERNEL_SETTINGS_RESET),
|
||||
0, "Kernel settings are still clear");
|
||||
|
||||
/* Writing identical settings doesn't cause the CRC to regenerate */
|
||||
c.flags = 0;
|
||||
vb2_nv_init(&c);
|
||||
test_changed(&c, 0, "No regen CRC on open");
|
||||
for (vnf = nvfields; vnf->desc; vnf++)
|
||||
vb2_nv_set(&c, vnf->param, vnf->test_value2);
|
||||
test_changed(&c, 0, "No regen CRC if data not changed");
|
||||
|
||||
/* Test out-of-range fields mapping to defaults or failing */
|
||||
vb2_nv_init(&c);
|
||||
vb2_nv_set(&c, VB2_NV_TRY_COUNT, 16);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_TRY_COUNT),
|
||||
15, "Try b count out of range");
|
||||
vb2_nv_set(&c, VB2_NV_RECOVERY_REQUEST, 0x101);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_RECOVERY_REQUEST),
|
||||
VB2_RECOVERY_LEGACY, "Recovery request out of range");
|
||||
vb2_nv_set(&c, VB2_NV_LOCALIZATION_INDEX, 0x102);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_LOCALIZATION_INDEX),
|
||||
0, "Localization index out of range");
|
||||
|
||||
vb2_nv_set(&c, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN + 1);
|
||||
vb2_nv_set(&c, VB2_NV_FW_RESULT, VB2_FW_RESULT_UNKNOWN + 100);
|
||||
TEST_EQ(vb2_nv_get(&c, VB2_NV_FW_RESULT),
|
||||
VB2_FW_RESULT_UNKNOWN, "Firmware result out of range");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
nv_storage_test();
|
||||
|
||||
return gTestSuccess ? 0 : 255;
|
||||
}
|
||||
103
tests/vb2_secdata_tests.c
Normal file
103
tests/vb2_secdata_tests.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/* 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 firmware secure storage library.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "test_common.h"
|
||||
#include "vboot_common.h"
|
||||
|
||||
#include "2common.h"
|
||||
#include "2api.h"
|
||||
#include "2secdata.h"
|
||||
|
||||
static void test_changed(struct vb2_context *ctx, int changed, const char *why)
|
||||
{
|
||||
if (changed)
|
||||
TEST_NEQ(ctx->flags & VB2_CONTEXT_SECDATA_CHANGED, 0, why);
|
||||
else
|
||||
TEST_EQ(ctx->flags & VB2_CONTEXT_SECDATA_CHANGED, 0, why);
|
||||
|
||||
ctx->flags &= ~VB2_CONTEXT_SECDATA_CHANGED;
|
||||
};
|
||||
|
||||
static void secdata_test(void)
|
||||
{
|
||||
uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE];
|
||||
struct vb2_context c = {
|
||||
.flags = 0,
|
||||
.workbuf = workbuf,
|
||||
.workbuf_size = sizeof(workbuf),
|
||||
};
|
||||
struct vb2_secdata *s = (struct vb2_secdata *)c.secdata;
|
||||
uint32_t v = 1;
|
||||
|
||||
/* Blank data is invalid */
|
||||
memset(c.secdata, 0xa6, sizeof(c.secdata));
|
||||
TEST_NEQ(vb2_secdata_check_crc(&c), 0, "Check blank CRC");
|
||||
TEST_NEQ(vb2_secdata_init(&c), 0, "Init blank CRC");
|
||||
|
||||
/* Create good data */
|
||||
TEST_EQ(vb2_secdata_create(&c), 0, "Create");
|
||||
TEST_EQ(vb2_secdata_check_crc(&c), 0, "Check created CRC");
|
||||
TEST_EQ(vb2_secdata_init(&c), 0, "Init created CRC");
|
||||
test_changed(&c, 1, "Create changes data");
|
||||
|
||||
/* Now corrupt it */
|
||||
c.secdata[2]++;
|
||||
TEST_NEQ(vb2_secdata_check_crc(&c), 0, "Check invalid CRC");
|
||||
TEST_NEQ(vb2_secdata_init(&c), 0, "Init invalid CRC");
|
||||
|
||||
/* Version 1 didn't have a CRC, so init should reject it */
|
||||
vb2_secdata_create(&c);
|
||||
s->struct_version = 1;
|
||||
TEST_NEQ(vb2_secdata_init(&c), 0, "Init old version");
|
||||
|
||||
vb2_secdata_create(&c);
|
||||
c.flags = 0;
|
||||
|
||||
/* Read/write flags */
|
||||
TEST_EQ(vb2_secdata_get(&c, VB2_SECDATA_FLAGS, &v), 0, "Get flags");
|
||||
TEST_EQ(v, 0, "Flags created 0");
|
||||
test_changed(&c, 0, "Get doesn't change data");
|
||||
TEST_EQ(vb2_secdata_set(&c, VB2_SECDATA_FLAGS, 0x12), 0, "Set flags");
|
||||
test_changed(&c, 1, "Set changes data");
|
||||
TEST_EQ(vb2_secdata_set(&c, VB2_SECDATA_FLAGS, 0x12), 0, "Set flags 2");
|
||||
test_changed(&c, 0, "Set again doesn't change data");
|
||||
TEST_EQ(vb2_secdata_get(&c, VB2_SECDATA_FLAGS, &v), 0, "Get flags 2");
|
||||
TEST_EQ(v, 0x12, "Flags changed");
|
||||
TEST_NEQ(vb2_secdata_set(&c, VB2_SECDATA_FLAGS, 0x100), 0, "Bad flags");
|
||||
|
||||
/* Read/write versions */
|
||||
TEST_EQ(vb2_secdata_get(&c, VB2_SECDATA_VERSIONS, &v),
|
||||
0, "Get versions");
|
||||
TEST_EQ(v, 0, "Versions created 0");
|
||||
test_changed(&c, 0, "Get doesn't change data");
|
||||
TEST_EQ(vb2_secdata_set(&c, VB2_SECDATA_VERSIONS, 0x123456ff),
|
||||
0, "Set versions");
|
||||
test_changed(&c, 1, "Set changes data");
|
||||
TEST_EQ(vb2_secdata_set(&c, VB2_SECDATA_VERSIONS, 0x123456ff),
|
||||
0, "Set versions 2");
|
||||
test_changed(&c, 0, "Set again doesn't change data");
|
||||
TEST_EQ(vb2_secdata_get(&c, VB2_SECDATA_VERSIONS, &v), 0,
|
||||
"Get versions 2");
|
||||
TEST_EQ(v, 0x123456ff, "Versions changed");
|
||||
|
||||
/* Invalid field fails */
|
||||
TEST_NEQ(vb2_secdata_get(&c, -1, &v), 0, "Get invalid");
|
||||
TEST_NEQ(vb2_secdata_set(&c, -1, 456), 0, "Set invalid");
|
||||
test_changed(&c, 0, "Set invalid field doesn't change data");
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
secdata_test();
|
||||
|
||||
return gTestSuccess ? 0 : 255;
|
||||
}
|
||||
Reference in New Issue
Block a user