[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