From patchwork Mon Jan 20 02:36:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1225599 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 481G8q32XTz9sR1 for ; Mon, 20 Jan 2020 13:39:39 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 481G8q2JbmzDqZm for ; Mon, 20 Jan 2020 13:39:39 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 481G6674KmzDqXw for ; Mon, 20 Jan 2020 13:37:18 +1100 (AEDT) Received: from pps.filterd (m0098409.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.42/8.16.0.42) with SMTP id 00K2WsKT020274 for ; Sun, 19 Jan 2020 21:37:16 -0500 Received: from e06smtp03.uk.ibm.com (e06smtp03.uk.ibm.com [195.75.94.99]) by mx0a-001b2d01.pphosted.com with ESMTP id 2xmfyx8q8b-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sun, 19 Jan 2020 21:37:16 -0500 Received: from localhost by e06smtp03.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 20 Jan 2020 02:37:14 -0000 Received: from b06cxnps4076.portsmouth.uk.ibm.com (9.149.109.198) by e06smtp03.uk.ibm.com (192.168.101.133) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Mon, 20 Jan 2020 02:37:11 -0000 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id 00K2b94O44105744 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 20 Jan 2020 02:37:09 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 975764C052; Mon, 20 Jan 2020 02:37:09 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id DF3A34C044; Mon, 20 Jan 2020 02:37:08 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.232]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Mon, 20 Jan 2020 02:37:08 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sun, 19 Jan 2020 20:36:54 -0600 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20200120023700.5373-1-erichte@linux.ibm.com> References: <20200120023700.5373-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 20012002-0012-0000-0000-0000037EDFB3 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 20012002-0013-0000-0000-000021BB1B04 Message-Id: <20200120023700.5373-7-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:6.0.138, 18.0.572 definitions=2020-01-19_08:2020-01-16, 2020-01-19 signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 adultscore=0 bulkscore=0 impostorscore=0 lowpriorityscore=0 suspectscore=1 mlxlogscore=999 clxscore=1015 mlxscore=0 spamscore=0 phishscore=0 priorityscore=1501 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.12.0-1910280000 definitions=main-2001200020 Subject: [Skiboot] [PATCH v2 06/12] secvar_tpmnv: add high-level tpm nv index abstraction for secvar X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: nayna@linux.ibm.com Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Multiple components, like the storage driver or backend driver, may need to store information in the one TPM NV index assigned for secure boot. This abstraction provides a method for these components to share the index space without stomping on each other's data, and without them needing to understand anything about the other. This is probably an overengineered solution to the problem, but the intent is to keep the drivers as independent from one another as possible. NOTE: This version of the patch now includes the ability to switch between a "Fake TPMNV" mode simulated using PNOR, and use of an actual TPM. The simulated mode exists for unit test and review purposes on machines without a TPM. It is not intended for production use. Signed-off-by: Eric Richter --- libstb/secvar/Makefile.inc | 3 +- libstb/secvar/secvar_tpmnv.c | 265 +++++++++++++++++++++++++++++++++++ libstb/secvar/secvar_tpmnv.h | 16 +++ 3 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 libstb/secvar/secvar_tpmnv.c create mode 100644 libstb/secvar/secvar_tpmnv.h diff --git a/libstb/secvar/Makefile.inc b/libstb/secvar/Makefile.inc index f4b196d9..1d68941e 100644 --- a/libstb/secvar/Makefile.inc +++ b/libstb/secvar/Makefile.inc @@ -8,8 +8,7 @@ SUBDIRS += $(SECVAR_DIR) include $(SECVAR_DIR)/storage/Makefile.inc include $(SECVAR_DIR)/backend/Makefile.inc -SECVAR_SRCS = secvar_main.c secvar_util.c secvar_devtree.c -SECVAR_SRCS = secvar_main.c secvar_util.c secvar_devtree.c secvar_api.c +SECVAR_SRCS = secvar_main.c secvar_util.c secvar_devtree.c secvar_api.c secvar_tpmnv.c SECVAR_OBJS = $(SECVAR_SRCS:%.c=%.o) SECVAR = $(SECVAR_DIR)/built-in.a diff --git a/libstb/secvar/secvar_tpmnv.c b/libstb/secvar/secvar_tpmnv.c new file mode 100644 index 00000000..2944ece4 --- /dev/null +++ b/libstb/secvar/secvar_tpmnv.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: Apache-2.0 +/* Copyright 2019 IBM Corp. */ +#ifndef pr_fmt +#define pr_fmt(fmt) "SECVAR_TPMNV: " fmt +#endif + +#include +#include +#include +#include +#include "secvar_tpmnv.h" + +#define TPM_SECVAR_NV_INDEX 0x01c10191 +#define TPM_SECVAR_MAGIC_NUM 0x53544e56 + +struct tpm_nv_id { + uint32_t id; + uint32_t size; + char data[0]; +} __packed; + +struct tpm_nv { + uint32_t magic_num; + uint32_t version; + struct tpm_nv_id vars[0]; +} __packed; + +int tpm_ready = 0; +int tpm_error = 0; +int tpm_first_init = 0; +struct tpm_nv *tpm_image; +size_t tpm_nv_size = 0; + +// Values set by a platform to enable TPMNV simulation mode +// NOT INTENDED FOR PRODUCTION USE +int tpm_fake_nv = 0; // Use fake NV mode using pnor +uint64_t tpm_fake_nv_offset = 0; // Offset into SECBOOT pnor to use +uint64_t tpm_fake_nv_max_size = 0; + +static int TSS_Fake_Read(uint32_t nvIndex, void *buf, size_t bufsize, uint64_t off) +{ + (void) nvIndex; + (void) off; + return platform.secboot_read(buf, tpm_fake_nv_offset, bufsize); +} + +static int TSS_Fake_Write(uint32_t nvIndex, void *buf, size_t bufsize, uint64_t off) +{ + (void) nvIndex; + (void) off; + return platform.secboot_write(tpm_fake_nv_offset, buf, bufsize); +} + +static int TSS_Fake_Define_Space(uint32_t nvIndex, const char hierarchy, + const char hierarchy_authorization, + uint16_t dataSize) +{ + (void) nvIndex; + (void) hierarchy; + (void) hierarchy_authorization; + (void) dataSize; + return 0; +} + +struct tpmnv_ops_s { + int (*tss_nv_read)(uint32_t, void*, size_t, uint64_t); + int (*tss_nv_write)(uint32_t, void*, size_t, uint64_t); + int (*tss_nv_define_space)(uint32_t, const char, const char, uint16_t); +}; + +struct tpmnv_ops_s TSS_tpmnv_ops = { + .tss_nv_read = TSS_NV_Read, + .tss_nv_write = TSS_NV_Write, + .tss_nv_define_space = TSS_NV_Define_Space, +}; + +struct tpmnv_ops_s Fake_tpmnv_ops = { + .tss_nv_read = TSS_Fake_Read, + .tss_nv_write = TSS_Fake_Write, + .tss_nv_define_space = TSS_Fake_Define_Space, +}; + +struct tpmnv_ops_s *tpmnv_ops = &TSS_tpmnv_ops; + +// This function should be replaced with logic that performs the initial +// TPM NV Index definition, and any first-write logic +static int secvar_tpmnv_format(void) +{ + int rc; + + memset(tpm_image, 0, sizeof(tpm_nv_size)); + + // TODO: Determine the proper auths + rc = tpmnv_ops->tss_nv_define_space(TPM_SECVAR_NV_INDEX, 'p', 'p', tpm_nv_size); + if (rc) { + prlog(PR_INFO, "Failed to define NV index, rc = %d\n", rc); + return rc; + } + + tpm_image->magic_num = TPM_SECVAR_MAGIC_NUM; + tpm_image->version = 1; + + tpm_first_init = 1; + + return tpmnv_ops->tss_nv_write(TPM_SECVAR_NV_INDEX, tpm_image, tpm_nv_size, 0); +} + + +static int secvar_tpmnv_init(void) +{ + int rc; + + if (tpm_ready) + return OPAL_SUCCESS; + if (tpm_error) + return OPAL_HARDWARE; + + prlog(PR_INFO, "Initializing TPMNV space...\n"); + + // Check here if TPM NV Index is defined + // if not, call secvar_tpmnv_format() here + + // Using the minimum defined by the spec for now + // This value should probably be determined by tss_get_capatibility + tpm_nv_size = 1024; + + tpm_image = malloc(tpm_nv_size); + if (!tpm_image) { + tpm_error = 1; + return OPAL_NO_MEM; + } + + if (tpm_fake_nv) { + prlog(PR_INFO, "Enabling fake TPM NV mode\n"); + tpmnv_ops = &Fake_tpmnv_ops; + } + + prlog(PR_INFO, "Reading in from TPM NV...\n"); + rc = tpmnv_ops->tss_nv_read(TPM_SECVAR_NV_INDEX, tpm_image, tpm_nv_size, 0); + if (rc) { + prlog(PR_INFO, "Failed to read from NV index, rc = %d\n", rc); + tpm_error = 1; + return OPAL_HARDWARE; + } + + if (tpm_image->magic_num != TPM_SECVAR_MAGIC_NUM) { + prlog(PR_INFO, "Magic num mismatch, reformatting NV space...\n"); + rc = secvar_tpmnv_format(); + if (rc) { + prlog(PR_INFO, "Failed to format tpmnv space, rc = %d\n", rc); + tpm_error = 1; + return OPAL_HARDWARE; + } + } + prlog(PR_INFO, "TPMNV space initialized successfully\n"); + tpm_ready = 1; + + return OPAL_SUCCESS; +} + + +static struct tpm_nv_id *find_tpmnv_id(uint32_t id) +{ + struct tpm_nv_id *tmp; + char *cur, *end; + + cur = (char *) tpm_image->vars; + end = ((char *) tpm_image) + tpm_nv_size; + while (cur < end) { + tmp = (struct tpm_nv_id *) cur; + if (tmp->id == 0) + return NULL; + if (tmp->id == id) + return tmp; + cur += sizeof(struct tpm_nv_id) + tmp->size; + } + + return NULL; +} + + +// "Allocate" space within the secvar tpm +int secvar_tpmnv_alloc(uint32_t id, int32_t size) +{ + struct tpm_nv_id *tmp; + char *cur; + char *end; + + if (secvar_tpmnv_init()) + return OPAL_RESOURCE; + + cur = (char *) tpm_image->vars; + end = ((char *) tpm_image) + tpm_nv_size; + while (cur < end) { + tmp = (struct tpm_nv_id *) cur; + if (tmp->id == 0) + goto allocate; + if (tmp->id == id) + return OPAL_SUCCESS; // Already allocated + + cur += sizeof(struct tpm_nv_id) + tmp->size; + } + // We ran out of space... + return OPAL_EMPTY; + +allocate: + tmp->id = id; + + // Special case: size of -1 gives remaining space + if (size == -1) + tmp->size = end - tmp->data; + else + tmp->size = size; + + return OPAL_SUCCESS; +} + + +int secvar_tpmnv_read(uint32_t id, void *buf, size_t size, size_t off) +{ + struct tpm_nv_id *var; + + if (secvar_tpmnv_init()) + return OPAL_RESOURCE; + + var = find_tpmnv_id(id); + if (!var) + return OPAL_EMPTY; + + size = MIN(size, var->size); + memcpy(buf, var->data + off, size); + + return 0; +} + + +int secvar_tpmnv_write(uint32_t id, void *buf, size_t size, size_t off) +{ + struct tpm_nv_id *var; + + if (secvar_tpmnv_init()) + return OPAL_RESOURCE; + + var = find_tpmnv_id(id); + if (!var) + return OPAL_EMPTY; + + size = MIN(size, var->size); + memcpy(var->data, buf + off, size); + + return tpmnv_ops->tss_nv_write(TPM_SECVAR_NV_INDEX, tpm_image, tpm_nv_size, 0); +} + +int secvar_tpmnv_size(uint32_t id) +{ + struct tpm_nv_id *var; + + if (secvar_tpmnv_init()) + return OPAL_RESOURCE; + + var = find_tpmnv_id(id); + if (!var) + return 0; + return var->size; +} diff --git a/libstb/secvar/secvar_tpmnv.h b/libstb/secvar/secvar_tpmnv.h new file mode 100644 index 00000000..697a52c2 --- /dev/null +++ b/libstb/secvar/secvar_tpmnv.h @@ -0,0 +1,16 @@ +#ifndef _SECVAR_TPMNV_H_ +#define _SECVAR_TPMNV_H_ +#include + +extern int tpm_first_init; + +int secvar_tpmnv_alloc(uint32_t id, int32_t size); +int secvar_tpmnv_read(uint32_t id, void *buf, size_t size, size_t off); +int secvar_tpmnv_write(uint32_t id, void *buf, size_t size, size_t off); +int secvar_tpmnv_size(uint32_t id); + +extern int tpm_fake_nv; +extern uint64_t tpm_fake_nv_offset; + +#endif +