[Skiboot] [PATCH 15/15] Add libstb

Stewart Smith stewart at linux.vnet.ibm.com
Tue Sep 20 18:39:11 AEST 2016


Claudio Carvalho <cclaudio at linux.vnet.ibm.com> writes:
> 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"},
> +};

I wonder if this should be up in the platform code? There's also
RESOURCE_ID_INITRAMFS, currently only used on FSP platforms.

Any thoughts on what would happen on a FSP platform with the additional
LID(s) we need loading? (vpd and hostservices).

> +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);

If we're not enforcing, would we not end up saying "Verified" and then
returning success? That seems pretty counter-intuitive for a sb_verify()
function that should probably fail if things fail to verify.

In fact... the abort()/assert()/sound_the_alarm() should probably come
in the caller to sb_verify() ?

> 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);

size parameter?

> +/**
> + * 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 */

-- 
Stewart Smith
OPAL Architect, IBM.



More information about the Skiboot mailing list