Philipp Deppenwiese has uploaded this change for review. ( https://review.coreboot.org/22867
Change subject: security/tpm: Add TPM measurement code ......................................................................
security/tpm: Add TPM measurement code
* Add TPM hash_{start,update,complete} functionality * Add TCPA ACPI logging functionality * Add TSPI functions for measuring and hashing data
Change-Id: I0a52494f647d21e2587231af26ed13d62b3a72f5 Signed-off-by: Philipp Deppenwiese zaolin@das-labor.org --- M src/security/tpm/tspi.h M src/security/tpm/tspi/tspi.c M src/security/tpm/tss.h M src/security/tpm/tss/tcg-1.2/tss.c M src/security/tpm/tss/tcg-1.2/tss_structures.h M src/security/tpm/tss/tcg-2.0/tss.c 6 files changed, 196 insertions(+), 18 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/67/22867/1
diff --git a/src/security/tpm/tspi.h b/src/security/tpm/tspi.h index de3849a..1a84c62 100644 --- a/src/security/tpm/tspi.h +++ b/src/security/tpm/tspi.h @@ -18,6 +18,20 @@
#include <security/tpm/tss.h>
+#define TPM_PCR_MAX_LENGTH 64 + +/** + * TPM measurement with acpi log functionality based on binary data. + */ +uint32_t tpm_measure_data(int pcr, const uint8_t *data, uint32_t data_length, + const char *name); + +/** + * TPM hash binary data. + */ +uint32_t tpm_hash(const uint8_t *data, size_t data_length, uint8_t **digest, + uint32_t *digest_length); + /** * Ask vboot for a digest and extend a TPM PCR with it. */ @@ -33,5 +47,4 @@ */ uint32_t tpm_setup(int s3flag);
- -#endif /* TSPI_H_ */ +#endif /* TSPI_H_ */ diff --git a/src/security/tpm/tspi/tspi.c b/src/security/tpm/tspi/tspi.c index 9969cd3..891cc6a 100644 --- a/src/security/tpm/tspi/tspi.c +++ b/src/security/tpm/tspi/tspi.c @@ -14,13 +14,13 @@ * GNU General Public License for more details. */
+#include <console/cbmem_console.h> +#include <console/console.h> +#include <reset.h> +#include <security/tpm/tspi.h> +#include <security/tpm/tss.h> #include <stdlib.h> #include <string.h> -#include <security/tpm/tss.h> -#include <security/tpm/tspi.h> -#include <console/console.h> -#include <console/cbmem_console.h> -#include <reset.h>
/* * SetupTPM starts the TPM and establishes the root of trust for the @@ -79,13 +79,16 @@ */ result = tlcl_physical_presence_cmd_enable(); if (result != TPM_SUCCESS) { - printk(BIOS_ERR, "TPM: Can't enable physical presence command.\n"); + printk( + BIOS_ERR, + "TPM: Can't enable physical presence command.\n"); return result; }
result = tlcl_assert_physical_presence(); if (result != TPM_SUCCESS) { - printk(BIOS_ERR, "TPM: Can't assert physical presence.\n"); + printk(BIOS_ERR, + "TPM: Can't assert physical presence.\n"); return result; } } @@ -98,8 +101,9 @@ }
if (disable || deactivated) { - printk(BIOS_INFO, "TPM: disabled (%d) or deactivated (%d). Fixing...\n", - disable, deactivated); + printk(BIOS_INFO, + "TPM: disabled (%d) or deactivated (%d). Fixing...\n", + disable, deactivated);
result = tlcl_set_enable(); if (result != TPM_SUCCESS) { @@ -130,7 +134,7 @@ uint32_t result = __tpm_setup(s3flag);
if (IS_ENABLED(CONFIG_TPM_INIT_FAILURE_IS_FATAL) && - result != TPM_SUCCESS) { + result != TPM_SUCCESS) { printk(BIOS_ERR, "Hard reset!\n"); post_code(POST_TPM_FAILURE); if (IS_ENABLED(CONFIG_CONSOLE_CBMEM_DUMP_TO_UART)) @@ -181,3 +185,72 @@
return tlcl_extend(pcr, digest, NULL); } + +uint32_t tpm_hash(const uint8_t *data, size_t data_length, uint8_t **digest, + uint32_t *digest_length) +{ + uint32_t data_max_length = 0; + uint32_t result; + size_t i, hash_rounds = 0; + + result = tlcl_hash_start(&data_max_length); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Start hash routine.\n"); + return result; + } + + hash_rounds = (size_t)(data_max_length / data_length); + for (i = 0; i < hash_rounds; i++) { + result = tlcl_hash_update(data + (i * data_max_length), + data_max_length); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Update hash routine.\n"); + return result; + } + } + + if (data_max_length % data_length == 0) { + result = tlcl_hash_complete(NULL, 0, digest, digest_length); + } else { + result = tlcl_hash_complete( + data + (hash_rounds * data_max_length), + data_max_length % data_length, digest, digest_length); + } + + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Complete hash routine.\n"); + return result; + } + + return result; +} + +uint32_t tpm_measure_data(int pcr, const uint8_t *data, uint32_t data_length, + const char *name) +{ + uint8_t digest[TPM_PCR_MAX_LENGTH]; + uint32_t digest_length = 0; + uint32_t result; + + result = + tpm_hash(data, data_length, (uint8_t **)&digest, &digest_length); + if (result != TPM_SUCCESS && digest != NULL) { + printk(BIOS_ERR, "TPM: Hashing data failed.\n"); + return result; + } + + result = tlcl_extend(pcr, digest, NULL); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, "TPM: Extending hash into PCR failed.\n"); + return result; + } + + result = tlcl_tcpa_log(pcr, digest, digest_length, name); + if (result != TPM_SUCCESS) { + printk(BIOS_ERR, + "TPM: Writing measurement meta information failed.\n"); + return result; + } + + return result; +} diff --git a/src/security/tpm/tss.h b/src/security/tpm/tss.h index 612df0f..a423e41 100644 --- a/src/security/tpm/tss.h +++ b/src/security/tpm/tss.h @@ -179,7 +179,13 @@ * */ uint32_t tlcl_hash_complete(const void *message, uint32_t message_length, - uint8_t **digest); + uint8_t **digest, uint32_t *digest_length); + +/** + * TCPA ACPI log + */ +uint32_t tlcl_tcpa_log(int pcr, uint8_t *digest, uint32_t digest_length, + const char *name);
/** * CR50 specific tpm command to enable nvmem commits before internal timeout @@ -199,4 +205,4 @@ uint32_t tlcl_cr50_enable_update(uint16_t timeout_ms, uint8_t *num_restored_headers);
-#endif /* TSS_H_ */ +#endif /* TSS_H_ */ diff --git a/src/security/tpm/tss/tcg-1.2/tss.c b/src/security/tpm/tss/tcg-1.2/tss.c index 2bb2269..3fa31bb 100644 --- a/src/security/tpm/tss/tcg-1.2/tss.c +++ b/src/security/tpm/tss/tcg-1.2/tss.c @@ -1,4 +1,5 @@ /* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Copyright 2017 Facebook Inc. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ @@ -16,6 +17,7 @@
#include <arch/early_variables.h> #include <assert.h> +#include <cbmem.h> #include <security/tpm/tis.h> #include <security/tpm/tss.h> #include <string.h> @@ -386,7 +388,7 @@ }
uint32_t tlcl_hash_complete(const void *message, uint32_t message_length, - uint8_t **digest) + uint8_t **digest, uint32_t *digest_length) { struct s_tpm_sha1_complete_cmd cmd; uint8_t response[TPM_LARGE_ENOUGH_COMMAND_SIZE]; @@ -405,9 +407,11 @@ message_length);
result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); - if (result == TPM_SUCCESS) + if (result == TPM_SUCCESS) { memcpy(*digest, response + kTpmResponseHeaderLength, kPcrDigestLength); + *digest_length = TPM_PCR_DIGEST; + }
return result; } @@ -424,7 +428,67 @@ result = tlcl_send_receive(cmd.buffer, response, sizeof(response)); if (result == TPM_SUCCESS) memcpy(out_digest, response + kTpmResponseHeaderLength, - kPcrDigestLength); + kPcrDigestLength);
return result; } + +uint32_t tlcl_tcpa_log(int pcr, uint8_t *digest, uint32_t digest_length, + const char *name) +{ + const struct cbmem_entry *ce; + TPM_PCR_EVENT tcpa_event; + TPM_DIGEST pcr_digest; + void *lasa; + uint8_t *ptr; + size_t size; + + if (name == NULL) { + printk(BIOS_ERR, "TCPA log message is NULL\n"); + return 1; + } + + if (strlen(name) >= TPM_EVENT_DATA_SIZE) { + printk(BIOS_ERR, "TCPA log message is too big\n"); + return 1; + } + + memcpy(pcr_digest.digest, digest, digest_length); + + tcpa_event.PCRIndex = pcr; + tcpa_event.EventType = 5; // ACTION type for linux kernel. + tcpa_event.Digest = pcr_digest; + tcpa_event.EventSize = TPM_EVENT_DATA_SIZE; + + memset(tcpa_event.Event, 0, TPM_EVENT_DATA_SIZE); + memcpy(tcpa_event.Event, name, strlen(name)); + + ce = cbmem_entry_find(CBMEM_ID_TCPA_LOG); + if (ce) { + lasa = cbmem_entry_start(ce); + + ptr = (lasa + TCPA_LOG_CBEM_SIZE - 1); + size = sizeof(TPM_PCR_EVENT) * (*ptr); + if (size >= (TCPA_LOG_CBEM_SIZE - sizeof(TPM_PCR_EVENT))) { + printk(BIOS_ERR, "TCPA log is full\n"); + return 1; + } + + lasa += size; + *ptr += 1; + } else { + lasa = cbmem_add(CBMEM_ID_TCPA_LOG, TCPA_LOG_CBEM_SIZE); + if (!lasa) { + printk(BIOS_ERR, "TCPA log creation failed\n"); + return 1; + } + } + + memset(lasa, 0, TCPA_LOG_CBEM_SIZE); + ptr = (lasa + TCPA_LOG_CBEM_SIZE - 1); + *ptr += 1; + + memcpy(lasa, &tcpa_event, sizeof(TPM_PCR_EVENT)); + + return 0; +} diff --git a/src/security/tpm/tss/tcg-1.2/tss_structures.h b/src/security/tpm/tss/tcg-1.2/tss_structures.h index c06bbf7..37ff3b7 100644 --- a/src/security/tpm/tss/tcg-1.2/tss_structures.h +++ b/src/security/tpm/tss/tcg-1.2/tss_structures.h @@ -14,6 +14,9 @@ #define TPM_LARGE_ENOUGH_COMMAND_SIZE 256 /* saves space in the firmware */ #define TPM_PUBEK_SIZE 256 #define TPM_PCR_DIGEST 20 +#define TPM_EVENT_DATA_SIZE 25 +#define MAX_EVENT_STRUCT_SIZE 100 +#define TCPA_LOG_CBEM_SIZE 2000
#define TPM_E_NON_FATAL 0x800
@@ -64,6 +67,8 @@
typedef uint8_t TSS_BOOL; typedef uint16_t TPM_STRUCTURE_TAG; +typedef uint32_t TSS_EVENTTYPE; +typedef uint32_t TSS_PCRINDEX;
typedef struct tdTPM_PERMANENT_FLAGS { TPM_STRUCTURE_TAG tag; @@ -98,4 +103,16 @@ TSS_BOOL bGlobalLock; } TPM_STCLEAR_FLAGS;
+typedef struct tdTPM_DIGEST { + uint8_t digest[TPM_PCR_DIGEST]; +} TPM_DIGEST; + +typedef struct tdTPM_PCR_EVENT { + TSS_PCRINDEX PCRIndex; //PCRIndex event extended to + TSS_EVENTTYPE EventType; //See Table 7-1, below + TPM_DIGEST Digest; //Value extended into PCRIndex + uint32_t EventSize; //Size of the event data + uint8_t Event[TPM_EVENT_DATA_SIZE]; //The event data +} TPM_PCR_EVENT; + #endif /* TCG_TSS_STRUCTURES_H_ */ diff --git a/src/security/tpm/tss/tcg-2.0/tss.c b/src/security/tpm/tss/tcg-2.0/tss.c index 0bee09b..d31028f 100644 --- a/src/security/tpm/tss/tcg-2.0/tss.c +++ b/src/security/tpm/tss/tcg-2.0/tss.c @@ -412,7 +412,7 @@ }
uint32_t tlcl_hash_complete(const void *message, uint32_t message_length, - uint8_t **digest) + uint8_t **digest, uint32_t *digest_length) { return TPM_SUCCESS; } @@ -421,3 +421,8 @@ { return TPM_SUCCESS; } + +uint32_t tlcl_tcpa_log(int pcr, const uint8_t *digest, const char *name) +{ + return TPM_SUCCESS; +}