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:
Randall Spangler
2014-12-03 12:29:37 -08:00
committed by chrome-internal-fetch
parent fe2714923b
commit 6f1b82ac14
26 changed files with 1716 additions and 1502 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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_ */

View File

@@ -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

View File

@@ -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 */

View File

@@ -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
View 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
View 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;
}

View 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_ */

View 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
View 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;
}

View File

@@ -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)
{ {

View File

@@ -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
View 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;
}

View File

@@ -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"

View File

@@ -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
View 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;
}

View File

@@ -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 */

View File

@@ -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.

View File

@@ -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;

View File

@@ -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");

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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