mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
vboot2: Move old struct handling to lib20/
This is part 4 of a series of changes to rearrange the vboot2 library
so that it's possible to start using the new-style data structs. This
change moves knowledge of the old vboot1 data structs into lib20; 2lib
now contains only code which is common to both vboot2.x libraries
(that is, code which is data structure version agnostic).
No functional changes; just rearranging code and tests.
BUG=chromium:423882
BRANCH=none
TEST=make runtests && VBOOT2=1 make runtests (works with/withoug VBOOT2 flag)
And compile firmware for veyron_pinky
CQ-DEPEND=CL:233051
Change-Id: I8f9e67157575e5be14952ef4809c3dfafd92596d
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/233021
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
This commit is contained in:
committed by
chrome-internal-fetch
parent
fe2714923b
commit
6f1b82ac14
70
Makefile
70
Makefile
@@ -235,8 +235,12 @@ endif
|
|||||||
# this source tree locally and link to it directly.
|
# this source tree locally and link to it directly.
|
||||||
FWLIB = ${BUILD}/vboot_fw.a
|
FWLIB = ${BUILD}/vboot_fw.a
|
||||||
|
|
||||||
# Smaller firmware library. TODO: Do we still need to export this?
|
# Smaller firmware library
|
||||||
|
# Stuff common to all vboot 2.x
|
||||||
|
FWLIB2X = ${BUILD}/vboot_fw2x.a
|
||||||
|
# Vboot 2.0 (stuck with this filename due to dependencies in coreboot)
|
||||||
FWLIB20 = ${BUILD}/vboot_fw2.a
|
FWLIB20 = ${BUILD}/vboot_fw2.a
|
||||||
|
# Vboot 2.1
|
||||||
FWLIB21 = ${BUILD}/vboot_fw21.a
|
FWLIB21 = ${BUILD}/vboot_fw21.a
|
||||||
|
|
||||||
# Firmware library sources needed by VbInit() call
|
# Firmware library sources needed by VbInit() call
|
||||||
@@ -278,6 +282,7 @@ VBSLK_SRCS = \
|
|||||||
firmware/lib/region-kernel.c \
|
firmware/lib/region-kernel.c \
|
||||||
|
|
||||||
# Firmware library source needed for smaller library 2
|
# Firmware library source needed for smaller library 2
|
||||||
|
# Code common to vboot 2.0 (old structs) and 2.1 (new structs)
|
||||||
FWLIB2_SRCS = \
|
FWLIB2_SRCS = \
|
||||||
firmware/2lib/2api.c \
|
firmware/2lib/2api.c \
|
||||||
firmware/2lib/2common.c \
|
firmware/2lib/2common.c \
|
||||||
@@ -292,7 +297,10 @@ FWLIB2_SRCS = \
|
|||||||
firmware/2lib/2sha_utility.c
|
firmware/2lib/2sha_utility.c
|
||||||
|
|
||||||
FWLIB20_SRCS = \
|
FWLIB20_SRCS = \
|
||||||
firmware/2lib/2packed_key.c
|
firmware/lib20/api.c \
|
||||||
|
firmware/lib20/common.c \
|
||||||
|
firmware/lib20/misc.c \
|
||||||
|
firmware/lib20/packed_key.c
|
||||||
|
|
||||||
FWLIB21_SRCS = \
|
FWLIB21_SRCS = \
|
||||||
firmware/lib21/api.c \
|
firmware/lib21/api.c \
|
||||||
@@ -631,19 +639,23 @@ ifdef REGION_READ
|
|||||||
TEST_NAMES += tests/vboot_region_tests
|
TEST_NAMES += tests/vboot_region_tests
|
||||||
endif
|
endif
|
||||||
|
|
||||||
TEST20_NAMES = \
|
TEST2X_NAMES = \
|
||||||
tests/vb2_api_tests \
|
tests/vb2_api_tests \
|
||||||
tests/vb2_common_tests \
|
tests/vb2_common_tests \
|
||||||
tests/vb2_common2_tests \
|
|
||||||
tests/vb2_common3_tests \
|
|
||||||
tests/vb2_misc_tests \
|
tests/vb2_misc_tests \
|
||||||
tests/vb2_misc2_tests \
|
|
||||||
tests/vb2_nvstorage_tests \
|
tests/vb2_nvstorage_tests \
|
||||||
tests/vb2_rsa_padding_tests \
|
|
||||||
tests/vb2_rsa_utility_tests \
|
tests/vb2_rsa_utility_tests \
|
||||||
tests/vb2_secdata_tests \
|
tests/vb2_secdata_tests \
|
||||||
tests/vb2_sha_tests
|
tests/vb2_sha_tests
|
||||||
|
|
||||||
|
TEST20_NAMES = \
|
||||||
|
tests/vb20_api_tests \
|
||||||
|
tests/vb20_common_tests \
|
||||||
|
tests/vb20_common2_tests \
|
||||||
|
tests/vb20_common3_tests \
|
||||||
|
tests/vb20_misc_tests \
|
||||||
|
tests/vb20_rsa_padding_tests
|
||||||
|
|
||||||
TEST21_NAMES = \
|
TEST21_NAMES = \
|
||||||
tests/vb21_api_tests \
|
tests/vb21_api_tests \
|
||||||
tests/vb21_common_tests \
|
tests/vb21_common_tests \
|
||||||
@@ -656,7 +668,7 @@ TEST21_NAMES = \
|
|||||||
tests/vb21_host_sig_tests
|
tests/vb21_host_sig_tests
|
||||||
|
|
||||||
ifneq (${VBOOT2},)
|
ifneq (${VBOOT2},)
|
||||||
TEST_NAMES += ${TEST20_NAMES} ${TEST21_NAMES}
|
TEST_NAMES += ${TEST2X_NAMES} ${TEST20_NAMES} ${TEST21_NAMES}
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# And a few more...
|
# And a few more...
|
||||||
@@ -679,6 +691,7 @@ TEST_NAMES += ${TLCL_TEST_NAMES}
|
|||||||
TEST_BINS = $(addprefix ${BUILD}/,${TEST_NAMES})
|
TEST_BINS = $(addprefix ${BUILD}/,${TEST_NAMES})
|
||||||
TEST_OBJS += $(addsuffix .o,${TEST_BINS})
|
TEST_OBJS += $(addsuffix .o,${TEST_BINS})
|
||||||
|
|
||||||
|
TEST2X_BINS = $(addprefix ${BUILD}/,${TEST2X_NAMES})
|
||||||
TEST20_BINS = $(addprefix ${BUILD}/,${TEST20_NAMES})
|
TEST20_BINS = $(addprefix ${BUILD}/,${TEST20_NAMES})
|
||||||
TEST21_BINS = $(addprefix ${BUILD}/,${TEST21_NAMES})
|
TEST21_BINS = $(addprefix ${BUILD}/,${TEST21_NAMES})
|
||||||
|
|
||||||
@@ -700,7 +713,7 @@ _dir_create := $(foreach d, \
|
|||||||
# Default target.
|
# Default target.
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: fwlib \
|
all: fwlib \
|
||||||
$(if ${VBOOT2},fwlib2 fwlib21) \
|
$(if ${VBOOT2},fwlib2x fwlib2 fwlib21) \
|
||||||
$(if ${FIRMWARE_ARCH},,host_stuff) \
|
$(if ${FIRMWARE_ARCH},,host_stuff) \
|
||||||
$(if ${COV},coverage)
|
$(if ${COV},coverage)
|
||||||
|
|
||||||
@@ -772,6 +785,7 @@ ifeq (${FIRMWARE_ARCH},)
|
|||||||
${FWLIB_OBJS}: CFLAGS += -DDISABLE_ROLLBACK_TPM
|
${FWLIB_OBJS}: CFLAGS += -DDISABLE_ROLLBACK_TPM
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
${FWLIB20_OBJS}: INCLUDES += -Ifirmware/lib20/include
|
||||||
${FWLIB21_OBJS}: INCLUDES += -Ifirmware/lib21/include
|
${FWLIB21_OBJS}: INCLUDES += -Ifirmware/lib21/include
|
||||||
|
|
||||||
# Linktest ensures firmware lib doesn't rely on outside libraries
|
# Linktest ensures firmware lib doesn't rely on outside libraries
|
||||||
@@ -800,6 +814,16 @@ ${FWLIB}: ${FWLIB_OBJS}
|
|||||||
@$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n"
|
@$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n"
|
||||||
${Q}ar qc $@ $^
|
${Q}ar qc $@ $^
|
||||||
|
|
||||||
|
.PHONY: fwlib2x
|
||||||
|
fwlib2x: ${FWLIB2X}
|
||||||
|
|
||||||
|
${FWLIB2X}: ${FWLIB2_OBJS}
|
||||||
|
@$(PRINTF) " RM $(subst ${BUILD}/,,$@)\n"
|
||||||
|
${Q}rm -f $@
|
||||||
|
@$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n"
|
||||||
|
${Q}ar qc $@ $^
|
||||||
|
|
||||||
|
# TODO: it'd be nice to call this fwlib20, but coreboot expects fwlib2
|
||||||
.PHONY: fwlib2
|
.PHONY: fwlib2
|
||||||
fwlib2: ${FWLIB20}
|
fwlib2: ${FWLIB20}
|
||||||
|
|
||||||
@@ -841,9 +865,7 @@ ${UTILLIB}: ${UTILLIB_OBJS} ${FWLIB_OBJS}
|
|||||||
utillib21: ${UTILLIB21}
|
utillib21: ${UTILLIB21}
|
||||||
|
|
||||||
${UTILLIB21}: INCLUDES += -Ihost/lib21/include -Ifirmware/lib21/include
|
${UTILLIB21}: INCLUDES += -Ihost/lib21/include -Ifirmware/lib21/include
|
||||||
|
${UTILLIB21}: ${UTILLIB21_OBJS} ${FWLIB2_OBJS} ${FWLIB21_OBJS}
|
||||||
# TODO: right now, firmware lib 2.1 isn't a complete standalone copy
|
|
||||||
${UTILLIB21}: ${UTILLIB21_OBJS} ${FWLIB2_OBJS} ${FWLIB20_OBJS} ${FWLIB21_OBJS}
|
|
||||||
@$(PRINTF) " RM $(subst ${BUILD}/,,$@)\n"
|
@$(PRINTF) " RM $(subst ${BUILD}/,,$@)\n"
|
||||||
${Q}rm -f $@
|
${Q}rm -f $@
|
||||||
@$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n"
|
@$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n"
|
||||||
@@ -938,12 +960,12 @@ signing_install: ${SIGNING_SCRIPTS} ${SIGNING_SCRIPTS_DEV} ${SIGNING_COMMON}
|
|||||||
futil: ${FUTIL_STATIC_BIN} ${FUTIL_BIN}
|
futil: ${FUTIL_STATIC_BIN} ${FUTIL_BIN}
|
||||||
|
|
||||||
${FUTIL_STATIC_BIN}: ${FUTIL_STATIC_OBJS} ${UTILLIB} \
|
${FUTIL_STATIC_BIN}: ${FUTIL_STATIC_OBJS} ${UTILLIB} \
|
||||||
$(if ${VBOOT2},${UTILLIB21})
|
$(if ${VBOOT2},${FWLIB20})
|
||||||
@$(PRINTF) " LD $(subst ${BUILD}/,,$@)\n"
|
@$(PRINTF) " LD $(subst ${BUILD}/,,$@)\n"
|
||||||
${Q}${LD} -o $@ ${CFLAGS} ${LDFLAGS} -static $^ ${LDLIBS}
|
${Q}${LD} -o $@ ${CFLAGS} ${LDFLAGS} -static $^ ${LDLIBS}
|
||||||
|
|
||||||
${FUTIL_BIN}: LDLIBS += ${CRYPTO_LIBS}
|
${FUTIL_BIN}: LDLIBS += ${CRYPTO_LIBS}
|
||||||
${FUTIL_BIN}: ${FUTIL_OBJS} ${UTILLIB} $(if ${VBOOT2},${UTILLIB21})
|
${FUTIL_BIN}: ${FUTIL_OBJS} ${UTILLIB} $(if ${VBOOT2},${FWLIB20})
|
||||||
@$(PRINTF) " LD $(subst ${BUILD}/,,$@)\n"
|
@$(PRINTF) " LD $(subst ${BUILD}/,,$@)\n"
|
||||||
${Q}${LD} -o $@ ${CFLAGS} ${LDFLAGS} $^ ${LDLIBS}
|
${Q}${LD} -o $@ ${CFLAGS} ${LDFLAGS} $^ ${LDLIBS}
|
||||||
|
|
||||||
@@ -981,7 +1003,11 @@ ${TEST_BINS}: ${UTILLIB} ${TESTLIB}
|
|||||||
${TEST_BINS}: INCLUDES += -Itests
|
${TEST_BINS}: INCLUDES += -Itests
|
||||||
${TEST_BINS}: LIBS = ${TESTLIB} ${UTILLIB}
|
${TEST_BINS}: LIBS = ${TESTLIB} ${UTILLIB}
|
||||||
|
|
||||||
|
${TEST2X_BINS}: ${FWLIB2X}
|
||||||
|
${TEST2X_BINS}: LIBS += ${FWLIB2X}
|
||||||
|
|
||||||
${TEST20_BINS}: ${FWLIB20}
|
${TEST20_BINS}: ${FWLIB20}
|
||||||
|
${TEST20_BINS}: INCLUDES += -Ifirmware/lib20/include
|
||||||
${TEST20_BINS}: LIBS += ${FWLIB20}
|
${TEST20_BINS}: LIBS += ${FWLIB20}
|
||||||
|
|
||||||
${TEST21_BINS}: ${UTILLIB21}
|
${TEST21_BINS}: ${UTILLIB21}
|
||||||
@@ -1041,8 +1067,8 @@ ${BUILD}/utility/signature_digest_utility: LDLIBS += ${CRYPTO_LIBS}
|
|||||||
${BUILD}/host/linktest/main: LDLIBS += ${CRYPTO_LIBS}
|
${BUILD}/host/linktest/main: LDLIBS += ${CRYPTO_LIBS}
|
||||||
${BUILD}/tests/vboot_common2_tests: LDLIBS += ${CRYPTO_LIBS}
|
${BUILD}/tests/vboot_common2_tests: LDLIBS += ${CRYPTO_LIBS}
|
||||||
${BUILD}/tests/vboot_common3_tests: LDLIBS += ${CRYPTO_LIBS}
|
${BUILD}/tests/vboot_common3_tests: LDLIBS += ${CRYPTO_LIBS}
|
||||||
${BUILD}/tests/vb2_common2_tests: LDLIBS += ${CRYPTO_LIBS}
|
${BUILD}/tests/vb20_common2_tests: LDLIBS += ${CRYPTO_LIBS}
|
||||||
${BUILD}/tests/vb2_common3_tests: LDLIBS += ${CRYPTO_LIBS}
|
${BUILD}/tests/vb20_common3_tests: LDLIBS += ${CRYPTO_LIBS}
|
||||||
|
|
||||||
${TEST21_BINS}: LDLIBS += ${CRYPTO_LIBS}
|
${TEST21_BINS}: LDLIBS += ${CRYPTO_LIBS}
|
||||||
|
|
||||||
@@ -1219,14 +1245,16 @@ runmisctests: test_setup
|
|||||||
run2tests: test_setup
|
run2tests: test_setup
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_api_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb2_api_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_common_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb2_common_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_common2_tests ${TEST_KEYS}
|
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_common3_tests ${TEST_KEYS}
|
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_misc_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb2_misc_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_misc2_tests
|
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_tests
|
||||||
|
${RUNTEST} ${BUILD_RUN}/tests/vb20_api_tests
|
||||||
|
${RUNTEST} ${BUILD_RUN}/tests/vb20_common_tests
|
||||||
|
${RUNTEST} ${BUILD_RUN}/tests/vb20_common2_tests ${TEST_KEYS}
|
||||||
|
${RUNTEST} ${BUILD_RUN}/tests/vb20_common3_tests ${TEST_KEYS}
|
||||||
|
${RUNTEST} ${BUILD_RUN}/tests/vb20_misc_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb21_api_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb21_api_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb21_common_tests
|
${RUNTEST} ${BUILD_RUN}/tests/vb21_common_tests
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb21_common2_tests ${TEST_KEYS}
|
${RUNTEST} ${BUILD_RUN}/tests/vb21_common2_tests ${TEST_KEYS}
|
||||||
@@ -1250,8 +1278,8 @@ runlongtests: test_setup genkeys genfuzztestcases
|
|||||||
${RUNTEST} ${BUILD_RUN}/tests/vboot_common2_tests ${TEST_KEYS} --all
|
${RUNTEST} ${BUILD_RUN}/tests/vboot_common2_tests ${TEST_KEYS} --all
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vboot_common3_tests ${TEST_KEYS} --all
|
${RUNTEST} ${BUILD_RUN}/tests/vboot_common3_tests ${TEST_KEYS} --all
|
||||||
ifneq (${VBOOT2},)
|
ifneq (${VBOOT2},)
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_common2_tests ${TEST_KEYS} --all
|
${RUNTEST} ${BUILD_RUN}/tests/vb20_common2_tests ${TEST_KEYS} --all
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb2_common3_tests ${TEST_KEYS} --all
|
${RUNTEST} ${BUILD_RUN}/tests/vb20_common3_tests ${TEST_KEYS} --all
|
||||||
${RUNTEST} ${BUILD_RUN}/tests/vb21_common2_tests ${TEST_KEYS} --all
|
${RUNTEST} ${BUILD_RUN}/tests/vb21_common2_tests ${TEST_KEYS} --all
|
||||||
endif
|
endif
|
||||||
tests/run_preamble_tests.sh --all
|
tests/run_preamble_tests.sh --all
|
||||||
|
|||||||
@@ -100,94 +100,6 @@ int vb2api_fw_phase2(struct vb2_context *ctx)
|
|||||||
return VB2_SUCCESS;
|
return VB2_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vb2api_fw_phase3(struct vb2_context *ctx)
|
|
||||||
{
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
/* Verify firmware keyblock */
|
|
||||||
rv = vb2_load_fw_keyblock(ctx);
|
|
||||||
if (rv) {
|
|
||||||
vb2_fail(ctx, VB2_RECOVERY_RO_INVALID_RW, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify firmware preamble */
|
|
||||||
rv = vb2_load_fw_preamble(ctx);
|
|
||||||
if (rv) {
|
|
||||||
vb2_fail(ctx, VB2_RECOVERY_RO_INVALID_RW, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2api_init_hash(struct vb2_context *ctx, uint32_t tag, uint32_t *size)
|
|
||||||
{
|
|
||||||
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
|
||||||
const struct vb2_fw_preamble *pre;
|
|
||||||
struct vb2_digest_context *dc;
|
|
||||||
struct vb2_public_key key;
|
|
||||||
struct vb2_workbuf wb;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
vb2_workbuf_from_ctx(ctx, &wb);
|
|
||||||
|
|
||||||
if (tag == VB2_HASH_TAG_INVALID)
|
|
||||||
return VB2_ERROR_API_INIT_HASH_TAG;
|
|
||||||
|
|
||||||
/* Get preamble pointer */
|
|
||||||
if (!sd->workbuf_preamble_size)
|
|
||||||
return VB2_ERROR_API_INIT_HASH_PREAMBLE;
|
|
||||||
pre = (const struct vb2_fw_preamble *)
|
|
||||||
(ctx->workbuf + sd->workbuf_preamble_offset);
|
|
||||||
|
|
||||||
/* For now, we only support the firmware body tag */
|
|
||||||
if (tag != VB2_HASH_TAG_FW_BODY)
|
|
||||||
return VB2_ERROR_API_INIT_HASH_TAG;
|
|
||||||
|
|
||||||
/* Allocate workbuf space for the hash */
|
|
||||||
if (sd->workbuf_hash_size) {
|
|
||||||
dc = (struct vb2_digest_context *)
|
|
||||||
(ctx->workbuf + sd->workbuf_hash_offset);
|
|
||||||
} else {
|
|
||||||
uint32_t dig_size = sizeof(*dc);
|
|
||||||
|
|
||||||
dc = vb2_workbuf_alloc(&wb, dig_size);
|
|
||||||
if (!dc)
|
|
||||||
return VB2_ERROR_API_INIT_HASH_WORKBUF;
|
|
||||||
|
|
||||||
sd->workbuf_hash_offset = vb2_offset_of(ctx->workbuf, dc);
|
|
||||||
sd->workbuf_hash_size = dig_size;
|
|
||||||
ctx->workbuf_used = sd->workbuf_hash_offset + dig_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Unpack the firmware data key to see which hashing algorithm we
|
|
||||||
* should use.
|
|
||||||
*
|
|
||||||
* TODO: really, the firmware body should be hashed, and not signed,
|
|
||||||
* because the signature we're checking is already signed as part of
|
|
||||||
* the firmware preamble. But until we can change the signing scripts,
|
|
||||||
* we're stuck with a signature here instead of a hash.
|
|
||||||
*/
|
|
||||||
if (!sd->workbuf_data_key_size)
|
|
||||||
return VB2_ERROR_API_INIT_HASH_DATA_KEY;
|
|
||||||
|
|
||||||
rv = vb2_unpack_key(&key,
|
|
||||||
ctx->workbuf + sd->workbuf_data_key_offset,
|
|
||||||
sd->workbuf_data_key_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
sd->hash_tag = tag;
|
|
||||||
sd->hash_remaining_size = pre->body_signature.data_size;
|
|
||||||
|
|
||||||
if (size)
|
|
||||||
*size = pre->body_signature.data_size;
|
|
||||||
|
|
||||||
return vb2_digest_init(dc, key.hash_alg);
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2api_extend_hash(struct vb2_context *ctx,
|
int vb2api_extend_hash(struct vb2_context *ctx,
|
||||||
const void *buf,
|
const void *buf,
|
||||||
uint32_t size)
|
uint32_t size)
|
||||||
@@ -208,73 +120,3 @@ int vb2api_extend_hash(struct vb2_context *ctx,
|
|||||||
|
|
||||||
return vb2_digest_extend(dc, buf, size);
|
return vb2_digest_extend(dc, buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vb2api_check_hash(struct vb2_context *ctx)
|
|
||||||
{
|
|
||||||
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
|
||||||
struct vb2_digest_context *dc = (struct vb2_digest_context *)
|
|
||||||
(ctx->workbuf + sd->workbuf_hash_offset);
|
|
||||||
struct vb2_workbuf wb;
|
|
||||||
|
|
||||||
uint8_t *digest;
|
|
||||||
uint32_t digest_size = vb2_digest_size(dc->hash_alg);
|
|
||||||
|
|
||||||
struct vb2_fw_preamble *pre;
|
|
||||||
struct vb2_public_key key;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
vb2_workbuf_from_ctx(ctx, &wb);
|
|
||||||
|
|
||||||
/* Get preamble pointer */
|
|
||||||
if (!sd->workbuf_preamble_size)
|
|
||||||
return VB2_ERROR_API_CHECK_HASH_PREAMBLE;
|
|
||||||
pre = (struct vb2_fw_preamble *)
|
|
||||||
(ctx->workbuf + sd->workbuf_preamble_offset);
|
|
||||||
|
|
||||||
/* Must have initialized hash digest work area */
|
|
||||||
if (!sd->workbuf_hash_size)
|
|
||||||
return VB2_ERROR_API_CHECK_HASH_WORKBUF;
|
|
||||||
|
|
||||||
/* Should have hashed the right amount of data */
|
|
||||||
if (sd->hash_remaining_size)
|
|
||||||
return VB2_ERROR_API_CHECK_HASH_SIZE;
|
|
||||||
|
|
||||||
/* Allocate the digest */
|
|
||||||
digest = vb2_workbuf_alloc(&wb, digest_size);
|
|
||||||
if (!digest)
|
|
||||||
return VB2_ERROR_API_CHECK_HASH_WORKBUF_DIGEST;
|
|
||||||
|
|
||||||
/* Finalize the digest */
|
|
||||||
rv = vb2_digest_finalize(dc, digest, digest_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* The code below is specific to the body signature */
|
|
||||||
if (sd->hash_tag != VB2_HASH_TAG_FW_BODY)
|
|
||||||
return VB2_ERROR_API_CHECK_HASH_TAG;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The body signature is currently a *signature* of the body data, not
|
|
||||||
* just its hash. So we need to verify the signature.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Unpack the data key */
|
|
||||||
if (!sd->workbuf_data_key_size)
|
|
||||||
return VB2_ERROR_API_CHECK_HASH_DATA_KEY;
|
|
||||||
|
|
||||||
rv = vb2_unpack_key(&key,
|
|
||||||
ctx->workbuf + sd->workbuf_data_key_offset,
|
|
||||||
sd->workbuf_data_key_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check digest vs. signature. Note that this destroys the signature.
|
|
||||||
* That's ok, because we only check each signature once per boot.
|
|
||||||
*/
|
|
||||||
rv = vb2_verify_digest(&key, &pre->body_signature, digest, &wb);
|
|
||||||
if (rv)
|
|
||||||
vb2_fail(ctx, VB2_RECOVERY_RO_INVALID_RW, rv);
|
|
||||||
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -110,267 +110,7 @@ void vb2_workbuf_free(struct vb2_workbuf *wb, uint32_t size)
|
|||||||
wb->size += size;
|
wb->size += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *vb2_signature_data(struct vb2_signature *sig)
|
|
||||||
{
|
|
||||||
return (uint8_t *)sig + sig->sig_offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptrdiff_t vb2_offset_of(const void *base, const void *ptr)
|
ptrdiff_t vb2_offset_of(const void *base, const void *ptr)
|
||||||
{
|
{
|
||||||
return (uintptr_t)ptr - (uintptr_t)base;
|
return (uintptr_t)ptr - (uintptr_t)base;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vb2_verify_member_inside(const void *parent, size_t parent_size,
|
|
||||||
const void *member, size_t member_size,
|
|
||||||
ptrdiff_t member_data_offset,
|
|
||||||
size_t member_data_size)
|
|
||||||
{
|
|
||||||
const uintptr_t parent_end = (uintptr_t)parent + parent_size;
|
|
||||||
const ptrdiff_t member_offs = vb2_offset_of(parent, member);
|
|
||||||
const ptrdiff_t member_end_offs = member_offs + member_size;
|
|
||||||
const ptrdiff_t data_offs = member_offs + member_data_offset;
|
|
||||||
const ptrdiff_t data_end_offs = data_offs + member_data_size;
|
|
||||||
|
|
||||||
/* Make sure parent doesn't wrap */
|
|
||||||
if (parent_size < 0 || parent_end < (uintptr_t)parent)
|
|
||||||
return VB2_ERROR_INSIDE_PARENT_WRAPS;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Make sure the member is fully contained in the parent and doesn't
|
|
||||||
* wrap. Use >, not >=, since member_size = 0 is possible.
|
|
||||||
*/
|
|
||||||
if (member_size < 0 || member_end_offs < member_offs)
|
|
||||||
return VB2_ERROR_INSIDE_MEMBER_WRAPS;
|
|
||||||
if (member_offs < 0 || member_offs > parent_size ||
|
|
||||||
member_end_offs > parent_size)
|
|
||||||
return VB2_ERROR_INSIDE_MEMBER_OUTSIDE;
|
|
||||||
|
|
||||||
/* Make sure the member data is after the member */
|
|
||||||
if (member_data_size > 0 && data_offs < member_end_offs)
|
|
||||||
return VB2_ERROR_INSIDE_DATA_OVERLAP;
|
|
||||||
|
|
||||||
/* Make sure parent fully contains member data, if any */
|
|
||||||
if (member_data_size < 0 || data_end_offs < data_offs)
|
|
||||||
return VB2_ERROR_INSIDE_DATA_WRAPS;
|
|
||||||
if (data_offs < 0 || data_offs > parent_size ||
|
|
||||||
data_end_offs > parent_size)
|
|
||||||
return VB2_ERROR_INSIDE_DATA_OUTSIDE;
|
|
||||||
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_verify_signature_inside(const void *parent,
|
|
||||||
uint32_t parent_size,
|
|
||||||
const struct vb2_signature *sig)
|
|
||||||
{
|
|
||||||
return vb2_verify_member_inside(parent, parent_size,
|
|
||||||
sig, sizeof(*sig),
|
|
||||||
sig->sig_offset, sig->sig_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_verify_digest(const struct vb2_public_key *key,
|
|
||||||
struct vb2_signature *sig,
|
|
||||||
const uint8_t *digest,
|
|
||||||
const struct vb2_workbuf *wb)
|
|
||||||
{
|
|
||||||
uint8_t *sig_data = vb2_signature_data(sig);
|
|
||||||
|
|
||||||
if (sig->sig_size != vb2_rsa_sig_size(key->sig_alg)) {
|
|
||||||
VB2_DEBUG("Wrong data signature size for algorithm, "
|
|
||||||
"sig_size=%d, expected %d for algorithm %d.\n",
|
|
||||||
sig->sig_size, vb2_rsa_sig_size(key->sig_alg),
|
|
||||||
key->sig_alg);
|
|
||||||
return VB2_ERROR_VDATA_SIG_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return vb2_rsa_verify_digest(key, sig_data, digest, wb);
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_verify_data(const uint8_t *data,
|
|
||||||
uint32_t size,
|
|
||||||
struct vb2_signature *sig,
|
|
||||||
const struct vb2_public_key *key,
|
|
||||||
const struct vb2_workbuf *wb)
|
|
||||||
{
|
|
||||||
struct vb2_workbuf wblocal = *wb;
|
|
||||||
struct vb2_digest_context *dc;
|
|
||||||
uint8_t *digest;
|
|
||||||
uint32_t digest_size;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (sig->data_size > size) {
|
|
||||||
VB2_DEBUG("Data buffer smaller than length of signed data.\n");
|
|
||||||
return VB2_ERROR_VDATA_NOT_ENOUGH_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Digest goes at start of work buffer */
|
|
||||||
digest_size = vb2_digest_size(key->hash_alg);
|
|
||||||
if (!digest_size)
|
|
||||||
return VB2_ERROR_VDATA_DIGEST_SIZE;
|
|
||||||
|
|
||||||
digest = vb2_workbuf_alloc(&wblocal, digest_size);
|
|
||||||
if (!digest)
|
|
||||||
return VB2_ERROR_VDATA_WORKBUF_DIGEST;
|
|
||||||
|
|
||||||
/* Hashing requires temp space for the context */
|
|
||||||
dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc));
|
|
||||||
if (!dc)
|
|
||||||
return VB2_ERROR_VDATA_WORKBUF_HASHING;
|
|
||||||
|
|
||||||
rv = vb2_digest_init(dc, key->hash_alg);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
rv = vb2_digest_extend(dc, data, sig->data_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
rv = vb2_digest_finalize(dc, digest, digest_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
vb2_workbuf_free(&wblocal, sizeof(*dc));
|
|
||||||
|
|
||||||
return vb2_verify_digest(key, sig, digest, &wblocal);
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_verify_keyblock(struct vb2_keyblock *block,
|
|
||||||
uint32_t size,
|
|
||||||
const struct vb2_public_key *key,
|
|
||||||
const struct vb2_workbuf *wb)
|
|
||||||
{
|
|
||||||
struct vb2_signature *sig;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
/* Sanity checks before attempting signature of data */
|
|
||||||
if(size < sizeof(*block)) {
|
|
||||||
VB2_DEBUG("Not enough space for key block header.\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_TOO_SMALL_FOR_HEADER;
|
|
||||||
}
|
|
||||||
if (memcmp(block->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE)) {
|
|
||||||
VB2_DEBUG("Not a valid verified boot key block.\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_MAGIC;
|
|
||||||
}
|
|
||||||
if (block->header_version_major != KEY_BLOCK_HEADER_VERSION_MAJOR) {
|
|
||||||
VB2_DEBUG("Incompatible key block header version.\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_HEADER_VERSION;
|
|
||||||
}
|
|
||||||
if (size < block->keyblock_size) {
|
|
||||||
VB2_DEBUG("Not enough data for key block.\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check signature */
|
|
||||||
sig = &block->keyblock_signature;
|
|
||||||
|
|
||||||
if (vb2_verify_signature_inside(block, block->keyblock_size, sig)) {
|
|
||||||
VB2_DEBUG("Key block signature off end of block\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_SIG_OUTSIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure advertised signature data sizes are sane. */
|
|
||||||
if (block->keyblock_size < sig->data_size) {
|
|
||||||
VB2_DEBUG("Signature calculated past end of block\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_SIGNED_TOO_MUCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
VB2_DEBUG("Checking key block signature...\n");
|
|
||||||
rv = vb2_verify_data((const uint8_t *)block, size, sig, key, wb);
|
|
||||||
if (rv) {
|
|
||||||
VB2_DEBUG("Invalid key block signature.\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_SIG_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify we signed enough data */
|
|
||||||
if (sig->data_size < sizeof(struct vb2_keyblock)) {
|
|
||||||
VB2_DEBUG("Didn't sign enough data\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_SIGNED_TOO_LITTLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify data key is inside the block and inside signed data */
|
|
||||||
if (vb2_verify_packed_key_inside(block, block->keyblock_size,
|
|
||||||
&block->data_key)) {
|
|
||||||
VB2_DEBUG("Data key off end of key block\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_DATA_KEY_OUTSIDE;
|
|
||||||
}
|
|
||||||
if (vb2_verify_packed_key_inside(block, sig->data_size,
|
|
||||||
&block->data_key)) {
|
|
||||||
VB2_DEBUG("Data key off end of signed data\n");
|
|
||||||
return VB2_ERROR_KEYBLOCK_DATA_KEY_UNSIGNED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Success */
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble,
|
|
||||||
uint32_t size,
|
|
||||||
const struct vb2_public_key *key,
|
|
||||||
const struct vb2_workbuf *wb)
|
|
||||||
{
|
|
||||||
struct vb2_signature *sig = &preamble->preamble_signature;
|
|
||||||
|
|
||||||
VB2_DEBUG("Verifying preamble.\n");
|
|
||||||
|
|
||||||
/* Sanity checks before attempting signature of data */
|
|
||||||
if(size < sizeof(*preamble)) {
|
|
||||||
VB2_DEBUG("Not enough data for preamble header\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER;
|
|
||||||
}
|
|
||||||
if (preamble->header_version_major !=
|
|
||||||
FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR) {
|
|
||||||
VB2_DEBUG("Incompatible firmware preamble header version.\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_HEADER_VERSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (preamble->header_version_minor < 1) {
|
|
||||||
VB2_DEBUG("Only preamble header 2.1+ supported\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_HEADER_OLD;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size < preamble->preamble_size) {
|
|
||||||
VB2_DEBUG("Not enough data for preamble.\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check signature */
|
|
||||||
if (vb2_verify_signature_inside(preamble, preamble->preamble_size,
|
|
||||||
sig)) {
|
|
||||||
VB2_DEBUG("Preamble signature off end of preamble\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_SIG_OUTSIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure advertised signature data sizes are sane. */
|
|
||||||
if (preamble->preamble_size < sig->data_size) {
|
|
||||||
VB2_DEBUG("Signature calculated past end of the block\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_SIGNED_TOO_MUCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vb2_verify_data((const uint8_t *)preamble, size, sig, key, wb)) {
|
|
||||||
VB2_DEBUG("Preamble signature validation failed\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_SIG_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify we signed enough data */
|
|
||||||
if (sig->data_size < sizeof(struct vb2_fw_preamble)) {
|
|
||||||
VB2_DEBUG("Didn't sign enough data\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_SIGNED_TOO_LITTLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify body signature is inside the signed data */
|
|
||||||
if (vb2_verify_signature_inside(preamble, sig->data_size,
|
|
||||||
&preamble->body_signature)) {
|
|
||||||
VB2_DEBUG("Firmware body signature off end of preamble\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_BODY_SIG_OUTSIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify kernel subkey is inside the signed data */
|
|
||||||
if (vb2_verify_packed_key_inside(preamble, sig->data_size,
|
|
||||||
&preamble->kernel_subkey)) {
|
|
||||||
VB2_DEBUG("Kernel subkey off end of preamble\n");
|
|
||||||
return VB2_ERROR_PREAMBLE_KERNEL_SUBKEY_OUTSIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Success */
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -364,214 +364,3 @@ int vb2_select_fw_slot(struct vb2_context *ctx)
|
|||||||
|
|
||||||
return VB2_SUCCESS;
|
return VB2_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vb2_load_fw_keyblock(struct vb2_context *ctx)
|
|
||||||
{
|
|
||||||
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
|
||||||
struct vb2_workbuf wb;
|
|
||||||
|
|
||||||
uint8_t *key_data;
|
|
||||||
uint32_t key_size;
|
|
||||||
struct vb2_packed_key *packed_key;
|
|
||||||
struct vb2_public_key root_key;
|
|
||||||
|
|
||||||
struct vb2_keyblock *kb;
|
|
||||||
uint32_t block_size;
|
|
||||||
|
|
||||||
uint32_t sec_version;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
vb2_workbuf_from_ctx(ctx, &wb);
|
|
||||||
|
|
||||||
/* Read the root key */
|
|
||||||
key_size = sd->gbb_rootkey_size;
|
|
||||||
key_data = vb2_workbuf_alloc(&wb, key_size);
|
|
||||||
if (!key_data)
|
|
||||||
return VB2_ERROR_FW_KEYBLOCK_WORKBUF_ROOT_KEY;
|
|
||||||
|
|
||||||
rv = vb2ex_read_resource(ctx, VB2_RES_GBB, sd->gbb_rootkey_offset,
|
|
||||||
key_data, key_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* Unpack the root key */
|
|
||||||
rv = vb2_unpack_key(&root_key, key_data, key_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* Load the firmware keyblock header after the root key */
|
|
||||||
kb = vb2_workbuf_alloc(&wb, sizeof(*kb));
|
|
||||||
if (!kb)
|
|
||||||
return VB2_ERROR_FW_KEYBLOCK_WORKBUF_HEADER;
|
|
||||||
|
|
||||||
rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK, 0, kb, sizeof(*kb));
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
block_size = kb->keyblock_size;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Load the entire keyblock, now that we know how big it is. Note that
|
|
||||||
* we're loading the entire keyblock instead of just the piece after
|
|
||||||
* the header. That means we re-read the header. But that's a tiny
|
|
||||||
* amount of data, and it makes the code much more straightforward.
|
|
||||||
*/
|
|
||||||
kb = vb2_workbuf_realloc(&wb, sizeof(*kb), block_size);
|
|
||||||
if (!kb)
|
|
||||||
return VB2_ERROR_FW_KEYBLOCK_WORKBUF;
|
|
||||||
|
|
||||||
rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK, 0, kb, block_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* Verify the keyblock */
|
|
||||||
rv = vb2_verify_keyblock(kb, block_size, &root_key, &wb);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* Read the secure key version */
|
|
||||||
rv = vb2_secdata_get(ctx, VB2_SECDATA_VERSIONS, &sec_version);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* Key version is the upper 16 bits of the composite firmware version */
|
|
||||||
if (kb->data_key.key_version > 0xffff)
|
|
||||||
return VB2_ERROR_FW_KEYBLOCK_VERSION_RANGE;
|
|
||||||
if (kb->data_key.key_version < (sec_version >> 16))
|
|
||||||
return VB2_ERROR_FW_KEYBLOCK_VERSION_ROLLBACK;
|
|
||||||
|
|
||||||
sd->fw_version = kb->data_key.key_version << 16;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Save the data key in the work buffer. This overwrites the root key
|
|
||||||
* we read above. That's ok, because now that we have the data key we
|
|
||||||
* no longer need the root key.
|
|
||||||
*/
|
|
||||||
packed_key = (struct vb2_packed_key *)key_data;
|
|
||||||
|
|
||||||
packed_key->algorithm = kb->data_key.algorithm;
|
|
||||||
packed_key->key_version = kb->data_key.key_version;
|
|
||||||
packed_key->key_size = kb->data_key.key_size;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Use memmove() instead of memcpy(). In theory, the destination will
|
|
||||||
* never overlap because with the source because the root key is likely
|
|
||||||
* to be at least as large as the data key, but there's no harm here in
|
|
||||||
* being paranoid.
|
|
||||||
*/
|
|
||||||
memmove(key_data + packed_key->key_offset,
|
|
||||||
(uint8_t*)&kb->data_key + kb->data_key.key_offset,
|
|
||||||
packed_key->key_size);
|
|
||||||
|
|
||||||
/* Save the packed key offset and size */
|
|
||||||
sd->workbuf_data_key_offset = vb2_offset_of(ctx->workbuf, key_data);
|
|
||||||
sd->workbuf_data_key_size =
|
|
||||||
packed_key->key_offset + packed_key->key_size;
|
|
||||||
|
|
||||||
/* Preamble follows the keyblock in the vblock */
|
|
||||||
sd->vblock_preamble_offset = kb->keyblock_size;
|
|
||||||
|
|
||||||
/* Data key will persist in the workbuf after we return */
|
|
||||||
ctx->workbuf_used = sd->workbuf_data_key_offset +
|
|
||||||
sd->workbuf_data_key_size;
|
|
||||||
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_load_fw_preamble(struct vb2_context *ctx)
|
|
||||||
{
|
|
||||||
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
|
||||||
struct vb2_workbuf wb;
|
|
||||||
|
|
||||||
uint8_t *key_data = ctx->workbuf + sd->workbuf_data_key_offset;
|
|
||||||
uint32_t key_size = sd->workbuf_data_key_size;
|
|
||||||
struct vb2_public_key data_key;
|
|
||||||
|
|
||||||
/* Preamble goes in the next unused chunk of work buffer */
|
|
||||||
struct vb2_fw_preamble *pre;
|
|
||||||
uint32_t pre_size;
|
|
||||||
|
|
||||||
uint32_t sec_version;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
vb2_workbuf_from_ctx(ctx, &wb);
|
|
||||||
|
|
||||||
/* Unpack the firmware data key */
|
|
||||||
if (!sd->workbuf_data_key_size)
|
|
||||||
return VB2_ERROR_FW_PREAMBLE2_DATA_KEY;
|
|
||||||
|
|
||||||
rv = vb2_unpack_key(&data_key, key_data, key_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* Load the firmware preamble header */
|
|
||||||
pre = vb2_workbuf_alloc(&wb, sizeof(*pre));
|
|
||||||
if (!pre)
|
|
||||||
return VB2_ERROR_FW_PREAMBLE2_WORKBUF_HEADER;
|
|
||||||
|
|
||||||
rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK,
|
|
||||||
sd->vblock_preamble_offset,
|
|
||||||
pre, sizeof(*pre));
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
pre_size = pre->preamble_size;
|
|
||||||
|
|
||||||
/* Load the entire firmware preamble, now that we know how big it is */
|
|
||||||
pre = vb2_workbuf_realloc(&wb, sizeof(*pre), pre_size);
|
|
||||||
if (!pre)
|
|
||||||
return VB2_ERROR_FW_PREAMBLE2_WORKBUF;
|
|
||||||
|
|
||||||
rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK,
|
|
||||||
sd->vblock_preamble_offset,
|
|
||||||
pre, pre_size);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* Work buffer now contains the data subkey data and the preamble */
|
|
||||||
|
|
||||||
/* Verify the preamble */
|
|
||||||
rv = vb2_verify_fw_preamble(pre, pre_size, &data_key, &wb);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/* Read the secure key version */
|
|
||||||
rv = vb2_secdata_get(ctx, VB2_SECDATA_VERSIONS, &sec_version);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Firmware version is the lower 16 bits of the composite firmware
|
|
||||||
* version.
|
|
||||||
*/
|
|
||||||
if (pre->firmware_version > 0xffff)
|
|
||||||
return VB2_ERROR_FW_PREAMBLE2_VERSION_RANGE;
|
|
||||||
|
|
||||||
/* Combine with the key version from vb2_load_fw_keyblock() */
|
|
||||||
sd->fw_version |= pre->firmware_version;
|
|
||||||
if (sd->fw_version < sec_version)
|
|
||||||
return VB2_ERROR_FW_PREAMBLE2_VERSION_ROLLBACK;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If this is a newer version than in secure storage, and we
|
|
||||||
* successfully booted the same slot last boot, roll forward the
|
|
||||||
* version in secure storage.
|
|
||||||
*/
|
|
||||||
if (sd->fw_version > sec_version &&
|
|
||||||
sd->last_fw_slot == sd->fw_slot &&
|
|
||||||
sd->last_fw_result == VB2_FW_RESULT_SUCCESS) {
|
|
||||||
|
|
||||||
rv = vb2_secdata_set(ctx, VB2_SECDATA_VERSIONS, sd->fw_version);
|
|
||||||
if (rv)
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keep track of where we put the preamble */
|
|
||||||
sd->workbuf_preamble_offset = vb2_offset_of(ctx->workbuf, pre);
|
|
||||||
sd->workbuf_preamble_size = pre_size;
|
|
||||||
|
|
||||||
/* Preamble will persist in work buffer after we return */
|
|
||||||
ctx->workbuf_used = sd->workbuf_preamble_offset + pre_size;
|
|
||||||
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -146,172 +146,6 @@ int vb2_align(uint8_t **ptr,
|
|||||||
*/
|
*/
|
||||||
ptrdiff_t vb2_offset_of(const void *base, const void *ptr);
|
ptrdiff_t vb2_offset_of(const void *base, const void *ptr);
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper functions to get data pointed to by a public key or signature.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const uint8_t *vb2_packed_key_data(const struct vb2_packed_key *key);
|
|
||||||
uint8_t *vb2_signature_data(struct vb2_signature *sig);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify the data pointed to by a subfield is inside the parent data.
|
|
||||||
*
|
|
||||||
* The subfield has a header pointed to by member, and a separate data
|
|
||||||
* field at an offset relative to the header. That is:
|
|
||||||
*
|
|
||||||
* struct parent {
|
|
||||||
* (possibly other parent fields)
|
|
||||||
* struct member {
|
|
||||||
* (member header fields)
|
|
||||||
* };
|
|
||||||
* (possibly other parent fields)
|
|
||||||
* };
|
|
||||||
* (possibly some other parent data)
|
|
||||||
* (member data)
|
|
||||||
* (possibly some other parent data)
|
|
||||||
*
|
|
||||||
* @param parent Parent data
|
|
||||||
* @param parent_size Parent size in bytes
|
|
||||||
* @param member Subfield header
|
|
||||||
* @param member_size Size of subfield header in bytes
|
|
||||||
* @param member_data_offset Offset of member data from start of member
|
|
||||||
* @param member_data_size Size of member data in bytes
|
|
||||||
* @return VB2_SUCCESS, or non-zero if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_member_inside(const void *parent, size_t parent_size,
|
|
||||||
const void *member, size_t member_size,
|
|
||||||
ptrdiff_t member_data_offset,
|
|
||||||
size_t member_data_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the description of an object starting with a vb2_struct_common header.
|
|
||||||
*
|
|
||||||
* Does not sanity-check the buffer; merely returns the pointer.
|
|
||||||
*
|
|
||||||
* @param buf Pointer to common object
|
|
||||||
* @return A pointer to description or an empty string if none.
|
|
||||||
*/
|
|
||||||
const char *vb2_common_desc(const void *buf);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify the common struct header is fully contained in its parent data
|
|
||||||
*
|
|
||||||
* Also verifies the description is either zero-length or null-terminated.
|
|
||||||
*
|
|
||||||
* @param parent Parent data
|
|
||||||
* @param parent_size Parent size in bytes
|
|
||||||
* @return VB2_SUCCESS, or non-zero if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_common_header(const void *parent, uint32_t parent_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify a member is within the data for a parent object
|
|
||||||
*
|
|
||||||
* @param parent Parent data (starts with struct vb2_struct_common)
|
|
||||||
* @param min_offset Pointer to minimum offset where member can be located.
|
|
||||||
* If this offset is 0 on input, uses the size of the
|
|
||||||
* fixed header (and description, if any). This will be
|
|
||||||
* updated on return to the end of the passed member. On
|
|
||||||
* error, the value of min_offset is undefined.
|
|
||||||
* @param member_offset Offset of member data from start of parent, in bytes
|
|
||||||
* @param member_size Size of member data, in bytes
|
|
||||||
* @return VB2_SUCCESS, or non-zero if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_common_member(const void *parent,
|
|
||||||
uint32_t *min_offset,
|
|
||||||
uint32_t member_offset,
|
|
||||||
uint32_t member_size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify a member which starts with a common header is within the parent
|
|
||||||
*
|
|
||||||
* This does not verify the contents of the member or its header, only that the
|
|
||||||
* member's claimed total size fits within the parent's claimed total size at
|
|
||||||
* the specified offset.
|
|
||||||
*
|
|
||||||
* @param parent Parent data (starts with struct vb2_struct_common)
|
|
||||||
* @param min_offset Pointer to minimum offset where member can be located.
|
|
||||||
* If this offset is 0 on input, uses the size of the
|
|
||||||
* fixed header (and description, if any). This will be
|
|
||||||
* updated on return to the end of the passed member. On
|
|
||||||
* error, the value of min_offset is undefined.
|
|
||||||
* @param member_offset Offset of member data from start of parent, in bytes.
|
|
||||||
* This should be the start of the common header of the
|
|
||||||
* member.
|
|
||||||
* @return VB2_SUCCESS, or non-zero if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_common_subobject(const void *parent,
|
|
||||||
uint32_t *min_offset,
|
|
||||||
uint32_t member_offset);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify a signature is fully contained in its parent data
|
|
||||||
*
|
|
||||||
* @param parent Parent data
|
|
||||||
* @param parent_size Parent size in bytes
|
|
||||||
* @param sig Signature pointer
|
|
||||||
* @return VB2_SUCCESS, or non-zero if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_signature_inside(const void *parent,
|
|
||||||
uint32_t parent_size,
|
|
||||||
const struct vb2_signature *sig);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify a packed key is fully contained in its parent data
|
|
||||||
*
|
|
||||||
* @param parent Parent data
|
|
||||||
* @param parent_size Parent size in bytes
|
|
||||||
* @param key Packed key pointer
|
|
||||||
* @return VB2_SUCCESS, or non-zero if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_packed_key_inside(const void *parent,
|
|
||||||
uint32_t parent_size,
|
|
||||||
const struct vb2_packed_key *key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpack a vboot1-format key for use in verification
|
|
||||||
*
|
|
||||||
* The elements of the unpacked key will point into the source buffer, so don't
|
|
||||||
* free the source buffer until you're done with the key.
|
|
||||||
*
|
|
||||||
* @param key Destintion for unpacked key
|
|
||||||
* @param buf Source buffer containing packed key
|
|
||||||
* @param size Size of buffer in bytes
|
|
||||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
|
||||||
*/
|
|
||||||
int vb2_unpack_key(struct vb2_public_key *key,
|
|
||||||
const uint8_t *buf,
|
|
||||||
uint32_t size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpack a key for use in verification
|
|
||||||
*
|
|
||||||
* The elements of the unpacked key will point into the source buffer, so don't
|
|
||||||
* free the source buffer until you're done with the key.
|
|
||||||
*
|
|
||||||
* @param key Destintion for unpacked key
|
|
||||||
* @param buf Source buffer containing packed key
|
|
||||||
* @param size Size of buffer in bytes
|
|
||||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
|
||||||
*/
|
|
||||||
int vb2_unpack_key2(struct vb2_public_key *key,
|
|
||||||
const uint8_t *buf,
|
|
||||||
uint32_t size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpack the RSA data fields for a public key
|
|
||||||
*
|
|
||||||
* This is called by vb2_unpack_key2() to extract the arrays from a packed key.
|
|
||||||
* These elements of *key will point inside the key_data buffer.
|
|
||||||
*
|
|
||||||
* @param key Destination key for RSA data fields
|
|
||||||
* @param key_data Packed key data (from inside a packed key buffer)
|
|
||||||
* @param key_size Size of packed key data in bytes
|
|
||||||
*/
|
|
||||||
int vb2_unpack_key2_data(struct vb2_public_key *key,
|
|
||||||
const uint8_t *key_data,
|
|
||||||
uint32_t key_size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return expected signature size for a signature/hash algorithm pair
|
* Return expected signature size for a signature/hash algorithm pair
|
||||||
*
|
*
|
||||||
@@ -337,20 +171,6 @@ const struct vb2_guid *vb2_hash_guid(enum vb2_hash_algorithm hash_alg);
|
|||||||
*/
|
*/
|
||||||
#define VB2_VERIFY_DIGEST_WORKBUF_BYTES VB2_VERIFY_RSA_DIGEST_WORKBUF_BYTES
|
#define VB2_VERIFY_DIGEST_WORKBUF_BYTES VB2_VERIFY_RSA_DIGEST_WORKBUF_BYTES
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify a signature against an expected hash digest.
|
|
||||||
*
|
|
||||||
* @param key Key to use in signature verification
|
|
||||||
* @param sig Signature to verify (may be destroyed in process)
|
|
||||||
* @param digest Digest of signed data
|
|
||||||
* @param wb Work buffer
|
|
||||||
* @return VB2_SUCCESS, or non-zero if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_digest(const struct vb2_public_key *key,
|
|
||||||
struct vb2_signature *sig,
|
|
||||||
const uint8_t *digest,
|
|
||||||
const struct vb2_workbuf *wb);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Size of work buffer sufficient for vb2_verify_data() or vb2_verify_data2()
|
* Size of work buffer sufficient for vb2_verify_data() or vb2_verify_data2()
|
||||||
* worst case.
|
* worst case.
|
||||||
@@ -360,66 +180,16 @@ int vb2_verify_digest(const struct vb2_public_key *key,
|
|||||||
VB2_MAX(VB2_VERIFY_DIGEST_WORKBUF_BYTES, \
|
VB2_MAX(VB2_VERIFY_DIGEST_WORKBUF_BYTES, \
|
||||||
sizeof(struct vb2_digest_context)))
|
sizeof(struct vb2_digest_context)))
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify data matches signature.
|
|
||||||
*
|
|
||||||
* @param data Data to verify
|
|
||||||
* @param size Size of data buffer. Note that amount of data to
|
|
||||||
* actually validate is contained in sig->data_size.
|
|
||||||
* @param sig Signature of data (destroyed in process)
|
|
||||||
* @param key Key to use to validate signature
|
|
||||||
* @param wb Work buffer
|
|
||||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_data(const uint8_t *data,
|
|
||||||
uint32_t size,
|
|
||||||
struct vb2_signature *sig,
|
|
||||||
const struct vb2_public_key *key,
|
|
||||||
const struct vb2_workbuf *wb);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Size of work buffer sufficient for vb2_verify_keyblock() or
|
* Size of work buffer sufficient for vb2_verify_keyblock() or
|
||||||
* vb2_verify_keyblock2() worst case.
|
* vb2_verify_keyblock2() worst case.
|
||||||
*/
|
*/
|
||||||
#define VB2_KEY_BLOCK_VERIFY_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES
|
#define VB2_KEY_BLOCK_VERIFY_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the sanity of a key block using a public key.
|
|
||||||
*
|
|
||||||
* Header fields are also checked for sanity. Does not verify key index or key
|
|
||||||
* block flags. Signature inside block is destroyed during check.
|
|
||||||
*
|
|
||||||
* @param block Key block to verify
|
|
||||||
* @param size Size of key block buffer
|
|
||||||
* @param key Key to use to verify block
|
|
||||||
* @param wb Work buffer
|
|
||||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_keyblock(struct vb2_keyblock *block,
|
|
||||||
uint32_t size,
|
|
||||||
const struct vb2_public_key *key,
|
|
||||||
const struct vb2_workbuf *wb);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Size of work buffer sufficient for vb2_verify_fw_preamble() or
|
* Size of work buffer sufficient for vb2_verify_fw_preamble() or
|
||||||
* vb2_verify_fw_preamble2() worst case.
|
* vb2_verify_fw_preamble2() worst case.
|
||||||
*/
|
*/
|
||||||
#define VB2_VERIFY_FIRMWARE_PREAMBLE_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES
|
#define VB2_VERIFY_FIRMWARE_PREAMBLE_WORKBUF_BYTES VB2_VERIFY_DATA_WORKBUF_BYTES
|
||||||
|
|
||||||
/**
|
|
||||||
* Check the sanity of a firmware preamble using a public key.
|
|
||||||
*
|
|
||||||
* The signature in the preamble is destroyed during the check.
|
|
||||||
*
|
|
||||||
* @param preamble Preamble to verify
|
|
||||||
* @param size Size of preamble buffer
|
|
||||||
* @param key Key to use to verify preamble
|
|
||||||
* @param wb Work buffer
|
|
||||||
* @return VB2_SUCCESS, or non-zero error code if error.
|
|
||||||
*/
|
|
||||||
int vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble,
|
|
||||||
uint32_t size,
|
|
||||||
const struct vb2_public_key *key,
|
|
||||||
const struct vb2_workbuf *wb);
|
|
||||||
|
|
||||||
#endif /* VBOOT_REFERENCE_VBOOT_2COMMON_H_ */
|
#endif /* VBOOT_REFERENCE_VBOOT_2COMMON_H_ */
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "2api.h"
|
#include "2api.h"
|
||||||
|
|
||||||
struct vb2_gbb_header;
|
struct vb2_gbb_header;
|
||||||
|
struct vb2_workbuf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the shared data pointer from the vboot context
|
* Get the shared data pointer from the vboot context
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
#define VBOOT_REFERENCE_VBOOT_2STRUCT_H_
|
#define VBOOT_REFERENCE_VBOOT_2STRUCT_H_
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "2guid.h"
|
|
||||||
|
|
||||||
/* Algorithm types for signatures */
|
/* Algorithm types for signatures */
|
||||||
enum vb2_signature_algorithm {
|
enum vb2_signature_algorithm {
|
||||||
/* Invalid or unsupported signature type */
|
/* Invalid or unsupported signature type */
|
||||||
@@ -43,65 +41,10 @@ enum vb2_hash_algorithm {
|
|||||||
VB2_HASH_SHA512 = 3,
|
VB2_HASH_SHA512 = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
/*
|
/*
|
||||||
* Vboot1-compatible data structures
|
* Key block flags.
|
||||||
*
|
*
|
||||||
*
|
*The following flags set where the key is valid. Not used by firmware
|
||||||
* 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 (enum vb2_crypto_algorithm) */
|
|
||||||
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_VB2_PACKED_KEY_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;
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
#define EXPECTED_VB2_SIGNATURE_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.
|
* verification; only kernel verification.
|
||||||
*/
|
*/
|
||||||
#define VB2_KEY_BLOCK_FLAG_DEVELOPER_0 0x01 /* Developer switch off */
|
#define VB2_KEY_BLOCK_FLAG_DEVELOPER_0 0x01 /* Developer switch off */
|
||||||
@@ -109,117 +52,6 @@ struct vb2_signature {
|
|||||||
#define VB2_KEY_BLOCK_FLAG_RECOVERY_0 0x04 /* Not recovery mode */
|
#define VB2_KEY_BLOCK_FLAG_RECOVERY_0 0x04 /* Not recovery mode */
|
||||||
#define VB2_KEY_BLOCK_FLAG_RECOVERY_1 0x08 /* 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_VB2_KEYBLOCK_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_VB2_FW_PREAMBLE_SIZE 108
|
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/* Flags for vb2_shared_data.flags */
|
/* Flags for vb2_shared_data.flags */
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
#ifdef NEED_VB20_INTERNALS
|
#ifdef NEED_VB20_INTERNALS
|
||||||
#include "../2lib/include/2struct.h"
|
#include "../2lib/include/2struct.h"
|
||||||
|
#include "../lib20/include/vb2_struct.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* VBOOT_VB2_API_H_ */
|
#endif /* VBOOT_VB2_API_H_ */
|
||||||
|
|||||||
174
firmware/lib20/api.c
Normal file
174
firmware/lib20/api.c
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* Externally-callable APIs
|
||||||
|
* (Firmware portion)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "2sysincludes.h"
|
||||||
|
#include "2api.h"
|
||||||
|
#include "2misc.h"
|
||||||
|
#include "2nvstorage.h"
|
||||||
|
#include "2secdata.h"
|
||||||
|
#include "2sha.h"
|
||||||
|
#include "2rsa.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
|
|
||||||
|
int vb2api_fw_phase3(struct vb2_context *ctx)
|
||||||
|
{
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
/* Verify firmware keyblock */
|
||||||
|
rv = vb2_load_fw_keyblock(ctx);
|
||||||
|
if (rv) {
|
||||||
|
vb2_fail(ctx, VB2_RECOVERY_RO_INVALID_RW, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify firmware preamble */
|
||||||
|
rv = vb2_load_fw_preamble(ctx);
|
||||||
|
if (rv) {
|
||||||
|
vb2_fail(ctx, VB2_RECOVERY_RO_INVALID_RW, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2api_init_hash(struct vb2_context *ctx, uint32_t tag, uint32_t *size)
|
||||||
|
{
|
||||||
|
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
||||||
|
const struct vb2_fw_preamble *pre;
|
||||||
|
struct vb2_digest_context *dc;
|
||||||
|
struct vb2_public_key key;
|
||||||
|
struct vb2_workbuf wb;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
vb2_workbuf_from_ctx(ctx, &wb);
|
||||||
|
|
||||||
|
if (tag == VB2_HASH_TAG_INVALID)
|
||||||
|
return VB2_ERROR_API_INIT_HASH_TAG;
|
||||||
|
|
||||||
|
/* Get preamble pointer */
|
||||||
|
if (!sd->workbuf_preamble_size)
|
||||||
|
return VB2_ERROR_API_INIT_HASH_PREAMBLE;
|
||||||
|
pre = (const struct vb2_fw_preamble *)
|
||||||
|
(ctx->workbuf + sd->workbuf_preamble_offset);
|
||||||
|
|
||||||
|
/* For now, we only support the firmware body tag */
|
||||||
|
if (tag != VB2_HASH_TAG_FW_BODY)
|
||||||
|
return VB2_ERROR_API_INIT_HASH_TAG;
|
||||||
|
|
||||||
|
/* Allocate workbuf space for the hash */
|
||||||
|
if (sd->workbuf_hash_size) {
|
||||||
|
dc = (struct vb2_digest_context *)
|
||||||
|
(ctx->workbuf + sd->workbuf_hash_offset);
|
||||||
|
} else {
|
||||||
|
uint32_t dig_size = sizeof(*dc);
|
||||||
|
|
||||||
|
dc = vb2_workbuf_alloc(&wb, dig_size);
|
||||||
|
if (!dc)
|
||||||
|
return VB2_ERROR_API_INIT_HASH_WORKBUF;
|
||||||
|
|
||||||
|
sd->workbuf_hash_offset = vb2_offset_of(ctx->workbuf, dc);
|
||||||
|
sd->workbuf_hash_size = dig_size;
|
||||||
|
ctx->workbuf_used = sd->workbuf_hash_offset + dig_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Unpack the firmware data key to see which hashing algorithm we
|
||||||
|
* should use.
|
||||||
|
*
|
||||||
|
* TODO: really, the firmware body should be hashed, and not signed,
|
||||||
|
* because the signature we're checking is already signed as part of
|
||||||
|
* the firmware preamble. But until we can change the signing scripts,
|
||||||
|
* we're stuck with a signature here instead of a hash.
|
||||||
|
*/
|
||||||
|
if (!sd->workbuf_data_key_size)
|
||||||
|
return VB2_ERROR_API_INIT_HASH_DATA_KEY;
|
||||||
|
|
||||||
|
rv = vb2_unpack_key(&key,
|
||||||
|
ctx->workbuf + sd->workbuf_data_key_offset,
|
||||||
|
sd->workbuf_data_key_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
sd->hash_tag = tag;
|
||||||
|
sd->hash_remaining_size = pre->body_signature.data_size;
|
||||||
|
|
||||||
|
if (size)
|
||||||
|
*size = pre->body_signature.data_size;
|
||||||
|
|
||||||
|
return vb2_digest_init(dc, key.hash_alg);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2api_check_hash(struct vb2_context *ctx)
|
||||||
|
{
|
||||||
|
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
||||||
|
struct vb2_digest_context *dc = (struct vb2_digest_context *)
|
||||||
|
(ctx->workbuf + sd->workbuf_hash_offset);
|
||||||
|
struct vb2_workbuf wb;
|
||||||
|
|
||||||
|
uint8_t *digest;
|
||||||
|
uint32_t digest_size = vb2_digest_size(dc->hash_alg);
|
||||||
|
|
||||||
|
struct vb2_fw_preamble *pre;
|
||||||
|
struct vb2_public_key key;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
vb2_workbuf_from_ctx(ctx, &wb);
|
||||||
|
|
||||||
|
/* Get preamble pointer */
|
||||||
|
if (!sd->workbuf_preamble_size)
|
||||||
|
return VB2_ERROR_API_CHECK_HASH_PREAMBLE;
|
||||||
|
pre = (struct vb2_fw_preamble *)
|
||||||
|
(ctx->workbuf + sd->workbuf_preamble_offset);
|
||||||
|
|
||||||
|
/* Must have initialized hash digest work area */
|
||||||
|
if (!sd->workbuf_hash_size)
|
||||||
|
return VB2_ERROR_API_CHECK_HASH_WORKBUF;
|
||||||
|
|
||||||
|
/* Should have hashed the right amount of data */
|
||||||
|
if (sd->hash_remaining_size)
|
||||||
|
return VB2_ERROR_API_CHECK_HASH_SIZE;
|
||||||
|
|
||||||
|
/* Allocate the digest */
|
||||||
|
digest = vb2_workbuf_alloc(&wb, digest_size);
|
||||||
|
if (!digest)
|
||||||
|
return VB2_ERROR_API_CHECK_HASH_WORKBUF_DIGEST;
|
||||||
|
|
||||||
|
/* Finalize the digest */
|
||||||
|
rv = vb2_digest_finalize(dc, digest, digest_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* The code below is specific to the body signature */
|
||||||
|
if (sd->hash_tag != VB2_HASH_TAG_FW_BODY)
|
||||||
|
return VB2_ERROR_API_CHECK_HASH_TAG;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The body signature is currently a *signature* of the body data, not
|
||||||
|
* just its hash. So we need to verify the signature.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Unpack the data key */
|
||||||
|
if (!sd->workbuf_data_key_size)
|
||||||
|
return VB2_ERROR_API_CHECK_HASH_DATA_KEY;
|
||||||
|
|
||||||
|
rv = vb2_unpack_key(&key,
|
||||||
|
ctx->workbuf + sd->workbuf_data_key_offset,
|
||||||
|
sd->workbuf_data_key_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check digest vs. signature. Note that this destroys the signature.
|
||||||
|
* That's ok, because we only check each signature once per boot.
|
||||||
|
*/
|
||||||
|
rv = vb2_verify_digest(&key, &pre->body_signature, digest, &wb);
|
||||||
|
if (rv)
|
||||||
|
vb2_fail(ctx, VB2_RECOVERY_RO_INVALID_RW, rv);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
272
firmware/lib20/common.c
Normal file
272
firmware/lib20/common.c
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* Common functions between firmware and kernel verified boot.
|
||||||
|
* (Firmware portion)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "2sysincludes.h"
|
||||||
|
#include "2rsa.h"
|
||||||
|
#include "2sha.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
|
|
||||||
|
uint8_t *vb2_signature_data(struct vb2_signature *sig)
|
||||||
|
{
|
||||||
|
return (uint8_t *)sig + sig->sig_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_verify_member_inside(const void *parent, size_t parent_size,
|
||||||
|
const void *member, size_t member_size,
|
||||||
|
ptrdiff_t member_data_offset,
|
||||||
|
size_t member_data_size)
|
||||||
|
{
|
||||||
|
const uintptr_t parent_end = (uintptr_t)parent + parent_size;
|
||||||
|
const ptrdiff_t member_offs = vb2_offset_of(parent, member);
|
||||||
|
const ptrdiff_t member_end_offs = member_offs + member_size;
|
||||||
|
const ptrdiff_t data_offs = member_offs + member_data_offset;
|
||||||
|
const ptrdiff_t data_end_offs = data_offs + member_data_size;
|
||||||
|
|
||||||
|
/* Make sure parent doesn't wrap */
|
||||||
|
if (parent_size < 0 || parent_end < (uintptr_t)parent)
|
||||||
|
return VB2_ERROR_INSIDE_PARENT_WRAPS;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure the member is fully contained in the parent and doesn't
|
||||||
|
* wrap. Use >, not >=, since member_size = 0 is possible.
|
||||||
|
*/
|
||||||
|
if (member_size < 0 || member_end_offs < member_offs)
|
||||||
|
return VB2_ERROR_INSIDE_MEMBER_WRAPS;
|
||||||
|
if (member_offs < 0 || member_offs > parent_size ||
|
||||||
|
member_end_offs > parent_size)
|
||||||
|
return VB2_ERROR_INSIDE_MEMBER_OUTSIDE;
|
||||||
|
|
||||||
|
/* Make sure the member data is after the member */
|
||||||
|
if (member_data_size > 0 && data_offs < member_end_offs)
|
||||||
|
return VB2_ERROR_INSIDE_DATA_OVERLAP;
|
||||||
|
|
||||||
|
/* Make sure parent fully contains member data, if any */
|
||||||
|
if (member_data_size < 0 || data_end_offs < data_offs)
|
||||||
|
return VB2_ERROR_INSIDE_DATA_WRAPS;
|
||||||
|
if (data_offs < 0 || data_offs > parent_size ||
|
||||||
|
data_end_offs > parent_size)
|
||||||
|
return VB2_ERROR_INSIDE_DATA_OUTSIDE;
|
||||||
|
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_verify_signature_inside(const void *parent,
|
||||||
|
uint32_t parent_size,
|
||||||
|
const struct vb2_signature *sig)
|
||||||
|
{
|
||||||
|
return vb2_verify_member_inside(parent, parent_size,
|
||||||
|
sig, sizeof(*sig),
|
||||||
|
sig->sig_offset, sig->sig_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_verify_digest(const struct vb2_public_key *key,
|
||||||
|
struct vb2_signature *sig,
|
||||||
|
const uint8_t *digest,
|
||||||
|
const struct vb2_workbuf *wb)
|
||||||
|
{
|
||||||
|
uint8_t *sig_data = vb2_signature_data(sig);
|
||||||
|
|
||||||
|
if (sig->sig_size != vb2_rsa_sig_size(key->sig_alg)) {
|
||||||
|
VB2_DEBUG("Wrong data signature size for algorithm, "
|
||||||
|
"sig_size=%d, expected %d for algorithm %d.\n",
|
||||||
|
sig->sig_size, vb2_rsa_sig_size(key->sig_alg),
|
||||||
|
key->sig_alg);
|
||||||
|
return VB2_ERROR_VDATA_SIG_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vb2_rsa_verify_digest(key, sig_data, digest, wb);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_verify_data(const uint8_t *data,
|
||||||
|
uint32_t size,
|
||||||
|
struct vb2_signature *sig,
|
||||||
|
const struct vb2_public_key *key,
|
||||||
|
const struct vb2_workbuf *wb)
|
||||||
|
{
|
||||||
|
struct vb2_workbuf wblocal = *wb;
|
||||||
|
struct vb2_digest_context *dc;
|
||||||
|
uint8_t *digest;
|
||||||
|
uint32_t digest_size;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (sig->data_size > size) {
|
||||||
|
VB2_DEBUG("Data buffer smaller than length of signed data.\n");
|
||||||
|
return VB2_ERROR_VDATA_NOT_ENOUGH_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Digest goes at start of work buffer */
|
||||||
|
digest_size = vb2_digest_size(key->hash_alg);
|
||||||
|
if (!digest_size)
|
||||||
|
return VB2_ERROR_VDATA_DIGEST_SIZE;
|
||||||
|
|
||||||
|
digest = vb2_workbuf_alloc(&wblocal, digest_size);
|
||||||
|
if (!digest)
|
||||||
|
return VB2_ERROR_VDATA_WORKBUF_DIGEST;
|
||||||
|
|
||||||
|
/* Hashing requires temp space for the context */
|
||||||
|
dc = vb2_workbuf_alloc(&wblocal, sizeof(*dc));
|
||||||
|
if (!dc)
|
||||||
|
return VB2_ERROR_VDATA_WORKBUF_HASHING;
|
||||||
|
|
||||||
|
rv = vb2_digest_init(dc, key->hash_alg);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
rv = vb2_digest_extend(dc, data, sig->data_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
rv = vb2_digest_finalize(dc, digest, digest_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
vb2_workbuf_free(&wblocal, sizeof(*dc));
|
||||||
|
|
||||||
|
return vb2_verify_digest(key, sig, digest, &wblocal);
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_verify_keyblock(struct vb2_keyblock *block,
|
||||||
|
uint32_t size,
|
||||||
|
const struct vb2_public_key *key,
|
||||||
|
const struct vb2_workbuf *wb)
|
||||||
|
{
|
||||||
|
struct vb2_signature *sig;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
/* Sanity checks before attempting signature of data */
|
||||||
|
if(size < sizeof(*block)) {
|
||||||
|
VB2_DEBUG("Not enough space for key block header.\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_TOO_SMALL_FOR_HEADER;
|
||||||
|
}
|
||||||
|
if (memcmp(block->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE)) {
|
||||||
|
VB2_DEBUG("Not a valid verified boot key block.\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_MAGIC;
|
||||||
|
}
|
||||||
|
if (block->header_version_major != KEY_BLOCK_HEADER_VERSION_MAJOR) {
|
||||||
|
VB2_DEBUG("Incompatible key block header version.\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_HEADER_VERSION;
|
||||||
|
}
|
||||||
|
if (size < block->keyblock_size) {
|
||||||
|
VB2_DEBUG("Not enough data for key block.\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check signature */
|
||||||
|
sig = &block->keyblock_signature;
|
||||||
|
|
||||||
|
if (vb2_verify_signature_inside(block, block->keyblock_size, sig)) {
|
||||||
|
VB2_DEBUG("Key block signature off end of block\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_SIG_OUTSIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure advertised signature data sizes are sane. */
|
||||||
|
if (block->keyblock_size < sig->data_size) {
|
||||||
|
VB2_DEBUG("Signature calculated past end of block\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_SIGNED_TOO_MUCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
VB2_DEBUG("Checking key block signature...\n");
|
||||||
|
rv = vb2_verify_data((const uint8_t *)block, size, sig, key, wb);
|
||||||
|
if (rv) {
|
||||||
|
VB2_DEBUG("Invalid key block signature.\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_SIG_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify we signed enough data */
|
||||||
|
if (sig->data_size < sizeof(struct vb2_keyblock)) {
|
||||||
|
VB2_DEBUG("Didn't sign enough data\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_SIGNED_TOO_LITTLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify data key is inside the block and inside signed data */
|
||||||
|
if (vb2_verify_packed_key_inside(block, block->keyblock_size,
|
||||||
|
&block->data_key)) {
|
||||||
|
VB2_DEBUG("Data key off end of key block\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_DATA_KEY_OUTSIDE;
|
||||||
|
}
|
||||||
|
if (vb2_verify_packed_key_inside(block, sig->data_size,
|
||||||
|
&block->data_key)) {
|
||||||
|
VB2_DEBUG("Data key off end of signed data\n");
|
||||||
|
return VB2_ERROR_KEYBLOCK_DATA_KEY_UNSIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble,
|
||||||
|
uint32_t size,
|
||||||
|
const struct vb2_public_key *key,
|
||||||
|
const struct vb2_workbuf *wb)
|
||||||
|
{
|
||||||
|
struct vb2_signature *sig = &preamble->preamble_signature;
|
||||||
|
|
||||||
|
VB2_DEBUG("Verifying preamble.\n");
|
||||||
|
|
||||||
|
/* Sanity checks before attempting signature of data */
|
||||||
|
if(size < sizeof(*preamble)) {
|
||||||
|
VB2_DEBUG("Not enough data for preamble header\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_TOO_SMALL_FOR_HEADER;
|
||||||
|
}
|
||||||
|
if (preamble->header_version_major !=
|
||||||
|
FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR) {
|
||||||
|
VB2_DEBUG("Incompatible firmware preamble header version.\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_HEADER_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preamble->header_version_minor < 1) {
|
||||||
|
VB2_DEBUG("Only preamble header 2.1+ supported\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_HEADER_OLD;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size < preamble->preamble_size) {
|
||||||
|
VB2_DEBUG("Not enough data for preamble.\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check signature */
|
||||||
|
if (vb2_verify_signature_inside(preamble, preamble->preamble_size,
|
||||||
|
sig)) {
|
||||||
|
VB2_DEBUG("Preamble signature off end of preamble\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_SIG_OUTSIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure advertised signature data sizes are sane. */
|
||||||
|
if (preamble->preamble_size < sig->data_size) {
|
||||||
|
VB2_DEBUG("Signature calculated past end of the block\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_SIGNED_TOO_MUCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vb2_verify_data((const uint8_t *)preamble, size, sig, key, wb)) {
|
||||||
|
VB2_DEBUG("Preamble signature validation failed\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_SIG_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify we signed enough data */
|
||||||
|
if (sig->data_size < sizeof(struct vb2_fw_preamble)) {
|
||||||
|
VB2_DEBUG("Didn't sign enough data\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_SIGNED_TOO_LITTLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify body signature is inside the signed data */
|
||||||
|
if (vb2_verify_signature_inside(preamble, sig->data_size,
|
||||||
|
&preamble->body_signature)) {
|
||||||
|
VB2_DEBUG("Firmware body signature off end of preamble\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_BODY_SIG_OUTSIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify kernel subkey is inside the signed data */
|
||||||
|
if (vb2_verify_packed_key_inside(preamble, sig->data_size,
|
||||||
|
&preamble->kernel_subkey)) {
|
||||||
|
VB2_DEBUG("Kernel subkey off end of preamble\n");
|
||||||
|
return VB2_ERROR_PREAMBLE_KERNEL_SUBKEY_OUTSIDE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
159
firmware/lib20/include/vb2_common.h
Normal file
159
firmware/lib20/include/vb2_common.h
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* Common functions between firmware and kernel verified boot.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VBOOT_REFERENCE_VB2_COMMON_H_
|
||||||
|
#define VBOOT_REFERENCE_VB2_COMMON_H_
|
||||||
|
|
||||||
|
#include "2api.h"
|
||||||
|
#include "2common.h"
|
||||||
|
#include "2return_codes.h"
|
||||||
|
#include "2sha.h"
|
||||||
|
#include "2struct.h"
|
||||||
|
#include "vb2_struct.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper functions to get data pointed to by a public key or signature.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint8_t *vb2_packed_key_data(const struct vb2_packed_key *key);
|
||||||
|
uint8_t *vb2_signature_data(struct vb2_signature *sig);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the data pointed to by a subfield is inside the parent data.
|
||||||
|
*
|
||||||
|
* The subfield has a header pointed to by member, and a separate data
|
||||||
|
* field at an offset relative to the header. That is:
|
||||||
|
*
|
||||||
|
* struct parent {
|
||||||
|
* (possibly other parent fields)
|
||||||
|
* struct member {
|
||||||
|
* (member header fields)
|
||||||
|
* };
|
||||||
|
* (possibly other parent fields)
|
||||||
|
* };
|
||||||
|
* (possibly some other parent data)
|
||||||
|
* (member data)
|
||||||
|
* (possibly some other parent data)
|
||||||
|
*
|
||||||
|
* @param parent Parent data
|
||||||
|
* @param parent_size Parent size in bytes
|
||||||
|
* @param member Subfield header
|
||||||
|
* @param member_size Size of subfield header in bytes
|
||||||
|
* @param member_data_offset Offset of member data from start of member
|
||||||
|
* @param member_data_size Size of member data in bytes
|
||||||
|
* @return VB2_SUCCESS, or non-zero if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_member_inside(const void *parent, size_t parent_size,
|
||||||
|
const void *member, size_t member_size,
|
||||||
|
ptrdiff_t member_data_offset,
|
||||||
|
size_t member_data_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a signature is fully contained in its parent data
|
||||||
|
*
|
||||||
|
* @param parent Parent data
|
||||||
|
* @param parent_size Parent size in bytes
|
||||||
|
* @param sig Signature pointer
|
||||||
|
* @return VB2_SUCCESS, or non-zero if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_signature_inside(const void *parent,
|
||||||
|
uint32_t parent_size,
|
||||||
|
const struct vb2_signature *sig);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a packed key is fully contained in its parent data
|
||||||
|
*
|
||||||
|
* @param parent Parent data
|
||||||
|
* @param parent_size Parent size in bytes
|
||||||
|
* @param key Packed key pointer
|
||||||
|
* @return VB2_SUCCESS, or non-zero if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_packed_key_inside(const void *parent,
|
||||||
|
uint32_t parent_size,
|
||||||
|
const struct vb2_packed_key *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack a vboot1-format key for use in verification
|
||||||
|
*
|
||||||
|
* The elements of the unpacked key will point into the source buffer, so don't
|
||||||
|
* free the source buffer until you're done with the key.
|
||||||
|
*
|
||||||
|
* @param key Destintion for unpacked key
|
||||||
|
* @param buf Source buffer containing packed key
|
||||||
|
* @param size Size of buffer in bytes
|
||||||
|
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||||
|
*/
|
||||||
|
int vb2_unpack_key(struct vb2_public_key *key,
|
||||||
|
const uint8_t *buf,
|
||||||
|
uint32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a signature against an expected hash digest.
|
||||||
|
*
|
||||||
|
* @param key Key to use in signature verification
|
||||||
|
* @param sig Signature to verify (may be destroyed in process)
|
||||||
|
* @param digest Digest of signed data
|
||||||
|
* @param wb Work buffer
|
||||||
|
* @return VB2_SUCCESS, or non-zero if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_digest(const struct vb2_public_key *key,
|
||||||
|
struct vb2_signature *sig,
|
||||||
|
const uint8_t *digest,
|
||||||
|
const struct vb2_workbuf *wb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify data matches signature.
|
||||||
|
*
|
||||||
|
* @param data Data to verify
|
||||||
|
* @param size Size of data buffer. Note that amount of data to
|
||||||
|
* actually validate is contained in sig->data_size.
|
||||||
|
* @param sig Signature of data (destroyed in process)
|
||||||
|
* @param key Key to use to validate signature
|
||||||
|
* @param wb Work buffer
|
||||||
|
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_data(const uint8_t *data,
|
||||||
|
uint32_t size,
|
||||||
|
struct vb2_signature *sig,
|
||||||
|
const struct vb2_public_key *key,
|
||||||
|
const struct vb2_workbuf *wb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the sanity of a key block using a public key.
|
||||||
|
*
|
||||||
|
* Header fields are also checked for sanity. Does not verify key index or key
|
||||||
|
* block flags. Signature inside block is destroyed during check.
|
||||||
|
*
|
||||||
|
* @param block Key block to verify
|
||||||
|
* @param size Size of key block buffer
|
||||||
|
* @param key Key to use to verify block
|
||||||
|
* @param wb Work buffer
|
||||||
|
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_keyblock(struct vb2_keyblock *block,
|
||||||
|
uint32_t size,
|
||||||
|
const struct vb2_public_key *key,
|
||||||
|
const struct vb2_workbuf *wb);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the sanity of a firmware preamble using a public key.
|
||||||
|
*
|
||||||
|
* The signature in the preamble is destroyed during the check.
|
||||||
|
*
|
||||||
|
* @param preamble Preamble to verify
|
||||||
|
* @param size Size of preamble buffer
|
||||||
|
* @param key Key to use to verify preamble
|
||||||
|
* @param wb Work buffer
|
||||||
|
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_fw_preamble(struct vb2_fw_preamble *preamble,
|
||||||
|
uint32_t size,
|
||||||
|
const struct vb2_public_key *key,
|
||||||
|
const struct vb2_workbuf *wb);
|
||||||
|
|
||||||
|
#endif /* VBOOT_REFERENCE_VB2_COMMON_H_ */
|
||||||
179
firmware/lib20/include/vb2_struct.h
Normal file
179
firmware/lib20/include/vb2_struct.h
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* Vboot 2.0 data structures (compatible with vboot1)
|
||||||
|
*
|
||||||
|
* 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).
|
||||||
|
*
|
||||||
|
* Offsets should be padded to 32-bit boundaries, since some architectures
|
||||||
|
* have trouble with accessing unaligned integers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef VBOOT_REFERENCE_VB2_STRUCT_H_
|
||||||
|
#define VBOOT_REFERENCE_VB2_STRUCT_H_
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* 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 (enum vb2_crypto_algorithm) */
|
||||||
|
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_VB2_PACKED_KEY_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;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
#define EXPECTED_VB2_SIGNATURE_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
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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_VB2_KEYBLOCK_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, vboot1 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_VB2_FW_PREAMBLE_SIZE 108
|
||||||
|
|
||||||
|
#endif /* VBOOT_REFERENCE_VB2_STRUCT_H_ */
|
||||||
226
firmware/lib20/misc.c
Normal file
226
firmware/lib20/misc.c
Normal file
@@ -0,0 +1,226 @@
|
|||||||
|
/* 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 "2misc.h"
|
||||||
|
#include "2nvstorage.h"
|
||||||
|
#include "2secdata.h"
|
||||||
|
#include "2sha.h"
|
||||||
|
#include "2rsa.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
|
|
||||||
|
int vb2_load_fw_keyblock(struct vb2_context *ctx)
|
||||||
|
{
|
||||||
|
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
||||||
|
struct vb2_workbuf wb;
|
||||||
|
|
||||||
|
uint8_t *key_data;
|
||||||
|
uint32_t key_size;
|
||||||
|
struct vb2_packed_key *packed_key;
|
||||||
|
struct vb2_public_key root_key;
|
||||||
|
|
||||||
|
struct vb2_keyblock *kb;
|
||||||
|
uint32_t block_size;
|
||||||
|
|
||||||
|
uint32_t sec_version;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
vb2_workbuf_from_ctx(ctx, &wb);
|
||||||
|
|
||||||
|
/* Read the root key */
|
||||||
|
key_size = sd->gbb_rootkey_size;
|
||||||
|
key_data = vb2_workbuf_alloc(&wb, key_size);
|
||||||
|
if (!key_data)
|
||||||
|
return VB2_ERROR_FW_KEYBLOCK_WORKBUF_ROOT_KEY;
|
||||||
|
|
||||||
|
rv = vb2ex_read_resource(ctx, VB2_RES_GBB, sd->gbb_rootkey_offset,
|
||||||
|
key_data, key_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* Unpack the root key */
|
||||||
|
rv = vb2_unpack_key(&root_key, key_data, key_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* Load the firmware keyblock header after the root key */
|
||||||
|
kb = vb2_workbuf_alloc(&wb, sizeof(*kb));
|
||||||
|
if (!kb)
|
||||||
|
return VB2_ERROR_FW_KEYBLOCK_WORKBUF_HEADER;
|
||||||
|
|
||||||
|
rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK, 0, kb, sizeof(*kb));
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
block_size = kb->keyblock_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load the entire keyblock, now that we know how big it is. Note that
|
||||||
|
* we're loading the entire keyblock instead of just the piece after
|
||||||
|
* the header. That means we re-read the header. But that's a tiny
|
||||||
|
* amount of data, and it makes the code much more straightforward.
|
||||||
|
*/
|
||||||
|
kb = vb2_workbuf_realloc(&wb, sizeof(*kb), block_size);
|
||||||
|
if (!kb)
|
||||||
|
return VB2_ERROR_FW_KEYBLOCK_WORKBUF;
|
||||||
|
|
||||||
|
rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK, 0, kb, block_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* Verify the keyblock */
|
||||||
|
rv = vb2_verify_keyblock(kb, block_size, &root_key, &wb);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* Read the secure key version */
|
||||||
|
rv = vb2_secdata_get(ctx, VB2_SECDATA_VERSIONS, &sec_version);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* Key version is the upper 16 bits of the composite firmware version */
|
||||||
|
if (kb->data_key.key_version > 0xffff)
|
||||||
|
return VB2_ERROR_FW_KEYBLOCK_VERSION_RANGE;
|
||||||
|
if (kb->data_key.key_version < (sec_version >> 16))
|
||||||
|
return VB2_ERROR_FW_KEYBLOCK_VERSION_ROLLBACK;
|
||||||
|
|
||||||
|
sd->fw_version = kb->data_key.key_version << 16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save the data key in the work buffer. This overwrites the root key
|
||||||
|
* we read above. That's ok, because now that we have the data key we
|
||||||
|
* no longer need the root key.
|
||||||
|
*/
|
||||||
|
packed_key = (struct vb2_packed_key *)key_data;
|
||||||
|
|
||||||
|
packed_key->algorithm = kb->data_key.algorithm;
|
||||||
|
packed_key->key_version = kb->data_key.key_version;
|
||||||
|
packed_key->key_size = kb->data_key.key_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use memmove() instead of memcpy(). In theory, the destination will
|
||||||
|
* never overlap because with the source because the root key is likely
|
||||||
|
* to be at least as large as the data key, but there's no harm here in
|
||||||
|
* being paranoid.
|
||||||
|
*/
|
||||||
|
memmove(key_data + packed_key->key_offset,
|
||||||
|
(uint8_t*)&kb->data_key + kb->data_key.key_offset,
|
||||||
|
packed_key->key_size);
|
||||||
|
|
||||||
|
/* Save the packed key offset and size */
|
||||||
|
sd->workbuf_data_key_offset = vb2_offset_of(ctx->workbuf, key_data);
|
||||||
|
sd->workbuf_data_key_size =
|
||||||
|
packed_key->key_offset + packed_key->key_size;
|
||||||
|
|
||||||
|
/* Preamble follows the keyblock in the vblock */
|
||||||
|
sd->vblock_preamble_offset = kb->keyblock_size;
|
||||||
|
|
||||||
|
/* Data key will persist in the workbuf after we return */
|
||||||
|
ctx->workbuf_used = sd->workbuf_data_key_offset +
|
||||||
|
sd->workbuf_data_key_size;
|
||||||
|
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_load_fw_preamble(struct vb2_context *ctx)
|
||||||
|
{
|
||||||
|
struct vb2_shared_data *sd = vb2_get_sd(ctx);
|
||||||
|
struct vb2_workbuf wb;
|
||||||
|
|
||||||
|
uint8_t *key_data = ctx->workbuf + sd->workbuf_data_key_offset;
|
||||||
|
uint32_t key_size = sd->workbuf_data_key_size;
|
||||||
|
struct vb2_public_key data_key;
|
||||||
|
|
||||||
|
/* Preamble goes in the next unused chunk of work buffer */
|
||||||
|
struct vb2_fw_preamble *pre;
|
||||||
|
uint32_t pre_size;
|
||||||
|
|
||||||
|
uint32_t sec_version;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
vb2_workbuf_from_ctx(ctx, &wb);
|
||||||
|
|
||||||
|
/* Unpack the firmware data key */
|
||||||
|
if (!sd->workbuf_data_key_size)
|
||||||
|
return VB2_ERROR_FW_PREAMBLE2_DATA_KEY;
|
||||||
|
|
||||||
|
rv = vb2_unpack_key(&data_key, key_data, key_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* Load the firmware preamble header */
|
||||||
|
pre = vb2_workbuf_alloc(&wb, sizeof(*pre));
|
||||||
|
if (!pre)
|
||||||
|
return VB2_ERROR_FW_PREAMBLE2_WORKBUF_HEADER;
|
||||||
|
|
||||||
|
rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK,
|
||||||
|
sd->vblock_preamble_offset,
|
||||||
|
pre, sizeof(*pre));
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
pre_size = pre->preamble_size;
|
||||||
|
|
||||||
|
/* Load the entire firmware preamble, now that we know how big it is */
|
||||||
|
pre = vb2_workbuf_realloc(&wb, sizeof(*pre), pre_size);
|
||||||
|
if (!pre)
|
||||||
|
return VB2_ERROR_FW_PREAMBLE2_WORKBUF;
|
||||||
|
|
||||||
|
rv = vb2ex_read_resource(ctx, VB2_RES_FW_VBLOCK,
|
||||||
|
sd->vblock_preamble_offset,
|
||||||
|
pre, pre_size);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* Work buffer now contains the data subkey data and the preamble */
|
||||||
|
|
||||||
|
/* Verify the preamble */
|
||||||
|
rv = vb2_verify_fw_preamble(pre, pre_size, &data_key, &wb);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/* Read the secure key version */
|
||||||
|
rv = vb2_secdata_get(ctx, VB2_SECDATA_VERSIONS, &sec_version);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Firmware version is the lower 16 bits of the composite firmware
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
if (pre->firmware_version > 0xffff)
|
||||||
|
return VB2_ERROR_FW_PREAMBLE2_VERSION_RANGE;
|
||||||
|
|
||||||
|
/* Combine with the key version from vb2_load_fw_keyblock() */
|
||||||
|
sd->fw_version |= pre->firmware_version;
|
||||||
|
if (sd->fw_version < sec_version)
|
||||||
|
return VB2_ERROR_FW_PREAMBLE2_VERSION_ROLLBACK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If this is a newer version than in secure storage, and we
|
||||||
|
* successfully booted the same slot last boot, roll forward the
|
||||||
|
* version in secure storage.
|
||||||
|
*/
|
||||||
|
if (sd->fw_version > sec_version &&
|
||||||
|
sd->last_fw_slot == sd->fw_slot &&
|
||||||
|
sd->last_fw_result == VB2_FW_RESULT_SUCCESS) {
|
||||||
|
|
||||||
|
rv = vb2_secdata_set(ctx, VB2_SECDATA_VERSIONS, sd->fw_version);
|
||||||
|
if (rv)
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keep track of where we put the preamble */
|
||||||
|
sd->workbuf_preamble_offset = vb2_offset_of(ctx->workbuf, pre);
|
||||||
|
sd->workbuf_preamble_size = pre_size;
|
||||||
|
|
||||||
|
/* Preamble will persist in work buffer after we return */
|
||||||
|
ctx->workbuf_used = sd->workbuf_preamble_offset + pre_size;
|
||||||
|
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
@@ -6,8 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "2sysincludes.h"
|
#include "2sysincludes.h"
|
||||||
#include "2common.h"
|
|
||||||
#include "2rsa.h"
|
#include "2rsa.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
|
|
||||||
const uint8_t *vb2_packed_key_data(const struct vb2_packed_key *key)
|
const uint8_t *vb2_packed_key_data(const struct vb2_packed_key *key)
|
||||||
{
|
{
|
||||||
@@ -15,6 +15,96 @@
|
|||||||
#include "2struct.h"
|
#include "2struct.h"
|
||||||
#include "vb2_struct.h"
|
#include "vb2_struct.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the description of an object starting with a vb2_struct_common header.
|
||||||
|
*
|
||||||
|
* Does not sanity-check the buffer; merely returns the pointer.
|
||||||
|
*
|
||||||
|
* @param buf Pointer to common object
|
||||||
|
* @return A pointer to description or an empty string if none.
|
||||||
|
*/
|
||||||
|
const char *vb2_common_desc(const void *buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the common struct header is fully contained in its parent data
|
||||||
|
*
|
||||||
|
* Also verifies the description is either zero-length or null-terminated.
|
||||||
|
*
|
||||||
|
* @param parent Parent data
|
||||||
|
* @param parent_size Parent size in bytes
|
||||||
|
* @return VB2_SUCCESS, or non-zero if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_common_header(const void *parent, uint32_t parent_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a member is within the data for a parent object
|
||||||
|
*
|
||||||
|
* @param parent Parent data (starts with struct vb2_struct_common)
|
||||||
|
* @param min_offset Pointer to minimum offset where member can be located.
|
||||||
|
* If this offset is 0 on input, uses the size of the
|
||||||
|
* fixed header (and description, if any). This will be
|
||||||
|
* updated on return to the end of the passed member. On
|
||||||
|
* error, the value of min_offset is undefined.
|
||||||
|
* @param member_offset Offset of member data from start of parent, in bytes
|
||||||
|
* @param member_size Size of member data, in bytes
|
||||||
|
* @return VB2_SUCCESS, or non-zero if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_common_member(const void *parent,
|
||||||
|
uint32_t *min_offset,
|
||||||
|
uint32_t member_offset,
|
||||||
|
uint32_t member_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify a member which starts with a common header is within the parent
|
||||||
|
*
|
||||||
|
* This does not verify the contents of the member or its header, only that the
|
||||||
|
* member's claimed total size fits within the parent's claimed total size at
|
||||||
|
* the specified offset.
|
||||||
|
*
|
||||||
|
* @param parent Parent data (starts with struct vb2_struct_common)
|
||||||
|
* @param min_offset Pointer to minimum offset where member can be located.
|
||||||
|
* If this offset is 0 on input, uses the size of the
|
||||||
|
* fixed header (and description, if any). This will be
|
||||||
|
* updated on return to the end of the passed member. On
|
||||||
|
* error, the value of min_offset is undefined.
|
||||||
|
* @param member_offset Offset of member data from start of parent, in bytes.
|
||||||
|
* This should be the start of the common header of the
|
||||||
|
* member.
|
||||||
|
* @return VB2_SUCCESS, or non-zero if error.
|
||||||
|
*/
|
||||||
|
int vb2_verify_common_subobject(const void *parent,
|
||||||
|
uint32_t *min_offset,
|
||||||
|
uint32_t member_offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack a key for use in verification
|
||||||
|
*
|
||||||
|
* The elements of the unpacked key will point into the source buffer, so don't
|
||||||
|
* free the source buffer until you're done with the key.
|
||||||
|
*
|
||||||
|
* @param key Destintion for unpacked key
|
||||||
|
* @param buf Source buffer containing packed key
|
||||||
|
* @param size Size of buffer in bytes
|
||||||
|
* @return VB2_SUCCESS, or non-zero error code if error.
|
||||||
|
*/
|
||||||
|
int vb2_unpack_key2(struct vb2_public_key *key,
|
||||||
|
const uint8_t *buf,
|
||||||
|
uint32_t size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack the RSA data fields for a public key
|
||||||
|
*
|
||||||
|
* This is called by vb2_unpack_key2() to extract the arrays from a packed key.
|
||||||
|
* These elements of *key will point inside the key_data buffer.
|
||||||
|
*
|
||||||
|
* @param key Destination key for RSA data fields
|
||||||
|
* @param key_data Packed key data (from inside a packed key buffer)
|
||||||
|
* @param key_size Size of packed key data in bytes
|
||||||
|
*/
|
||||||
|
int vb2_unpack_key2_data(struct vb2_public_key *key,
|
||||||
|
const uint8_t *key_data,
|
||||||
|
uint32_t key_size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify the integrity of a signature struct
|
* Verify the integrity of a signature struct
|
||||||
* @param sig Signature struct
|
* @param sig Signature struct
|
||||||
|
|||||||
346
tests/vb20_api_tests.c
Normal file
346
tests/vb20_api_tests.c
Normal file
@@ -0,0 +1,346 @@
|
|||||||
|
/* 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 <stdio.h>
|
||||||
|
|
||||||
|
#include "2sysincludes.h"
|
||||||
|
#include "2api.h"
|
||||||
|
#include "2misc.h"
|
||||||
|
#include "2nvstorage.h"
|
||||||
|
#include "2rsa.h"
|
||||||
|
#include "2secdata.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
|
#include "test_common.h"
|
||||||
|
|
||||||
|
/* Common context for tests */
|
||||||
|
static uint8_t workbuf[VB2_WORKBUF_RECOMMENDED_SIZE]
|
||||||
|
__attribute__ ((aligned (16)));
|
||||||
|
static struct vb2_context cc;
|
||||||
|
static struct vb2_shared_data *sd;
|
||||||
|
|
||||||
|
const char mock_body[320] = "Mock body";
|
||||||
|
const int mock_body_size = sizeof(mock_body);
|
||||||
|
const int mock_algorithm = VB2_ALG_RSA2048_SHA256;
|
||||||
|
const int mock_hash_alg = VB2_HASH_SHA256;
|
||||||
|
const int mock_sig_size = 64;
|
||||||
|
|
||||||
|
/* Mocked function data */
|
||||||
|
|
||||||
|
static int retval_vb2_load_fw_keyblock;
|
||||||
|
static int retval_vb2_load_fw_preamble;
|
||||||
|
static int retval_vb2_digest_finalize;
|
||||||
|
static int retval_vb2_verify_digest;
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
struct vb2_fw_preamble *pre;
|
||||||
|
struct vb2_packed_key *k;
|
||||||
|
|
||||||
|
memset(workbuf, 0xaa, sizeof(workbuf));
|
||||||
|
|
||||||
|
memset(&cc, 0, sizeof(cc));
|
||||||
|
cc.workbuf = workbuf;
|
||||||
|
cc.workbuf_size = sizeof(workbuf);
|
||||||
|
|
||||||
|
vb2_init_context(&cc);
|
||||||
|
sd = vb2_get_sd(&cc);
|
||||||
|
|
||||||
|
vb2_nv_init(&cc);
|
||||||
|
|
||||||
|
vb2_secdata_create(&cc);
|
||||||
|
vb2_secdata_init(&cc);
|
||||||
|
|
||||||
|
retval_vb2_load_fw_keyblock = VB2_SUCCESS;
|
||||||
|
retval_vb2_load_fw_preamble = VB2_SUCCESS;
|
||||||
|
retval_vb2_digest_finalize = VB2_SUCCESS;
|
||||||
|
retval_vb2_verify_digest = VB2_SUCCESS;
|
||||||
|
|
||||||
|
sd->workbuf_preamble_offset = cc.workbuf_used;
|
||||||
|
sd->workbuf_preamble_size = sizeof(*pre);
|
||||||
|
cc.workbuf_used = sd->workbuf_preamble_offset
|
||||||
|
+ sd->workbuf_preamble_size;
|
||||||
|
pre = (struct vb2_fw_preamble *)
|
||||||
|
(cc.workbuf + sd->workbuf_preamble_offset);
|
||||||
|
pre->body_signature.data_size = mock_body_size;
|
||||||
|
pre->body_signature.sig_size = mock_sig_size;
|
||||||
|
|
||||||
|
sd->workbuf_data_key_offset = cc.workbuf_used;
|
||||||
|
sd->workbuf_data_key_size = sizeof(*k) + 8;
|
||||||
|
cc.workbuf_used = sd->workbuf_data_key_offset +
|
||||||
|
sd->workbuf_data_key_size;
|
||||||
|
k = (struct vb2_packed_key *)
|
||||||
|
(cc.workbuf + sd->workbuf_data_key_offset);
|
||||||
|
k->algorithm = mock_algorithm;
|
||||||
|
|
||||||
|
if (t == FOR_EXTEND_HASH || t == FOR_CHECK_HASH)
|
||||||
|
vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, NULL);
|
||||||
|
|
||||||
|
if (t == FOR_CHECK_HASH)
|
||||||
|
vb2api_extend_hash(&cc, mock_body, mock_body_size);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Mocked functions */
|
||||||
|
|
||||||
|
int vb2_load_fw_keyblock(struct vb2_context *ctx)
|
||||||
|
{
|
||||||
|
return retval_vb2_load_fw_keyblock;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_load_fw_preamble(struct vb2_context *ctx)
|
||||||
|
{
|
||||||
|
return retval_vb2_load_fw_preamble;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_unpack_key(struct vb2_public_key *key,
|
||||||
|
const uint8_t *buf,
|
||||||
|
uint32_t size)
|
||||||
|
{
|
||||||
|
struct vb2_packed_key *k = (struct vb2_packed_key *)buf;
|
||||||
|
|
||||||
|
if (size != sizeof(*k) + 8)
|
||||||
|
return VB2_ERROR_UNPACK_KEY_SIZE;
|
||||||
|
|
||||||
|
key->sig_alg = vb2_crypto_to_signature(k->algorithm);
|
||||||
|
key->hash_alg = vb2_crypto_to_hash(k->algorithm);
|
||||||
|
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_digest_init(struct vb2_digest_context *dc,
|
||||||
|
enum vb2_hash_algorithm hash_alg)
|
||||||
|
{
|
||||||
|
if (hash_alg != mock_hash_alg)
|
||||||
|
return VB2_ERROR_SHA_INIT_ALGORITHM;
|
||||||
|
|
||||||
|
dc->hash_alg = hash_alg;
|
||||||
|
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_digest_extend(struct vb2_digest_context *dc,
|
||||||
|
const uint8_t *buf,
|
||||||
|
uint32_t size)
|
||||||
|
{
|
||||||
|
if (dc->hash_alg != mock_hash_alg)
|
||||||
|
return VB2_ERROR_SHA_EXTEND_ALGORITHM;
|
||||||
|
|
||||||
|
return VB2_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_digest_finalize(struct vb2_digest_context *dc,
|
||||||
|
uint8_t *digest,
|
||||||
|
uint32_t digest_size)
|
||||||
|
{
|
||||||
|
return retval_vb2_digest_finalize;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t vb2_rsa_sig_size(enum vb2_signature_algorithm sig_alg)
|
||||||
|
{
|
||||||
|
return mock_sig_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vb2_rsa_verify_digest(const struct vb2_public_key *key,
|
||||||
|
uint8_t *sig,
|
||||||
|
const uint8_t *digest,
|
||||||
|
const struct vb2_workbuf *wb)
|
||||||
|
{
|
||||||
|
return retval_vb2_verify_digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tests */
|
||||||
|
|
||||||
|
static void phase3_tests(void)
|
||||||
|
{
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
TEST_SUCC(vb2api_fw_phase3(&cc), "phase3 good");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
retval_vb2_load_fw_keyblock = VB2_ERROR_MOCK;
|
||||||
|
TEST_EQ(vb2api_fw_phase3(&cc), VB2_ERROR_MOCK, "phase3 keyblock");
|
||||||
|
TEST_EQ(vb2_nv_get(&cc, VB2_NV_RECOVERY_REQUEST),
|
||||||
|
VB2_RECOVERY_RO_INVALID_RW, " recovery reason");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
retval_vb2_load_fw_preamble = VB2_ERROR_MOCK;
|
||||||
|
TEST_EQ(vb2api_fw_phase3(&cc), VB2_ERROR_MOCK, "phase3 keyblock");
|
||||||
|
TEST_EQ(vb2_nv_get(&cc, VB2_NV_RECOVERY_REQUEST),
|
||||||
|
VB2_RECOVERY_RO_INVALID_RW, " recovery reason");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_hash_tests(void)
|
||||||
|
{
|
||||||
|
struct vb2_packed_key *k;
|
||||||
|
int wb_used_before;
|
||||||
|
uint32_t size;
|
||||||
|
|
||||||
|
/* For now, all we support is body signature hash */
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
wb_used_before = cc.workbuf_used;
|
||||||
|
TEST_SUCC(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
||||||
|
"init hash good");
|
||||||
|
TEST_EQ(sd->workbuf_hash_offset,
|
||||||
|
(wb_used_before + (VB2_WORKBUF_ALIGN - 1)) &
|
||||||
|
~(VB2_WORKBUF_ALIGN - 1),
|
||||||
|
"hash context offset");
|
||||||
|
TEST_EQ(sd->workbuf_hash_size, sizeof(struct vb2_digest_context),
|
||||||
|
"hash context size");
|
||||||
|
TEST_EQ(cc.workbuf_used,
|
||||||
|
sd->workbuf_hash_offset + sd->workbuf_hash_size,
|
||||||
|
"hash uses workbuf");
|
||||||
|
TEST_EQ(sd->hash_tag, VB2_HASH_TAG_FW_BODY, "hash tag");
|
||||||
|
TEST_EQ(sd->hash_remaining_size, mock_body_size, "hash remaining");
|
||||||
|
|
||||||
|
wb_used_before = cc.workbuf_used;
|
||||||
|
TEST_SUCC(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, NULL),
|
||||||
|
"init hash again");
|
||||||
|
TEST_EQ(cc.workbuf_used, wb_used_before, "init hash reuses context");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_INVALID, &size),
|
||||||
|
VB2_ERROR_API_INIT_HASH_TAG, "init hash invalid tag");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
sd->workbuf_preamble_size = 0;
|
||||||
|
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
||||||
|
VB2_ERROR_API_INIT_HASH_PREAMBLE, "init hash preamble");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY + 1, &size),
|
||||||
|
VB2_ERROR_API_INIT_HASH_TAG, "init hash unknown tag");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
cc.workbuf_used =
|
||||||
|
cc.workbuf_size - sizeof(struct vb2_digest_context) + 8;
|
||||||
|
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
||||||
|
VB2_ERROR_API_INIT_HASH_WORKBUF, "init hash workbuf");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
sd->workbuf_data_key_size = 0;
|
||||||
|
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
||||||
|
VB2_ERROR_API_INIT_HASH_DATA_KEY, "init hash data key");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
sd->workbuf_data_key_size--;
|
||||||
|
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
||||||
|
VB2_ERROR_UNPACK_KEY_SIZE, "init hash data key size");
|
||||||
|
|
||||||
|
reset_common_data(FOR_MISC);
|
||||||
|
k = (struct vb2_packed_key *)(cc.workbuf + sd->workbuf_data_key_offset);
|
||||||
|
k->algorithm--;
|
||||||
|
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
||||||
|
VB2_ERROR_SHA_INIT_ALGORITHM, "init hash algorithm");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void extend_hash_tests(void)
|
||||||
|
{
|
||||||
|
struct vb2_digest_context *dc;
|
||||||
|
|
||||||
|
reset_common_data(FOR_EXTEND_HASH);
|
||||||
|
TEST_SUCC(vb2api_extend_hash(&cc, mock_body, 32),
|
||||||
|
"hash extend good");
|
||||||
|
TEST_EQ(sd->hash_remaining_size, mock_body_size - 32,
|
||||||
|
"hash extend remaining");
|
||||||
|
TEST_SUCC(vb2api_extend_hash(&cc, 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(&cc, 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(&cc, 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(&cc, mock_body, 0),
|
||||||
|
VB2_ERROR_API_EXTEND_HASH_SIZE, "hash extend empty");
|
||||||
|
|
||||||
|
reset_common_data(FOR_EXTEND_HASH);
|
||||||
|
dc = (struct vb2_digest_context *)
|
||||||
|
(cc.workbuf + sd->workbuf_hash_offset);
|
||||||
|
dc->hash_alg = mock_hash_alg + 1;
|
||||||
|
TEST_EQ(vb2api_extend_hash(&cc, mock_body, mock_body_size),
|
||||||
|
VB2_ERROR_SHA_EXTEND_ALGORITHM, "hash extend fail");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void check_hash_tests(void)
|
||||||
|
{
|
||||||
|
struct vb2_fw_preamble *pre;
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
TEST_SUCC(vb2api_check_hash(&cc), "check hash good");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
sd->workbuf_preamble_size = 0;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_API_CHECK_HASH_PREAMBLE, "check hash preamble");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
sd->workbuf_hash_size = 0;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_API_CHECK_HASH_WORKBUF, "check hash no workbuf");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
sd->hash_remaining_size = 1;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_API_CHECK_HASH_SIZE, "check hash size");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
cc.workbuf_used = cc.workbuf_size;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_API_CHECK_HASH_WORKBUF_DIGEST, "check hash workbuf");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
retval_vb2_digest_finalize = VB2_ERROR_MOCK;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc), VB2_ERROR_MOCK, "check hash finalize");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
sd->hash_tag = VB2_HASH_TAG_INVALID;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_API_CHECK_HASH_TAG, "check hash tag");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
sd->workbuf_data_key_size = 0;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_API_CHECK_HASH_DATA_KEY, "check hash data key");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
sd->workbuf_data_key_size--;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_UNPACK_KEY_SIZE, "check hash data key size");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
pre = (struct vb2_fw_preamble *)
|
||||||
|
(cc.workbuf + sd->workbuf_preamble_offset);
|
||||||
|
pre->body_signature.sig_size++;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_VDATA_SIG_SIZE, "check hash sig size");
|
||||||
|
|
||||||
|
reset_common_data(FOR_CHECK_HASH);
|
||||||
|
retval_vb2_digest_finalize = VB2_ERROR_RSA_VERIFY_DIGEST;
|
||||||
|
TEST_EQ(vb2api_check_hash(&cc),
|
||||||
|
VB2_ERROR_RSA_VERIFY_DIGEST, "check hash finalize");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
phase3_tests();
|
||||||
|
init_hash_tests();
|
||||||
|
extend_hash_tests();
|
||||||
|
check_hash_tests();
|
||||||
|
|
||||||
|
return gTestSuccess ? 0 : 255;
|
||||||
|
}
|
||||||
@@ -10,10 +10,10 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "2sysincludes.h"
|
#include "2sysincludes.h"
|
||||||
#include "2common.h"
|
|
||||||
#include "2rsa.h"
|
#include "2rsa.h"
|
||||||
#include "file_keys.h"
|
#include "file_keys.h"
|
||||||
#include "host_common.h"
|
#include "host_common.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
#include "vboot_common.h"
|
#include "vboot_common.h"
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
@@ -8,7 +8,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "2sysincludes.h"
|
#include "2sysincludes.h"
|
||||||
#include "2common.h"
|
|
||||||
#include "2rsa.h"
|
#include "2rsa.h"
|
||||||
|
|
||||||
#include "file_keys.h"
|
#include "file_keys.h"
|
||||||
@@ -16,6 +15,7 @@
|
|||||||
#include "host_key.h"
|
#include "host_key.h"
|
||||||
#include "host_keyblock.h"
|
#include "host_keyblock.h"
|
||||||
#include "host_signature.h"
|
#include "host_signature.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
#include "vboot_common.h"
|
#include "vboot_common.h"
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
174
tests/vb20_common_tests.c
Normal file
174
tests/vb20_common_tests.c
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
/* 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 2common.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "2sysincludes.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
|
#include "vboot_struct.h" /* For old struct sizes */
|
||||||
|
#include "test_common.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Test struct packing for vboot_struct.h structs which are passed between
|
||||||
|
* firmware and OS, or passed between different phases of firmware.
|
||||||
|
*/
|
||||||
|
static void test_struct_packing(void)
|
||||||
|
{
|
||||||
|
/* Test vboot2 versions of vboot1 structs */
|
||||||
|
TEST_EQ(EXPECTED_VB2_PACKED_KEY_SIZE,
|
||||||
|
sizeof(struct vb2_packed_key),
|
||||||
|
"sizeof(vb2_packed_key)");
|
||||||
|
TEST_EQ(EXPECTED_VB2_SIGNATURE_SIZE,
|
||||||
|
sizeof(struct vb2_signature),
|
||||||
|
"sizeof(vb2_signature)");
|
||||||
|
TEST_EQ(EXPECTED_VB2_KEYBLOCK_SIZE,
|
||||||
|
sizeof(struct vb2_keyblock),
|
||||||
|
"sizeof(vb2_keyblock)");
|
||||||
|
TEST_EQ(EXPECTED_VB2_FW_PREAMBLE_SIZE,
|
||||||
|
sizeof(struct vb2_fw_preamble),
|
||||||
|
"sizeof(vb2_fw_preamble)");
|
||||||
|
TEST_EQ(EXPECTED_VB2_GBB_HEADER_SIZE,
|
||||||
|
sizeof(struct vb2_gbb_header),
|
||||||
|
"sizeof(vb2_gbb_header)");
|
||||||
|
|
||||||
|
/* And make sure they're the same as their vboot1 equivalents */
|
||||||
|
TEST_EQ(EXPECTED_VB2_PACKED_KEY_SIZE,
|
||||||
|
EXPECTED_VBPUBLICKEY_SIZE,
|
||||||
|
"vboot1->2 packed key sizes same");
|
||||||
|
TEST_EQ(EXPECTED_VB2_SIGNATURE_SIZE,
|
||||||
|
EXPECTED_VBSIGNATURE_SIZE,
|
||||||
|
"vboot1->2 signature sizes same");
|
||||||
|
TEST_EQ(EXPECTED_VB2_KEYBLOCK_SIZE,
|
||||||
|
EXPECTED_VBKEYBLOCKHEADER_SIZE,
|
||||||
|
"vboot1->2 keyblock sizes same");
|
||||||
|
TEST_EQ(EXPECTED_VB2_FW_PREAMBLE_SIZE,
|
||||||
|
EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
|
||||||
|
"vboot1->2 firmware preamble sizes same");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper functions not dependent on specific key sizes
|
||||||
|
*/
|
||||||
|
static void test_helper_functions(void)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)test_helper_functions;
|
||||||
|
TEST_EQ((int)vb2_offset_of(p, p), 0, "vb2_offset_of() equal");
|
||||||
|
TEST_EQ((int)vb2_offset_of(p, p+10), 10,
|
||||||
|
"vb2_offset_of() positive");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct vb2_packed_key k = {.key_offset = sizeof(k)};
|
||||||
|
TEST_EQ((int)vb2_offset_of(&k, vb2_packed_key_data(&k)),
|
||||||
|
sizeof(k), "vb2_packed_key_data() adjacent");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct vb2_packed_key k = {.key_offset = 123};
|
||||||
|
TEST_EQ((int)vb2_offset_of(&k, vb2_packed_key_data(&k)), 123,
|
||||||
|
"vb2_packed_key_data() spaced");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct vb2_signature s = {.sig_offset = sizeof(s)};
|
||||||
|
TEST_EQ((int)vb2_offset_of(&s, vb2_signature_data(&s)),
|
||||||
|
sizeof(s), "vb2_signature_data() adjacent");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct vb2_signature s = {.sig_offset = 123};
|
||||||
|
TEST_EQ((int)vb2_offset_of(&s, vb2_signature_data(&s)), 123,
|
||||||
|
"vb2_signature_data() spaced");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)test_helper_functions;
|
||||||
|
TEST_SUCC(vb2_verify_member_inside(p, 20, p, 6, 11, 3),
|
||||||
|
"MemberInside ok 1");
|
||||||
|
TEST_SUCC(vb2_verify_member_inside(p, 20, p+4, 4, 8, 4),
|
||||||
|
"MemberInside ok 2");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p-4, 4, 8, 4),
|
||||||
|
VB2_ERROR_INSIDE_MEMBER_OUTSIDE,
|
||||||
|
"MemberInside member before parent");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p+20, 4, 8, 4),
|
||||||
|
VB2_ERROR_INSIDE_MEMBER_OUTSIDE,
|
||||||
|
"MemberInside member after parent");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p, 21, 0, 0),
|
||||||
|
VB2_ERROR_INSIDE_MEMBER_OUTSIDE,
|
||||||
|
"MemberInside member too big");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p, 4, 21, 0),
|
||||||
|
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
||||||
|
"MemberInside data after parent");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p, 4, SIZE_MAX, 0),
|
||||||
|
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
||||||
|
"MemberInside data before parent");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p, 4, 4, 17),
|
||||||
|
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
||||||
|
"MemberInside data too big");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p, 8, 4, 8),
|
||||||
|
VB2_ERROR_INSIDE_DATA_OVERLAP,
|
||||||
|
"MemberInside data overlaps member");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, -8, p, 12, 0, 0),
|
||||||
|
VB2_ERROR_INSIDE_PARENT_WRAPS,
|
||||||
|
"MemberInside wraparound 1");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p, -8, 0, 0),
|
||||||
|
VB2_ERROR_INSIDE_MEMBER_WRAPS,
|
||||||
|
"MemberInside wraparound 2");
|
||||||
|
TEST_EQ(vb2_verify_member_inside(p, 20, p, 4, 4, -12),
|
||||||
|
VB2_ERROR_INSIDE_DATA_WRAPS,
|
||||||
|
"MemberInside wraparound 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct vb2_packed_key k = {.key_offset = sizeof(k),
|
||||||
|
.key_size = 128};
|
||||||
|
TEST_SUCC(vb2_verify_packed_key_inside(&k, sizeof(k)+128, &k),
|
||||||
|
"PublicKeyInside ok 1");
|
||||||
|
TEST_SUCC(vb2_verify_packed_key_inside(&k - 1,
|
||||||
|
2*sizeof(k)+128, &k),
|
||||||
|
"PublicKeyInside ok 2");
|
||||||
|
TEST_EQ(vb2_verify_packed_key_inside(&k, 128, &k),
|
||||||
|
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
||||||
|
"PublicKeyInside key too big");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct vb2_packed_key k = {.key_offset = 100,
|
||||||
|
.key_size = 4};
|
||||||
|
TEST_EQ(vb2_verify_packed_key_inside(&k, 99, &k),
|
||||||
|
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
||||||
|
"PublicKeyInside offset too big");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct vb2_signature s = {.sig_offset = sizeof(s),
|
||||||
|
.sig_size = 128};
|
||||||
|
TEST_SUCC(vb2_verify_signature_inside(&s, sizeof(s)+128, &s),
|
||||||
|
"SignatureInside ok 1");
|
||||||
|
TEST_SUCC(vb2_verify_signature_inside(&s - 1,
|
||||||
|
2*sizeof(s)+128, &s),
|
||||||
|
"SignatureInside ok 2");
|
||||||
|
TEST_EQ(vb2_verify_signature_inside(&s, 128, &s),
|
||||||
|
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
||||||
|
"SignatureInside sig too big");
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct vb2_signature s = {.sig_offset = 100,
|
||||||
|
.sig_size = 4};
|
||||||
|
TEST_EQ(vb2_verify_signature_inside(&s, 99, &s),
|
||||||
|
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
||||||
|
"SignatureInside offset too big");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
test_struct_packing();
|
||||||
|
test_helper_functions();
|
||||||
|
|
||||||
|
return gTestSuccess ? 0 : 255;
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
#include "2misc.h"
|
#include "2misc.h"
|
||||||
#include "2nvstorage.h"
|
#include "2nvstorage.h"
|
||||||
#include "2secdata.h"
|
#include "2secdata.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
/* Common context for tests */
|
/* Common context for tests */
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
|
|
||||||
#include "2sysincludes.h"
|
#include "2sysincludes.h"
|
||||||
#include "2common.h"
|
|
||||||
#include "2rsa.h"
|
#include "2rsa.h"
|
||||||
|
#include "vb2_common.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert an old-style RSA public key struct to a new one.
|
* Convert an old-style RSA public key struct to a new one.
|
||||||
@@ -30,7 +30,6 @@ static struct vb2_shared_data *sd;
|
|||||||
|
|
||||||
static const uint8_t mock_body[320] = "Mock body";
|
static const uint8_t mock_body[320] = "Mock body";
|
||||||
static const int mock_body_size = sizeof(mock_body);
|
static const int mock_body_size = sizeof(mock_body);
|
||||||
static const int mock_algorithm = VB2_ALG_RSA2048_SHA256;
|
|
||||||
static const int mock_hash_alg = VB2_HASH_SHA256;
|
static const int mock_hash_alg = VB2_HASH_SHA256;
|
||||||
static int mock_sig_size;
|
static int mock_sig_size;
|
||||||
|
|
||||||
@@ -198,6 +197,40 @@ static void init_hash_tests(void)
|
|||||||
VB2_ERROR_SHA_INIT_ALGORITHM, "init hash algorithm");
|
VB2_ERROR_SHA_INIT_ALGORITHM, "init hash algorithm");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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");
|
||||||
|
|
||||||
|
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)
|
static void check_hash_tests(void)
|
||||||
{
|
{
|
||||||
struct vb2_fw_preamble2 *pre;
|
struct vb2_fw_preamble2 *pre;
|
||||||
@@ -249,6 +282,7 @@ int main(int argc, char* argv[])
|
|||||||
{
|
{
|
||||||
phase3_tests();
|
phase3_tests();
|
||||||
init_hash_tests();
|
init_hash_tests();
|
||||||
|
extend_hash_tests();
|
||||||
check_hash_tests();
|
check_hash_tests();
|
||||||
|
|
||||||
return gTestSuccess ? 0 : 255;
|
return gTestSuccess ? 0 : 255;
|
||||||
|
|||||||
@@ -245,7 +245,7 @@ static void load_keyblock_tests(void)
|
|||||||
|
|
||||||
reset_common_data(FOR_KEYBLOCK);
|
reset_common_data(FOR_KEYBLOCK);
|
||||||
ctx.workbuf_used = ctx.workbuf_size - sd->gbb_rootkey_size
|
ctx.workbuf_used = ctx.workbuf_size - sd->gbb_rootkey_size
|
||||||
- sizeof(struct vb2_keyblock);
|
- sizeof(struct vb2_keyblock2);
|
||||||
TEST_EQ(vb2_load_fw_keyblock2(&ctx),
|
TEST_EQ(vb2_load_fw_keyblock2(&ctx),
|
||||||
VB2_ERROR_READ_RESOURCE_OBJECT_BUF,
|
VB2_ERROR_READ_RESOURCE_OBJECT_BUF,
|
||||||
"keyblock not enough workbuf for entire keyblock");
|
"keyblock not enough workbuf for entire keyblock");
|
||||||
@@ -310,7 +310,7 @@ static void load_preamble_tests(void)
|
|||||||
|
|
||||||
reset_common_data(FOR_PREAMBLE);
|
reset_common_data(FOR_PREAMBLE);
|
||||||
ctx.workbuf_used = ctx.workbuf_size
|
ctx.workbuf_used = ctx.workbuf_size
|
||||||
- sizeof(struct vb2_fw_preamble) + 8;
|
- sizeof(struct vb2_fw_preamble2) + 8;
|
||||||
TEST_EQ(vb2_load_fw_preamble2(&ctx),
|
TEST_EQ(vb2_load_fw_preamble2(&ctx),
|
||||||
VB2_ERROR_READ_RESOURCE_OBJECT_BUF,
|
VB2_ERROR_READ_RESOURCE_OBJECT_BUF,
|
||||||
"preamble not enough workbuf for header");
|
"preamble not enough workbuf for header");
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
#include "2nvstorage.h"
|
#include "2nvstorage.h"
|
||||||
#include "2rsa.h"
|
#include "2rsa.h"
|
||||||
#include "2secdata.h"
|
#include "2secdata.h"
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
/* Common context for tests */
|
/* Common context for tests */
|
||||||
@@ -27,7 +26,6 @@ const char mock_body[320] = "Mock body";
|
|||||||
const int mock_body_size = sizeof(mock_body);
|
const int mock_body_size = sizeof(mock_body);
|
||||||
const int mock_algorithm = VB2_ALG_RSA2048_SHA256;
|
const int mock_algorithm = VB2_ALG_RSA2048_SHA256;
|
||||||
const int mock_hash_alg = VB2_HASH_SHA256;
|
const int mock_hash_alg = VB2_HASH_SHA256;
|
||||||
const int mock_sig_size = 64;
|
|
||||||
|
|
||||||
/* Mocked function data */
|
/* Mocked function data */
|
||||||
|
|
||||||
@@ -35,23 +33,14 @@ static int retval_vb2_fw_parse_gbb;
|
|||||||
static int retval_vb2_check_dev_switch;
|
static int retval_vb2_check_dev_switch;
|
||||||
static int retval_vb2_check_tpm_clear;
|
static int retval_vb2_check_tpm_clear;
|
||||||
static int retval_vb2_select_fw_slot;
|
static int retval_vb2_select_fw_slot;
|
||||||
static int retval_vb2_load_fw_keyblock;
|
|
||||||
static int retval_vb2_load_fw_preamble;
|
|
||||||
static int retval_vb2_digest_finalize;
|
|
||||||
static int retval_vb2_verify_digest;
|
|
||||||
|
|
||||||
/* Type of test to reset for */
|
/* Type of test to reset for */
|
||||||
enum reset_type {
|
enum reset_type {
|
||||||
FOR_MISC,
|
FOR_MISC,
|
||||||
FOR_EXTEND_HASH,
|
|
||||||
FOR_CHECK_HASH,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void reset_common_data(enum reset_type t)
|
static void reset_common_data(enum reset_type t)
|
||||||
{
|
{
|
||||||
struct vb2_fw_preamble *pre;
|
|
||||||
struct vb2_packed_key *k;
|
|
||||||
|
|
||||||
memset(workbuf, 0xaa, sizeof(workbuf));
|
memset(workbuf, 0xaa, sizeof(workbuf));
|
||||||
|
|
||||||
memset(&cc, 0, sizeof(cc));
|
memset(&cc, 0, sizeof(cc));
|
||||||
@@ -70,33 +59,6 @@ static void reset_common_data(enum reset_type t)
|
|||||||
retval_vb2_check_dev_switch = VB2_SUCCESS;
|
retval_vb2_check_dev_switch = VB2_SUCCESS;
|
||||||
retval_vb2_check_tpm_clear = VB2_SUCCESS;
|
retval_vb2_check_tpm_clear = VB2_SUCCESS;
|
||||||
retval_vb2_select_fw_slot = VB2_SUCCESS;
|
retval_vb2_select_fw_slot = VB2_SUCCESS;
|
||||||
retval_vb2_load_fw_keyblock = VB2_SUCCESS;
|
|
||||||
retval_vb2_load_fw_preamble = VB2_SUCCESS;
|
|
||||||
retval_vb2_digest_finalize = VB2_SUCCESS;
|
|
||||||
retval_vb2_verify_digest = VB2_SUCCESS;
|
|
||||||
|
|
||||||
sd->workbuf_preamble_offset = cc.workbuf_used;
|
|
||||||
sd->workbuf_preamble_size = sizeof(*pre);
|
|
||||||
cc.workbuf_used = sd->workbuf_preamble_offset
|
|
||||||
+ sd->workbuf_preamble_size;
|
|
||||||
pre = (struct vb2_fw_preamble *)
|
|
||||||
(cc.workbuf + sd->workbuf_preamble_offset);
|
|
||||||
pre->body_signature.data_size = mock_body_size;
|
|
||||||
pre->body_signature.sig_size = mock_sig_size;
|
|
||||||
|
|
||||||
sd->workbuf_data_key_offset = cc.workbuf_used;
|
|
||||||
sd->workbuf_data_key_size = sizeof(*k) + 8;
|
|
||||||
cc.workbuf_used = sd->workbuf_data_key_offset +
|
|
||||||
sd->workbuf_data_key_size;
|
|
||||||
k = (struct vb2_packed_key *)
|
|
||||||
(cc.workbuf + sd->workbuf_data_key_offset);
|
|
||||||
k->algorithm = mock_algorithm;
|
|
||||||
|
|
||||||
if (t == FOR_EXTEND_HASH || t == FOR_CHECK_HASH)
|
|
||||||
vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, NULL);
|
|
||||||
|
|
||||||
if (t == FOR_CHECK_HASH)
|
|
||||||
vb2api_extend_hash(&cc, mock_body, mock_body_size);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Mocked functions */
|
/* Mocked functions */
|
||||||
@@ -121,72 +83,6 @@ int vb2_select_fw_slot(struct vb2_context *ctx)
|
|||||||
return retval_vb2_select_fw_slot;
|
return retval_vb2_select_fw_slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vb2_load_fw_keyblock(struct vb2_context *ctx)
|
|
||||||
{
|
|
||||||
return retval_vb2_load_fw_keyblock;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_load_fw_preamble(struct vb2_context *ctx)
|
|
||||||
{
|
|
||||||
return retval_vb2_load_fw_preamble;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_unpack_key(struct vb2_public_key *key,
|
|
||||||
const uint8_t *buf,
|
|
||||||
uint32_t size)
|
|
||||||
{
|
|
||||||
struct vb2_packed_key *k = (struct vb2_packed_key *)buf;
|
|
||||||
|
|
||||||
if (size != sizeof(*k) + 8)
|
|
||||||
return VB2_ERROR_UNPACK_KEY_SIZE;
|
|
||||||
|
|
||||||
key->sig_alg = vb2_crypto_to_signature(k->algorithm);
|
|
||||||
key->hash_alg = vb2_crypto_to_hash(k->algorithm);
|
|
||||||
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_digest_init(struct vb2_digest_context *dc,
|
|
||||||
enum vb2_hash_algorithm hash_alg)
|
|
||||||
{
|
|
||||||
if (hash_alg != mock_hash_alg)
|
|
||||||
return VB2_ERROR_SHA_INIT_ALGORITHM;
|
|
||||||
|
|
||||||
dc->hash_alg = hash_alg;
|
|
||||||
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_digest_extend(struct vb2_digest_context *dc,
|
|
||||||
const uint8_t *buf,
|
|
||||||
uint32_t size)
|
|
||||||
{
|
|
||||||
if (dc->hash_alg != mock_hash_alg)
|
|
||||||
return VB2_ERROR_SHA_EXTEND_ALGORITHM;
|
|
||||||
|
|
||||||
return VB2_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_digest_finalize(struct vb2_digest_context *dc,
|
|
||||||
uint8_t *digest,
|
|
||||||
uint32_t digest_size)
|
|
||||||
{
|
|
||||||
return retval_vb2_digest_finalize;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t vb2_rsa_sig_size(enum vb2_signature_algorithm sig_alg)
|
|
||||||
{
|
|
||||||
return mock_sig_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
int vb2_rsa_verify_digest(const struct vb2_public_key *key,
|
|
||||||
uint8_t *sig,
|
|
||||||
const uint8_t *digest,
|
|
||||||
const struct vb2_workbuf *wb)
|
|
||||||
{
|
|
||||||
return retval_vb2_verify_digest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Tests */
|
/* Tests */
|
||||||
|
|
||||||
static void misc_tests(void)
|
static void misc_tests(void)
|
||||||
@@ -270,190 +166,11 @@ static void phase2_tests(void)
|
|||||||
VB2_RECOVERY_FW_SLOT, " recovery reason");
|
VB2_RECOVERY_FW_SLOT, " recovery reason");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void phase3_tests(void)
|
|
||||||
{
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
TEST_SUCC(vb2api_fw_phase3(&cc), "phase3 good");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
retval_vb2_load_fw_keyblock = VB2_ERROR_MOCK;
|
|
||||||
TEST_EQ(vb2api_fw_phase3(&cc), VB2_ERROR_MOCK, "phase3 keyblock");
|
|
||||||
TEST_EQ(vb2_nv_get(&cc, VB2_NV_RECOVERY_REQUEST),
|
|
||||||
VB2_RECOVERY_RO_INVALID_RW, " recovery reason");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
retval_vb2_load_fw_preamble = VB2_ERROR_MOCK;
|
|
||||||
TEST_EQ(vb2api_fw_phase3(&cc), VB2_ERROR_MOCK, "phase3 keyblock");
|
|
||||||
TEST_EQ(vb2_nv_get(&cc, VB2_NV_RECOVERY_REQUEST),
|
|
||||||
VB2_RECOVERY_RO_INVALID_RW, " recovery reason");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_hash_tests(void)
|
|
||||||
{
|
|
||||||
struct vb2_packed_key *k;
|
|
||||||
int wb_used_before;
|
|
||||||
uint32_t size;
|
|
||||||
|
|
||||||
/* For now, all we support is body signature hash */
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
wb_used_before = cc.workbuf_used;
|
|
||||||
TEST_SUCC(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
|
||||||
"init hash good");
|
|
||||||
TEST_EQ(sd->workbuf_hash_offset,
|
|
||||||
(wb_used_before + (VB2_WORKBUF_ALIGN - 1)) &
|
|
||||||
~(VB2_WORKBUF_ALIGN - 1),
|
|
||||||
"hash context offset");
|
|
||||||
TEST_EQ(sd->workbuf_hash_size, sizeof(struct vb2_digest_context),
|
|
||||||
"hash context size");
|
|
||||||
TEST_EQ(cc.workbuf_used,
|
|
||||||
sd->workbuf_hash_offset + sd->workbuf_hash_size,
|
|
||||||
"hash uses workbuf");
|
|
||||||
TEST_EQ(sd->hash_tag, VB2_HASH_TAG_FW_BODY, "hash tag");
|
|
||||||
TEST_EQ(sd->hash_remaining_size, mock_body_size, "hash remaining");
|
|
||||||
|
|
||||||
wb_used_before = cc.workbuf_used;
|
|
||||||
TEST_SUCC(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, NULL),
|
|
||||||
"init hash again");
|
|
||||||
TEST_EQ(cc.workbuf_used, wb_used_before, "init hash reuses context");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_INVALID, &size),
|
|
||||||
VB2_ERROR_API_INIT_HASH_TAG, "init hash invalid tag");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
sd->workbuf_preamble_size = 0;
|
|
||||||
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
|
||||||
VB2_ERROR_API_INIT_HASH_PREAMBLE, "init hash preamble");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY + 1, &size),
|
|
||||||
VB2_ERROR_API_INIT_HASH_TAG, "init hash unknown tag");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
cc.workbuf_used =
|
|
||||||
cc.workbuf_size - sizeof(struct vb2_digest_context) + 8;
|
|
||||||
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
|
||||||
VB2_ERROR_API_INIT_HASH_WORKBUF, "init hash workbuf");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
sd->workbuf_data_key_size = 0;
|
|
||||||
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
|
||||||
VB2_ERROR_API_INIT_HASH_DATA_KEY, "init hash data key");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
sd->workbuf_data_key_size--;
|
|
||||||
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
|
||||||
VB2_ERROR_UNPACK_KEY_SIZE, "init hash data key size");
|
|
||||||
|
|
||||||
reset_common_data(FOR_MISC);
|
|
||||||
k = (struct vb2_packed_key *)(cc.workbuf + sd->workbuf_data_key_offset);
|
|
||||||
k->algorithm--;
|
|
||||||
TEST_EQ(vb2api_init_hash(&cc, VB2_HASH_TAG_FW_BODY, &size),
|
|
||||||
VB2_ERROR_SHA_INIT_ALGORITHM, "init hash algorithm");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void extend_hash_tests(void)
|
|
||||||
{
|
|
||||||
struct vb2_digest_context *dc;
|
|
||||||
|
|
||||||
reset_common_data(FOR_EXTEND_HASH);
|
|
||||||
TEST_SUCC(vb2api_extend_hash(&cc, mock_body, 32),
|
|
||||||
"hash extend good");
|
|
||||||
TEST_EQ(sd->hash_remaining_size, mock_body_size - 32,
|
|
||||||
"hash extend remaining");
|
|
||||||
TEST_SUCC(vb2api_extend_hash(&cc, 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(&cc, 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(&cc, 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(&cc, mock_body, 0),
|
|
||||||
VB2_ERROR_API_EXTEND_HASH_SIZE, "hash extend empty");
|
|
||||||
|
|
||||||
reset_common_data(FOR_EXTEND_HASH);
|
|
||||||
dc = (struct vb2_digest_context *)
|
|
||||||
(cc.workbuf + sd->workbuf_hash_offset);
|
|
||||||
dc->hash_alg = mock_hash_alg + 1;
|
|
||||||
TEST_EQ(vb2api_extend_hash(&cc, mock_body, mock_body_size),
|
|
||||||
VB2_ERROR_SHA_EXTEND_ALGORITHM, "hash extend fail");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void check_hash_tests(void)
|
|
||||||
{
|
|
||||||
struct vb2_fw_preamble *pre;
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
TEST_SUCC(vb2api_check_hash(&cc), "check hash good");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
sd->workbuf_preamble_size = 0;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_API_CHECK_HASH_PREAMBLE, "check hash preamble");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
sd->workbuf_hash_size = 0;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_API_CHECK_HASH_WORKBUF, "check hash no workbuf");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
sd->hash_remaining_size = 1;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_API_CHECK_HASH_SIZE, "check hash size");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
cc.workbuf_used = cc.workbuf_size;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_API_CHECK_HASH_WORKBUF_DIGEST, "check hash workbuf");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
retval_vb2_digest_finalize = VB2_ERROR_MOCK;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc), VB2_ERROR_MOCK, "check hash finalize");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
sd->hash_tag = VB2_HASH_TAG_INVALID;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_API_CHECK_HASH_TAG, "check hash tag");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
sd->workbuf_data_key_size = 0;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_API_CHECK_HASH_DATA_KEY, "check hash data key");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
sd->workbuf_data_key_size--;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_UNPACK_KEY_SIZE, "check hash data key size");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
pre = (struct vb2_fw_preamble *)
|
|
||||||
(cc.workbuf + sd->workbuf_preamble_offset);
|
|
||||||
pre->body_signature.sig_size++;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_VDATA_SIG_SIZE, "check hash sig size");
|
|
||||||
|
|
||||||
reset_common_data(FOR_CHECK_HASH);
|
|
||||||
retval_vb2_digest_finalize = VB2_ERROR_RSA_VERIFY_DIGEST;
|
|
||||||
TEST_EQ(vb2api_check_hash(&cc),
|
|
||||||
VB2_ERROR_RSA_VERIFY_DIGEST, "check hash finalize");
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
misc_tests();
|
misc_tests();
|
||||||
phase1_tests();
|
phase1_tests();
|
||||||
phase2_tests();
|
phase2_tests();
|
||||||
phase3_tests();
|
|
||||||
init_hash_tests();
|
|
||||||
extend_hash_tests();
|
|
||||||
check_hash_tests();
|
|
||||||
|
|
||||||
return gTestSuccess ? 0 : 255;
|
return gTestSuccess ? 0 : 255;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,9 +7,6 @@
|
|||||||
|
|
||||||
#include "2sysincludes.h"
|
#include "2sysincludes.h"
|
||||||
#include "2common.h"
|
#include "2common.h"
|
||||||
#include "2rsa.h"
|
|
||||||
#include "vboot_struct.h" /* For old struct sizes */
|
|
||||||
|
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -108,168 +105,11 @@ static void test_workbuf(void)
|
|||||||
TEST_EQ(wb.size, 8, " size");
|
TEST_EQ(wb.size, 8, " size");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Test struct packing for vboot_struct.h structs which are passed between
|
|
||||||
* firmware and OS, or passed between different phases of firmware.
|
|
||||||
*/
|
|
||||||
static void test_struct_packing(void)
|
|
||||||
{
|
|
||||||
/* Test vboot2 versions of vboot1 structs */
|
|
||||||
TEST_EQ(EXPECTED_VB2_PACKED_KEY_SIZE,
|
|
||||||
sizeof(struct vb2_packed_key),
|
|
||||||
"sizeof(vb2_packed_key)");
|
|
||||||
TEST_EQ(EXPECTED_VB2_SIGNATURE_SIZE,
|
|
||||||
sizeof(struct vb2_signature),
|
|
||||||
"sizeof(vb2_signature)");
|
|
||||||
TEST_EQ(EXPECTED_VB2_KEYBLOCK_SIZE,
|
|
||||||
sizeof(struct vb2_keyblock),
|
|
||||||
"sizeof(vb2_keyblock)");
|
|
||||||
TEST_EQ(EXPECTED_VB2_FW_PREAMBLE_SIZE,
|
|
||||||
sizeof(struct vb2_fw_preamble),
|
|
||||||
"sizeof(vb2_fw_preamble)");
|
|
||||||
TEST_EQ(EXPECTED_VB2_GBB_HEADER_SIZE,
|
|
||||||
sizeof(struct vb2_gbb_header),
|
|
||||||
"sizeof(vb2_gbb_header)");
|
|
||||||
|
|
||||||
/* And make sure they're the same as their vboot1 equivalents */
|
|
||||||
TEST_EQ(EXPECTED_VB2_PACKED_KEY_SIZE,
|
|
||||||
EXPECTED_VBPUBLICKEY_SIZE,
|
|
||||||
"vboot1->2 packed key sizes same");
|
|
||||||
TEST_EQ(EXPECTED_VB2_SIGNATURE_SIZE,
|
|
||||||
EXPECTED_VBSIGNATURE_SIZE,
|
|
||||||
"vboot1->2 signature sizes same");
|
|
||||||
TEST_EQ(EXPECTED_VB2_KEYBLOCK_SIZE,
|
|
||||||
EXPECTED_VBKEYBLOCKHEADER_SIZE,
|
|
||||||
"vboot1->2 keyblock sizes same");
|
|
||||||
TEST_EQ(EXPECTED_VB2_FW_PREAMBLE_SIZE,
|
|
||||||
EXPECTED_VBFIRMWAREPREAMBLEHEADER2_1_SIZE,
|
|
||||||
"vboot1->2 firmware preamble sizes same");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper functions not dependent on specific key sizes
|
|
||||||
*/
|
|
||||||
static void test_helper_functions(void)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
uint8_t *p = (uint8_t *)test_helper_functions;
|
|
||||||
TEST_EQ((int)vb2_offset_of(p, p), 0, "vb2_offset_of() equal");
|
|
||||||
TEST_EQ((int)vb2_offset_of(p, p+10), 10,
|
|
||||||
"vb2_offset_of() positive");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct vb2_packed_key k = {.key_offset = sizeof(k)};
|
|
||||||
TEST_EQ((int)vb2_offset_of(&k, vb2_packed_key_data(&k)),
|
|
||||||
sizeof(k), "vb2_packed_key_data() adjacent");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct vb2_packed_key k = {.key_offset = 123};
|
|
||||||
TEST_EQ((int)vb2_offset_of(&k, vb2_packed_key_data(&k)), 123,
|
|
||||||
"vb2_packed_key_data() spaced");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct vb2_signature s = {.sig_offset = sizeof(s)};
|
|
||||||
TEST_EQ((int)vb2_offset_of(&s, vb2_signature_data(&s)),
|
|
||||||
sizeof(s), "vb2_signature_data() adjacent");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct vb2_signature s = {.sig_offset = 123};
|
|
||||||
TEST_EQ((int)vb2_offset_of(&s, vb2_signature_data(&s)), 123,
|
|
||||||
"vb2_signature_data() spaced");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
uint8_t *p = (uint8_t *)test_helper_functions;
|
|
||||||
TEST_SUCC(vb2_verify_member_inside(p, 20, p, 6, 11, 3),
|
|
||||||
"MemberInside ok 1");
|
|
||||||
TEST_SUCC(vb2_verify_member_inside(p, 20, p+4, 4, 8, 4),
|
|
||||||
"MemberInside ok 2");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p-4, 4, 8, 4),
|
|
||||||
VB2_ERROR_INSIDE_MEMBER_OUTSIDE,
|
|
||||||
"MemberInside member before parent");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p+20, 4, 8, 4),
|
|
||||||
VB2_ERROR_INSIDE_MEMBER_OUTSIDE,
|
|
||||||
"MemberInside member after parent");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p, 21, 0, 0),
|
|
||||||
VB2_ERROR_INSIDE_MEMBER_OUTSIDE,
|
|
||||||
"MemberInside member too big");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p, 4, 21, 0),
|
|
||||||
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
|
||||||
"MemberInside data after parent");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p, 4, SIZE_MAX, 0),
|
|
||||||
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
|
||||||
"MemberInside data before parent");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p, 4, 4, 17),
|
|
||||||
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
|
||||||
"MemberInside data too big");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p, 8, 4, 8),
|
|
||||||
VB2_ERROR_INSIDE_DATA_OVERLAP,
|
|
||||||
"MemberInside data overlaps member");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, -8, p, 12, 0, 0),
|
|
||||||
VB2_ERROR_INSIDE_PARENT_WRAPS,
|
|
||||||
"MemberInside wraparound 1");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p, -8, 0, 0),
|
|
||||||
VB2_ERROR_INSIDE_MEMBER_WRAPS,
|
|
||||||
"MemberInside wraparound 2");
|
|
||||||
TEST_EQ(vb2_verify_member_inside(p, 20, p, 4, 4, -12),
|
|
||||||
VB2_ERROR_INSIDE_DATA_WRAPS,
|
|
||||||
"MemberInside wraparound 3");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct vb2_packed_key k = {.key_offset = sizeof(k),
|
|
||||||
.key_size = 128};
|
|
||||||
TEST_SUCC(vb2_verify_packed_key_inside(&k, sizeof(k)+128, &k),
|
|
||||||
"PublicKeyInside ok 1");
|
|
||||||
TEST_SUCC(vb2_verify_packed_key_inside(&k - 1,
|
|
||||||
2*sizeof(k)+128, &k),
|
|
||||||
"PublicKeyInside ok 2");
|
|
||||||
TEST_EQ(vb2_verify_packed_key_inside(&k, 128, &k),
|
|
||||||
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
|
||||||
"PublicKeyInside key too big");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct vb2_packed_key k = {.key_offset = 100,
|
|
||||||
.key_size = 4};
|
|
||||||
TEST_EQ(vb2_verify_packed_key_inside(&k, 99, &k),
|
|
||||||
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
|
||||||
"PublicKeyInside offset too big");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct vb2_signature s = {.sig_offset = sizeof(s),
|
|
||||||
.sig_size = 128};
|
|
||||||
TEST_SUCC(vb2_verify_signature_inside(&s, sizeof(s)+128, &s),
|
|
||||||
"SignatureInside ok 1");
|
|
||||||
TEST_SUCC(vb2_verify_signature_inside(&s - 1,
|
|
||||||
2*sizeof(s)+128, &s),
|
|
||||||
"SignatureInside ok 2");
|
|
||||||
TEST_EQ(vb2_verify_signature_inside(&s, 128, &s),
|
|
||||||
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
|
||||||
"SignatureInside sig too big");
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
struct vb2_signature s = {.sig_offset = 100,
|
|
||||||
.sig_size = 4};
|
|
||||||
TEST_EQ(vb2_verify_signature_inside(&s, 99, &s),
|
|
||||||
VB2_ERROR_INSIDE_DATA_OUTSIDE,
|
|
||||||
"SignatureInside offset too big");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
test_memcmp();
|
test_memcmp();
|
||||||
test_align();
|
test_align();
|
||||||
test_workbuf();
|
test_workbuf();
|
||||||
test_struct_packing();
|
|
||||||
test_helper_functions();
|
|
||||||
|
|
||||||
return gTestSuccess ? 0 : 255;
|
return gTestSuccess ? 0 : 255;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ function test_signatures {
|
|||||||
done
|
done
|
||||||
done
|
done
|
||||||
echo -e "Peforming ${COL_YELLOW}PKCS #1 v1.5 Padding Tests${COL_STOP}..."
|
echo -e "Peforming ${COL_YELLOW}PKCS #1 v1.5 Padding Tests${COL_STOP}..."
|
||||||
${TEST_DIR}/vb2_rsa_padding_tests ${TESTKEY_DIR}/rsa_padding_test_pubkey.keyb
|
${TEST_DIR}/vb20_rsa_padding_tests ${TESTKEY_DIR}/rsa_padding_test_pubkey.keyb
|
||||||
}
|
}
|
||||||
|
|
||||||
check_test_keys
|
check_test_keys
|
||||||
|
|||||||
Reference in New Issue
Block a user