[Skiboot] [PATCH 10/15] libstb: Add tpm interface
Claudio Carvalho
cclaudio at linux.vnet.ibm.com
Thu Aug 11 15:23:52 AEST 2016
This adds the TPM interface for libstb:
- tpm_init(): load drivers compatible with the tpm devices.
- tpm_extendl(): record and event to the event log and extend the pcr of
both sha1 and sha256 banks.
The tpm interface is documented in 'libstb/tpm.h' and the tpm device
tree node is documented in 'doc/device-tree/tpm.txt'
Signed-off-by: Claudio Carvalho <cclaudio at linux.vnet.ibm.com>
---
libstb/Makefile.inc | 2 +-
libstb/status_codes.h | 27 +++++
libstb/tpm.c | 304 ++++++++++++++++++++++++++++++++++++++++++++++++++
libstb/tpm.h | 43 +++++++
4 files changed, 375 insertions(+), 1 deletion(-)
create mode 100644 libstb/status_codes.h
create mode 100644 libstb/tpm.c
diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc
index 642269f..4cffd54 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -4,7 +4,7 @@ LIBSTB_DIR = libstb
SUBDIRS += $(LIBSTB_DIR)
-LIBSTB_SRCS = container.c
+LIBSTB_SRCS = container.c tpm.c
LIBSTB_OBJS = $(LIBSTB_SRCS:%.c=%.o)
LIBSTB = $(LIBSTB_DIR)/built-in.o
diff --git a/libstb/status_codes.h b/libstb/status_codes.h
new file mode 100644
index 0000000..3a742c3
--- /dev/null
+++ b/libstb/status_codes.h
@@ -0,0 +1,27 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __STB_STATUS_CODES_H
+#define __STB_STATUS_CODES_H
+
+/* general return codes */
+#define STB_SUCCESS 0
+
+/* trusted boot */
+#define STB_EVENTLOG_FAILED -200
+#define STB_PCR_EXTEND_FAILED -201
+
+#endif /* __STB_STATUS_CODES_H */
diff --git a/libstb/tpm.c b/libstb/tpm.c
new file mode 100644
index 0000000..26b411b
--- /dev/null
+++ b/libstb/tpm.c
@@ -0,0 +1,304 @@
+/* Copyright 2013-2016 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <skiboot.h>
+#include <device.h>
+#include <string.h>
+
+#include "status_codes.h"
+#include "container.h"
+#include "tss/trustedbootCmds.H"
+#include "tpm.h"
+
+/* For debugging only */
+//#define STB_DEBUG
+
+enum tpm_chip_id {
+ TPM_MASTER,
+ TPM_BACKUP,
+ MAX_TPM_CHIP_ID
+};
+
+static const char *tpm_label[MAX_TPM_CHIP_ID] = {
+ "tpm",
+ "tpm-backup"
+};
+
+static struct list_head tpm_list = LIST_HEAD_INIT(tpm_list);
+
+static struct tpm_chip* tpm_lookup(enum tpm_chip_id id)
+{
+ struct tpm_chip *tpm = NULL;
+
+ list_for_each(&tpm_list, tpm, link) {
+ if (tpm->id == id)
+ return tpm;
+ }
+ return NULL;
+}
+
+#ifdef STB_DEBUG
+static void tpm_print_pcr(struct tpm_chip *tpm, TPM_Pcr pcr, TPM_Alg_Id alg,
+ size_t size)
+{
+ int rc;
+ uint8_t digest[TPM_ALG_SHA256_SIZE];
+
+ memset(digest, 0, size);
+
+ /* print the result of the extend operation */
+ rc = tpmCmdPcrRead(tpm, pcr, alg, digest, size);
+ if (rc) {
+ /**
+ * @fwts-label STBPCRReadFailed¬
+ * @fwts-advice STB_DEBUG should not be enabled
+ * in production. PCR read operation failed.
+ * This TSS implementation is part of hostboot,
+ * but the source code is shared with skiboot.
+ * 1) The hostboot TSS may have been updated.
+ * 2) This may be caused by the short I2C
+ * timeout and can be fixed by increasing the
+ * timeout. Otherwise this indicates a bug in
+ * the TSS or the TPM device driver. Each one
+ * has local debug macros that can help.
+ */
+ prlog(PR_ERR, "STB: tpmCmdPcrRead() failed: "
+ "tpm%d, alg=%x, pcr%d, rc=%d\n", tpm->id,
+ alg, pcr, rc);
+ }
+
+ prlog(PR_NOTICE,"STB: print pcr-read: tpm%d alg=%x pcr%d\n",
+ tpm->id, alg, pcr);
+ stb_print_data(digest, size);
+}
+#endif
+
+struct tpm_chip* tpm_allocate_chip(const struct dt_node *node)
+{
+ int i, rc;
+ uint64_t sml_base;
+ uint32_t sml_size;
+ const struct dt_property *p;
+ struct tpm_chip *tpm;
+
+ tpm = (struct tpm_chip*) malloc(sizeof(struct tpm_chip));
+ assert(tpm);
+
+ /* id */
+ p = dt_find_property(node, "label");
+ if (p) {
+ for (i = 0; i < MAX_TPM_CHIP_ID; i++) {
+ if (!strcasecmp(p->prop, tpm_label[i])) {
+ tpm->id = i;
+ break;
+ }
+ }
+ if (i == MAX_TPM_CHIP_ID) {
+ /**
+ * @fwts-label TPMInvalidLabel
+ * @fwts-advice TPM label value invalid. Hostboot
+ * creates the tpm node and the label property. Check
+ * that the tpm node still have the same design.
+ */
+ prlog(PR_ERR, "STB: invalid tpm label=%s\n", p->prop);
+ goto error;
+
+ } else if (tpm_lookup(i)) {
+ /**
+ * @fwts-label TPMAlreadyRegistered
+ * @fwts-advice TPM node already registered. The same
+ * node is being registered twice or there is a
+ * tpm node duplicate in the device tree
+ */
+ prlog(PR_WARNING, "TPM: tpm%d already registered\n", i);
+ goto error;
+ }
+ }
+
+ tpm->node = (struct dt_node*) node;
+ tpm->enabled = true;
+
+ /**
+ * event log
+ * sml = shared memory log
+ */
+ sml_base = dt_prop_get_u64(node, "linux,sml-base");
+ sml_size = dt_prop_get_u32(node, "linux,sml-size");
+
+ rc = TpmLogMgr_initializeUsingExistingLog(&tpm->logmgr,
+ (uint8_t*) sml_base, sml_size);
+
+ if (rc) {
+ /**
+ * @fwts-label TPMInitEventLogFailed
+ * @fwts-advice Hostboot creates and adds entries to the
+ * event log. The failed init function is part of hostboot,
+ * but the source code is shared with skiboot. If the hostboot
+ * TpmLogMgr code (or friends) has been updated, the changes
+ * need to be applied to skiboot as well.
+ */
+ prlog(PR_ERR, "TPM: eventlog init failed: tpm%d rc=%d",
+ tpm->id, rc);
+ goto error;
+ }
+ return tpm;
+
+error:
+ free(tpm);
+ return NULL;
+}
+
+void tpm_init(void)
+{
+ if (!list_empty(&tpm_list)) {
+ /**
+ * @fwts-label TPMAlreadyInitialized
+ * @fwts-advice TPM already initialized. Check if tpm is being
+ * initialized more than once.
+ */
+ prlog(PR_WARNING, "TPM: tpm device(s) already initialized\n");
+ return;
+ }
+
+ list_head_init(&tpm_list);
+
+ /* tpm drivers supported */
+
+ if (list_empty(&tpm_list)) {
+ /**
+ * @fwts-label TPMNotInitialized
+ * @fwts-advice No TPM chip has been initialized. We may not
+ * have a compatible tpm driver or there is no tpm node in the
+ * device tree with the expected bindings.
+ */
+ prlog(PR_ERR, "TPM: no tpm chip has been initialized\n");
+ }
+}
+
+void tpm_cleanup(void)
+{
+ struct tpm_chip *tpm = NULL;
+
+ tpm = list_pop(&tpm_list, struct tpm_chip, link);
+ while (tpm) {
+
+ /* deallocate memory */
+ if (tpm->dev)
+ free(tpm->dev);
+
+ tpm->driver = NULL;
+ free(tpm);
+
+ tpm = list_pop(&tpm_list, struct tpm_chip, link);
+ }
+ list_head_init(&tpm_list);
+}
+
+void tpm_register_chip(struct tpm_chip *tpm)
+{
+ list_add_tail(&tpm_list, &tpm->link);
+ prlog(PR_NOTICE, "TPM: tpm%d registered: driver=%s elsz=%d\n",
+ tpm->id, tpm->driver->name, tpm->logmgr.logSize);
+}
+
+int tpm_extendl(TPM_Pcr pcr,
+ TPM_Alg_Id alg1, uint8_t* buf1, size_t size1,
+ TPM_Alg_Id alg2, uint8_t* buf2, size_t size2,
+ uint32_t etype, const char* emsg)
+{
+ int rc;
+ TCG_PCR_EVENT2 event;
+ struct tpm_chip *tpm = NULL;
+
+ rc = STB_SUCCESS;
+
+ list_for_each(&tpm_list, tpm, link) {
+
+ if (!tpm->enabled)
+ continue;
+
+ event = TpmLogMgr_genLogEventPcrExtend(pcr, alg1, buf1, size1,
+ alg2, buf2, size2, etype, emsg);
+
+ /* eventlog recording */
+ rc = TpmLogMgr_addEvent(&tpm->logmgr, &event);
+
+ if (rc) {
+ /**
+ * @fwts-label STBAddEventFailed
+ * @fwts-advice TpmLogMgr failed to add a new event to the event
+ * log. TpmLogMgr is part of hostboot, but the source code is
+ * shared with skiboot. 1) The hostboot TpmLogMgr code may have
+ * been updated. 2) Check that max event log size was not
+ * reached and log marshall executed with no error. Enabling the
+ * trace routines in trustedbootUtils.H may help.
+ */
+ prlog(PR_ERR, "TPM: %s -> elog%d FAILED: pcr%d et=%x rc=%d\n",
+ emsg, tpm->id, pcr, etype, rc);
+ rc = STB_EVENTLOG_FAILED;
+ goto error;
+ }
+
+ prlog(PR_DEBUG, "TPM: %s -> elog%d: pcr%d et=%x ls=%d\n",
+ emsg, tpm->id, pcr, etype, tpm->logmgr.logSize);
+
+#ifdef STB_DEBUG
+ tpm_print_pcr(tpm, pcr, alg1, size1);
+ tpm_print_pcr(tpm, pcr, alg2, size2);
+#endif
+ /* extend pcr of both sha1 and sha256 banks*/
+ rc = tpmCmdPcrExtend2Hash(tpm, pcr,
+ alg1, buf1, size1,
+ alg2, buf2, size2);
+
+ if (rc) {
+ /**
+ * @fwts-label STBPCRExtendFailed
+ * @fwts-advice PCR extend operation failed. This TSS
+ * implementation is part of hostboot, but the source code is
+ * shared with skiboot. 1) The hostboot TSS may have been
+ * updated. 2) This may be caused by the short I2C timeout and
+ * can be fixed by increasing the timeout.
+ * Otherwise this indicates a bug in the TSS or the TPM
+ * device driver. Each one has local debug macros that can help.
+ */
+ prlog(PR_ERR, "TPM: %s -> tpm%d FAILED: pcr%d rc=%d\n",
+ emsg, tpm->id, pcr, rc);
+ rc = STB_PCR_EXTEND_FAILED;
+ goto error;
+ }
+
+ prlog(PR_DEBUG, "TPM: %s -> tpm%d: pcr%d\n", emsg, tpm->id, pcr);
+
+#ifdef STB_DEBUG
+ tpm_print_pcr(tpm, pcr, alg1, size1);
+ tpm_print_pcr(tpm, pcr, alg2, size2);
+#endif
+ }
+ return rc;
+
+error:
+ tpm->enabled = false;
+ return rc;
+}
+
+void tpm_add_status_property(void) {
+ struct tpm_chip *tpm;
+ list_for_each(&tpm_list, tpm, link) {
+ dt_add_property_string(tpm->node, "status",
+ tpm->enabled ? "okay" : "disabled");
+ }
+}
diff --git a/libstb/tpm.h b/libstb/tpm.h
index 546458e..0de1a35 100644
--- a/libstb/tpm.h
+++ b/libstb/tpm.h
@@ -23,26 +23,69 @@
#include "tss/trustedTypes.H"
struct tpm_dev {
+
+ /* TPM bus id */
int bus_id;
+
+ /* TPM address in the bus */
int xscom_base;
};
struct tpm_driver {
+
+ /* Driver name */
const char* name;
+
+ /* Transmit the TPM command stored in buf to the tpm device */
int (*transmit)(struct tpm_dev *dev, uint8_t* buf, size_t cmdlen,
size_t *buflen);
};
struct tpm_chip {
+
+ /* TPM chip id */
int id;
+
+ /* Indicates whether or not the device is functional */
bool enabled;
+
+ /* TPM device tree node */
struct dt_node *node;
+
+ /* Event log handler */
struct _TpmLogMgr logmgr;
+
+ /* TPM device handler */
struct tpm_dev *dev;
+
+ /* TPM driver handler */
struct tpm_driver *driver;
+
+
struct list_node link;
};
+/* TSS tweak */
typedef struct tpm_chip TpmTarget;
+/* Allocate and register tpm chip structures for drivers */
+extern struct tpm_chip* tpm_allocate_chip(const struct dt_node *node);
+extern void tpm_register_chip(struct tpm_chip *tpm);
+
+/**
+ * Extend the two measurements (hashes) to the indicated PCR in a single
+ * TPM operation. It also creates an event accordingly and record it into the
+ * event log
+ */
+extern int tpm_extendl(TPM_Pcr pcr,
+ TPM_Alg_Id alg1, uint8_t* buf1, size_t size1,
+ TPM_Alg_Id alg2, uint8_t* buf2, size_t size2,
+ uint32_t etype, const char* emsg);
+
+/* Add status property to the TPM devices */
+extern void tpm_add_status_property(void);
+
+extern void tpm_init(void);
+extern void tpm_cleanup(void);
+
#endif /* __TPM_H */
--
1.9.1
More information about the Skiboot
mailing list