aboutsummaryrefslogtreecommitdiffstats
path: root/roms/skiboot/libstb/trustedboot.c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/skiboot/libstb/trustedboot.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/libstb/trustedboot.c')
-rw-r--r--roms/skiboot/libstb/trustedboot.c258
1 files changed, 258 insertions, 0 deletions
diff --git a/roms/skiboot/libstb/trustedboot.c b/roms/skiboot/libstb/trustedboot.c
new file mode 100644
index 000000000..1be2f07e6
--- /dev/null
+++ b/roms/skiboot/libstb/trustedboot.c
@@ -0,0 +1,258 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+/* Copyright 2013-2019 IBM Corp. */
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) "STB: " fmt
+#endif
+
+#include <skiboot.h>
+#include <device.h>
+#include <nvram.h>
+#include <opal-api.h>
+#include "secureboot.h"
+#include "trustedboot.h"
+#include "tpm_chip.h"
+#include "ibmtss/TPM_Types.h"
+
+/* For debugging only */
+//#define STB_DEBUG
+
+static bool trusted_mode = false;
+static bool trusted_init = false;
+static bool boot_services_exited = false;
+
+/*
+ * Partitions retrieved from PNOR must be extended to the proper PCR and
+ * recorded in the event log. Later, customers may use: the PCR values to attest
+ * the boot security, and the event log to inspect what measurements were
+ * extended to the PCRs.
+ *
+ * The list below should map every skiboot event (or resource) to a PCR
+ * following the TCG PC Client Platform Firmware Profile specification,
+ * Family 2.0, Level 00, Revision 1.03 v51.
+ *
+ * Convention for skiboot events:
+ * - Events that represents data should be extended to PCR 4.
+ * - Events that represents config should be extended to PCR 5.
+ * - For the lack of an event type that fits the specific purpose,
+ * both data and config events should be logged as EV_COMPACT_HASH.
+ */
+static struct {
+ enum resource_id id;
+ TPMI_DH_PCR pcr;
+} resources[] = {
+ { RESOURCE_ID_IMA_CATALOG, PCR_4},
+ { RESOURCE_ID_KERNEL, PCR_4},
+ { RESOURCE_ID_CAPP, PCR_4},
+ { RESOURCE_ID_VERSION, PCR_4}, /* Also data for Hostboot */
+};
+
+/*
+ * Event Separator - digest of 0xFFFFFFFF
+ */
+static struct {
+ const unsigned char *event;
+ const unsigned char *sha1;
+ const unsigned char *sha256;
+} ev_separator = {
+
+ .event = "\xff\xff\xff\xff",
+
+ .sha1 = "\xd9\xbe\x65\x24\xa5\xf5\x04\x7d\xb5\x86"
+ "\x68\x13\xac\xf3\x27\x78\x92\xa7\xa3\x0a",
+
+ .sha256 = "\xad\x95\x13\x1b\xc0\xb7\x99\xc0\xb1\xaf"
+ "\x47\x7f\xb1\x4f\xcf\x26\xa6\xa9\xf7\x60"
+ "\x79\xe4\x8b\xf0\x90\xac\xb7\xe8\x36\x7b"
+ "\xfd\x0e"
+};
+
+static TPM_Pcr map_pcr(enum resource_id id)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(resources); i++) {
+ if (resources[i].id == id)
+ return resources[i].pcr;
+ }
+ return -1;
+}
+
+void trustedboot_init(void)
+{
+ struct dt_node *node;
+
+ node = dt_find_by_path(dt_root, "/ibm,secureboot");
+ if (!node) {
+ prlog(PR_NOTICE, "trusted boot not supported\n");
+ return;
+ }
+
+ if (!secureboot_is_compatible(node, NULL, NULL)) {
+ /**
+ * @fwts-label TrustedBootNotCompatible
+ * @fwts-advice Compatible trustedboot driver not found. Probably,
+ * hostboot/mambo/skiboot has updated the
+ * /ibm,secureboot/compatible without adding a driver that
+ * supports it.
+ */
+ prlog(PR_ERR, "trustedboot init FAILED, '%s' node not "
+ "compatible.\n", node->name);
+ return;
+ }
+
+ if (nvram_query_eq_dangerous("force-trusted-mode", "true")) {
+ trusted_mode = true;
+ prlog(PR_NOTICE, "trusted mode on (FORCED by nvram)\n");
+ } else {
+ trusted_mode = dt_has_node_property(node, "trusted-enabled", NULL);
+ prlog(PR_INFO, "trusted mode %s\n",
+ trusted_mode ? "on" : "off");
+ }
+
+ if (!trusted_mode)
+ return;
+
+ cvc_init();
+ tpm_init();
+
+ trusted_init = true;
+ boot_services_exited = false;
+}
+
+int trustedboot_exit_boot_services(void)
+{
+ uint32_t pcr;
+ int rc = 0;
+ bool failed = false;
+
+ if (!trusted_mode)
+ goto out_free;
+
+ if (boot_services_exited) {
+ prlog(PR_WARNING, "Trusted boot services exited before.\n");
+ goto out_free;
+ }
+
+ boot_services_exited = true;
+#ifdef STB_DEBUG
+ prlog(PR_NOTICE, "ev_separator.event: %s\n", ev_separator.event);
+ prlog(PR_NOTICE, "ev_separator.sha1:\n");
+ stb_print_data((uint8_t*) ev_separator.sha1, SHA1_DIGEST_SIZE);
+ prlog(PR_NOTICE, "ev_separator.sha256:\n");
+ stb_print_data((uint8_t*) ev_separator.sha256, SHA256_DIGEST_SIZE);
+#endif
+ /*
+ * Extend the digest of 0xFFFFFFFF to PCR[0-7] and record it as
+ * EV_SEPARATOR
+ */
+ for (pcr = 0; pcr < 8; pcr++) {
+ rc = tpm_extendl(pcr,
+ TPM_ALG_SHA256, (uint8_t*) ev_separator.sha256,
+ TPM_ALG_SHA1, (uint8_t*) ev_separator.sha1,
+ EV_SEPARATOR, ev_separator.event,
+ strlen(ev_separator.event));
+ if (rc)
+ failed = true;
+ }
+ tpm_add_status_property();
+ tss_set_platform_auth();
+
+out_free:
+ tpm_cleanup();
+
+ return (failed) ? -1 : 0;
+}
+
+int trustedboot_measure(enum resource_id id, void *buf, size_t len)
+{
+ uint8_t digest[SHA512_DIGEST_LENGTH];
+ void *buf_aux;
+ size_t len_aux;
+ const char *name;
+ TPMI_DH_PCR pcr;
+ int rc = -1;
+
+ if (!trusted_mode)
+ return 1;
+
+ name = flash_map_resource_name(id);
+ if (!name) {
+ /**
+ * @fwts-label ResourceNotMeasuredUnknown
+ * @fwts-advice This is a bug in the trustedboot_measure()
+ * caller, which is passing an unknown resource_id.
+ */
+ prlog(PR_ERR, "resource NOT MEASURED, resource_id=%d unknown\n", id);
+ return -1;
+ }
+
+ if (!trusted_init) {
+ prlog(PR_ERR, "resource NOT MEASURED, resource_id=%d "
+ "trustedboot not yet initialized\n", id);
+ return -1;
+ }
+
+ if (boot_services_exited) {
+ prlog(PR_ERR, "%s NOT MEASURED. Already exited from boot "
+ "services\n", name);
+ return -1;
+ }
+ pcr = map_pcr(id);
+ if (pcr == -1) {
+ /**
+ * @fwts-label ResourceNotMappedToPCR
+ * @fwts-advice This is a bug. The resource cannot be measured
+ * because it is not mapped to a PCR in the resources[] array.
+ */
+ prlog(PR_ERR, "%s NOT MEASURED, it's not mapped to a PCR\n", name);
+ return -1;
+ }
+ if (!buf) {
+ /**
+ * @fwts-label ResourceNotMeasuredNull
+ * @fwts-advice This is a bug. The trustedboot_measure() caller
+ * provided a NULL container.
+ */
+ prlog(PR_ERR, "%s NOT MEASURED, it's null\n", name);
+ return -1;
+ }
+ if (stb_is_container(buf, len)) {
+ buf_aux = buf + SECURE_BOOT_HEADERS_SIZE;
+ len_aux = len - SECURE_BOOT_HEADERS_SIZE;
+ } else {
+ buf_aux = buf;
+ len_aux = len;
+ }
+
+ rc = call_cvc_sha512(buf_aux, len_aux, digest, SHA512_DIGEST_LENGTH);
+
+ if (rc == OPAL_SUCCESS) {
+ prlog(PR_NOTICE, "%s hash calculated\n", name);
+ } else if (rc == OPAL_PARAMETER) {
+ prlog(PR_ERR, "%s NOT MEASURED, invalid param. buf=%p, "
+ "len=%zd, digest=%p\n", name, buf_aux,
+ len_aux, digest);
+ return -1;
+ } else if (rc == OPAL_UNSUPPORTED) {
+ prlog(PR_ERR, "%s NOT MEASURED, CVC-sha512 service not "
+ "supported\n", name);
+ return -1;
+ } else {
+ prlog(PR_ERR, "%s NOT MEASURED, unknown CVC-sha512 error. "
+ "rc=%d\n", name, rc);
+ return -1;
+ }
+
+#ifdef STB_DEBUG
+ stb_print_data(digest, SHA256_DIGEST_SIZE);
+
+#endif
+ /*
+ * Extend the given PCR number in both sha256 and sha1 banks with the
+ * sha512 hash calculated. The hash is truncated accordingly to fit the
+ * PCR.
+ */
+ return tpm_extendl(pcr, TPM_ALG_SHA256, (uint8_t*) digest,
+ TPM_ALG_SHA1, (uint8_t*) digest,
+ EV_COMPACT_HASH, name, strlen(name));
+}