diff mbox series

[v4,05/33] tpm: Extend firmware API

Message ID 20191211202728.127996-6-stefanb@linux.vnet.ibm.com
State Superseded
Headers show
Series Add vTPM support to SLOF | expand

Commit Message

Stefan Berger Dec. 11, 2019, 8:27 p.m. UTC
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(+)
diff mbox series

Patch

diff --git a/board-qemu/slof/vio-vtpm-cdriver.fs b/board-qemu/slof/vio-vtpm-cdriver.fs
index f873456..53aad4d 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 -- 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
diff --git a/board-qemu/slof/vtpm-sml.fs b/board-qemu/slof/vtpm-sml.fs
index 51c3db5..aa75f46 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 31d3eb0..4a340d9 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
@@ -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);
+}
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 11f91a7..b3ab0ad 100644
--- a/lib/libtpm/tcgbios_int.h
+++ b/lib/libtpm/tcgbios_int.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
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)