summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/2lib/2api.c158
-rw-r--r--firmware/2lib/2common.c260
-rw-r--r--firmware/2lib/2misc.c211
-rw-r--r--firmware/2lib/include/2common.h230
-rw-r--r--firmware/2lib/include/2misc.h1
-rw-r--r--firmware/2lib/include/2struct.h172
-rw-r--r--firmware/include/vb2_api.h1
-rw-r--r--firmware/lib20/api.c174
-rw-r--r--firmware/lib20/common.c272
-rw-r--r--firmware/lib20/include/vb2_common.h159
-rw-r--r--firmware/lib20/include/vb2_struct.h179
-rw-r--r--firmware/lib20/misc.c226
-rw-r--r--firmware/lib20/packed_key.c (renamed from firmware/2lib/2packed_key.c)2
-rw-r--r--firmware/lib21/include/vb2_common.h90
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