From 3281d5a41a825fce5b935e8929971a8847611fc8 Mon Sep 17 00:00:00 2001 From: Claudio Carvalho Date: Sat, 9 Dec 2017 02:52:20 -0200 Subject: libstb/trustedboot.c: import tb_measure() from stb.c This imports tb_measure() from stb.c, but now it calls the CVC sha512 wrapper to calculate the sha512 hash of the firmware image provided. In trustedboot.c, the tb_measure() is renamed to trustedboot_measure(). The new function, trustedboot_measure(), no longer checks if the container payload hash calculated at boot time matches with the hash found in the container header. A few reasons: - If the system admin wants the container header to be checked/validated, the secure boot jumper must be set. Otherwise, the container header information may not be reliable. - The container layout is expected to change over time. Skiboot would need to maintain a parser for each container layout change. - Skiboot could be checking the hash against a container version that is not supported by the Container-Verification-Code (CVC). The tb_measure() calls are updated to trustedboot_measure() in a subsequent patch. Signed-off-by: Claudio Carvalho Signed-off-by: Stewart Smith --- asm/cvc_entry.S | 4 +- libstb/cvc.c | 28 ++++++++++++ libstb/cvc.h | 13 ++++++ libstb/drivers/romcode.c | 4 +- libstb/trustedboot.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++ libstb/trustedboot.h | 18 ++++++++ 6 files changed, 175 insertions(+), 4 deletions(-) diff --git a/asm/cvc_entry.S b/asm/cvc_entry.S index ccca006..069ed09 100644 --- a/asm/cvc_entry.S +++ b/asm/cvc_entry.S @@ -26,10 +26,10 @@ .section .text .global __cvc_verify_v1 -.global call_rom_SHA512 +.global __cvc_sha512_v1 __cvc_verify_v1: -call_rom_SHA512: +__cvc_sha512_v1: call_rom_entry: std %r2, 40(%r1) diff --git a/libstb/cvc.c b/libstb/cvc.c index 96c48f4..b0f5cd3 100644 --- a/libstb/cvc.c +++ b/libstb/cvc.c @@ -33,6 +33,8 @@ */ ROM_response __cvc_verify_v1(void *func_ptr, ROM_container_raw *container, ROM_hw_params *params); +void __cvc_sha512_v1(void *func_ptr, const uint8_t *data, size_t len, + uint8_t *digest); struct container_verification_code { uint64_t start_addr; @@ -200,6 +202,32 @@ int cvc_init(void) return rc; } +int call_cvc_sha512(const uint8_t *data, size_t data_len, uint8_t *digest, + size_t digest_size) +{ + struct cvc_service *service; + + if (!data || !digest || digest_size < SHA512_DIGEST_LENGTH) + return OPAL_PARAMETER; + + if (data_len <= 0) + return OPAL_SUCCESS; + + memset(digest, 0, SHA512_DIGEST_LENGTH); + + service = cvc_find_service(CVC_SHA512_SERVICE); + + if (!service) + return OPAL_UNSUPPORTED; + + if (service->version == 1) + __cvc_sha512_v1((void*) service->addr, data, data_len, digest); + else + return OPAL_UNSUPPORTED; + + return OPAL_SUCCESS; +} + int call_cvc_verify(void *container, size_t len, const void *hw_key_hash, size_t hw_key_hash_size, uint64_t *log) { diff --git a/libstb/cvc.h b/libstb/cvc.h index 14e8cd2..13c1b33 100644 --- a/libstb/cvc.h +++ b/libstb/cvc.h @@ -44,4 +44,17 @@ int cvc_init(void); int call_cvc_verify(void *buf, size_t size, const void *hw_key_hash, size_t hw_key_hash_size, uint64_t *log); +/* + * call_cvc_sha512 - Call the CVC-sha512 service to calculate a sha512 hash. + * + * @data - buffer that has data to be hashed + * @data_len - number of bytes from @data to be considered in the hash + * calculation + * @digest - buffer to store the calculated hash + * @digest_size - number of bytes allocated for @digest + * + */ +int call_cvc_sha512(const uint8_t *data, size_t data_len, uint8_t *digest, + size_t digest_size); + #endif /* __CVC_H */ diff --git a/libstb/drivers/romcode.c b/libstb/drivers/romcode.c index d914ba1..ab5f1aa 100644 --- a/libstb/drivers/romcode.c +++ b/libstb/drivers/romcode.c @@ -44,7 +44,7 @@ static sha2_hash_t *hw_key_hash = NULL; */ ROM_response __cvc_verify_v1(void *func_ptr, ROM_container_raw *container, ROM_hw_params *params); -void call_rom_SHA512(void *func_ptr, const uint8_t *data, size_t len, +void __cvc_sha512_v1(void *func_ptr, const uint8_t *data, size_t len, uint8_t *digest); static int romcode_verify(void *container) @@ -71,7 +71,7 @@ static int romcode_verify(void *container) static void romcode_sha512(const uint8_t *data, size_t len, uint8_t *digest) { memset(digest, 0, sizeof(sha2_hash_t)); - call_rom_SHA512(romcode_base_addr + ROMCODE_SHA512_OFFSET, + __cvc_sha512_v1(romcode_base_addr + ROMCODE_SHA512_OFFSET, data, len, digest); } diff --git a/libstb/trustedboot.c b/libstb/trustedboot.c index 9644d1a..f829c0b 100644 --- a/libstb/trustedboot.c +++ b/libstb/trustedboot.c @@ -21,12 +21,41 @@ #include #include #include +#include #include "secureboot.h" #include "trustedboot.h" #include "tpm_chip.h" +/* For debugging only */ +//#define STB_DEBUG + static bool trusted_mode = false; +/* + * This maps a PCR for each resource we can measure. The PCR number is + * mapped according to the TCG PC Client Platform Firmware Profile + * specification, Revision 00.21 + * Only resources included in this whitelist can be measured. + */ +static struct { + enum resource_id id; + TPM_Pcr pcr; +} resources[] = { + { RESOURCE_ID_IMA_CATALOG, PCR_2 }, + { RESOURCE_ID_KERNEL, PCR_4 }, + { RESOURCE_ID_CAPP, PCR_2 }, +}; + +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; @@ -61,6 +90,89 @@ void trustedboot_init(void) if (!trusted_mode) return; + cvc_init(); tpm_init(); } + +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; + TPM_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; + } + 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_INFO, "%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, TPM_ALG_SHA256_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, digest, TPM_ALG_SHA256_SIZE, + TPM_ALG_SHA1, digest, TPM_ALG_SHA1_SIZE, + EV_ACTION, name); +} diff --git a/libstb/trustedboot.h b/libstb/trustedboot.h index 4597514..bd5ac91 100644 --- a/libstb/trustedboot.h +++ b/libstb/trustedboot.h @@ -17,6 +17,24 @@ #ifndef __TRUSTEDBOOT_H #define __TRUSTEDBOOT_H +#include + void trustedboot_init(void); +/** + * trustedboot_measure - measure a resource + * @id : resource id + * @buf : data to be measured + * @len : buf length + * + * This measures a resource downloaded from PNOR if trusted mode is on. That is, + * an EV_ACTION event is recorded in the event log for the mapped PCR, and the + * the sha1 and sha256 measurements are extended in the mapped PCR. + * + * For more information please refer to 'doc/stb.rst' + * + * returns: 0 or an error as defined in status_codes.h + */ +int trustedboot_measure(enum resource_id id, void *buf, size_t len); + #endif /* __TRUSTEDBOOT_H */ -- cgit v1.1