diff options
author | Randall Spangler <rspangler@chromium.org> | 2014-12-03 12:29:37 -0800 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-12-04 09:46:43 +0000 |
commit | 6f1b82ac14f341d9733d6e95d518b3ee352002ef (patch) | |
tree | 0d37f86365c8324416e42f1ce5cd3969de54a178 /firmware | |
parent | fe2714923b986bc461b692d45c1b5eb1b469ddc4 (diff) | |
download | vboot-6f1b82ac14f341d9733d6e95d518b3ee352002ef.tar.gz |
vboot2: Move old struct handling to lib20/
This is part 4 of a series of changes to rearrange the vboot2 library
so that it's possible to start using the new-style data structs. This
change moves knowledge of the old vboot1 data structs into lib20; 2lib
now contains only code which is common to both vboot2.x libraries
(that is, code which is data structure version agnostic).
No functional changes; just rearranging code and tests.
BUG=chromium:423882
BRANCH=none
TEST=make runtests && VBOOT2=1 make runtests (works with/withoug VBOOT2 flag)
And compile firmware for veyron_pinky
CQ-DEPEND=CL:233051
Change-Id: I8f9e67157575e5be14952ef4809c3dfafd92596d
Signed-off-by: Randall Spangler <rspangler@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/233021
Reviewed-by: Bill Richardson <wfrichar@chromium.org>
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/2lib/2api.c | 158 | ||||
-rw-r--r-- | firmware/2lib/2common.c | 260 | ||||
-rw-r--r-- | firmware/2lib/2misc.c | 211 | ||||
-rw-r--r-- | firmware/2lib/include/2common.h | 230 | ||||
-rw-r--r-- | firmware/2lib/include/2misc.h | 1 | ||||
-rw-r--r-- | firmware/2lib/include/2struct.h | 172 | ||||
-rw-r--r-- | firmware/include/vb2_api.h | 1 | ||||
-rw-r--r-- | firmware/lib20/api.c | 174 | ||||
-rw-r--r-- | firmware/lib20/common.c | 272 | ||||
-rw-r--r-- | firmware/lib20/include/vb2_common.h | 159 | ||||
-rw-r--r-- | firmware/lib20/include/vb2_struct.h | 179 | ||||
-rw-r--r-- | firmware/lib20/misc.c | 226 | ||||
-rw-r--r-- | firmware/lib20/packed_key.c (renamed from firmware/2lib/2packed_key.c) | 2 | ||||
-rw-r--r-- | firmware/lib21/include/vb2_common.h | 90 |
14 files changed, 1105 insertions, 1030 deletions
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 |