diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/skiboot/libstb/trustedboot.c | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/skiboot/libstb/trustedboot.c')
-rw-r--r-- | roms/skiboot/libstb/trustedboot.c | 258 |
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)); +} |