heads/patches/coreboot-4.11/0001-Add-Heads-TPM-measured-boot-support.patch

477 lines
13 KiB
Diff
Raw Normal View History

Add new board: Purism Librem Server L1UM (#858) * modules/coreboot: add option to use coreboot 4.11 Port patches from coreboot 4.8.1 to 4.11: * 0000-measure-boot -> 0001 * 0010-cross-compiler-support All other patches for coreboot 4.8.1 have either already been integrated, or are for platforms which do not need to be migrated to coreboot 4.11 (they will move to 4.12 or newer). Signed-off-by: Matt DeVillier <matt.devillier@puri.sm> * patches/coreboot-4.11: Add Broadwell-DE platform patch Add a patch for FSP Broadwell-DE to make use of Heads' measured boot. Signed-off-by: Matt DeVillier <matt.devillier@puri.sm> * patches/coreboot-4.11: Add patch to read serial # from CBFS Will be used by multiple Librem boards. Signed-off-by: Matt DeVillier <matt.devillier@puri.sm> * patches/coreboot-4.11: add board support for Librem Server L1UM Signed-off-by: Matt DeVillier <matt.devillier@puri.sm> * Librem Server L1UM: add new board Add board config, coreboot config, kernel config files. Add conditional purism-blobs dependency to coreboot-4.11 module. Signed-off-by: Matt DeVillier <matt.devillier@puri.sm> * flash.sh: add special handling for librem_l1um board Add support for persisting PCIe config via PCHSTRP9 in flash descriptor. This is needed to support multiple variants of the L1UM server which use the same firmware but differ in PCIe lane configuration via the PCH straps configuration in the flash descriptor. Signed-off-by: Matt DeVillier <matt.devillier@puri.sm> * patches/coreboot-4.11: Add 'Use PRIxPTR to print uintptr_t' patch Cherry-picked from upstream coreboot (post-4.11), fixes compilation issue. Signed-off-by: Matt DeVillier <matt.devillier@puri.sm> * CircleCI: add target to build board librem_l1um Signed-off-by: Matt DeVillier <matt.devillier@puri.sm>
2020-10-18 18:48:25 +00:00
From 48784d452a85ee282823d1d8c8d3d4eec56de3a2 Mon Sep 17 00:00:00 2001
From: Martin Kepplinger <martink@posteo.de>
Date: Wed, 15 May 2019 11:55:24 +0200
Subject: [PATCH] Add Heads TPM measured boot support
Change-Id: I3a64998de2fbb7f2059cb8c68cfbf949b0665665
Signed-off-by: Martin Kepplinger <martink@posteo.de>
---
src/Kconfig | 15 +++
src/include/program_loading.h | 2 +
src/lib/cbfs.c | 19 ++-
src/lib/hardwaremain.c | 8 ++
src/lib/rmodule.c | 3 +-
src/security/tpm/Makefile.inc | 5 +
src/security/tpm/sha1.c | 180 +++++++++++++++++++++++++++++
src/security/tpm/sha1.h | 47 ++++++++
src/security/tpm/tspi/tspi.c | 2 +-
src/security/tpm/tss.h | 5 +
src/security/tpm/tss/tcg-1.2/tss.c | 19 +++
11 files changed, 299 insertions(+), 6 deletions(-)
create mode 100644 src/security/tpm/sha1.c
create mode 100644 src/security/tpm/sha1.h
diff --git a/src/Kconfig b/src/Kconfig
index c0315239fc..48e53dc239 100644
--- a/src/Kconfig
+++ b/src/Kconfig
@@ -332,6 +332,21 @@ config BOOTSPLASH_FILE
config HAVE_RAMPAYLOAD
bool
+config MEASURED_BOOT
+ bool "Enable TPM measured boot"
+ default n
+ select TPM1
+ depends on MAINBOARD_HAS_LPC_TPM
+ depends on !VBOOT
+ help
+ Enable this option to measure the bootblock, romstage and
+ CBFS files into TPM PCRs. This does not verify these values
+ (that is the job of something like vboot), but makes it possible
+ for the payload to validate the boot path and allow something
+ like Heads to attest to the user that the system is likely safe.
+
+ You probably want to say N.
+
config RAMPAYLOAD
bool "Enable coreboot flow without executing ramstage"
default y if ARCH_X86
diff --git a/src/include/program_loading.h b/src/include/program_loading.h
index 1b71fadb1b..afd8ba0c54 100644
--- a/src/include/program_loading.h
+++ b/src/include/program_loading.h
@@ -26,6 +26,8 @@ enum {
/* Last segment of program. Can be used to take different actions for
* cache maintenance of a program load. */
SEG_FINAL = 1 << 0,
+ /* Indicate that the program segment should not be measured */
+ SEG_NO_MEASURE = 1 << 1,
};
enum prog_type {
diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c
index fbe6e43496..b0a4f8843a 100644
--- a/src/lib/cbfs.c
+++ b/src/lib/cbfs.c
@@ -97,7 +97,13 @@ void *cbfs_boot_map_with_leak(const char *name, uint32_t type, size_t *size)
if (size != NULL)
*size = fsize;
- return rdev_mmap(&fh.data, 0, fsize);
+ void *buffer = rdev_mmap(&fh.data, 0, fsize);
+
+#ifndef __SMM__
+ prog_segment_loaded((uintptr_t)buffer, fsize, 0);
+#endif
+
+ return buffer;
}
int cbfs_locate_file_in_region(struct cbfsf *fh, const char *region_name,
@@ -125,7 +131,8 @@ size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
return 0;
if (rdev_readat(rdev, buffer, offset, in_size) != in_size)
return 0;
- return in_size;
+ out_size = in_size;
+ break;
case CBFS_COMPRESS_LZ4:
if ((ENV_BOOTBLOCK || ENV_VERSTAGE) &&
@@ -143,7 +150,7 @@ size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
timestamp_add_now(TS_START_ULZ4F);
out_size = ulz4fn(compr_start, in_size, buffer, buffer_size);
timestamp_add_now(TS_END_ULZ4F);
- return out_size;
+ break;
case CBFS_COMPRESS_LZMA:
/* We assume here romstage and postcar are never compressed. */
@@ -165,11 +172,15 @@ size_t cbfs_load_and_decompress(const struct region_device *rdev, size_t offset,
rdev_munmap(rdev, map);
- return out_size;
+ break;
default:
return 0;
}
+
+ prog_segment_loaded((uintptr_t)buffer, out_size, 0);
+
+ return out_size;
}
static inline int tohex4(unsigned int c)
diff --git a/src/lib/hardwaremain.c b/src/lib/hardwaremain.c
index 51ff330d84..358d3e40b3 100644
--- a/src/lib/hardwaremain.c
+++ b/src/lib/hardwaremain.c
@@ -32,6 +32,7 @@
#include <stdlib.h>
#include <boot/tables.h>
#include <program_loading.h>
+#include <security/tpm/tss.h>
#if CONFIG(HAVE_ACPI_RESUME)
#include <arch/acpi.h>
#endif
@@ -540,3 +541,10 @@ void boot_state_current_unblock(void)
{
boot_state_unblock(current_phase.state_id, current_phase.seq);
}
+
+// ramstage measurements go into PCR3 if we are doing measured boot
+void platform_segment_loaded(uintptr_t start, size_t size, int flags)
+{
+ if (CONFIG(MEASURED_BOOT) && !(flags & SEG_NO_MEASURE))
+ tlcl_measure(2, (const void *) start, size);
+}
diff --git a/src/lib/rmodule.c b/src/lib/rmodule.c
index 56529d2fb2..2702b9d36e 100644
--- a/src/lib/rmodule.c
+++ b/src/lib/rmodule.c
@@ -197,7 +197,8 @@ int rmodule_load(void *base, struct rmodule *module)
rmodule_clear_bss(module);
prog_segment_loaded((uintptr_t)module->location,
- rmodule_memory_size(module), SEG_FINAL);
+ rmodule_memory_size(module),
+ SEG_FINAL | SEG_NO_MEASURE);
return 0;
}
diff --git a/src/security/tpm/Makefile.inc b/src/security/tpm/Makefile.inc
index a2d32cff89..e9a785b797 100644
--- a/src/security/tpm/Makefile.inc
+++ b/src/security/tpm/Makefile.inc
@@ -18,6 +18,11 @@ romstage-y += tspi/tspi.c
verstage-$(CONFIG_VBOOT) += tspi/tspi.c
postcar-$(CONFIG_VBOOT) += tspi/tspi.c
+ifeq ($(CONFIG_MEASURED_BOOT),y)
+romstage-y += sha1.c
+ramstage-y += sha1.c
+endif # CONFIG_MEASURED_BOOT
+
ramstage-$(CONFIG_VBOOT_MEASURED_BOOT) += tspi/log.c
romstage-$(CONFIG_VBOOT_MEASURED_BOOT) += tspi/log.c
verstage-$(CONFIG_VBOOT_MEASURED_BOOT) += tspi/log.c
diff --git a/src/security/tpm/sha1.c b/src/security/tpm/sha1.c
new file mode 100644
index 0000000000..9879f729b1
--- /dev/null
+++ b/src/security/tpm/sha1.c
@@ -0,0 +1,180 @@
+/* Copyright (c) 2010 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.
+ *
+ * SHA-1 implementation largely based on libmincrypt in the the Android
+ * Open Source Project (platorm/system/core.git/libmincrypt/sha.c
+ */
+
+#include <security/tpm/sha1.h>
+#include <string.h>
+
+static uint32_t ror27(uint32_t val)
+{
+ return (val >> 27) | (val << 5);
+}
+static uint32_t ror2(uint32_t val)
+{
+ return (val >> 2) | (val << 30);
+}
+static uint32_t ror31(uint32_t val)
+{
+ return (val >> 31) | (val << 1);
+}
+
+static void sha1_transform(struct sha1_ctx *ctx)
+{
+ uint32_t W[80];
+ register uint32_t A, B, C, D, E;
+ int t;
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+#define SHA_F1(A, B, C, D, E, t) do { \
+ E += ror27(A) + \
+ (W[t] = __builtin_bswap32(ctx->buf.w[t])) + \
+ (D^(B&(C^D))) + 0x5A827999; \
+ B = ror2(B); \
+ } while (0)
+
+ for (t = 0; t < 15; t += 5) {
+ SHA_F1(A, B, C, D, E, t + 0);
+ SHA_F1(E, A, B, C, D, t + 1);
+ SHA_F1(D, E, A, B, C, t + 2);
+ SHA_F1(C, D, E, A, B, t + 3);
+ SHA_F1(B, C, D, E, A, t + 4);
+ }
+ SHA_F1(A, B, C, D, E, t + 0); /* 16th one, t == 15 */
+
+#undef SHA_F1
+
+#define SHA_F1(A, B, C, D, E, t) do { \
+ E += ror27(A) + \
+ (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
+ (D^(B&(C^D))) + 0x5A827999; \
+ B = ror2(B); \
+ } while (0)
+
+ SHA_F1(E, A, B, C, D, t + 1);
+ SHA_F1(D, E, A, B, C, t + 2);
+ SHA_F1(C, D, E, A, B, t + 3);
+ SHA_F1(B, C, D, E, A, t + 4);
+
+#undef SHA_F1
+
+#define SHA_F2(A, B, C, D, E, t) do { \
+ E += ror27(A) + \
+ (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
+ (B^C^D) + 0x6ED9EBA1; \
+ B = ror2(B); \
+ } while (0)
+
+ for (t = 20; t < 40; t += 5) {
+ SHA_F2(A, B, C, D, E, t + 0);
+ SHA_F2(E, A, B, C, D, t + 1);
+ SHA_F2(D, E, A, B, C, t + 2);
+ SHA_F2(C, D, E, A, B, t + 3);
+ SHA_F2(B, C, D, E, A, t + 4);
+ }
+
+#undef SHA_F2
+
+#define SHA_F3(A, B, C, D, E, t) do { \
+ E += ror27(A) + \
+ (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
+ ((B&C)|(D&(B|C))) + 0x8F1BBCDC; \
+ B = ror2(B); \
+ } while (0)
+
+ for (; t < 60; t += 5) {
+ SHA_F3(A, B, C, D, E, t + 0);
+ SHA_F3(E, A, B, C, D, t + 1);
+ SHA_F3(D, E, A, B, C, t + 2);
+ SHA_F3(C, D, E, A, B, t + 3);
+ SHA_F3(B, C, D, E, A, t + 4);
+ }
+
+#undef SHA_F3
+
+#define SHA_F4(A, B, C, D, E, t) do { \
+ E += ror27(A) + \
+ (W[t] = ror31(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16])) + \
+ (B^C^D) + 0xCA62C1D6; \
+ B = ror2(B); \
+ } while (0)
+
+ for (; t < 80; t += 5) {
+ SHA_F4(A, B, C, D, E, t + 0);
+ SHA_F4(E, A, B, C, D, t + 1);
+ SHA_F4(D, E, A, B, C, t + 2);
+ SHA_F4(C, D, E, A, B, t + 3);
+ SHA_F4(B, C, D, E, A, t + 4);
+ }
+
+#undef SHA_F4
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+}
+
+void sha1_update(struct sha1_ctx *ctx, const uint8_t *data, uint32_t len)
+{
+ int i = ctx->count % sizeof(ctx->buf);
+ const uint8_t *p = (const uint8_t *)data;
+
+ ctx->count += len;
+
+ while (len > sizeof(ctx->buf) - i) {
+ memcpy(&ctx->buf.b[i], p, sizeof(ctx->buf) - i);
+ len -= sizeof(ctx->buf) - i;
+ p += sizeof(ctx->buf) - i;
+ sha1_transform(ctx);
+ i = 0;
+ }
+
+ while (len--) {
+ ctx->buf.b[i++] = *p++;
+ if (i == sizeof(ctx->buf)) {
+ sha1_transform(ctx);
+ i = 0;
+ }
+ }
+}
+
+
+uint8_t *sha1_final(struct sha1_ctx *ctx)
+{
+ uint32_t cnt = ctx->count * 8;
+ int i;
+
+ sha1_update(ctx, (uint8_t *)"\x80", 1);
+ while ((ctx->count % sizeof(ctx->buf)) != (sizeof(ctx->buf) - 8))
+ sha1_update(ctx, (uint8_t *)"\0", 1);
+
+ for (i = 0; i < 8; ++i) {
+ uint8_t tmp = cnt >> ((7 - i) * 8);
+ sha1_update(ctx, &tmp, 1);
+ }
+
+ for (i = 0; i < 5; i++)
+ ctx->buf.w[i] = __builtin_bswap32(ctx->state[i]);
+
+ return ctx->buf.b;
+}
+
+void sha1_init(struct sha1_ctx *ctx)
+{
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+ ctx->count = 0;
+}
diff --git a/src/security/tpm/sha1.h b/src/security/tpm/sha1.h
new file mode 100644
index 0000000000..bc3faa58ea
--- /dev/null
+++ b/src/security/tpm/sha1.h
@@ -0,0 +1,47 @@
+/* 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.
+ */
+
+/* SHA-1 functions */
+
+#ifndef _sha1_h_
+#define _sha1_h_
+
+#include <stdint.h>
+#include <commonlib/helpers.h>
+
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_BLOCK_SIZE 64
+
+/*
+ * FIXME the DIV_ROUND_UP statement expression blows up here:
+ In file included from src/security/tpm/sha1.h:12,
+ from src/security/tpm/sha1.c:9:
+ src/commonlib/include/commonlib/helpers.h:81:28: error: braced-group
+ within expression allowed only inside a function
+ #define DIV_ROUND_UP(x, y) ({ \
+ ^
+ src/security/tpm/sha1.h:23:14: note: in expansion of macro'DIV_ROUND_UP'
+ uint32_t w[DIV_ROUND_UP(SHA1_BLOCK_SIZE, sizeof(uint32_t))];
+ ^~~~~~~~~~~~
+ make[1]: *** [Makefile:356: x230/romstage/security/tpm/sha1.o] Error 1
+ */
+#undef DIV_ROUND_UP
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y))
+
+/* SHA-1 context */
+struct sha1_ctx {
+ uint32_t count;
+ uint32_t state[5];
+ union {
+ uint8_t b[SHA1_BLOCK_SIZE];
+ uint32_t w[DIV_ROUND_UP(SHA1_BLOCK_SIZE, sizeof(uint32_t))];
+ } buf;
+};
+
+void sha1_init(struct sha1_ctx *ctx);
+void sha1_update(struct sha1_ctx *ctx, const uint8_t *data, uint32_t len);
+uint8_t *sha1_final(struct sha1_ctx *ctx);
+
+#endif /* _sha1_h_ */
diff --git a/src/security/tpm/tspi/tspi.c b/src/security/tpm/tspi/tspi.c
index 966b8b7c77..9076ced37a 100644
--- a/src/security/tpm/tspi/tspi.c
+++ b/src/security/tpm/tspi/tspi.c
@@ -20,8 +20,8 @@
#include <security/tpm/tspi.h>
#include <security/tpm/tss.h>
#include <stdlib.h>
-#if CONFIG(VBOOT)
#include <vb2_api.h>
+#if CONFIG(VBOOT)
#include <vb2_sha.h>
#include <assert.h>
#endif
diff --git a/src/security/tpm/tss.h b/src/security/tpm/tss.h
index 336935d911..90a96621ed 100644
--- a/src/security/tpm/tss.h
+++ b/src/security/tpm/tss.h
@@ -52,6 +52,11 @@ uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
*/
uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags);
+/**
+ * Perform a SHA1 hash on a region and extend a PCR with the hash.
+ */
+uint32_t tlcl_measure(int pcr_num, const void *start, size_t len);
+
#endif
#if CONFIG(TPM2)
diff --git a/src/security/tpm/tss/tcg-1.2/tss.c b/src/security/tpm/tss/tcg-1.2/tss.c
index b11d6a3d16..ef4f4d8b86 100644
--- a/src/security/tpm/tss/tcg-1.2/tss.c
+++ b/src/security/tpm/tss/tcg-1.2/tss.c
@@ -17,6 +17,7 @@
#include <arch/early_variables.h>
#include <assert.h>
#include <string.h>
+#include <security/tpm/sha1.h>
#include <security/tpm/tis.h>
#include <vb2_api.h>
#include <security/tpm/tss.h>
@@ -361,3 +362,21 @@ uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
kPcrDigestLength);
return result;
}
+
+uint32_t tlcl_measure(int pcr_num, const void *start, size_t len)
+{
+ VBDEBUG("TPM: pcr %d measure %p @ %zu: ", pcr_num, start, len);
+
+ struct sha1_ctx sha;
+ sha1_init(&sha);
+ sha1_update(&sha, start, len);
+
+ const uint8_t *hash = sha1_final(&sha);
+ for (unsigned int i = 0; i < SHA1_DIGEST_SIZE; i++)
+ VBDEBUG("%02x", hash[i]);
+ VBDEBUG("\n");
+
+ //hexdump(start, 128);
+
+ return tlcl_extend(pcr_num, hash, NULL);
+}
--
2.20.1