summaryrefslogtreecommitdiffstats
path: root/libstb/stb.c
diff options
context:
space:
mode:
authorClaudio Carvalho <cclaudio@linux.vnet.ibm.com>2016-09-28 05:01:30 -0300
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-10-10 15:29:36 +1100
commitd15dd47d4a0f766282a034641621529e58ae8b25 (patch)
tree659ebfdd0e1e6c187b85f88827d468c751e23fc6 /libstb/stb.c
parent3837c6f0cf4cffb5de874413eed755c0c698b076 (diff)
downloadtalos-skiboot-d15dd47d4a0f766282a034641621529e58ae8b25.tar.gz
talos-skiboot-d15dd47d4a0f766282a034641621529e58ae8b25.zip
libstb: add secure and trusted boot interface
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@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'libstb/stb.c')
-rw-r--r--libstb/stb.c305
1 files changed, 305 insertions, 0 deletions
diff --git a/libstb/stb.c b/libstb/stb.c
new file mode 100644
index 00000000..6e1dcefd
--- /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;
+}
OpenPOWER on IntegriCloud