@@ -14,6 +14,7 @@
false VALUE vtpm-debug?
0 VALUE vtpm-unit
+0 VALUE vtpm-ihandle
: setup-alias
" ibm,vtpm" find-alias 0= IF
@@ -56,6 +57,47 @@ false VALUE vtpm-debug?
r> to my-self
;
+\ forward a call to /ibm,vtpm, which implements the function with the
+\ given name
+: vtpm-call-forward ( arg ... arg name namelen -- ret ... ret failure? )
+ \ assign /ibm,vtpm node to vtpm-ihandle, if not assigned
+ vtpm-ihandle 0= IF
+ s" /ibm,vtpm" open-dev to vtpm-ihandle
+ THEN
+
+ vtpm-ihandle 0<> IF
+ vtpm-ihandle ( arg ... arg name namelen ihandle )
+ $call-method ( ret ... ret )
+ false ( ret ... ret false )
+ ELSE
+ true ( true )
+ THEN
+;
+
+\ firmware API call
+: hash-all ( data-ptr data-len hash-ptr -- )
+ " hash-all" vtpm-call-forward IF
+ \ vtpm-call-forward failed; clean up stack
+ 3drop
+ THEN
+;
+
+\ firmware API call
+: log-event ( event-ptr -- success? )
+ " log-event" vtpm-call-forward IF
+ drop
+ false
+ THEN
+;
+
+\ firmware API call
+: hash-log-extend-event ( event-ptr -- rc )
+ " hash-log-extend-event" vtpm-call-forward IF
+ drop
+ 9 \ TPM_FAIL
+ THEN
+;
+
: open ( )
vtpm-debug? IF ." VTPM: vTPM open()" cr THEN
true
@@ -45,6 +45,38 @@ log-base LOG-SIZE tpm-set-log-parameters
move
;
+: hash-all ( data-ptr data-len hash-ptr -- )
+ vtpm-debug? IF
+ ." Call to hash-all" cr
+ THEN
+ tpm-hash-all ( errcode )
+ dup 0<> IF
+ ." VTPM: Error code from tpm-hash-all: " . cr
+ ELSE
+ drop
+ THEN
+;
+
+: log-event ( event-ptr -- success? )
+ vtpm-debug? IF
+ ." Call to log-event" cr
+ THEN
+ tpm-log-event ( success? )
+ dup 0= IF
+ ." VTPM: Returned bool from tpm-log-event: " dup . cr
+ THEN
+;
+
+: hash-log-extend-event ( event-ptr -- rc )
+ vtpm-debug? IF
+ ." Call to hash-log-extend-event" cr
+ THEN
+ tpm-hash-log-extend-event ( rc )
+ dup 0<> IF
+ ." VTPM: Error code from tpm-hash-log-extend-event: " dup . cr
+ THEN
+;
+
\
\ internal API calls
\
@@ -18,6 +18,8 @@
* http://www.trustedcomputinggroup.org/resources/pc_client_work_group_specific_implementation_specification_for_conventional_bios
*/
+#include <stddef.h>
+
#include "types.h"
#include "byteorder.h"
#include "tpm_drivers.h"
@@ -25,6 +27,8 @@
#include "tcgbios.h"
#include "tcgbios_int.h"
#include "stdio.h"
+#include "sha1.h"
+#include "helpers.h"
#undef TCGBIOS_DEBUG
//#define TCGBIOS_DEBUG
@@ -45,6 +49,9 @@ struct tpm_state {
/* size of the logging area */
uint32_t log_area_size;
+
+ /* where to write the next log entry to */
+ uint8_t *log_area_next_entry;
};
static struct tpm_state tpm_state;
@@ -161,6 +168,38 @@ static int tpm12_determine_timeouts(void)
return 0;
}
+/*
+ * Extend a PCR of the TPM with the given hash
+ *
+ * @hash: sha1 hash (20 bytes) to extend PCR with
+ * @pcrindex: the PCR to extend [ 0..23 ]
+ */
+static int tpm_extend(uint8_t *hash, uint32_t pcrindex)
+{
+ struct tpm_req_extend tre = {
+ .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
+ .hdr.totlen = cpu_to_be32(sizeof(tre)),
+ .hdr.ordinal = cpu_to_be32(TPM_ORD_EXTEND),
+ .pcrindex = cpu_to_be32(pcrindex),
+ };
+ struct tpm_rsp_extend rsp;
+ uint32_t resp_length = sizeof(rsp);
+ int ret;
+
+ memcpy(tre.digest, hash, sizeof(tre.digest));
+
+ ret = tpmhw_transmit(0, &tre.hdr, &rsp, &resp_length,
+ TPM_DURATION_TYPE_SHORT);
+
+ if (ret || resp_length != sizeof(rsp) || rsp.hdr.errcode) {
+ dprintf("TPM_Extend response has unexpected size: %u\n",
+ resp_length);
+ return -1;
+ }
+
+ return 0;
+}
+
/****************************************************************
* Setup and Measurements
****************************************************************/
@@ -182,6 +221,58 @@ static void tpm_set_failure(void)
tpm_state.tpm_working = false;
}
+/*
+ * Extend the OFDT log with the given entry by copying the
+ * entry data into the log.
+ *
+ * @pcpes: Pointer to the structure to be copied into the log
+ * @event: The event to be appended to 'pcpes'
+ * @event_length: The length of the event
+ *
+ * Returns 0 on success, an error code otherwise.
+ */
+static uint32_t tpm_log_event_long(struct pcpes *pcpes,
+ const void *event, uint32_t event_length)
+{
+ uint32_t size;
+
+ dprintf("log base address = %p, next entry = %p\n",
+ tpm_state.log_base, tpm_state.log_area_next_entry);
+
+ if (tpm_state.log_area_next_entry == NULL)
+ return TCGBIOS_LOGOVERFLOW;
+
+ size = offset_of(struct pcpes, event) + event_length;
+
+ if ((tpm_state.log_area_next_entry + size - tpm_state.log_base) >
+ tpm_state.log_area_size) {
+ dprintf("LOG OVERFLOW: size = %d\n", size);
+ return TCGBIOS_LOGOVERFLOW;
+ }
+
+ pcpes->eventdatasize = event_length;
+
+ memcpy(tpm_state.log_area_next_entry, pcpes,
+ offset_of(struct pcpes, event));
+ memcpy(tpm_state.log_area_next_entry + offset_of(struct pcpes, event),
+ event, event_length);
+
+ tpm_state.log_area_next_entry += size;
+
+ return 0;
+}
+
+bool tpm_log_event(struct pcpes *pcpes)
+{
+ const char *event = NULL;
+ uint32_t event_length = pcpes->eventdatasize;
+
+ if (event_length)
+ event = (void *)pcpes + offset_of(struct pcpes, event);
+
+ return (tpm_log_event_long(pcpes, event, event_length) == 0);
+}
+
static int tpm12_assert_physical_presence(void)
{
struct tpm_permanent_flags pf;
@@ -285,5 +376,57 @@ void tpm_set_log_parameters(void *addr, unsigned int size)
dprintf("Log is at 0x%llx; size is %u bytes\n",
(uint64_t)addr, size);
tpm_state.log_base = addr;
+ tpm_state.log_area_next_entry = addr;
tpm_state.log_area_size = size;
}
+
+/*
+ * tpm_hash_all: Function for interfacing with the firmware API
+ */
+uint32_t tpm_hash_all(const void *data, uint32_t datalen, void *hashptr)
+{
+ return sha1(data, datalen, hashptr);
+}
+
+static uint32_t hash_log_extend(struct pcpes *pcpes,
+ const void *hashdata,
+ uint32_t hashdata_length,
+ const char *event, uint32_t event_length,
+ bool extend)
+{
+ int ret;
+
+ if (pcpes->pcrindex >= 24)
+ return TCGBIOS_INVALID_INPUT_PARA;
+ if (hashdata)
+ tpm_hash_all(hashdata, hashdata_length, pcpes->digest);
+
+ if (extend) {
+ ret = tpm_extend(pcpes->digest, pcpes->pcrindex);
+ if (ret)
+ return TCGBIOS_COMMAND_ERROR;
+ }
+ ret = tpm_log_event_long(pcpes, event, event_length);
+ if (ret)
+ return TCGBIOS_LOGOVERFLOW;
+ return 0;
+}
+
+/*
+ * tpm_hash_log_extend_event: Function for interfacing with the firmware API
+ */
+uint32_t tpm_hash_log_extend_event(struct pcpes *pcpes)
+{
+ const char *event = NULL;
+ uint32_t event_length = pcpes->eventdatasize;
+
+ if (!tpm_is_working())
+ return TCGBIOS_GENERAL_ERROR;
+
+ if (event_length)
+ event = (void *)pcpes + offset_of(struct pcpes, event);
+
+ return hash_log_extend(pcpes,
+ &pcpes->event, pcpes->eventdatasize,
+ event, event_length, true);
+}
@@ -14,10 +14,16 @@
#define TCGBIOS_H
#include <stdint.h>
+#include <stdbool.h>
+
+struct pcpes;
uint32_t tpm_start(void);
void tpm_finalize(void);
uint32_t tpm_unassert_physical_presence(void);
void tpm_set_log_parameters(void *address, unsigned int size);
+uint32_t tpm_hash_log_extend_event(struct pcpes *pcpes);
+bool tpm_log_event(struct pcpes *pcpes);
+uint32_t tpm_hash_all(const void *data, uint32_t datalen, void *hashptr);
#endif /* TCGBIOS_H */
@@ -48,6 +48,7 @@
#define TPM_PP_NOT_PRESENT_LOCK 0x0014
#define TPM_TAG_RQU_CMD 0x00c1
+#define TPM_TAG_RSP_CMD 0x00c4
/* TPM command error codes */
#define TPM_INVALID_POSTINIT 0x26
@@ -55,3 +55,35 @@ PRIM(tpm_X2d_set_X2d_log_X2d_parameters)
void *addr = TOS.a; POP;
tpm_set_log_parameters(addr, size);
MIRP
+
+/**************************************************/
+/* Firmware API */
+/* SLOF: tpm-log-event ( eventptr -- success? ) */
+/* LIBTPM: success = tpm-log-event */
+/**************************************************/
+PRIM(tpm_X2d_log_X2d_event)
+ void *eventptr = TOS.a;
+ TOS.n = tpm_log_event(eventptr);
+MIRP
+
+/********************************************************/
+/* Firmware API */
+/* SLOF: tpm-hash-log-extend-event ( eventptr -- rc ) */
+/* LIBTPM: errcode = tpm-hash-log-extend-event */
+/********************************************************/
+PRIM(tpm_X2d_hash_X2d_log_X2d_extend_X2d_event)
+ void *eventptr = TOS.a;
+ TOS.n = tpm_hash_log_extend_event(eventptr);
+MIRP
+
+/*****************************************************************/
+/* Firmware API */
+/* SLOF: tpm-hash-all ( data-ptr data-len hash-ptr -- errcode) */
+/* LIBTPM: errcode = tpm-hash-all */
+/*****************************************************************/
+PRIM(tpm_X2d_hash_X2d_all)
+ void *hashptr = TOS.a; POP;
+ int datalen = TOS.n; POP;
+ void *dataptr = TOS.a;
+ TOS.n = tpm_hash_all(dataptr, datalen, hashptr);
+MIRP
@@ -17,3 +17,6 @@ cod(tpm-start)
cod(tpm-finalize)
cod(tpm-unassert-physical-presence)
cod(tpm-set-log-parameters)
+cod(tpm-log-event)
+cod(tpm-hash-log-extend-event)
+cod(tpm-hash-all)
Extend the internal API of the TPM firmware support with additional functions for hashing data, extending the TPM's platform configuration registers with a hash, and appending to the log that is recording what was hashed. Add the TPM firmware API calls hash-all, log-event, and hash-log-extend-event. These firmware calls are implemented in /vdevice/vtpm and /ibm,vtpm but the former merely forwards the calls to the latter. The implementation follows the Virtual TPM firmware documentation. These particular 3 API calls enable trusted grub extensions. Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com> --- board-qemu/slof/vio-vtpm-cdriver.fs | 42 ++++++++ board-qemu/slof/vtpm-sml.fs | 32 +++++++ lib/libtpm/tcgbios.c | 143 ++++++++++++++++++++++++++++ lib/libtpm/tcgbios.h | 6 ++ lib/libtpm/tcgbios_int.h | 1 + lib/libtpm/tpm.code | 32 +++++++ lib/libtpm/tpm.in | 3 + 7 files changed, 259 insertions(+)