diff options
26 files changed, 1716 insertions, 1502 deletions
@@ -235,8 +235,12 @@ endif # this source tree locally and link to it directly. 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 +# Vboot 2.1 FWLIB21 = ${BUILD}/vboot_fw21.a # Firmware library sources needed by VbInit() call @@ -278,6 +282,7 @@ VBSLK_SRCS = \ firmware/lib/region-kernel.c \ # Firmware library source needed for smaller library 2 +# Code common to vboot 2.0 (old structs) and 2.1 (new structs) FWLIB2_SRCS = \ firmware/2lib/2api.c \ firmware/2lib/2common.c \ @@ -292,7 +297,10 @@ FWLIB2_SRCS = \ firmware/2lib/2sha_utility.c 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 = \ firmware/lib21/api.c \ @@ -631,19 +639,23 @@ ifdef REGION_READ TEST_NAMES += tests/vboot_region_tests endif -TEST20_NAMES = \ +TEST2X_NAMES = \ tests/vb2_api_tests \ tests/vb2_common_tests \ - tests/vb2_common2_tests \ - tests/vb2_common3_tests \ tests/vb2_misc_tests \ - tests/vb2_misc2_tests \ tests/vb2_nvstorage_tests \ - tests/vb2_rsa_padding_tests \ tests/vb2_rsa_utility_tests \ tests/vb2_secdata_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 = \ tests/vb21_api_tests \ tests/vb21_common_tests \ @@ -656,7 +668,7 @@ TEST21_NAMES = \ tests/vb21_host_sig_tests ifneq (${VBOOT2},) -TEST_NAMES += ${TEST20_NAMES} ${TEST21_NAMES} +TEST_NAMES += ${TEST2X_NAMES} ${TEST20_NAMES} ${TEST21_NAMES} endif # And a few more... @@ -679,6 +691,7 @@ TEST_NAMES += ${TLCL_TEST_NAMES} TEST_BINS = $(addprefix ${BUILD}/,${TEST_NAMES}) TEST_OBJS += $(addsuffix .o,${TEST_BINS}) +TEST2X_BINS = $(addprefix ${BUILD}/,${TEST2X_NAMES}) TEST20_BINS = $(addprefix ${BUILD}/,${TEST20_NAMES}) TEST21_BINS = $(addprefix ${BUILD}/,${TEST21_NAMES}) @@ -700,7 +713,7 @@ _dir_create := $(foreach d, \ # Default target. .PHONY: all all: fwlib \ - $(if ${VBOOT2},fwlib2 fwlib21) \ + $(if ${VBOOT2},fwlib2x fwlib2 fwlib21) \ $(if ${FIRMWARE_ARCH},,host_stuff) \ $(if ${COV},coverage) @@ -772,6 +785,7 @@ ifeq (${FIRMWARE_ARCH},) ${FWLIB_OBJS}: CFLAGS += -DDISABLE_ROLLBACK_TPM endif +${FWLIB20_OBJS}: INCLUDES += -Ifirmware/lib20/include ${FWLIB21_OBJS}: INCLUDES += -Ifirmware/lib21/include # Linktest ensures firmware lib doesn't rely on outside libraries @@ -800,6 +814,16 @@ ${FWLIB}: ${FWLIB_OBJS} @$(PRINTF) " AR $(subst ${BUILD}/,,$@)\n" ${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 fwlib2: ${FWLIB20} @@ -841,9 +865,7 @@ ${UTILLIB}: ${UTILLIB_OBJS} ${FWLIB_OBJS} utillib21: ${UTILLIB21} ${UTILLIB21}: INCLUDES += -Ihost/lib21/include -Ifirmware/lib21/include - -# TODO: right now, firmware lib 2.1 isn't a complete standalone copy -${UTILLIB21}: ${UTILLIB21_OBJS} ${FWLIB2_OBJS} ${FWLIB20_OBJS} ${FWLIB21_OBJS} +${UTILLIB21}: ${UTILLIB21_OBJS} ${FWLIB2_OBJS} ${FWLIB21_OBJS} @$(PRINTF) " RM $(subst ${BUILD}/,,$@)\n" ${Q}rm -f $@ @$(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_STATIC_BIN}: ${FUTIL_STATIC_OBJS} ${UTILLIB} \ - $(if ${VBOOT2},${UTILLIB21}) + $(if ${VBOOT2},${FWLIB20}) @$(PRINTF) " LD $(subst ${BUILD}/,,$@)\n" ${Q}${LD} -o $@ ${CFLAGS} ${LDFLAGS} -static $^ ${LDLIBS} ${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" ${Q}${LD} -o $@ ${CFLAGS} ${LDFLAGS} $^ ${LDLIBS} @@ -981,7 +1003,11 @@ ${TEST_BINS}: ${UTILLIB} ${TESTLIB} ${TEST_BINS}: INCLUDES += -Itests ${TEST_BINS}: LIBS = ${TESTLIB} ${UTILLIB} +${TEST2X_BINS}: ${FWLIB2X} +${TEST2X_BINS}: LIBS += ${FWLIB2X} + ${TEST20_BINS}: ${FWLIB20} +${TEST20_BINS}: INCLUDES += -Ifirmware/lib20/include ${TEST20_BINS}: LIBS += ${FWLIB20} ${TEST21_BINS}: ${UTILLIB21} @@ -1041,8 +1067,8 @@ ${BUILD}/utility/signature_digest_utility: LDLIBS += ${CRYPTO_LIBS} ${BUILD}/host/linktest/main: LDLIBS += ${CRYPTO_LIBS} ${BUILD}/tests/vboot_common2_tests: LDLIBS += ${CRYPTO_LIBS} ${BUILD}/tests/vboot_common3_tests: LDLIBS += ${CRYPTO_LIBS} -${BUILD}/tests/vb2_common2_tests: LDLIBS += ${CRYPTO_LIBS} -${BUILD}/tests/vb2_common3_tests: LDLIBS += ${CRYPTO_LIBS} +${BUILD}/tests/vb20_common2_tests: LDLIBS += ${CRYPTO_LIBS} +${BUILD}/tests/vb20_common3_tests: LDLIBS += ${CRYPTO_LIBS} ${TEST21_BINS}: LDLIBS += ${CRYPTO_LIBS} @@ -1219,14 +1245,16 @@ runmisctests: test_setup run2tests: test_setup ${RUNTEST} ${BUILD_RUN}/tests/vb2_api_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_misc2_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_nvstorage_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_rsa_utility_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_secdata_tests ${RUNTEST} ${BUILD_RUN}/tests/vb2_sha_tests + ${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_common_tests ${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_common3_tests ${TEST_KEYS} --all ifneq (${VBOOT2},) - ${RUNTEST} ${BUILD_RUN}/tests/vb2_common2_tests ${TEST_KEYS} --all - ${RUNTEST} ${BUILD_RUN}/tests/vb2_common3_tests ${TEST_KEYS} --all + ${RUNTEST} ${BUILD_RUN}/tests/vb20_common2_tests ${TEST_KEYS} --all + ${RUNTEST} ${BUILD_RUN}/tests/vb20_common3_tests ${TEST_KEYS} --all ${RUNTEST} ${BUILD_RUN}/tests/vb21_common2_tests ${TEST_KEYS} --all endif tests/run_preamble_tests.sh --all diff --git a/firmware/2lib/2api.c b/firmware/2lib/2api.c index a01c7f57..5d2775f0 100644 --- a/firmware/2lib/2api.c +++ b/firmware/2lib/2api.c @@ -100,94 +100,6 @@ int vb2api_fw_phase2(struct vb2_context *ctx) 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, const void *buf, uint32_t size) @@ -208,73 +120,3 @@ int vb2api_extend_hash(struct vb2_context *ctx, 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; -} diff --git a/firmware/2lib/2common.c b/firmware/2lib/2common.c index e15ddb77..9e75d0c3 100644 --- a/firmware/2lib/2common.c +++ b/firmware/2lib/2common.c @@ -110,267 +110,7 @@ void vb2_workbuf_free(struct vb2_workbuf *wb, uint32_t 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) { 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; -} diff --git a/firmware/2lib/2misc.c b/firmware/2lib/2misc.c index 48357bea..5dc0014c 100644 --- a/firmware/2lib/2misc.c +++ b/firmware/2lib/2misc.c @@ -364,214 +364,3 @@ int vb2_select_fw_slot(struct vb2_context *ctx) 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; -} diff --git a/firmware/2lib/include/2common.h b/firmware/2lib/include/2common.h index 672bd00c..06d0ee0f 100644 --- a/firmware/2lib/include/2common.h +++ b/firmware/2lib/include/2common.h @@ -146,172 +146,6 @@ int vb2_align(uint8_t **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 * @@ -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 -/** - * 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() * worst case. @@ -360,66 +180,16 @@ int vb2_verify_digest(const struct vb2_public_key *key, VB2_MAX(VB2_VERIFY_DIGEST_WORKBUF_BYTES, \ 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 * vb2_verify_keyblock2() worst case. */ #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 * vb2_verify_fw_preamble2() worst case. */ #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_ */ diff --git a/firmware/2lib/include/2misc.h b/firmware/2lib/include/2misc.h index 24b32db7..e3d9bec0 100644 --- a/firmware/2lib/include/2misc.h +++ b/firmware/2lib/include/2misc.h @@ -11,6 +11,7 @@ #include "2api.h" struct vb2_gbb_header; +struct vb2_workbuf; /** * Get the shared data pointer from the vboot context diff --git a/firmware/2lib/include/2struct.h b/firmware/2lib/include/2struct.h index b2b35f24..c8ff2378 100644 --- a/firmware/2lib/include/2struct.h +++ b/firmware/2lib/include/2struct.h @@ -10,8 +10,6 @@ #define VBOOT_REFERENCE_VBOOT_2STRUCT_H_ #include <stdint.h> -#include "2guid.h" - /* Algorithm types for signatures */ enum vb2_signature_algorithm { /* Invalid or unsupported signature type */ @@ -43,65 +41,10 @@ enum vb2_hash_algorithm { VB2_HASH_SHA512 = 3, }; -/****************************************************************************/ /* - * Vboot1-compatible data structures + * Key block flags. * - * - * 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 + *The following flags set where the key is valid. Not used by firmware * verification; only kernel verification. */ #define VB2_KEY_BLOCK_FLAG_DEVELOPER_0 0x01 /* Developer switch off */ @@ -109,117 +52,6 @@ struct vb2_signature { #define VB2_KEY_BLOCK_FLAG_RECOVERY_0 0x04 /* Not recovery mode */ #define VB2_KEY_BLOCK_FLAG_RECOVERY_1 0x08 /* Recovery mode */ -/* - * Key block, containing the public key used to sign some other chunk of data. - * - * This should be followed by: - * 1) The data_key key data, pointed to by data_key.key_offset. - * 2) The checksum data for (vb2_keyblock + data_key data), pointed to - * by keyblock_checksum.sig_offset. - * 3) The signature data for (vb2_keyblock + data_key data), pointed to - * by keyblock_signature.sig_offset. - */ -struct vb2_keyblock { - /* Magic number */ - uint8_t magic[KEY_BLOCK_MAGIC_SIZE]; - - /* Version of this header format */ - uint32_t header_version_major; - - /* Version of this header format */ - uint32_t header_version_minor; - - /* - * Length of this entire key block, including keys, signatures, and - * padding, in bytes - */ - uint32_t keyblock_size; - uint32_t reserved0; - - /* - * Signature for this key block (header + data pointed to by data_key) - * For use with signed data keys - */ - struct vb2_signature keyblock_signature; - - /* - * SHA-512 checksum for this key block (header + data pointed to by - * data_key) For use with unsigned data keys. - * - * Note that the vb2 lib currently only supports signed blocks. - */ - struct vb2_signature keyblock_checksum_unused; - - /* Flags for key (VB2_KEY_BLOCK_FLAG_*) */ - uint32_t keyblock_flags; - uint32_t reserved1; - - /* Key to verify the chunk of data */ - struct vb2_packed_key data_key; -} __attribute__((packed)); - -#define EXPECTED_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 */ diff --git a/firmware/include/vb2_api.h b/firmware/include/vb2_api.h index 8b1bc4d5..0b32a782 100644 --- a/firmware/include/vb2_api.h +++ b/firmware/include/vb2_api.h @@ -25,6 +25,7 @@ */ #ifdef NEED_VB20_INTERNALS #include "../2lib/include/2struct.h" +#include "../lib20/include/vb2_struct.h" #endif #endif /* VBOOT_VB2_API_H_ */ diff --git a/firmware/lib20/api.c b/firmware/lib20/api.c new file mode 100644 index 00000000..16ad6dc1 --- /dev/null +++ b/firmware/lib20/api.c @@ -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; +} diff --git a/firmware/lib20/common.c b/firmware/lib20/common.c new file mode 100644 index 00000000..9ce9d840 --- /dev/null +++ b/firmware/lib20/common.c @@ -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; +} diff --git a/firmware/lib20/include/vb2_common.h b/firmware/lib20/include/vb2_common.h new file mode 100644 index 00000000..4067d694 --- /dev/null +++ b/firmware/lib20/include/vb2_common.h @@ -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_ */ diff --git a/firmware/lib20/include/vb2_struct.h b/firmware/lib20/include/vb2_struct.h new file mode 100644 index 00000000..136ce91a --- /dev/null +++ b/firmware/lib20/include/vb2_struct.h @@ -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_ */ diff --git a/firmware/lib20/misc.c b/firmware/lib20/misc.c new file mode 100644 index 00000000..7fa3787b --- /dev/null +++ b/firmware/lib20/misc.c @@ -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; +} diff --git a/firmware/2lib/2packed_key.c b/firmware/lib20/packed_key.c index 098296e4..4baf97ce 100644 --- a/firmware/2lib/2packed_key.c +++ b/firmware/lib20/packed_key.c @@ -6,8 +6,8 @@ */ #include "2sysincludes.h" -#include "2common.h" #include "2rsa.h" +#include "vb2_common.h" const uint8_t *vb2_packed_key_data(const struct vb2_packed_key *key) { diff --git a/firmware/lib21/include/vb2_common.h b/firmware/lib21/include/vb2_common.h index 5abac4c0..db296046 100644 --- a/firmware/lib21/include/vb2_common.h +++ b/firmware/lib21/include/vb2_common.h @@ -16,6 +16,96 @@ #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 * @param sig Signature struct * @param size Size of buffer containing signature struct diff --git a/tests/vb20_api_tests.c b/tests/vb20_api_tests.c new file mode 100644 index 00000000..a7be957f --- /dev/null +++ b/tests/vb20_api_tests.c @@ -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; +} diff --git a/tests/vb2_common2_tests.c b/tests/vb20_common2_tests.c index ec9ef183..75e05249 100644 --- a/tests/vb2_common2_tests.c +++ b/tests/vb20_common2_tests.c @@ -10,10 +10,10 @@ #include <string.h> #include "2sysincludes.h" -#include "2common.h" #include "2rsa.h" #include "file_keys.h" #include "host_common.h" +#include "vb2_common.h" #include "vboot_common.h" #include "test_common.h" diff --git a/tests/vb2_common3_tests.c b/tests/vb20_common3_tests.c index 61484fb5..365c7700 100644 --- a/tests/vb2_common3_tests.c +++ b/tests/vb20_common3_tests.c @@ -8,7 +8,6 @@ #include <stdio.h> #include "2sysincludes.h" -#include "2common.h" #include "2rsa.h" #include "file_keys.h" @@ -16,6 +15,7 @@ #include "host_key.h" #include "host_keyblock.h" #include "host_signature.h" +#include "vb2_common.h" #include "vboot_common.h" #include "test_common.h" diff --git a/tests/vb20_common_tests.c b/tests/vb20_common_tests.c new file mode 100644 index 00000000..4f4d6813 --- /dev/null +++ b/tests/vb20_common_tests.c @@ -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; +} diff --git a/tests/vb2_misc2_tests.c b/tests/vb20_misc_tests.c index 796d8e6a..aa602ac9 100644 --- a/tests/vb2_misc2_tests.c +++ b/tests/vb20_misc_tests.c @@ -13,7 +13,7 @@ #include "2misc.h" #include "2nvstorage.h" #include "2secdata.h" - +#include "vb2_common.h" #include "test_common.h" /* Common context for tests */ diff --git a/tests/vb2_rsa_padding_tests.c b/tests/vb20_rsa_padding_tests.c index 8c9e80b6..e9789e90 100644 --- a/tests/vb2_rsa_padding_tests.c +++ b/tests/vb20_rsa_padding_tests.c @@ -14,8 +14,8 @@ #include "utility.h" #include "2sysincludes.h" -#include "2common.h" #include "2rsa.h" +#include "vb2_common.h" /** * Convert an old-style RSA public key struct to a new one. diff --git a/tests/vb21_api_tests.c b/tests/vb21_api_tests.c index 052d89b6..52ca0d9e 100644 --- a/tests/vb21_api_tests.c +++ b/tests/vb21_api_tests.c @@ -30,7 +30,6 @@ static struct vb2_shared_data *sd; static const uint8_t mock_body[320] = "Mock body"; static const int mock_body_size = sizeof(mock_body); -static const int mock_algorithm = VB2_ALG_RSA2048_SHA256; static const int mock_hash_alg = VB2_HASH_SHA256; static int mock_sig_size; @@ -198,6 +197,40 @@ static void init_hash_tests(void) 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) { struct vb2_fw_preamble2 *pre; @@ -249,6 +282,7 @@ int main(int argc, char* argv[]) { phase3_tests(); init_hash_tests(); + extend_hash_tests(); check_hash_tests(); return gTestSuccess ? 0 : 255; diff --git a/tests/vb21_misc_tests.c b/tests/vb21_misc_tests.c index 9f6489fc..03b8e4fb 100644 --- a/tests/vb21_misc_tests.c +++ b/tests/vb21_misc_tests.c @@ -245,7 +245,7 @@ static void load_keyblock_tests(void) reset_common_data(FOR_KEYBLOCK); 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), VB2_ERROR_READ_RESOURCE_OBJECT_BUF, "keyblock not enough workbuf for entire keyblock"); @@ -310,7 +310,7 @@ static void load_preamble_tests(void) reset_common_data(FOR_PREAMBLE); 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), VB2_ERROR_READ_RESOURCE_OBJECT_BUF, "preamble not enough workbuf for header"); diff --git a/tests/vb2_api_tests.c b/tests/vb2_api_tests.c index a7893012..ddbd8164 100644 --- a/tests/vb2_api_tests.c +++ b/tests/vb2_api_tests.c @@ -14,7 +14,6 @@ #include "2nvstorage.h" #include "2rsa.h" #include "2secdata.h" - #include "test_common.h" /* 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_algorithm = VB2_ALG_RSA2048_SHA256; const int mock_hash_alg = VB2_HASH_SHA256; -const int mock_sig_size = 64; /* 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_tpm_clear; 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 */ 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)); @@ -70,33 +59,6 @@ static void reset_common_data(enum reset_type t) retval_vb2_check_dev_switch = VB2_SUCCESS; retval_vb2_check_tpm_clear = 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 */ @@ -121,72 +83,6 @@ int vb2_select_fw_slot(struct vb2_context *ctx) 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 */ static void misc_tests(void) @@ -270,190 +166,11 @@ static void phase2_tests(void) 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[]) { misc_tests(); phase1_tests(); phase2_tests(); - phase3_tests(); - init_hash_tests(); - extend_hash_tests(); - check_hash_tests(); return gTestSuccess ? 0 : 255; } diff --git a/tests/vb2_common_tests.c b/tests/vb2_common_tests.c index f8502957..4c033fbd 100644 --- a/tests/vb2_common_tests.c +++ b/tests/vb2_common_tests.c @@ -7,9 +7,6 @@ #include "2sysincludes.h" #include "2common.h" -#include "2rsa.h" -#include "vboot_struct.h" /* For old struct sizes */ - #include "test_common.h" /** @@ -108,168 +105,11 @@ static void test_workbuf(void) 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[]) { test_memcmp(); test_align(); test_workbuf(); - test_struct_packing(); - test_helper_functions(); return gTestSuccess ? 0 : 255; } diff --git a/tests/vb2_rsa_tests.sh b/tests/vb2_rsa_tests.sh index ff570d01..903d38da 100755 --- a/tests/vb2_rsa_tests.sh +++ b/tests/vb2_rsa_tests.sh @@ -33,7 +33,7 @@ function test_signatures { done done 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 |