[Skiboot] [PATCH 15/15] Add libstb
Claudio Carvalho
cclaudio at linux.vnet.ibm.com
Thu Aug 11 15:23:57 AEST 2016
Libstb implements 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
the control is passed 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.txt'.
Signed-off-by: Claudio Carvalho <cclaudio at linux.vnet.ibm.com>
---
libstb/Makefile.inc | 2 +-
libstb/status_codes.h | 2 +
libstb/stb.c | 333 ++++++++++++++++++++++++++++++++++++++++++++++++++
libstb/stb.h | 74 +++++++++++
4 files changed, 410 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 d395631..a88ac0d 100644
--- a/libstb/Makefile.inc
+++ b/libstb/Makefile.inc
@@ -4,7 +4,7 @@ LIBSTB_DIR = libstb
SUBDIRS += $(LIBSTB_DIR)
-LIBSTB_SRCS = container.c tpm.c rom.c
+LIBSTB_SRCS = stb.c container.c tpm.c rom.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 106853c..e936e7e 100644
--- a/libstb/status_codes.h
+++ b/libstb/status_codes.h
@@ -23,9 +23,11 @@
#define STB_DRIVER_ERROR -2
/* 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..59279a0
--- /dev/null
+++ b/libstb/stb.c
@@ -0,0 +1,333 @@
+/* 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.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 specs.
+ * 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;
+};
+
+/*
+ * Digests of 0xFFFFFFFF for the EV_SEPARATOR event
+ */
+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)
+{
+ /* FIXME: we want BMC to 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();
+}
+
+static void sb_init(const struct dt_node *node)
+{
+#ifdef STB_FORCE_SECURE_MODE
+ secure_mode = true;
+ prlog(PR_NOTICE, "STB: secure mode enabled (forced!)\n");
+#else
+ secure_mode = dt_has_node_property(node, "secure-enabled", NULL);
+ prlog(PR_NOTICE, "STB: secure mode %s\n",
+ secure_mode ? "enabled" : "disabled");
+#endif
+
+ rom_driver = rom_init(node);
+
+ if (secure_mode && !rom_driver) {
+ prlog(PR_EMERG, "STB: rom driver not found\n");
+ sb_enforce();
+ }
+}
+
+static void tb_init(const struct dt_node *node)
+{
+#ifdef STB_FORCE_TRUSTED_MODE
+ trusted_mode = true;
+ prlog(PR_NOTICE, "STB: trusted mode enabled (forced!)\n");
+#else
+ trusted_mode = dt_has_node_property(node, "trusted-enabled", NULL);
+ prlog(PR_NOTICE, "STB: trusted mode %s\n",
+ trusted_mode ? "enabled" : "disabled");
+#endif
+
+ if (trusted_mode) {
+ tpm_init();
+ }
+}
+
+void stb_init(void)
+{
+ const struct dt_node *ibm_secureboot;
+
+ /**
+ * The ibm,secureboot device tree properties are documented in
+ * 'doc/device-tree/ibm,secureboot.txt'
+ */
+ 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;
+ }
+
+ /* Initialize secure boot and trusted boot */
+ sb_init(ibm_secureboot);
+ tb_init(ibm_secureboot);
+}
+
+int stb_final(void)
+{
+ uint32_t pcr;
+ int rc = STB_SUCCESS;
+
+ 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
+ */
+ for (pcr = 0; pcr < 8; pcr++) {
+ rc = tpm_extendl(pcr, TPM_ALG_SHA1,
+ (uint8_t*) evFF.sha1,
+ TPM_ALG_SHA1_SIZE, TPM_ALG_SHA256,
+ (uint8_t*) evFF.sha256,
+ TPM_ALG_SHA256_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 = STB_SUCCESS;
+ 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)) {
+
+ digestp = (uint8_t*) stb_sw_payload_hash(buf);
+ memcpy(digest, digestp, TPM_ALG_SHA256_SIZE);
+
+ } else if (!secure_mode && stb_is_container(buf)) {
+ rom_driver->sha512(
+ (void*)((uint8_t*)buf + SECURE_BOOT_HEADERS_SIZE),
+ len - SECURE_BOOT_HEADERS_SIZE, digest);
+ } else {
+ rom_driver->sha512(buf, len, digest);
+ }
+
+#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 it */
+ rc = tpm_extendl(resource_map[r].pcr,
+ TPM_ALG_SHA1, digest, TPM_ALG_SHA1_SIZE,
+ TPM_ALG_SHA256, digest, TPM_ALG_SHA256_SIZE,
+ EV_ACTION, resource_map[r].name);
+ if (rc)
+ return rc;
+
+ prlog(PR_NOTICE, "STB: %s%d measured\n", resource_map[r].name, subid);
+
+ return STB_SUCCESS;
+}
+
+int sb_verify(enum resource_id id, uint32_t subid, void *buf)
+{
+ 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 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) {
+ prlog(PR_EMERG, "STB: %s failed: resource %d/%d, container null\n",
+ __func__, id, subid);
+ sb_enforce();
+ }
+
+ /* verify failed */
+ 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 STB_SUCCESS;
+}
diff --git a/libstb/stb.h b/libstb/stb.h
new file mode 100644
index 0000000..478a061
--- /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.txt'
+ *
+ * returns: STB_SUCCESS otherwise the boot process is aborted
+ */
+extern int sb_verify(enum resource_id id, uint32_t subid, void *buf);
+
+
+/**
+ * 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.txt'
+ *
+ * returns: STB_SUCCESS 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