[SLOF] [PATCH v3 05/17] Extend firmware API
Stefan Berger
stefanb at us.ibm.com
Tue Dec 1 09:01:48 AEDT 2015
From: Stefan Berger <stefanb at linux.vnet.ibm.com>
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 at linux.vnet.ibm.com>
---
board-qemu/slof/vio-vtpm-cdriver.fs | 42 ++++++++++
board-qemu/slof/vtpm-sml.fs | 32 +++++++
lib/libtpm/tcgbios.c | 162 ++++++++++++++++++++++++++++++++++++
lib/libtpm/tcgbios.h | 6 ++
lib/libtpm/tcgbios_int.h | 1 +
lib/libtpm/tpm.code | 32 +++++++
lib/libtpm/tpm.in | 3 +
7 files changed, 278 insertions(+)
diff --git a/board-qemu/slof/vio-vtpm-cdriver.fs b/board-qemu/slof/vio-vtpm-cdriver.fs
index f873456..79f484c 100644
--- a/board-qemu/slof/vio-vtpm-cdriver.fs
+++ b/board-qemu/slof/vio-vtpm-cdriver.fs
@@ -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 -- failure? ret ... ret )
+ \ 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 --- 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
diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs
index 2d1eb32..981bb1c 100644
--- a/board-qemu/slof/vtpm-sml.fs
+++ b/board-qemu/slof/vtpm-sml.fs
@@ -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
\
diff --git a/lib/libtpm/tcgbios.c b/lib/libtpm/tcgbios.c
index 5fca5cc..8f11079 100644
--- a/lib/libtpm/tcgbios.c
+++ b/lib/libtpm/tcgbios.c
@@ -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
@@ -75,6 +79,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;
@@ -88,9 +95,62 @@ 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;
}
+/*
+ * 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 char *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 void probe_tpm(void)
{
tpm_state.tpm_probed = true;
@@ -347,3 +407,105 @@ err_exit:
return rc;
return TCGBIOS_COMMAND_ERROR;
}
+
+/*
+ * 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 uint32_t tpm_extend(uint8_t *hash, uint32_t pcrindex)
+{
+ struct tpm_req_extend req = {
+ .hdr.tag = cpu_to_be16(TPM_TAG_RQU_CMD),
+ .hdr.totlen = cpu_to_be32(sizeof(req)),
+ .hdr.ordinal = cpu_to_be32(TPM_ORD_EXTEND),
+ .pcrindex = cpu_to_be32(pcrindex),
+ };
+ struct tpm_rsp_extend rsp;
+ uint32_t rsplen = sizeof(rsp);
+ uint32_t rc;
+
+ memcpy(req.digest, hash, sizeof(req.digest));
+
+ rc = transmit(&req.hdr, (uint8_t *)&rsp, &rsplen,
+ TPM_DURATION_TYPE_SHORT);
+
+ if (rc || rsplen != sizeof(rsp)) {
+ dprintf("TPM_Extend response has unexpected size: %u\n",
+ rsplen);
+ tpm_set_failure();
+ }
+
+ return rc;
+}
+
+/*
+ * 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);
+}
+
+/*
+ * Hash the given input data and append the hash to the log
+ *
+ * @hashdata: the data to hash
+ * @hashdatalen: the size of the data to hash
+ * @pcpes: the 'pcpes' to append to the log; the hash will be written into this
+ * structure
+ * @event: the event to append to the pcpes
+ * @event_length: the lenth of the event array
+ */
+static uint32_t hash_log_event(const void *hashdata,
+ uint32_t hashdatalen,
+ struct pcpes *pcpes,
+ const char *event, uint32_t event_length)
+{
+ /* TPM has PCRs 0 to 23 */
+ if (pcpes->pcrindex >= 24)
+ return TCGBIOS_INVALID_INPUT_PARA;
+
+ if (hashdata)
+ sha1(hashdata, hashdatalen, pcpes->digest);
+
+ return tpm_log_event_long(pcpes, event, event_length);
+}
+
+static uint32_t hash_log_extend_event(const void *hashdata,
+ uint32_t hashdatalen,
+ struct pcpes *pcpes,
+ const char *event, uint32_t event_length,
+ uint32_t pcrindex)
+{
+ uint32_t rc;
+
+ rc = hash_log_event(hashdata, hashdatalen, pcpes, event, event_length);
+
+ /*
+ * Like PCCLient spec.: evn if log is full extend the PCR
+ */
+ tpm_extend(pcpes->digest, pcrindex);
+
+ return rc;
+}
+
+/*
+ * tpm_hash_log_extend_event: Function for interfacing with then firmware API
+ */
+uint32_t tpm_hash_log_extend_event(struct pcpes *pcpes)
+{
+ const char *event = NULL;
+ uint32_t event_length = pcpes->eventdatasize;
+
+ if (!has_working_tpm())
+ return TCGBIOS_GENERAL_ERROR;
+
+ if (event_length)
+ event = (void *)pcpes + offset_of(struct pcpes, event);
+
+ return hash_log_extend_event(&pcpes->event, pcpes->eventdatasize,
+ pcpes, event, event_length,
+ pcpes->pcrindex);
+}
diff --git a/lib/libtpm/tcgbios.h b/lib/libtpm/tcgbios.h
index 7f7691a..c54eb91 100644
--- a/lib/libtpm/tcgbios.h
+++ b/lib/libtpm/tcgbios.h
@@ -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 */
diff --git a/lib/libtpm/tcgbios_int.h b/lib/libtpm/tcgbios_int.h
index c0cb960..be7a606 100644
--- a/lib/libtpm/tcgbios_int.h
+++ b/lib/libtpm/tcgbios_int.h
@@ -44,6 +44,7 @@
#define TPM_ST_DEACTIVATED 0x3
#define TPM_TAG_RQU_CMD 0x00c1
+#define TPM_TAG_RSP_CMD 0x00c4
/* TPM command error codes */
#define TPM_INVALID_POSTINIT 0x26
diff --git a/lib/libtpm/tpm.code b/lib/libtpm/tpm.code
index 2f3e198..80a50f8 100644
--- a/lib/libtpm/tpm.code
+++ b/lib/libtpm/tpm.code
@@ -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
diff --git a/lib/libtpm/tpm.in b/lib/libtpm/tpm.in
index c6ad91c..0086f33 100644
--- a/lib/libtpm/tpm.in
+++ b/lib/libtpm/tpm.in
@@ -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)
--
2.4.3
More information about the SLOF
mailing list