// 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 #include #include #include #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)); }