summaryrefslogtreecommitdiff
path: root/firmware/lib20/kernel.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/lib20/kernel.c')
-rw-r--r--firmware/lib20/kernel.c131
1 files changed, 122 insertions, 9 deletions
diff --git a/firmware/lib20/kernel.c b/firmware/lib20/kernel.c
index 3650c7fe..609f2461 100644
--- a/firmware/lib20/kernel.c
+++ b/firmware/lib20/kernel.c
@@ -9,6 +9,7 @@
#include "2misc.h"
#include "2nvstorage.h"
#include "2rsa.h"
+#include "2secdata.h"
#include "2sha.h"
#include "vb2_common.h"
@@ -17,6 +18,27 @@ static const uint8_t *vb2_signature_data_const(const struct vb2_signature *sig)
return (uint8_t *)sig + sig->sig_offset;
}
+/**
+ * Returns non-zero if the kernel needs to have a valid signature, instead of
+ * just a valid hash.
+ */
+static int vb2_need_signed_kernel(struct vb2_context *ctx)
+{
+ /* Recovery kernels are always signed */
+ if (ctx->flags & VB2_CONTEXT_RECOVERY_MODE)
+ return 1;
+
+ /* Normal mode kernels are always signed */
+ if (!(ctx->flags & VB2_CONTEXT_DEVELOPER_MODE))
+ return 1;
+
+ /* Developers may require signed kernels */
+ if (vb2_nv_get(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY))
+ return 1;
+
+ return 0;
+}
+
int vb2_verify_keyblock_hash(const struct vb2_keyblock *block,
uint32_t size,
const struct vb2_workbuf *wb)
@@ -83,7 +105,7 @@ int vb2_load_kernel_keyblock(struct vb2_context *ctx)
int rec_switch = (ctx->flags & VB2_CONTEXT_RECOVERY_MODE) != 0;
int dev_switch = (ctx->flags & VB2_CONTEXT_DEVELOPER_MODE) != 0;
- int need_keyblock_valid = 1;
+ int need_keyblock_valid = vb2_need_signed_kernel(ctx);
int keyblock_is_valid = 1;
int rv;
@@ -91,14 +113,6 @@ int vb2_load_kernel_keyblock(struct vb2_context *ctx)
vb2_workbuf_from_ctx(ctx, &wb);
/*
- * The only time we don't need a valid keyblock is if we're in
- * developer mode and not set to require a signed kernel.
- */
- if (dev_switch && !rec_switch &&
- !vb2_nv_get(ctx, VB2_NV_DEV_BOOT_SIGNED_ONLY))
- need_keyblock_valid = 0;
-
- /*
* Clear any previous keyblock-valid flag (for example, from a previous
* kernel where the keyblock was signed but the preamble failed
* verification).
@@ -329,3 +343,102 @@ int vb2_verify_kernel_preamble(struct vb2_kernel_preamble *preamble,
/* Success */
return VB2_SUCCESS;
}
+
+int vb2_load_kernel_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 */
+ /* TODO: what's the minimum workbuf size? Kernel preamble is usually
+ * padded to around 64KB. */
+ struct vb2_kernel_preamble *pre;
+ uint32_t pre_size;
+
+ int rv;
+
+ vb2_workbuf_from_ctx(ctx, &wb);
+
+ /* Unpack the kernel data key */
+ if (!sd->workbuf_data_key_size)
+ return VB2_ERROR_KERNEL_PREAMBLE2_DATA_KEY;
+
+ rv = vb2_unpack_key(&data_key, key_data, key_size);
+ if (rv)
+ return rv;
+
+ /* Load the kernel preamble header */
+ pre = vb2_workbuf_alloc(&wb, sizeof(*pre));
+ if (!pre)
+ return VB2_ERROR_KERNEL_PREAMBLE2_WORKBUF_HEADER;
+
+ rv = vb2ex_read_resource(ctx, VB2_RES_KERNEL_VBLOCK,
+ sd->vblock_preamble_offset,
+ pre, sizeof(*pre));
+ if (rv)
+ return rv;
+
+ pre_size = pre->preamble_size;
+
+ /* Load the entire preamble, now that we know how big it is */
+ pre = vb2_workbuf_realloc(&wb, sizeof(*pre), pre_size);
+ if (!pre)
+ return VB2_ERROR_KERNEL_PREAMBLE2_WORKBUF;
+
+ rv = vb2ex_read_resource(ctx, VB2_RES_KERNEL_VBLOCK,
+ sd->vblock_preamble_offset,
+ pre, pre_size);
+ if (rv)
+ return rv;
+
+ /*
+ * Work buffer now contains:
+ * - vb2_shared_data
+ * - kernel key
+ * - packed kernel data key
+ * - kernel preamble
+ */
+
+ /* Verify the preamble */
+ rv = vb2_verify_kernel_preamble(pre, pre_size, &data_key, &wb);
+ if (rv)
+ return rv;
+
+ /*
+ * Kernel preamble version is the lower 16 bits of the composite kernel
+ * version.
+ */
+ if (pre->kernel_version > 0xffff)
+ return VB2_ERROR_KERNEL_PREAMBLE_VERSION_RANGE;
+
+ /* Combine with the key version from vb2_load_kernel_keyblock() */
+ sd->kernel_version |= pre->kernel_version;
+
+ if (vb2_need_signed_kernel(ctx) &&
+ sd->kernel_version < sd->kernel_version_secdatak)
+ return VB2_ERROR_KERNEL_PREAMBLE_VERSION_ROLLBACK;
+
+ /* 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.
+ *
+ * Work buffer now contains:
+ * - vb2_shared_data
+ * - kernel key
+ * - packed kernel data key
+ * - kernel preamble
+ *
+ * TODO: we could move the preamble down over the kernel data key
+ * since we don't need it anymore.
+ */
+ ctx->workbuf_used = sd->workbuf_preamble_offset + pre_size;
+
+ return VB2_SUCCESS;
+}