[Skiboot] [PATCH v2 31/31] libstb: add secure and trusted boot interface

Claudio Carvalho cclaudio at linux.vnet.ibm.com
Wed Sep 28 18:01:30 AEST 2016


stb.c implements the libstb API, which is an API for secure and trusted boot:

- stb_init(): read secure mode and trusted mode from device tree and
  load drivers accordingly

- tb_measure(): measure a resource downloaded from PNOR if trusted mode
  is on. That is, an EV_ACTION event is recorded in the event log for
  the mapped PCR and the sha1 and sha256 measurements are extended in
  the mapped PCR.

- sb_verify(): verify the integrity and authenticity of a resource
  downloaded from PNOR if secure mode is on. The boot process is aborted
  if the verification fails.

- stb_final(): this is called to add marks to TPM and event log before
  handover to petitboot kernel. Basically, it records an EV_SEPARATOR
  event in the event log for PCR[0-7], extends the sha1 and sha256
  digests of 0xFFFFFFFF in PCR[0-7], and deallocates the memory allocated
  for secure and trusted boot.

For more information please refer to 'doc/stb.rst'.

Signed-off-by: Claudio Carvalho <cclaudio at linux.vnet.ibm.com>
---
 libstb/Makefile.inc   |   2 +-
 libstb/status_codes.h |   2 +
 libstb/stb.c          | 305 ++++++++++++++++++++++++++++++++++++++++++++++++++
 libstb/stb.h          |  74 ++++++++++++
 4 files changed, 382 insertions(+), 1 deletion(-)
 create mode 100644 libstb/stb.c
 create mode 100644 libstb/stb.h

diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc
index cb6c30e..337b9e4 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -4,7 +4,7 @@ LIBSTB_DIR = libstb
 
 SUBDIRS += $(LIBSTB_DIR)
 
-LIBSTB_SRCS = container.c rom.c tpm_chip.c
+LIBSTB_SRCS = container.c rom.c tpm_chip.c stb.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
index 5fd9757..64f9325 100644
--- a/libstb/status_codes.h
+++ b/libstb/status_codes.h
@@ -23,9 +23,11 @@
 #define STB_DRIVER_ERROR	-3
 
 /* secure boot */
+#define STB_SECURE_MODE_DISABLED	 100
 #define STB_VERIFY_FAILED  		-100
 
 /* trusted boot */
+#define STB_TRUSTED_MODE_DISABLED	 200
 #define STB_EVENTLOG_FAILED	-200
 #define STB_PCR_EXTEND_FAILED	-201
 
diff --git a/libstb/stb.c b/libstb/stb.c
new file mode 100644
index 0000000..6e1dcef
--- /dev/null
+++ b/libstb/stb.c
@@ -0,0 +1,305 @@
+/* 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 <platform.h>
+#include <string.h>
+#include <stdio.h>
+#include "stb.h"
+#include "status_codes.h"
+#include "container.h"
+#include "rom.h"
+#include "tpm_chip.h"
+
+/* For debugging only */
+//#define STB_DEBUG
+//#define STB_FORCE_SECURE_MODE
+//#define STB_FORCE_TRUSTED_MODE
+
+static bool secure_mode = false;
+static bool trusted_mode = false;
+
+static struct rom_driver_ops *rom_driver = NULL;
+
+#define MAX_RESOURCE_NAME	15
+
+/*
+ * This maps a PCR for each resource we can measure. The PCR number is
+ * mapped according to the TCG PC Client Platform Firmware Profile
+ * specification, Revision 00.21
+ * Only resources included in this whitelist can be measured.
+ */
+static struct {
+
+	/* PNOR partition id */
+	enum resource_id id;
+
+	/* PCR mapping for the resource id */
+	TPM_Pcr pcr;
+
+	/* Resource name */
+	const char name[MAX_RESOURCE_NAME+1];
+
+} resource_map[] = {
+	{ RESOURCE_ID_KERNEL, PCR_4, "BOOTKERNEL" },
+	{ RESOURCE_ID_CAPP,   PCR_2, "CAPP"},
+};
+
+struct event_hash {
+	const unsigned char *sha1;
+	const unsigned char *sha256;
+};
+
+/*
+ * Event Separator - digest of 0xFFFFFFFF
+ */
+static struct event_hash evFF = {
+	.sha1   = "\xd9\xbe\x65\x24\xa5\xf5\x04\x7d\xb5\x86"
+		  "\x68\x13\xac\xf3\x27\x78\x92\xa7\xa3\x0a",
+
+	.sha256 = "\xad\x95\x13\x1b\xc0\xb7\x99\xc0\xb1\xaf"
+		  "\x47\x7f\xb1\x4f\xcf\x26\xa6\xa9\xf7\x60"
+		  "\x79\xe4\x8b\xf0\x90\xac\xb7\xe8\x36\x7b"
+		  "\xfd\x0e"
+};
+
+static int stb_resource_lookup(enum resource_id id)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(resource_map); i++)
+		if (resource_map[i].id == id)
+			return i;
+	return -1;
+}
+
+static void sb_enforce(void)
+{
+	/*
+	 * TODO: Ideally, the BMC should decide what security policy to apply
+	 * (power off, reboot, switch PNOR sides, etc). We may need
+	 * to provide extra info to BMC other than just abort.
+	 * Terminate Immediate Attention ? (TI)
+	 */
+	prlog(PR_EMERG, "STB: Secure mode enforced, aborting.\n");
+	abort();
+}
+
+void stb_init(void)
+{
+	const struct dt_node *ibm_secureboot;
+	/*
+	 * The ibm,secureboot device tree properties are documented in
+	 * 'doc/device-tree/ibm,secureboot.rst'
+	 */
+	ibm_secureboot = dt_find_by_path(dt_root, "/ibm,secureboot");
+	if (ibm_secureboot == NULL) {
+		prlog(PR_NOTICE,"STB: secure and trusted boot not supported\n");
+		return;
+	}
+
+#ifdef STB_FORCE_SECURE_MODE
+	secure_mode = true;
+	prlog(PR_NOTICE, "STB: secure mode on (forced!)\n");
+#else
+	secure_mode = dt_has_node_property(ibm_secureboot, "secure-enabled",
+					   NULL);
+	prlog(PR_NOTICE, "STB: secure mode %s\n",
+	      secure_mode ? "on" : "off");
+#endif
+
+#ifdef STB_FORCE_TRUSTED_MODE
+	trusted_mode = true;
+	prlog(PR_NOTICE, "STB: trusted mode on (forced!)\n");
+#else
+	trusted_mode = dt_has_node_property(ibm_secureboot, "trusted-enabled",
+					    NULL);
+	prlog(PR_NOTICE, "STB: trusted mode %s\n",
+	      trusted_mode ? "on" : "off");
+#endif
+
+	if (!secure_mode && !trusted_mode)
+		return;
+	rom_driver = rom_init(ibm_secureboot);
+	if (secure_mode && !rom_driver) {
+		prlog(PR_EMERG, "STB: compatible romcode driver not found\n");
+		sb_enforce();
+	}
+	if (trusted_mode)
+		tpm_init();
+}
+
+int stb_final(void)
+{
+	uint32_t pcr;
+	int rc = 0;
+
+	if (trusted_mode) {
+#ifdef STB_DEBUG
+		prlog(PR_NOTICE, "STB: evFF.sha1:\n");
+		stb_print_data((uint8_t*) evFF.sha1, TPM_ALG_SHA1_SIZE);
+		prlog(PR_NOTICE, "STB: evFF.sha256:\n");
+		stb_print_data((uint8_t*) evFF.sha256, TPM_ALG_SHA256_SIZE);
+#endif
+		/*
+		 * We are done. Extending the digest of 0xFFFFFFFF
+		 * in PCR[0-7], and recording an EV_SEPARATOR event in
+		 * event log as defined in the TCG Platform Firmware Profile
+		 * specification, Revision 00.21
+		 */
+		for (pcr = 0; pcr < 8; pcr++) {
+			rc = tpm_extendl(pcr, TPM_ALG_SHA256,
+					(uint8_t*) evFF.sha256,
+					TPM_ALG_SHA256_SIZE, TPM_ALG_SHA1,
+					(uint8_t*) evFF.sha1,
+					TPM_ALG_SHA1_SIZE, EV_SEPARATOR,
+					"Skiboot Boot");
+			if (rc)
+				return rc;
+			prlog(PR_NOTICE, "STB: 0xFFFFFFFF measured "
+			      "to pcr%d\n", pcr);
+		}
+		tpm_add_status_property();
+	}
+	if (rom_driver) {
+		rom_driver->cleanup();
+		rom_driver = NULL;
+	}
+	tpm_cleanup();
+	secure_mode = false;
+	trusted_mode = false;
+	return rc;
+}
+
+int tb_measure(enum resource_id id, uint32_t subid, void *buf, size_t len)
+{
+	int rc, r;
+	uint8_t digest[SHA512_DIGEST_LENGTH];
+	uint8_t* digestp;
+
+	rc = 0;
+	digestp = NULL;
+	if (!trusted_mode) {
+		prlog(PR_NOTICE, "STB: %s skipped resource %d, "
+		      "trusted_mode=0\n", __func__, id);
+		return STB_TRUSTED_MODE_DISABLED;
+	}
+	r = stb_resource_lookup(id);
+	if (r == -1) {
+		/**
+		 * @fwts-label STBMeasureResourceNotMapped
+		 * @fwts-advice The resource is not registered in the resource_map[]
+		 * array, but it should be otherwise the resource cannot be
+		 * measured if trusted mode is on.
+		 */
+		prlog(PR_ERR, "STB: %s failed, resource %d not mapped\n",
+		      __func__, id);
+		return STB_ARG_ERROR;
+	}
+	if (!buf) {
+		/**
+		 * @fwts-label STBNullResourceReceived
+		 * @fwts-advice Null resource passed to tb_measure. This has
+		 * come from the resource load framework and likely indicates a
+		 * bug in the framework.
+		 */
+		prlog(PR_ERR, "STB: %s failed: resource %s%d, buf null\n",
+		      __func__, resource_map[r].name, subid);
+		return STB_ARG_ERROR;
+	}
+	memset(digest, 0, SHA512_DIGEST_LENGTH);
+	/*
+	 * In secure mode we can use the sw-payload-hash from the container
+	 * header to measure the container payload. Otherwise we must calculate
+	 * the hash of the container payload (if it's a container) or the image
+	 * (if it's not a container)
+	 */
+	if (secure_mode && stb_is_container(buf, len)) {
+		digestp = (uint8_t*) stb_sw_payload_hash(buf, len);
+		memcpy(digest, digestp, TPM_ALG_SHA256_SIZE);
+	} else if (!secure_mode && stb_is_container(buf, len)) {
+		rom_driver->sha512(
+			      (void*)((uint8_t*)buf + SECURE_BOOT_HEADERS_SIZE),
+			      len - SECURE_BOOT_HEADERS_SIZE, digest);
+		prlog(PR_INFO, "STB: %s sha512 hash re-calculated\n",
+		      resource_map[r].name);
+	} else {
+		rom_driver->sha512(buf, len, digest);
+		prlog(PR_INFO, "STB: %s sha512 hash calculated\n",
+		      resource_map[r].name);
+	}
+#ifdef STB_DEBUG
+	/* print the payload/image hash */
+	prlog(PR_NOTICE, "STB: %s hash:\n", resource_map[r].name);
+	stb_print_data(digest, TPM_ALG_SHA256_SIZE);
+#endif
+	/*
+	 * Measure the resource. Since the ROM code doesn't provide a sha1 hash
+	 * algorithm, the sha512 hash is truncated to match the size required
+	 * by each PCR bank.
+	 */
+	rc = tpm_extendl(resource_map[r].pcr,
+			 TPM_ALG_SHA256, digest, TPM_ALG_SHA256_SIZE,
+			 TPM_ALG_SHA1,   digest, TPM_ALG_SHA1_SIZE,
+			 EV_ACTION, resource_map[r].name);
+	if (rc)
+		return rc;
+	prlog(PR_NOTICE, "STB: %s%d measured to pcr%d\n", resource_map[r].name,
+	      subid, resource_map[r].pcr);
+	return 0;
+}
+
+int sb_verify(enum resource_id id, uint32_t subid, void *buf, size_t len)
+{
+	int r;
+	const char *name = NULL;
+
+	if (!secure_mode) {
+		prlog(PR_NOTICE, "STB: %s skipped resource %d, "
+		      "secure_mode=0\n", __func__, id);
+		return STB_SECURE_MODE_DISABLED;
+	}
+	r = stb_resource_lookup(id);
+	if (r == -1)
+		/**
+		 * @fwts-label STBVerifyResourceNotMapped
+		 * @fwts-advice Unregistered resources can be verified, but not
+		 * measured. The resource should be registered in the
+		 * resource_map[] array, otherwise the resource cannot be
+		 * measured if trusted mode is on.
+		 */
+		prlog(PR_WARNING, "STB: verifying the non-expected "
+		      "resource %d/%d\n", id, subid);
+	else
+		name = resource_map[r].name;
+	if (!rom_driver || !rom_driver->verify) {
+		prlog(PR_EMERG, "STB: secure boot not initialized\n");
+		sb_enforce();
+	}
+	if (!buf || len < SECURE_BOOT_HEADERS_SIZE) {
+		prlog(PR_EMERG, "STB: %s arg error: id %d/%d, buf %p, len %zd\n",
+		      __func__, id, subid, buf, len);
+		sb_enforce();
+	}
+	if (rom_driver->verify(buf)) {
+		prlog(PR_EMERG, "STB: %s failed: resource %s%d, "
+		      "eyecatcher 0x%016llx\n", __func__, name, subid,
+		      *((uint64_t*)buf));
+		sb_enforce();
+	}
+	prlog(PR_NOTICE, "STB: %s%d verified\n", name, subid);
+	return 0;
+}
diff --git a/libstb/stb.h b/libstb/stb.h
new file mode 100644
index 0000000..cd60148
--- /dev/null
+++ b/libstb/stb.h
@@ -0,0 +1,74 @@
+/* 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_H
+#define __STB_H
+
+/**
+ * This reads secure mode and trusted mode from device tree and
+ * loads drivers accordingly.
+ */
+extern void stb_init(void);
+
+/**
+ * As defined in the TCG Platform Firmware Profile specification, the
+ * digest of 0xFFFFFFFF or 0x00000000  must be extended in PCR[0-7] and
+ * an EV_SEPARATOR event must be recorded in the event log for PCR[0-7]
+ * prior to the first invocation of the first Ready to Boot call.
+ *
+ * This function should be called before the control is passed to petitboot
+ * kernel in order to do the proper PCR extend and event log recording as
+ * defined above. This function also deallocates the memory allocated for secure
+ * and trusted boot.
+ */
+extern int stb_final(void);
+
+/**
+ * sb_verify - verify a resource
+ * @id   : resource id
+ * @subid: subpartition id
+ * @buf  : data to be verified
+ *
+ * This verifies the integrity and authenticity of a resource downloaded from
+ * PNOR if secure mode is on. The verification is done by the
+ * verification code flashed in the secure ROM.
+ *
+ * For more information refer to 'doc/stb.rst'
+ *
+ * returns: 0 otherwise the boot process is aborted
+ */
+extern int sb_verify(enum resource_id id, uint32_t subid, void *buf, size_t len);
+
+
+/**
+ * tb_measure - measure a resource
+ * @id    : resource id
+ * @subid : subpartition id
+ * @buf   : data to be measured
+ * @len   : buf length
+ *
+ * This measures a resource downloaded from PNOR if trusted mode is on. That is,
+ * an EV_ACTION event is recorded in the event log for the mapped PCR, and the
+ * the sha1 and sha256 measurements are extended in the mapped PCR.
+ *
+ * For more information please refer to 'doc/stb.rst'
+ *
+ * returns: 0 or an error as defined in status_codes.h
+ */
+extern int tb_measure(enum resource_id id, uint32_t subid, void *buf,
+		      size_t len);
+
+#endif /* __STB_H */
-- 
1.9.1



More information about the Skiboot mailing list