From patchwork Tue Jun 25 22:02:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122327 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45YKtn2Yfpz9s3l for ; Wed, 26 Jun 2019 08:04:01 +1000 (AEST) 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 45YKtl5Xt1zDqT8 for ; Wed, 26 Jun 2019 08:03:59 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; 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 (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 45YKs13FMVzDqNn for ; Wed, 26 Jun 2019 08:02:29 +1000 (AEST) Received: from pps.filterd (m0098420.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM207Q002427 for ; Tue, 25 Jun 2019 18:02:25 -0400 Received: from e06smtp03.uk.ibm.com (e06smtp03.uk.ibm.com [195.75.94.99]) by mx0b-001b2d01.pphosted.com with ESMTP id 2tbs0uxx42-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:25 -0400 Received: from localhost by e06smtp03.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:23 +0100 Received: from b06avi18878370.portsmouth.uk.ibm.com (9.149.26.194) 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) Tue, 25 Jun 2019 23:02:21 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18878370.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2JZI36438510 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:19 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D0C4411C058; Tue, 25 Jun 2019 22:02:19 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id ED39B11C050; Tue, 25 Jun 2019 22:02:18 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:18 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:07 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-0012-0000-0000-0000032C5F3C X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-0013-0000-0000-00002165965C Message-Id: <20190625220215.27134-2-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [PATCH v2 1/9] core/flash.c: add SECBOOT read and write support 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" From: Claudio Carvalho In secure boot enabled systems, the petitboot linux kernel verifies the OS kernel against x509 certificates that are wrapped in secure variables controlled by OPAL. These secure variables are stored in the PNOR SECBOOT partition, as well as the updates submitted for them using userspace tools. This patch adds read and write support to the PNOR SECBOOT partition in a similar fashion to that of NVRAM, so that OPAL can handle the secure variables. V2: - lowered logging level for secboot_probe CC: Jeremy Kerr Signed-off-by: Claudio Carvalho Signed-off-by: Eric Richter --- core/flash.c | 130 +++++++++++++++++++++++++++++++++++++++++++++ include/platform.h | 4 ++ 2 files changed, 134 insertions(+) diff --git a/core/flash.c b/core/flash.c index 3da6d4a4..ada086b6 100644 --- a/core/flash.c +++ b/core/flash.c @@ -65,6 +65,10 @@ static struct lock flash_lock; static struct flash *nvram_flash; static u32 nvram_offset, nvram_size; +/* secboot-on-flash support */ +static struct flash *secboot_flash; +static u32 secboot_offset, secboot_size; + bool flash_reserve(void) { bool rc = false; @@ -88,6 +92,91 @@ void flash_release(void) unlock(&flash_lock); } +static int flash_secboot_info(uint32_t *total_size) +{ + int rc; + + lock(&flash_lock); + if (!secboot_flash) { + rc = OPAL_HARDWARE; + } else if (secboot_flash->busy) { + rc = OPAL_BUSY; + } else { + *total_size = secboot_size; + rc = OPAL_SUCCESS; + } + unlock(&flash_lock); + + return rc; +} + +static int flash_secboot_read(void *dst, uint32_t src, uint32_t len) +{ + int rc; + + if (!try_lock(&flash_lock)) + return OPAL_BUSY; + + if (!secboot_flash) { + rc = OPAL_HARDWARE; + goto out; + } + + if (secboot_flash->busy) { + rc = OPAL_BUSY; + goto out; + } + + if ((src + len) > secboot_size) { + prerror("FLASH_SECBOOT: read out of bound (0x%x,0x%x)\n", + src, len); + rc = OPAL_PARAMETER; + goto out; + } + + secboot_flash->busy = true; + unlock(&flash_lock); + + rc = blocklevel_read(secboot_flash->bl, secboot_offset + src, dst, len); + + lock(&flash_lock); + secboot_flash->busy = false; +out: + unlock(&flash_lock); + return rc; +} + +static int flash_secboot_write(uint32_t dst, void *src, uint32_t len) +{ + int rc; + + if (!try_lock(&flash_lock)) + return OPAL_BUSY; + + if (secboot_flash->busy) { + rc = OPAL_BUSY; + goto out; + } + + if ((dst + len) > secboot_size) { + prerror("FLASH_SECBOOT: write out of bound (0x%x,0x%x)\n", + dst, len); + rc = OPAL_PARAMETER; + goto out; + } + + secboot_flash->busy = true; + unlock(&flash_lock); + + rc = blocklevel_write(secboot_flash->bl, secboot_offset + dst, src, len); + + lock(&flash_lock); + secboot_flash->busy = false; +out: + unlock(&flash_lock); + return rc; +} + static int flash_nvram_info(uint32_t *total_size) { int rc; @@ -177,6 +266,46 @@ out: return rc; } + +static int flash_secboot_probe(struct flash *flash, struct ffs_handle *ffs) +{ + uint32_t start, size, part; + bool ecc; + int rc; + + prlog(PR_DEBUG, "FLASH: probing for SECBOOT\n"); + + rc = ffs_lookup_part(ffs, "SECBOOT", &part); + if (rc) { + prlog(PR_WARNING, "FLASH: no SECBOOT partition found\n"); + return OPAL_HARDWARE; + } + + rc = ffs_part_info(ffs, part, NULL, + &start, &size, NULL, &ecc); + if (rc) { + /** + * @fwts-label SECBOOTNoPartition + * @fwts-advice OPAL could not find an SECBOOT partition + * on the system flash. Check that the system flash + * has a valid partition table, and that the firmware + * build process has added a SECBOOT partition. + */ + prlog(PR_ERR, "FLASH: Can't parse ffs info for SECBOOT\n"); + return OPAL_HARDWARE; + } + + secboot_flash = flash; + secboot_offset = start; + secboot_size = ecc ? ecc_buffer_size_minus_ecc(size) : size; + + platform.secboot_info = flash_secboot_info; + platform.secboot_read = flash_secboot_read; + platform.secboot_write = flash_secboot_write; + + return 0; +} + static int flash_nvram_probe(struct flash *flash, struct ffs_handle *ffs) { uint32_t start, size, part; @@ -327,6 +456,7 @@ static void setup_system_flash(struct flash *flash, struct dt_node *node, prlog(PR_INFO, "FLASH: registered system flash device %s\n", name); flash_nvram_probe(flash, ffs); + flash_secboot_probe(flash, ffs); } static int num_flashes(void) diff --git a/include/platform.h b/include/platform.h index 4f8627a3..b29966f9 100644 --- a/include/platform.h +++ b/include/platform.h @@ -182,6 +182,10 @@ struct platform { uint32_t len); int (*nvram_write)(uint32_t dst, void *src, uint32_t len); + int (*secboot_info)(uint32_t *total_size); + int (*secboot_read)(void *dst, uint32_t src, uint32_t len); + int (*secboot_write)(uint32_t dst, void *src, uint32_t len); + /* * OCC timeout. This return how long we should wait for the OCC * before timing out. This lets us use a high value on larger FSP From patchwork Tue Jun 25 22:02:08 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122325 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 45YKt14n4Xz9s3l for ; Wed, 26 Jun 2019 08:03:21 +1000 (AEST) 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 45YKt130l1zDqNn for ; Wed, 26 Jun 2019 08:03:21 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) 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 45YKs15BfYzDqQJ for ; Wed, 26 Jun 2019 08:02:29 +1000 (AEST) Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM1WkZ122139 for ; Tue, 25 Jun 2019 18:02:27 -0400 Received: from e06smtp01.uk.ibm.com (e06smtp01.uk.ibm.com [195.75.94.97]) by mx0a-001b2d01.pphosted.com with ESMTP id 2tbs7jpph5-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:26 -0400 Received: from localhost by e06smtp01.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:24 +0100 Received: from b06avi18626390.portsmouth.uk.ibm.com (9.149.26.192) by e06smtp01.uk.ibm.com (192.168.101.131) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 25 Jun 2019 23:02:22 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2B6m28836324 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:11 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B4CF911C050; Tue, 25 Jun 2019 22:02:20 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 1803911C054; Tue, 25 Jun 2019 22:02:20 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:19 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:08 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-4275-0000-0000-0000034639B4 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-4276-0000-0000-000038563C4C Message-Id: <20190625220215.27134-3-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=4 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [PATCH v2 2/9] libstb/secvar: add secure variable internal abstraction 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" This patch implements a platform-independent abstraction for storing and retrieving secure variables, as required for host OS secure boot. This serves as the main entry point for initializing the in-memory cache of the secure variables, which also kicks off any platform-specific logic that may be needed. This patch also provides core functions for the subsequent patches in this series to utilize. The base secure variable implementation makes use of two types of drivers, to be selected by the platform: "storage" drivers, and "backend" drivers. The storage driver implements the hooks required to write the secure variables to some form of non-volatile memory, and load the variables on boot. The backend driver defines how the variables should be interpreted, and processed. Secure variables are stored in two types of banks, the "variable" bank and the "update" bank. Variables that have been validated and processed are stored in the variable bank. This bank is effectively read-only after the base secvar initialization. Any proposed variable updates are instead stored in the update bank. During secvar initialization, the backend driver processes variables from the update bank, and if valid, adds the new variable to the variable bank. NOTE: The name "backend" is subject to change. It operates more like a scheme, so unless a better name comes along, it will likely change to "scheme" or "schema" in the future. V2: - added secvar device tree node as child of ibm,secureboot - added version and compatible properties to backend driver struct - added secvar_ready flag for the API to detect if secvar initialized successfully - moved pre-process step to after initial variable load - moved flags field from secvar struct to secvar node Signed-off-by: Eric Richter --- include/platform.h | 1 + include/secvar.h | 47 ++++++++++++ libstb/Makefile.inc | 3 +- libstb/secvar/Makefile.inc | 14 ++++ libstb/secvar/backend/Makefile.inc | 11 +++ libstb/secvar/secvar.h | 72 ++++++++++++++++++ libstb/secvar/secvar_main.c | 117 +++++++++++++++++++++++++++++ libstb/secvar/secvar_util.c | 88 ++++++++++++++++++++++ libstb/secvar/storage/Makefile.inc | 11 +++ 9 files changed, 363 insertions(+), 1 deletion(-) create mode 100644 include/secvar.h create mode 100644 libstb/secvar/Makefile.inc create mode 100644 libstb/secvar/backend/Makefile.inc create mode 100644 libstb/secvar/secvar.h create mode 100644 libstb/secvar/secvar_main.c create mode 100644 libstb/secvar/secvar_util.c create mode 100644 libstb/secvar/storage/Makefile.inc diff --git a/include/platform.h b/include/platform.h index b29966f9..97e93c2a 100644 --- a/include/platform.h +++ b/include/platform.h @@ -186,6 +186,7 @@ struct platform { int (*secboot_read)(void *dst, uint32_t src, uint32_t len); int (*secboot_write)(uint32_t dst, void *src, uint32_t len); + int (*secvar_init)(void); /* * OCC timeout. This return how long we should wait for the OCC * before timing out. This lets us use a high value on larger FSP diff --git a/include/secvar.h b/include/secvar.h new file mode 100644 index 00000000..b5354f58 --- /dev/null +++ b/include/secvar.h @@ -0,0 +1,47 @@ +/* Copyright 2019 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 _SECVAR_DRIVER_ +#define _SECVAR_DRIVER_ + +#include + +struct secvar; + +struct secvar_storage_driver { + int (*load_bank)(struct list_head *bank, int section); + int (*write_bank)(struct list_head *bank, int section); + int (*store_init)(void); +}; + +struct secvar_backend_version { + int major; + int minor; +} __packed; + +struct secvar_backend_driver { + int (*pre_process)(void); // Perform any pre-processing stuff (e.g. determine secure boot state) + int (*process)(void); // Process all updates + int (*post_process)(void); // Perform any post-processing stuff (e.g. derive/update variables) + int (*validate)(struct secvar *var); // Validate a single variable, return boolean + char compatible[32]; // String to use for compatible in secvar node + uint64_t version; // Minor version for tracking additive backend features +}; + + +int secvar_main(struct secvar_storage_driver, struct secvar_backend_driver); + +#endif diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc index 6d54c5cd..d3f68496 100644 --- a/libstb/Makefile.inc +++ b/libstb/Makefile.inc @@ -8,11 +8,12 @@ LIBSTB_SRCS = container.c tpm_chip.c cvc.c secureboot.c trustedboot.c LIBSTB_OBJS = $(LIBSTB_SRCS:%.c=%.o) LIBSTB = $(LIBSTB_DIR)/built-in.a +include $(SRC)/$(LIBSTB_DIR)/secvar/Makefile.inc include $(SRC)/$(LIBSTB_DIR)/mbedtls/Makefile.inc include $(SRC)/$(LIBSTB_DIR)/drivers/Makefile.inc include $(SRC)/$(LIBSTB_DIR)/tss/Makefile.inc -$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(MBEDTLS) +$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(SECVAR) $(MBEDTLS) libstb/create-container: libstb/create-container.c libstb/container-utils.c $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) \ diff --git a/libstb/secvar/Makefile.inc b/libstb/secvar/Makefile.inc new file mode 100644 index 00000000..75870910 --- /dev/null +++ b/libstb/secvar/Makefile.inc @@ -0,0 +1,14 @@ +# -*-Makefile-*- + +SECVAR_DIR = libstb/secvar + +SUBDIRS += $(SECVAR_DIR) + +include $(SECVAR_DIR)/storage/Makefile.inc +include $(SECVAR_DIR)/backend/Makefile.inc + +SECVAR_SRCS = secvar_main.c secvar_util.c +SECVAR_OBJS = $(SECVAR_SRCS:%.c=%.o) +SECVAR = $(SECVAR_DIR)/built-in.a + +$(SECVAR): $(SECVAR_OBJS:%=$(SECVAR_DIR)/%) $(SECVAR_STORAGE) $(SECVAR_BACKEND) diff --git a/libstb/secvar/backend/Makefile.inc b/libstb/secvar/backend/Makefile.inc new file mode 100644 index 00000000..7a7ca1f7 --- /dev/null +++ b/libstb/secvar/backend/Makefile.inc @@ -0,0 +1,11 @@ +# -*-Makefile-*- + +SECVAR_BACKEND_DIR = libstb/secvar/backend + +SUBDIRS += $(SECVAR_BACKEND_DIR) + +SECVAR_BACKEND_SRCS = +SECVAR_BACKEND_OBJS = $(SECVAR_BACKEND_SRCS:%.c=%.o) +SECVAR_BACKEND = $(SECVAR_BACKEND_DIR)/built-in.a + +$(SECVAR_BACKEND): $(SECVAR_BACKEND_OBJS:%=$(SECVAR_BACKEND_DIR)/%) diff --git a/libstb/secvar/secvar.h b/libstb/secvar/secvar.h new file mode 100644 index 00000000..eb4f4558 --- /dev/null +++ b/libstb/secvar/secvar.h @@ -0,0 +1,72 @@ +/* Copyright 2019 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 _SECVAR_H_ +#define _SECVAR_H_ + +#include +#include +#include + +#define SECVAR_MAX_KEY_LEN 1024 +#define SECVAR_MAX_METADATA_SIZE 1024 +#define SECVAR_MAX_DATA_SIZE 2048 + +enum { + SECVAR_VARIABLE_BANK, + SECVAR_UPDATE_BANK, +}; + + +struct secvar_node { + struct list_node link; + struct secvar *var; + uint64_t flags; // Flag for how *var should be stored/allocated +}; + +#define SECVAR_FLAG_VOLATILE 0x1 // Instructs storage driver to ignore variable on writes +#define SECVAR_FLAG_DYN_ALLOC 0x2 // Set when variable needs to be freed +#define SECVAR_FLAG_SECURE_STORAGE 0x4 // Hint for storage driver to select storage location + +struct secvar { + char key[SECVAR_MAX_KEY_LEN]; + char metadata[SECVAR_MAX_METADATA_SIZE]; + char data[SECVAR_MAX_DATA_SIZE]; + uint64_t key_len; + uint64_t metadata_size; + uint64_t data_size; +}; + + +enum { + BACKEND_NONE = 0, + BACKEND_TC_COMPAT_V1, +}; + +extern struct list_head variable_bank; +extern struct list_head update_bank; +extern int secvar_enabled; +extern int secvar_ready; +extern struct secvar_storage_driver secvar_storage; +extern struct secvar_backend_driver secvar_backend; + +// Helper functions +void clear_bank_list(struct list_head *bank); +struct secvar_node *find_secvar(char *key, uint64_t key_len, struct list_head *bank); +int is_key_empty(char *key, uint64_t key_len); +int list_length(struct list_head *bank); + +#endif diff --git a/libstb/secvar/secvar_main.c b/libstb/secvar/secvar_main.c new file mode 100644 index 00000000..86895419 --- /dev/null +++ b/libstb/secvar/secvar_main.c @@ -0,0 +1,117 @@ +/* Copyright 2019 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 pr_fmt +#define pr_fmt(fmt) "SECVAR: " fmt +#endif + +#include +#include +#include +#include +#include +#include "secvar.h" + +struct list_head variable_bank; +struct list_head update_bank; + +int secvar_enabled = 0; // Set to 1 if secvar is supported +int secvar_ready = 0; // Set to 1 when base secvar inits correctly + +// To be filled in by platform.secvar_init +struct secvar_storage_driver secvar_storage = {0}; +struct secvar_backend_driver secvar_backend = {0}; + +// TODO: handle this better +struct dt_node *secvar_node; + +static void secvar_init_devnode(const char *status) +{ + struct dt_node *sb_root; + + sb_root = dt_find_by_path(dt_root, "/ibm,secureboot/"); + + secvar_node = dt_new(sb_root, "secvar"); + + dt_add_property_string(secvar_node, "status", status); + dt_add_property_string(secvar_node, "compatible", secvar_backend.compatible); + dt_add_property_u64(secvar_node, "version", secvar_backend.version); +} + +int secvar_main(struct secvar_storage_driver storage_driver, + struct secvar_backend_driver backend_driver) +{ + int rc = OPAL_UNSUPPORTED; + + secvar_storage = storage_driver; + secvar_backend = backend_driver; + + secvar_enabled = 1; + + list_head_init(&variable_bank); + list_head_init(&update_bank); + + rc = secvar_storage.store_init(); + if (rc) + goto fail; + + + rc = secvar_storage.load_bank(&variable_bank, SECVAR_VARIABLE_BANK); + if (rc) + goto fail; + + rc = secvar_storage.load_bank(&update_bank, SECVAR_UPDATE_BANK); + if (rc) + goto fail; + + // At this point, base secvar is functional. Rest is up to the backend + secvar_ready = 1; + secvar_init_devnode("okay"); + + if (secvar_backend.pre_process) + rc = secvar_backend.pre_process(); + + // Process is required, error if it doesn't exist + if (!secvar_backend.process) + goto out; + + rc = secvar_backend.process(); + if (rc == OPAL_SUCCESS) { + dt_add_property(secvar_node, "update-status", &rc, sizeof(rc)); + // TODO: Should being unable to write be a secvar/status = "fail"? + rc = secvar_storage.write_bank(&variable_bank, SECVAR_VARIABLE_BANK); + if (rc) + goto out; + + rc = secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK); + if (rc) + goto out; + } + else + dt_add_property(secvar_node, "update-status", &rc, sizeof(rc)); + + if (secvar_backend.post_process) + rc = secvar_backend.post_process(); + if (rc) + goto out; + + return OPAL_SUCCESS; +fail: + secvar_init_devnode("fail"); +out: + printf("Secure Variables Status %04x\n", rc); + return rc; +} diff --git a/libstb/secvar/secvar_util.c b/libstb/secvar/secvar_util.c new file mode 100644 index 00000000..18fcf041 --- /dev/null +++ b/libstb/secvar/secvar_util.c @@ -0,0 +1,88 @@ +/* Copyright 2019 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 pr_fmt +#define pr_fmt(fmt) "SECVAR: " fmt +#endif + +#include +#include +#include +#include +#include "secvar.h" + +void clear_bank_list(struct list_head *bank) +{ + struct secvar_node *node, *next; + + if (!bank) + return; + + list_for_each_safe(bank, node, next, link) { + list_del(&node->link); + + if (!node->var) { + free(node); + continue; + } + + if (node->flags & SECVAR_FLAG_DYN_ALLOC) { + free(node->var); + } + + free(node); + } +} + +struct secvar_node *find_secvar(char *key, uint64_t key_len, struct list_head *bank) +{ + struct secvar_node *node = NULL; + + list_for_each(bank, node, link) { + // Prevent matching shorter key subsets / bail early + if (key_len != node->var->key_len) + continue; + if (!memcmp(key, node->var->key, key_len)) { + return node; + } + } + + return NULL; +} + + +int is_key_empty(char *key, uint64_t key_len) +{ + int i; + for (i = 0; i < key_len; i++) { + if (key[i] != 0) + return 0; + } + + return 1; +} + +int list_length(struct list_head *bank) +{ + int ret = 0; + struct secvar_node *node; + + list_for_each(bank, node, link) { + ret++; + } + + return ret; +} diff --git a/libstb/secvar/storage/Makefile.inc b/libstb/secvar/storage/Makefile.inc new file mode 100644 index 00000000..c107736e --- /dev/null +++ b/libstb/secvar/storage/Makefile.inc @@ -0,0 +1,11 @@ +# -*-Makefile-*- + +SECVAR_STORAGE_DIR = libstb/secvar/storage + +SUBDIRS += $(SECVAR_STORAGE_DIR) + +SECVAR_STORAGE_SRCS = +SECVAR_STORAGE_OBJS = $(SECVAR_STORAGE_SRCS:%.c=%.o) +SECVAR_STORAGE = $(SECVAR_STORAGE_DIR)/built-in.a + +$(SECVAR_STORAGE): $(SECVAR_STORAGE_OBJS:%=$(SECVAR_STORAGE_DIR)/%) From patchwork Tue Jun 25 22:02:09 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122330 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 45YKvG2S5Bz9s3l for ; Wed, 26 Jun 2019 08:04:26 +1000 (AEST) 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 45YKvG1NqnzDqXR for ; Wed, 26 Jun 2019 08:04:26 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) 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 45YKs15nW7zDqSw for ; Wed, 26 Jun 2019 08:02:29 +1000 (AEST) Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM1Wka122139 for ; Tue, 25 Jun 2019 18:02:27 -0400 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0a-001b2d01.pphosted.com with ESMTP id 2tbs7jpphd-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:27 -0400 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:24 +0100 Received: from b06cxnps3075.portsmouth.uk.ibm.com (9.149.109.195) by e06smtp04.uk.ibm.com (192.168.101.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 25 Jun 2019 23:02:23 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2Led62783502 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:21 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8E8D311C04C; Tue, 25 Jun 2019 22:02:21 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id EF7A811C050; Tue, 25 Jun 2019 22:02:20 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:20 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:09 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-0016-0000-0000-0000028C54D1 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-0017-0000-0000-000032E9C969 Message-Id: <20190625220215.27134-4-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [PATCH v2 3/9] secureboot: initialize secure variables if supported by the platform 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" Platforms determine whether or not they support secure boot by implementing a specific hook. After firmware secureboot has been initialized, if the platform hook has been implemented, we increase the secureboot version to "ibm,secureboot-v3" indicating secure variables are supported. The secure variables are then initialized. Signed-off-by: Eric Richter --- libstb/secureboot.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libstb/secureboot.c b/libstb/secureboot.c index 1578f52e..d8ed61b8 100644 --- a/libstb/secureboot.c +++ b/libstb/secureboot.c @@ -75,6 +75,24 @@ bool secureboot_is_compatible(struct dt_node *node, int *version, const char **c return false; } +static int update_secureboot_compatible(void) +{ + struct dt_node *sb_node; + struct dt_property *sb_compat; + + sb_node = dt_find_by_path(dt_root, "/ibm,secureboot/"); + if (!sb_node) + return 1; + + sb_compat = (struct dt_property*) dt_find_property(sb_node, "compatible"); + if (!sb_compat) + return 2; + + strcpy(sb_compat->prop, "ibm,secureboot-v3"); + + return 0; +} + void secureboot_init(void) { struct dt_node *node; @@ -170,6 +188,11 @@ void secureboot_init(void) if (cvc_init()) secureboot_enforce(); + if (platform.secvar_init) { + if (update_secureboot_compatible()) + secureboot_enforce(); + platform.secvar_init(); + } secure_init = true; } From patchwork Tue Jun 25 22:02:10 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122332 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 45YKvf0HrHz9s3C for ; Wed, 26 Jun 2019 08:04:46 +1000 (AEST) 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 45YKvd6FDszDqV8 for ; Wed, 26 Jun 2019 08:04:45 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) 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 45YKs22Q9SzDqB3 for ; Wed, 26 Jun 2019 08:02:30 +1000 (AEST) Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM1XJU122208 for ; Tue, 25 Jun 2019 18:02:28 -0400 Received: from e06smtp01.uk.ibm.com (e06smtp01.uk.ibm.com [195.75.94.97]) by mx0a-001b2d01.pphosted.com with ESMTP id 2tbs7jppj1-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:28 -0400 Received: from localhost by e06smtp01.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:26 +0100 Received: from b06cxnps4074.portsmouth.uk.ibm.com (9.149.109.196) by e06smtp01.uk.ibm.com (192.168.101.131) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 25 Jun 2019 23:02:24 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps4074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2MJO41680964 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:22 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 84B1B11C05E; Tue, 25 Jun 2019 22:02:22 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D2E3911C04A; Tue, 25 Jun 2019 22:02:21 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:21 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:10 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-4275-0000-0000-0000034639B6 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-4276-0000-0000-000038563C4E Message-Id: <20190625220215.27134-5-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [PATCH v2 4/9] libstb/secvar: add secvar api implementation 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" This patch provides the OPAL runtime service frontend for the host OS to retrieve secure variables, and append new ones for processing on the next reboot. These calls operate on the internal abstraction or utilize the platform-provided driver hooks, and therefore this API should not need to be updated to support changes in storage or backend drivers. Included are the following functions: - opal_secvar_get() - opal_secvar_get_size() - opal_secvar_get_next() - opal_secvar_enqueue_update() opal_secvar_get() retrieves the data blob and metadata blob associated with a given key. Either the data blob or the metadata blob are optional. This runtime service only operates on the variable bank. opal_secvar_get_size() returns the size of the data and/or metadata blob associated with a given key. This is a convenience function to retrieve only the size values, and ignore any data blob. This runtime service only operates on the variable bank. opal_secvar_get_next() can be used to iterate through the list of variable keys in the variable bank. Supplying an empty key (or zero key length) returns the key of the first variable in the variable bank. Supplying a valid key returns the key of the next variable in sequence. opal_secvar_enqueue_update() provides a method for the host OS to submit a new variable for processing on next boot, by appending it to the update bank. As this does not affect the variable bank, appending a variable via this runtime service will not affect the output of the previous set of functions. The update queue is only processed during secvar initialization. V2: - removed opal_secvar_backend, replaced by DT node - removed unnecessary argument casting - all calls return OPAL_RESOURCE if secvar failed to init Signed-off-by: Eric Richter --- ccan/list/list.h | 38 +++++++ include/opal-api.h | 6 +- libstb/secvar/Makefile.inc | 2 +- libstb/secvar/secvar_api.c | 215 +++++++++++++++++++++++++++++++++++++ 4 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 libstb/secvar/secvar_api.c diff --git a/ccan/list/list.h b/ccan/list/list.h index 7cd3a83e..fdeddeb4 100644 --- a/ccan/list/list.h +++ b/ccan/list/list.h @@ -523,4 +523,42 @@ static inline struct list_node *list_node_from_off_(void *ptr, size_t off) (container_off_var(var, member) + \ check_type(var->member, struct list_node)) + +#if HAVE_TYPEOF +#define list_typeof(var) typeof(var) +#else +#define list_typeof(var) void * +#endif + + +/* Returns member, or NULL if at end of list. */ +static inline void *list_entry_or_null(const struct list_head *h, + const struct list_node *n, + size_t off) +{ + if (n == &h->n) + return NULL; + return (char *)n - off; +} + +/** + * list_next - get the next entry in a list + * @h: the list_head + * @i: a pointer to an entry in the list. + * @member: the list_node member of the structure + * + * If @i was the last entry in the list, returns NULL. + * + * Example: + * struct child *second; + * second = list_next(&parent->children, first, list); + * if (!second) + * printf("No second child!\n"); + */ +#define list_next(h, i, member) \ + ((list_typeof(i))list_entry_or_null(list_debug(h), \ + (i)->member.next, \ + list_off_var_((i), member))) + + #endif /* CCAN_LIST_H */ diff --git a/include/opal-api.h b/include/opal-api.h index 0b0ae196..df1803df 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -232,7 +232,11 @@ #define OPAL_XIVE_GET_VP_STATE 170 /* Get NVT state */ #define OPAL_NPU_MEM_ALLOC 171 #define OPAL_NPU_MEM_RELEASE 172 -#define OPAL_LAST 172 +#define OPAL_SECVAR_GET 173 +#define OPAL_SECVAR_GET_SIZE 174 +#define OPAL_SECVAR_GET_NEXT 175 +#define OPAL_SECVAR_ENQUEUE_UPDATE 176 +#define OPAL_LAST 176 #define QUIESCE_HOLD 1 /* Spin all calls at entry */ #define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */ diff --git a/libstb/secvar/Makefile.inc b/libstb/secvar/Makefile.inc index 75870910..50316b48 100644 --- a/libstb/secvar/Makefile.inc +++ b/libstb/secvar/Makefile.inc @@ -7,7 +7,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_SRCS = secvar_main.c secvar_util.c secvar_api.c SECVAR_OBJS = $(SECVAR_SRCS:%.c=%.o) SECVAR = $(SECVAR_DIR)/built-in.a diff --git a/libstb/secvar/secvar_api.c b/libstb/secvar/secvar_api.c new file mode 100644 index 00000000..36c27c15 --- /dev/null +++ b/libstb/secvar/secvar_api.c @@ -0,0 +1,215 @@ +/* Copyright 2019 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 pr_fmt +#define pr_fmt(fmt) "SECVAR_API: " fmt +#endif + +#include +#include "secvar.h" + + +static int64_t opal_secvar_get(char *key, uint64_t key_len, void *metadata, uint64_t *metadata_size, void *data, uint64_t *data_size) +{ + struct secvar_node *node; + int64_t rc = OPAL_SUCCESS; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key) + return OPAL_PARAMETER; + if (key_len == 0) + return OPAL_PARAMETER; + // buffer and size must both be valid OR both must be NULL + if ((!!metadata) != (!!metadata_size)) + return OPAL_PARAMETER; + if ((!!data) != (!!data_size)) + return OPAL_PARAMETER; + + node = find_secvar(key, key_len, &variable_bank); + + if (!node) + return OPAL_EMPTY; // Variable not found, bail early + + if (metadata) { + if (*metadata_size < node->var->metadata_size) + rc = OPAL_PARTIAL; + else + memcpy(metadata, node->var->metadata, node->var->metadata_size); + *metadata_size = node->var->metadata_size; + } + + if (data) { + if (*data_size < node->var->data_size) + rc = OPAL_PARTIAL; + else + memcpy(data, node->var->data, node->var->data_size); + *data_size = node->var->data_size; + } + + return rc; +} +opal_call(OPAL_SECVAR_GET, opal_secvar_get, 6); + + +static int64_t opal_secvar_get_size(char *key, uint64_t key_len, uint64_t *metadata_size, uint64_t *data_size) +{ + struct secvar_node *node; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key) + return OPAL_PARAMETER; + if (key_len == 0) + return OPAL_PARAMETER; + if ((!metadata_size) && (!data_size)) // Should return at least one of them + return OPAL_PARAMETER; + + node = find_secvar(key, key_len, &variable_bank); + if (!node) + return OPAL_EMPTY; + + if (metadata_size) + *metadata_size = node->var->metadata_size; + if (data_size) + *data_size = node->var->data_size; + + return OPAL_SUCCESS; +} +opal_call(OPAL_SECVAR_GET_SIZE, opal_secvar_get_size, 4); + + + +static int64_t opal_secvar_get_next(char *key, uint64_t *key_len, uint64_t key_size) +{ + struct secvar_node *node; + int i = 0; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key_len) + return OPAL_PARAMETER; + if (key_size == 0) + return OPAL_PARAMETER; + if (*key_len > SECVAR_MAX_KEY_LEN) + return OPAL_PARAMETER; + if (*key_len > key_size) + return OPAL_PARAMETER; + if (!key) + return OPAL_PARAMETER; + + // This should fall through if *key_len == 0, otherwise check for empty + for (i = 0; i < *key_len; i++) { + // If the buffer is not empty, we assume it is a key + if (key[i] != 0) { + goto have_key; + } + } + + node = list_top(&variable_bank, struct secvar_node, link); + goto send_var; + +have_key: + // Non-empty string + node = find_secvar(key, *key_len, &variable_bank); + if (!node) + return OPAL_PARAMETER; + + node = list_next(&variable_bank, node, link); + +send_var: + if (!node) + return OPAL_EMPTY; + + if (key_size < node->var->key_len) { + *key_len = node->var->key_len; + return OPAL_PARTIAL; + } + + *key_len = node->var->key_len; + memcpy(key, node->var->key, node->var->key_len); + + return OPAL_SUCCESS; +} +opal_call(OPAL_SECVAR_GET_NEXT, opal_secvar_get_next, 3); + +static int64_t opal_secvar_enqueue_update(char *key, uint64_t key_len, void *metadata, uint64_t metadata_size, void *data, uint64_t data_size) +{ + struct secvar_node *node; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key) + return OPAL_PARAMETER; + if (key_len == 0) + return OPAL_PARAMETER; + if (key_len > SECVAR_MAX_KEY_LEN) + return OPAL_PARAMETER; + if (metadata && (metadata_size > SECVAR_MAX_METADATA_SIZE)) + return OPAL_PARAMETER; + if (!data) + return OPAL_PARAMETER; + if (data_size == 0) + return OPAL_PARAMETER; // we don't support variable deletion this way + if (data_size > SECVAR_MAX_DATA_SIZE) + return OPAL_PARAMETER; + + // Key should not be empty + if (is_key_empty(key, key_len)) { + return OPAL_PARAMETER; + } + + node = zalloc(sizeof(struct secvar_node)); + if (!node) + return OPAL_NO_MEM; + + node->var = zalloc(sizeof(struct secvar)); + if (!node->var) + return OPAL_NO_MEM; + node->flags = SECVAR_FLAG_DYN_ALLOC; + + memcpy(node->var->key, key, key_len); + node->var->key_len = key_len; + memcpy(node->var->data, data, data_size); + node->var->data_size = data_size; + + if (metadata) { + memcpy(node->var->metadata, metadata, metadata_size); + node->var->metadata_size = metadata_size; + } + else { + memset(node->var->metadata, 0x00, SECVAR_MAX_METADATA_SIZE); + node->var->metadata_size = 0; + } + + list_add_tail(&update_bank, &node->link); + + if (!secvar_storage.write_bank) + return OPAL_HARDWARE; + + secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK); + + return OPAL_SUCCESS; +} +opal_call(OPAL_SECVAR_ENQUEUE_UPDATE, opal_secvar_enqueue_update, 6); From patchwork Tue Jun 25 22:02:11 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122334 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (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 45YKw10PDLz9s4V for ; Wed, 26 Jun 2019 08:05:05 +1000 (AEST) 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 45YKw04fwMzDqT8 for ; Wed, 26 Jun 2019 08:05:03 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; 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 (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 45YKs354c7zDqB3 for ; Wed, 26 Jun 2019 08:02:31 +1000 (AEST) Received: from pps.filterd (m0098419.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM1ZMK103460 for ; Tue, 25 Jun 2019 18:02:28 -0400 Received: from e06smtp02.uk.ibm.com (e06smtp02.uk.ibm.com [195.75.94.98]) by mx0b-001b2d01.pphosted.com with ESMTP id 2tbud81aku-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:28 -0400 Received: from localhost by e06smtp02.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:26 +0100 Received: from b06cxnps3074.portsmouth.uk.ibm.com (9.149.109.194) by e06smtp02.uk.ibm.com (192.168.101.132) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 25 Jun 2019 23:02:25 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2NUU32505964 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:23 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9051C11C054; Tue, 25 Jun 2019 22:02:23 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C971611C04C; Tue, 25 Jun 2019 22:02:22 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:22 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:11 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-0008-0000-0000-000002F6FE12 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-0009-0000-0000-000022643033 Message-Id: <20190625220215.27134-6-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [PATCH v2 5/9] doc: add opal secure variable documentation 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" This patch contains the work-in-progress documentation for the secure variable design in OPAL. Future revisions of this patch set will (hopefully) add new pieces of documentation here. Signed-off-by: Eric Richter --- doc/device-tree/ibm,secureboot.rst | 10 ++ doc/device-tree/secvar.rst | 40 +++++ doc/opal-api/opal-secvar.rst | 267 +++++++++++++++++++++++++++++ 3 files changed, 317 insertions(+) create mode 100644 doc/device-tree/secvar.rst create mode 100644 doc/opal-api/opal-secvar.rst diff --git a/doc/device-tree/ibm,secureboot.rst b/doc/device-tree/ibm,secureboot.rst index 42c4ed7d..b4729a9d 100644 --- a/doc/device-tree/ibm,secureboot.rst +++ b/doc/device-tree/ibm,secureboot.rst @@ -21,6 +21,13 @@ Required properties It described by the ibm,cvc child node. + ibm,secureboot-v3 : The container-verification-code + is stored in a reserved memory. + It described by the ibm,cvc child + node. Secure variables are + supported. `secvar` node should + be created. + secure-enabled: this property exists when the firmware stack is booting in secure mode (hardware secure boot jumper asserted). @@ -33,6 +40,9 @@ Required properties hw-key-hash-size: hw-key-hash size + secvar: this node is created if the platform supports secure + variables. Contains information about the current + secvar status, see 'secvar.rst'. Obsolete properties ------------------- diff --git a/doc/device-tree/secvar.rst b/doc/device-tree/secvar.rst new file mode 100644 index 00000000..5bfe932e --- /dev/null +++ b/doc/device-tree/secvar.rst @@ -0,0 +1,40 @@ +.. _device-tree/ibm,secureboot/secvar: + +secvar +====== + +The ``secvar`` node provides secure variable information for the secure +boot of the target OS. + +Required properties +------------------- + +.. code-block:: none + + compatible: this property is set based on the current secure + variable scheme as set by the platform. + + version: this property contains the minor version number + for the selected secure variable compatible. This + value should only be incremented for additive + features. + + status: set to "fail" if the secure variables could not + be initialized, validated, or some other + catastrophic failure. + + update-status: contains the return code of the update queue + process run during initialization. Signifies if + updates were processed or not, and if there was + an error. + +Example +------- + +.. code-block:: dts + + secvar { + compatible = "ibm,edk2-compat-v1"; + version = <0x1>; + status = "okay"; + }; diff --git a/doc/opal-api/opal-secvar.rst b/doc/opal-api/opal-secvar.rst new file mode 100644 index 00000000..46aad0af --- /dev/null +++ b/doc/opal-api/opal-secvar.rst @@ -0,0 +1,267 @@ +OPAL Secure Variable API +======================== + +Overview +-------- + +In order to support host OS secure boot on POWER systems, the platform needs +some form of tamper-resistant persistant storage for authorized public keys. +Furthermore, these keys must be retrieveable by the host kernel, and new +keys must be able to be submitted. + +OPAL exposes an abstracted "variable" API, in which these keys can be stored +and retrieved. At a high level, ``opal_secvar_get`` retrieves a specific +variable corresponding to a particular key. ``opal_secvar_get_next`` can be +used to iterate through the keys of the stored variables. +``opal_secvar_enqueue_update`` can be used to submit a new variable for +processing on next boot. + +OPAL_SECVAR_GET +=============== +:: + + #define OPAL_SECVAR_GET 173 + +``OPAL_SECVAR_GET`` call retrieves a data blob associated with the supplied +key. + + +Parameters +---------- +:: + + char *key + uint64_t key_len + void *metadata + uint64_t *metadata_size + void *data + uint64_t *data_size + +``key`` + a buffer used to associate with the variable data. May +be any encoding, but must not be all zeroes + +``key_len`` + size of the key buffer in bytes + +``metadata`` + return buffer to store any additional data specific to the +active variable scheme. This may not be used for certain schemes. +May be set to NULL to ignore returning the buffer only if +``metadata_size`` is also NULL. + +``metadata_size`` + reference to the size of the ``metadata`` buffer. OPAL sets this if +the buffer size is insufficient for the requested variable + +``data`` + return buffer to store the data blob of the requested variable if +a match was found. May be set to NULL to ignore returning the buffer +only if ``data_size`` is also NULL. + +``data_size`` + reference to the size of the ``data`` buffer. OPAL sets this if +the buffer size is insufficient for the requested variable + + +Return Values +------------- + +``OPAL_SUCCESS`` + the requested metadata and/or data blobs were copied successfully + +``OPAL_PARAMETER`` + ``key`` is NULL. ``key_len`` is zero. buffer and size pointers for +metadata or data retrieval are not both NULL or non-NULL + +``OPAL_EMPTY`` + no variable with the supplied ``key`` was found + +``OPAL_PARTIAL`` + the buffer size provided in either or both of ``metadata_size`` or +``data_size`` was insufficient. Insufficient value is set to the minimum +required size + +``OPAL_UNSUPPORTED`` + secure variables are not supported by the platform + +``OPAL_RESOURCE`` + secure variables are supported, but did not initialize properly + +OPAL_SECVAR_GET_SIZE +==================== +:: + + #define OPAL_SECVAR_GET_SIZE 174 + +``OPAL_SECVAR_GET_SIZE`` call retrieves the sizes of the metadata and/or +data blobs associated with a given key. Convenience function to use +as it returns the same size information as an insufficient +``opal_secvar_get`` call. + + +Parameters +---------- +:: + + char *key + uint64_t key_len + uint64_t *metadata_size + uint64_t *data_size + +``key`` + a buffer used to associate with the variable data. May +be any encoding, but must not be all zeroes + +``key_len`` + size of the key buffer in bytes + +``metadata_size`` + reference to store the size of the metadata buffer associated with +the ``key`` if found. May be NULL to ignore + +``data_size`` + reference to store the size of the data buffer associated with +the ``key`` if found. May be NULL to ignore + + +Return Values +------------- + +``OPAL_SUCCESS`` + the requested ``key`` exists, and the requested size values were +copied successfully + +``OPAL_PARAMETER`` + ``key`` is NULL. ``key_len`` is zero. Both size pointers are NULL + +``OPAL_EMPTY`` + no variable with the supplied ``key`` was found + +``OPAL_UNSUPPORTED`` + secure variables are not supported by the platform + +``OPAL_RESOURCE`` + secure variables are supported, but did not initialize properly + +OPAL_SECVAR_GET_NEXT +==================== +:: + + #define OPAL_SECVAR_GET_NEXT 175 + +``OPAL_SECVAR_GET_NEXT`` returns the key of the next variable in the secure +variable bank in sequence. + +Parameters +---------- +:: + + char *key + uint64_t *key_len + uint64_t key_size + + +``key`` + name of the previous variable or empty. The key of the next +variable in sequence will be copied to ``key``. If passed as empty, +returns the first variable in the bank + +``key_len`` + length in bytes of the key in the ``key`` buffer. OPAL sets +this to the length in bytes of the next variable in sequence + +``key_size`` + maximum size of the ``key`` buffer. The next key will not be +copied if this value is less than the length of the next key + + +Return Values +------------- + +``OPAL_SUCCESS`` + the key and length of the next variable in sequence was copied +successfully + +``OPAL_PARAMETER`` + ``key`` or ``key_length`` is NULL. ``key_size`` is zero. +``key_length`` is impossibly large. No variable with the associated +``key`` was found + +``OPAL_EMPTY`` + end of list reached + +``OPAL_PARTIAL`` + the size specified in ``key_size`` is insufficient for the next +variable's key length. ``key_length`` is set to the next variable's +length, but ``key`` is untouched + +``OPAL_UNSUPPORTED`` + secure variables are not supported by the platform + +``OPAL_RESOURCE`` + secure variables are supported, but did not initialize properly + +OPAL_SECVAR_ENQUEUE_UPDATE +========================== +:: + + #define OPAL_SECVAR_ENQUEUE_UPDATE 176 + +``OPAL_SECVAR_ENQUEUE`` call appends the supplied variable data to the +queue for processing on next boot. + +Parameters +---------- +:: + + char *key + uint64_t key_len + void *metadata + uint64_t metadata_size + void *data + uint64_t data_size + +``key`` + a buffer used to associate with the variable data. May +be any encoding, but must not be all zeroes + +``key_len`` + size of the key buffer in bytes + +``metadata`` + buffer containing the additional data specific to the +active variable scheme. This may not be used for certain schemes. +May be set to NULL to not set any metadata + +``metadata_size`` + size of the ``metadata`` buffer + +``data`` + buffer containing the blob of data to enqueue + +``data_size`` + size of the ``data`` buffer + +Return Values +------------- + +``OPAL_SUCCESS`` + the variable was appended to the update queue bank successfully + +``OPAL_PARAMETER`` + ``key`` or ``data`` was NULL. ``key`` was empty. ``key_len`` or +``data_size`` was zero. ``key_len``, ``metadata_size`` or ``data_size`` +were larger than their respective maximums + +``OPAL_NO_MEM`` + OPAL was unable to allocate memory for the variable update + +``OPAL_HARDWARE`` + OPAL was unable to write the update to persistant storage + +``OPAL_UNSUPPORTED`` + secure variables are not supported by the platform + +``OPAL_RESOURCE`` + secure variables are supported, but did not initialize properly From patchwork Tue Jun 25 22:02:12 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122335 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (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 45YKwJ4Cn8z9s3C for ; Wed, 26 Jun 2019 08:05:20 +1000 (AEST) 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 45YKwJ0GQhzDqXq for ; Wed, 26 Jun 2019 08:05:20 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; 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 (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 45YKs43RnSzDqNn for ; Wed, 26 Jun 2019 08:02:32 +1000 (AEST) Received: from pps.filterd (m0098417.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM1Q1V132443 for ; Tue, 25 Jun 2019 18:02:29 -0400 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0a-001b2d01.pphosted.com with ESMTP id 2tbu67hwpx-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:29 -0400 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:28 +0100 Received: from b06cxnps4075.portsmouth.uk.ibm.com (9.149.109.197) by e06smtp04.uk.ibm.com (192.168.101.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 25 Jun 2019 23:02:26 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2OdO49807594 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:24 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 72FB211C054; Tue, 25 Jun 2019 22:02:24 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CAD8911C058; Tue, 25 Jun 2019 22:02:23 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:23 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:12 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-0016-0000-0000-0000028C54D3 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-0017-0000-0000-000032E9C96B Message-Id: <20190625220215.27134-7-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=4 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [RFC PATCH v2 6/9] secvar/storage: add draft secvar storage driver for pnor-based p9 platforms 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" This patch implements the platform specific logic for persisting the secure variable storage banks across reboots via the SECBOOT PNOR partition. This is a base implementation meant to provide the minimal functionality required, and is a work-in-progress. For POWER 9, all secure variables and updates are stored in the in the SECBOOT PNOR partition. The partition is split into three sections: two variable bank sections, and a section for storing updates. For this initial implementation, the second variable bank section is ignored, but later patches will alternate writes between them to provide a back up in the event of a failure. Forthcoming patches will extend this implementation to utilize the TPM NV storage space to protect the PNOR storage from external tampering. NOTE: The name of this driver is subject to change, as it is not restricted to p9 systems. Will likely change to something like "secboot_tpm" to indicate it uses the SECBOOT partition and TPM NV storage. V2: - properly set DYN_ALLOC flag after loading from pnor - fixed "out of space" condition check in pnor writes Signed-off-by: Eric Richter --- include/secvar.h | 1 + libstb/secvar/storage/Makefile.inc | 2 +- libstb/secvar/storage/secboot_p9.c | 242 +++++++++++++++++++++++++++++ 3 files changed, 244 insertions(+), 1 deletion(-) create mode 100644 libstb/secvar/storage/secboot_p9.c diff --git a/include/secvar.h b/include/secvar.h index b5354f58..ebc5d399 100644 --- a/include/secvar.h +++ b/include/secvar.h @@ -41,6 +41,7 @@ struct secvar_backend_driver { uint64_t version; // Minor version for tracking additive backend features }; +extern struct secvar_storage_driver secboot_p9_driver; int secvar_main(struct secvar_storage_driver, struct secvar_backend_driver); diff --git a/libstb/secvar/storage/Makefile.inc b/libstb/secvar/storage/Makefile.inc index c107736e..1ade3ae7 100644 --- a/libstb/secvar/storage/Makefile.inc +++ b/libstb/secvar/storage/Makefile.inc @@ -4,7 +4,7 @@ SECVAR_STORAGE_DIR = libstb/secvar/storage SUBDIRS += $(SECVAR_STORAGE_DIR) -SECVAR_STORAGE_SRCS = +SECVAR_STORAGE_SRCS = secboot_p9.c SECVAR_STORAGE_OBJS = $(SECVAR_STORAGE_SRCS:%.c=%.o) SECVAR_STORAGE = $(SECVAR_STORAGE_DIR)/built-in.a diff --git a/libstb/secvar/storage/secboot_p9.c b/libstb/secvar/storage/secboot_p9.c new file mode 100644 index 00000000..cd884776 --- /dev/null +++ b/libstb/secvar/storage/secboot_p9.c @@ -0,0 +1,242 @@ +/* Copyright 2019 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 pr_fmt +#define pr_fmt(fmt) "SECBOOT_P9: " fmt +#endif + +#include +#include +#include +#include "../secvar.h" // TODO: fix relative imports + +// TODO: Determine reasonable values for these +#define SECBOOT_VARIABLE_BANK_SIZE 32000 +#define SECBOOT_UPDATE_BANK_SIZE 32000 + + +/* 0x5053424b = "PSBK" or Power Secure Boot Keystore */ +#define SECBOOT_MAGIC_NUMBER 0x5053424b +#define SECBOOT_VERSION 1 + +struct secboot_header { + uint32_t magic_number; + uint8_t version; + uint8_t reserved[3]; // Fix alignment +} __packed; + + +struct secboot { + struct secboot_header header; + char bank0[SECBOOT_VARIABLE_BANK_SIZE]; + char bank1[SECBOOT_VARIABLE_BANK_SIZE]; + char update[SECBOOT_UPDATE_BANK_SIZE]; +} __attribute__((packed)); + +struct secboot *secboot_image; + + +static int secboot_format(void) +{ + if (!platform.secboot_write) + return -1; + + memset(secboot_image, 0x00, sizeof(struct secboot)); + + secboot_image->header.magic_number = SECBOOT_MAGIC_NUMBER; + secboot_image->header.version = SECBOOT_VERSION; + + return platform.secboot_write(0, secboot_image, sizeof(struct secboot)); +} + + +static int secboot_serialize_bank(struct list_head *bank, char *target, size_t target_size) +{ + struct secvar_node *node; + char *tmp = target; + + if (!bank) + return -1; + if (!target) + return -1; + + list_for_each(bank, node, link) { + // Don't persist volatile variables to flash + if (node->flags & SECVAR_FLAG_VOLATILE) + continue; + + // TODO: skip over writing PK, write this to TPM in the future + if (node->flags & SECVAR_FLAG_SECURE_STORAGE) + continue; + + // Bail early if we are out of storage space + if ((target - tmp) + sizeof(struct secvar) > target_size) { + return -1; + } + + memcpy(target, node->var, sizeof(struct secvar)); + + target += sizeof(struct secvar); + } + + return 0; +} + + +static int secboot_write_to_pnor(struct list_head *bank, char *target, size_t max_size) +{ + int ret = 0; + + memset(target, 0, max_size); + + ret = secboot_serialize_bank(bank, target, max_size); + if (ret) + return ret; + + if (!platform.secboot_write) { + prlog(PR_ERR, "Failed to write: platform.secboot_write not set\n"); + return -1; + } + + ret = platform.secboot_write(0, secboot_image, sizeof(struct secboot)); + + return ret; +} + + +static int secboot_load_from_pnor(struct list_head *bank, char *source, size_t max_size) +{ + char *src; + struct secvar_node *tmp; + uint64_t empty = 0; + + src = source; + + while (src < (source + max_size)) { + // Peek to see if we are at the end of the bank + if (!memcmp(src, &empty, sizeof(empty))) { + break; + } + + tmp = malloc(sizeof(struct secvar_node)); + if (!tmp) { + prlog(PR_ERR, "Could not allocate memory for loading secvar from image\n"); + return -1; + } + + // TODO: reuse the memory here instead? +// tmp->var = (struct secvar *) src; + tmp->var = zalloc(sizeof(struct secvar)); + memcpy(tmp->var, src, sizeof(struct secvar)); + tmp->flags |= SECVAR_FLAG_DYN_ALLOC; + + list_add_tail(bank, &tmp->link); + src += sizeof(struct secvar); + } + + return 0; +} + +// TODO: support bank0 vs bank1 +static int secboot_p9_write_bank(struct list_head *bank, int section) +{ + switch(section) { + case SECVAR_VARIABLE_BANK: + return secboot_write_to_pnor(bank, secboot_image->bank0, SECBOOT_VARIABLE_BANK_SIZE); + case SECVAR_UPDATE_BANK: + return secboot_write_to_pnor(bank, secboot_image->update, SECBOOT_UPDATE_BANK_SIZE); + } + + return OPAL_HARDWARE; +} + +static int secboot_p9_load_bank(struct list_head *bank, int section) +{ + switch(section) { + case SECVAR_VARIABLE_BANK: + return secboot_load_from_pnor(bank, secboot_image->bank0, SECBOOT_VARIABLE_BANK_SIZE); + case SECVAR_UPDATE_BANK: + return secboot_load_from_pnor(bank, secboot_image->update, SECBOOT_UPDATE_BANK_SIZE); + } + + return OPAL_HARDWARE; +} + + + +static int secboot_p9_store_init(void) +{ + int ret; + unsigned secboot_size; + + /* Already initialized */ + if (secboot_image) + return 0; + + if (!platform.secboot_info) + return -1; + + prlog(PR_DEBUG, "Initializing for pnor-based p9 platform\n"); + + ret = platform.secboot_info(&secboot_size); + if (ret) { + prlog(PR_ERR, "error %d retrieving keystore info\n", ret); + return -1; + } + if (sizeof(struct secboot) > secboot_size) { + prlog(PR_ERR, "secboot partition %d KB too small. min=%ld\n", + secboot_size >> 10, sizeof(struct secboot)); + return -1; + } + + secboot_image = memalign(0x1000, sizeof(struct secboot)); + if (!secboot_image) { + prlog(PR_ERR, "Failed to allocate space for the secboot image\n"); + return -1; + } + + /* Read it in */ + ret = platform.secboot_read(secboot_image, 0, sizeof(struct secboot)); + if (ret) { + prlog(PR_ERR, "failed to read the secboot partition, rc=%d\n", ret); + goto out_free; + } + + if (secboot_image->header.magic_number != SECBOOT_MAGIC_NUMBER) { + prlog(PR_INFO, "Formatting secboot partition...\n"); + ret = secboot_format(); + if (ret) { + prlog(PR_ERR, "Failed to format secboot!\n"); + goto out_free; + } + } + + return 0; + +out_free: + if (secboot_image) { + free(secboot_image); + secboot_image = NULL; + } + + return -1; +} + +struct secvar_storage_driver secboot_p9_driver = { + .load_bank = secboot_p9_load_bank, + .write_bank = secboot_p9_write_bank, + .store_init = secboot_p9_store_init, +}; From patchwork Tue Jun 25 22:02:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122336 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 45YKwZ6w7zz9s3C for ; Wed, 26 Jun 2019 08:05:34 +1000 (AEST) 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 45YKwZ5xdrzDqSx for ; Wed, 26 Jun 2019 08:05:34 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) 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 45YKs45jywzDqB3 for ; Wed, 26 Jun 2019 08:02:32 +1000 (AEST) Received: from pps.filterd (m0098399.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM1Y5k122325 for ; Tue, 25 Jun 2019 18:02:31 -0400 Received: from e06smtp01.uk.ibm.com (e06smtp01.uk.ibm.com [195.75.94.97]) by mx0a-001b2d01.pphosted.com with ESMTP id 2tbs7jppk1-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:30 -0400 Received: from localhost by e06smtp01.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:28 +0100 Received: from b06cxnps4076.portsmouth.uk.ibm.com (9.149.109.198) by e06smtp01.uk.ibm.com (192.168.101.131) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 25 Jun 2019 23:02:27 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2Pme44826870 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:25 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7345411C05C; Tue, 25 Jun 2019 22:02:25 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AD8D211C052; Tue, 25 Jun 2019 22:02:24 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:24 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:13 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-4275-0000-0000-0000034639B8 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-4276-0000-0000-000038563C50 Message-Id: <20190625220215.27134-8-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=840 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [RFC PATCH v2 7/9] secvar/backend: add edk2 headers to support edk2 derived backend 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" From: Nayna Jain Edk2-style support for secure variables processing requires use of EFI-like data structures. These include authentication_header_2, EFI Signature Lists and GUIDs This patch includes the header file derived from edk2-staging branch of tianocore reference implementation[1]. The data types in use are merged into one file - edk2.h. The data types in use are kept intact except change of case and corresponding basic inbuilt types to match with skiboot coding style. [1] https://github.com/tianocore/edk2-staging.git Signed-off-by: Claudio Carvalho Signed-off-by: Nayna Jain Signed-off-by: Eric Richter --- libstb/secvar/backend/edk2/edk2.h | 249 ++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100644 libstb/secvar/backend/edk2/edk2.h diff --git a/libstb/secvar/backend/edk2/edk2.h b/libstb/secvar/backend/edk2/edk2.h new file mode 100644 index 00000000..fc40ea68 --- /dev/null +++ b/libstb/secvar/backend/edk2/edk2.h @@ -0,0 +1,249 @@ +/* Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. This + * program and the accompanying materials are licensed and made available + * under the terms and conditions of the 2-Clause BSD License which + * accompanies this distribution. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * This file is derived from the following files referred from edk2-staging[1] repo + * of tianocore + * + * MdePkg/Include/Guid/GlobalVariable.h + * MdePkg/Include/Guid/WinCertificate.h + * MdePkg/Include/Uefi/UefiMultiPhase.h + * MdePkg/Include/Uefi/UefiBaseType.h + * MdePkg/Include/Guid/ImageAuthentication.h + * + * [1] https://github.com/tianocore/edk2-staging + * + * Copyright 2019 IBM Corp. + */ + +#ifndef __EDK2_H__ +#define __EDK2_H__ + +#define EFI_GLOBAL_VARIABLE \ + { \ + 0x8B, 0xE4, 0xDF, 0x61, 0x93, 0xCA, 0x11, 0xd2, 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C \ + } + + +/// +/// This identifies a signature based on an X.509 certificate. If the signature is an X.509 +/// certificate then verification of the signature of an image should validate the public +/// key certificate in the image using certificate path verification, up to this X.509 +/// certificate as a trusted root. The SignatureHeader size shall always be 0. The +/// SignatureSize may vary but shall always be 16 (size of the SignatureOwner component) + +/// the size of the certificate itself. +/// Note: This means that each certificate will normally be in a separate EFI_SIGNATURE_LIST. +/// +#define EFI_CERT_X509_GUID \ + { \ + 0xa5, 0xc0, 0x59, 0xa1, 0x94, 0xe4, 0x4a, 0xa7, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72 \ + } + +#define EFI_CERT_TYPE_PKCS7_GUID \ + { \ + 0x4a, 0xaf, 0xd2, 0x9d, 0x68, 0xdf, 0x49, 0xee, 0x8a, 0xa9, 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7 \ + } + +#define EFI_VARIABLE_NON_VOLATILE 0x00000001 +#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002 +#define EFI_VARIABLE_RUNTIME_ACCESS 0x00000004 +/* + * This attribute is identified by the mnemonic 'HR' elsewhere in this + * specification. + */ +#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x00000008 +/* + * Attributes of Authenticated Variable + */ +#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x00000020 +#define EFI_VARIABLE_APPEND_WRITE 0x00000040 +/* + * NOTE: EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated and should be + * considered reserved. + */ +#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x00000010 + +/* + * win_certificate.w_certificate_type + */ +#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002 + +#define SECURE_BOOT_MODE_ENABLE 1 +#define SECURE_BOOT_MODE_DISABLE 0 +/// +/// Depricated value definition for SetupMode variable +/// +#define SETUP_MODE 1 +#define USER_MODE 0 + +struct efi_guid { + u32 data1; + u16 data2; + u16 data3; + u8 data4[8]; +}; + +/* + * EFI Time Abstraction: + * Year: 1900 - 9999 + * Month: 1 - 12 + * Day: 1 - 31 + * Hour: 0 - 23 + * Minute: 0 - 59 + * Second: 0 - 59 + * Nanosecond: 0 - 999,999,999 + * TimeZone: -1440 to 1440 or 2047 + */ +struct efi_time { + u16 year; + u8 month; + u8 day; + u8 hour; + u8 minute; + u8 second; + u8 pad1; + u32 nanosecond; + s16 timezone; + u8 daylight; + u8 pad2; +}; +//*********************************************************************** +// Signature Database +//*********************************************************************** +/// +/// The format of a signature database. +/// +#pragma pack(1) + +typedef struct { + /// + /// An identifier which identifies the agent which added the signature to the list. + /// + struct efi_guid SignatureOwner; + /// + /// The format of the signature is defined by the SignatureType. + /// + unsigned char SignatureData[1]; +} EFI_SIGNATURE_DATA; + +typedef struct { + /// + /// Type of the signature. GUID signature types are defined in below. + /// + struct efi_guid SignatureType; + /// + /// Total size of the signature list, including this header. + /// + uint32_t SignatureListSize; + /// + /// Size of the signature header which precedes the array of signatures. + /// + uint32_t SignatureHeaderSize; + /// + /// Size of each signature. + /// + uint32_t SignatureSize; + /// + /// Header before the array of signatures. The format of this header is specified + /// by the SignatureType. + /// UINT8 SignatureHeader[SignatureHeaderSize]; + /// + /// An array of signatures. Each signature is SignatureSize bytes in length. + /// EFI_SIGNATURE_DATA Signatures[][SignatureSize]; + /// +} EFI_SIGNATURE_LIST; + + +/* + * The win_certificate structure is part of the PE/COFF specification. + */ +struct win_certificate { + /* + * The length of the entire certificate, including the length of the + * header, in bytes. + */ + u32 dw_length; + /* + * The revision level of the WIN_CERTIFICATE structure. The current + * revision level is 0x0200. + */ + u16 w_revision; + /* + * The certificate type. See WIN_CERT_TYPE_xxx for the UEFI certificate + * types. The UEFI specification reserves the range of certificate type + * values from 0x0EF0 to 0x0EFF. + */ + u16 w_certificate_type; + /* + * The following is the actual certificate. The format of + * the certificate depends on wCertificateType. + */ + /// UINT8 bCertificate[ANYSIZE_ARRAY]; +}; + +/* + * Certificate which encapsulates a GUID-specific digital signature + */ +struct win_certificate_uefi_guid { + /* + * This is the standard win_certificate header, where w_certificate_type + * is set to WIN_CERT_TYPE_EFI_GUID. + */ + struct win_certificate hdr; + /* + * This is the unique id which determines the format of the cert_data. + */ + struct efi_guid cert_type; + /* + * The following is the certificate data. The format of the data is + * determined by the @cert_type. If @cert_type is + * EFI_CERT_TYPE_RSA2048_SHA256_GUID, the @cert_data will be + * EFI_CERT_BLOCK_RSA_2048_SHA256 structure. + */ + u8 cert_data[1]; +}; +/* + * When the attribute EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS is set, + * then the Data buffer shall begin with an instance of a complete (and + * serialized) EFI_VARIABLE_AUTHENTICATION_2 descriptor. The descriptor shall be + * followed by the new variable value and DataSize shall reflect the combined + * size of the descriptor and the new variable value. The authentication + * descriptor is not part of the variable data and is not returned by subsequent + * calls to GetVariable(). + */ +struct efi_variable_authentication_2 { + /* + * For the TimeStamp value, components Pad1, Nanosecond, TimeZone, Daylight and + * Pad2 shall be set to 0. This means that the time shall always be expressed in GMT. + */ + struct efi_time timestamp; + /* + * Only a CertType of EFI_CERT_TYPE_PKCS7_GUID is accepted. + */ + struct win_certificate_uefi_guid auth_info; +}; + +#endif From patchwork Tue Jun 25 22:02:14 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122337 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [203.11.71.2]) (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 45YKwv2x15z9s3C for ; Wed, 26 Jun 2019 08:05:51 +1000 (AEST) 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 45YKwv1NY6zDqNn for ; Wed, 26 Jun 2019 08:05:51 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=linux.ibm.com (client-ip=148.163.158.5; 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 (mx0b-001b2d01.pphosted.com [148.163.158.5]) (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 45YKs66Zg2zDqB3 for ; Wed, 26 Jun 2019 08:02:34 +1000 (AEST) Received: from pps.filterd (m0098421.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM1Pgf043307 for ; Tue, 25 Jun 2019 18:02:32 -0400 Received: from e06smtp02.uk.ibm.com (e06smtp02.uk.ibm.com [195.75.94.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 2tbu9qsabh-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:32 -0400 Received: from localhost by e06smtp02.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:30 +0100 Received: from b06avi18878370.portsmouth.uk.ibm.com (9.149.26.194) by e06smtp02.uk.ibm.com (192.168.101.132) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 25 Jun 2019 23:02:27 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18878370.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2Qhl40173908 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:26 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 60EB511C04C; Tue, 25 Jun 2019 22:02:26 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AE71411C054; Tue, 25 Jun 2019 22:02:25 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:25 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:14 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-0008-0000-0000-000002F6FE14 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-0009-0000-0000-000022643036 Message-Id: <20190625220215.27134-9-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=0 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [RFC PATCH v2 8/9] secvar/backend: add edk2 derived key updates processing 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" From: Nayna Jain As part of secureboot key management, the scheme for key updates processing is derived from tianocore reference implementation[1]. This includes the verification of key updates signed in the form of PKCS7 structure. This patch adds the PKCS7 verification support for the signed updates processed by the user. It also adds the preprocessing code which initializes the empty non-volatile variables and the secureboot state of the system. This patch is still a work-in-progress, for example. it still needs to add the support for post-processing steps and better failure handling. V2: - fixed memcpy based on sizeof(keylen) rather than the value - added version and compatible values to driver struct - renamed to edk2-compat [1] https://github.com/tianocore/edk2-staging.git Signed-off-by: Nayna Jain Signed-off-by: Eric Richter --- include/secvar.h | 1 + libstb/secvar/backend/Makefile.inc | 2 +- libstb/secvar/backend/edk2-compat/data.h | 70 +++ .../secvar/backend/edk2-compat/edk2-compat.c | 536 ++++++++++++++++++ .../backend/{edk2 => edk2-compat}/edk2.h | 0 libstb/secvar/secvar.h | 3 + 6 files changed, 611 insertions(+), 1 deletion(-) create mode 100644 libstb/secvar/backend/edk2-compat/data.h create mode 100644 libstb/secvar/backend/edk2-compat/edk2-compat.c rename libstb/secvar/backend/{edk2 => edk2-compat}/edk2.h (100%) diff --git a/include/secvar.h b/include/secvar.h index ebc5d399..1e125009 100644 --- a/include/secvar.h +++ b/include/secvar.h @@ -42,6 +42,7 @@ struct secvar_backend_driver { }; extern struct secvar_storage_driver secboot_p9_driver; +extern struct secvar_backend_driver edk2_compatible_v1; int secvar_main(struct secvar_storage_driver, struct secvar_backend_driver); diff --git a/libstb/secvar/backend/Makefile.inc b/libstb/secvar/backend/Makefile.inc index 7a7ca1f7..ab6e5b9e 100644 --- a/libstb/secvar/backend/Makefile.inc +++ b/libstb/secvar/backend/Makefile.inc @@ -4,7 +4,7 @@ SECVAR_BACKEND_DIR = libstb/secvar/backend SUBDIRS += $(SECVAR_BACKEND_DIR) -SECVAR_BACKEND_SRCS = +SECVAR_BACKEND_SRCS = ./edk2-compat/edk2-compat.c SECVAR_BACKEND_OBJS = $(SECVAR_BACKEND_SRCS:%.c=%.o) SECVAR_BACKEND = $(SECVAR_BACKEND_DIR)/built-in.a diff --git a/libstb/secvar/backend/edk2-compat/data.h b/libstb/secvar/backend/edk2-compat/data.h new file mode 100644 index 00000000..fe927537 --- /dev/null +++ b/libstb/secvar/backend/edk2-compat/data.h @@ -0,0 +1,70 @@ +/** + * This file defines the static empty supported variables. + * This sort of acts as whitelist for us. It also allows user + * to view the variables supported even if empty. + */ + + +#ifndef SECVAR_DATA_H +#define SECVAR_DATA_H + +#include "../../secvar.h" + +struct secvar pk = { + .key = {'P', 'K', '\0'}, + .key_len = 3, + .metadata = {'P', 0, 'K', 0, 0x8b, 0xe4, 0xdf, 0x61, 0x93, 0xca, 0x11, \ + 0xd2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c, \ + 0x00, 0x00, 0x00, 0x07}, + .metadata_size = 24, + .data = {}, + .data_size = 0, +}; + +struct secvar kek = { + .key = {'K', 'E', 'K', '\0'}, + .key_len = 4, + .metadata = {'K', 0, 'E', 0, 'K', 0, 0x8b, 0xe4, 0xdf, 0x61, 0x93, \ + 0xca, 0x11, 0xd2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, \ + 0x2b, 0x8c, 0x00, 0x00, 0x00, 0x07}, + .metadata_size = 26, + .data = {}, + .data_size = 0, +}; + +struct secvar db = { + .key = {'d', 'b', '\0'}, + .key_len = 3, + .metadata = {'d', 0, 'b', 0, 0xd7, 0x19, 0xb2, 0xcb, 0x3d, 0x3a, 0x45, \ + 0x96, 0xa3, 0xbc, 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f, \ + 0x00, 0x00, 0x01, 0x07}, + .metadata_size = 24, + .data = {}, + .data_size = 0, +}; + +struct secvar setup = { + .key = {'S', 'e', 't', 'u', 'p', 'M', 'o', 'd', 'e', '\0'}, + .key_len = 10, + .metadata = {'S', 0, 'e', 0, 't', 0, 'u', 0, 'p', 0, 'M', 0, 'o', 0, \ + 'd', 0, 'e', 0, 0x8b, 0xe4, 0xdf, 0x61, 0x93, 0xca, 0x11, \ + 0xd2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c, \ + 0x00, 0x00, 0x00, 0x06}, + .metadata_size = 38, + .data = {0x01}, + .data_size = 1, +}; + +struct secvar secureboot = { + .key = {'S', 'e', 'c', 'u', 'r', 'e', 'B', 'o', 'o', 't', '\0'}, + .key_len = 11, + .metadata = {'S', 0, 'e', 0, 'c', 0, 'u', 0, 'r', 0, 'e', 0, 'B', 0, \ + 'o', 0, 'o', 0, 't', 0, 0x8b, 0xe4, 0xdf, 0x61, 0x93, \ + 0xca, 0x11, 0xd2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, \ + 0x2b, 0x8c, 0x00, 0x00, 0x00, 0x06}, + .metadata_size = 40, + .data = {0x00}, + .data_size = 1, +}; + +#endif diff --git a/libstb/secvar/backend/edk2-compat/edk2-compat.c b/libstb/secvar/backend/edk2-compat/edk2-compat.c new file mode 100644 index 00000000..c87e5755 --- /dev/null +++ b/libstb/secvar/backend/edk2-compat/edk2-compat.c @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. This + * program and the accompanying materials are licensed and made available + * under the terms and conditions of the 2-Clause BSD License which + * accompanies this distribution. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * ​ + * Some of the concepts in this file are derived from the edk2-staging[1] repo + * of tianocore reference implementation + * [1] https://github.com/tianocore/edk2-staging + * ​ + * Copyright 2019 IBM Corp. + */ + +#include +#include +#include +#include +#include +#include +//#include +//#include +#include "data.h" +#include "edk2.h" +#include "opal-api.h" +#include "../../secvar.h" + +/** +static int esl_get_cert_size(unsigned char *buf) +{ + EFI_SIGNATURE_LIST list; + uint32_t sigsize; + + memset(&list, 0, sizeof(EFI_SIGNATURE_LIST)); + memcpy(&list, buf, sizeof(EFI_SIGNATURE_LIST)); + + sigsize = le32_to_cpu(list.SignatureListSize) - sizeof(list) + - le32_to_cpu(list.SignatureHeaderSize); + + return sigsize; +} + +static int esl_get_cert(unsigned char *buf, unsigned char **cert) +{ + int sig_data_offset; + int size; + EFI_SIGNATURE_LIST list; + + memset(&list, 0, sizeof(EFI_SIGNATURE_LIST)); + memcpy(&list, buf, sizeof(EFI_SIGNATURE_LIST)); + + sig_data_offset = sizeof(list.SignatureType) + + sizeof(list.SignatureListSize) + + sizeof(list.SignatureHeaderSize) + + sizeof(list.SignatureSize) + + le32_to_cpu(list.SignatureHeaderSize) + + 16 * sizeof(uint8_t); + + size = le32_to_cpu(list.SignatureSize) - sizeof(EFI_SIGNATURE_LIST); + memcpy(*cert, buf + sig_data_offset, size); + + return 0; +} +**/ + +static int update_secureboot_state(void) +{ + struct secvar_node *setupvar; + struct secvar_node *sbvar; + struct secvar_node *pkvar; + u8 newval; + u8 enable; + + /* Wondering what is the best return value if any of these + * variables are not found. + */ + pkvar = find_secvar((char *)"PK", 3, &variable_bank); + if (!pkvar) + return OPAL_INTERNAL_ERROR; + setupvar = find_secvar((char *)"SetupMode", 10, &variable_bank); + if (!setupvar) + return OPAL_INTERNAL_ERROR; + sbvar = find_secvar((char *)"SecureBoot", 11, &variable_bank); + if (!sbvar) + return OPAL_INTERNAL_ERROR; + + if (pkvar->var->data_size == 0) + newval = 1; + else + newval = 0; + memcpy(setupvar->var->data, &newval, sizeof(u8)); + + if (newval == 1) + enable = 0; + else + enable = 1; + memcpy(sbvar->var->data, &enable, sizeof(u8)); + + return 0; +} + +static int add_volatile_variables(void) { + struct secvar_node *setupvar; + struct secvar_node *sbvar; + int rc; + + setupvar = find_secvar((char *)"SetupMode", 10, &variable_bank); + if (!setupvar) { + setupvar = zalloc(sizeof(struct secvar_node)); + if (!setupvar) + return OPAL_NO_MEM; + + setupvar->var = (struct secvar *)&setup; + setupvar->var->data_size = sizeof(u8); + list_add_tail(&variable_bank, &setupvar->link); + } + + sbvar = find_secvar((char *)"SecureBoot", 11, &variable_bank); + if (!sbvar) { + sbvar = zalloc(sizeof(struct secvar_node)); + if (!sbvar) + return OPAL_NO_MEM; + + sbvar->var = (struct secvar *)&secureboot; + sbvar->var->data_size = sizeof(u8); + list_add_tail(&variable_bank, &sbvar->link); + } + rc = update_secureboot_state(); + + return rc; +} + +/** + * Initializes the supported variables as empty + * + * Returns OPAL Error if anything fails in initialization + */ +static int edk2_compat_pre_process(void) +{ + struct secvar_node *pkvar; + struct secvar_node *kekvar; + struct secvar_node *dbvar; + int rc; + + /* First initializes all non-volatile variables */ + pkvar = find_secvar((char *)"PK", 3, &variable_bank); + if (!pkvar) { + pkvar = zalloc(sizeof(struct secvar_node)); + if (!pkvar) + return OPAL_NO_MEM; + + pkvar->var = (struct secvar *)&pk; + list_add_tail(&variable_bank, &pkvar->link); + } + + kekvar = find_secvar((char *)"KEK", 4, &variable_bank); + if (!kekvar) { + kekvar = zalloc(sizeof(struct secvar_node)); + if (!kekvar) + return OPAL_NO_MEM; + + kekvar->var = (struct secvar *)&kek; + list_add_tail(&variable_bank, &kekvar->link); + } + + dbvar = find_secvar((char *)"db", 3, &variable_bank); + if (!dbvar) { + dbvar = zalloc(sizeof(struct secvar_node)); + if (!dbvar) + return OPAL_NO_MEM; + + dbvar->var = (struct secvar *)&db; + list_add_tail(&variable_bank, &dbvar->link); + } + + /* Initializes volatile variables */ + rc = add_volatile_variables(); + + return rc; +}; + +/** + * Extracts size of the PKCS7 signed data embedded in the + * struct Authentication Descriptor 2 Header + */ +static int get_pkcs7_len(struct efi_variable_authentication_2 *auth) +{ + uint32_t dw_length = le32_to_cpu(auth->auth_info.hdr.dw_length); + int size; + + size = dw_length - (sizeof(auth->auth_info.hdr.dw_length) + + sizeof(auth->auth_info.hdr.w_revision) + + sizeof(auth->auth_info.hdr.w_certificate_type) + + sizeof(auth->auth_info.cert_type)); + + return size; +} + +/** + * The data submitted by the user is + * auth_descriptor_2 + new ESL data + * This function returns the size of the auth_descriptor_2 + */ +static int get_auth_buffer_size(void *data) +{ + struct efi_variable_authentication_2 *auth; + uint64_t auth_buffer_size; + int len = 0; + + auth = (struct efi_variable_authentication_2 *)data; + + len = get_pkcs7_len(auth); + + auth_buffer_size = sizeof(struct efi_time) + + sizeof(u32) + + sizeof(u16) + + sizeof(u16) + + sizeof(struct efi_guid) + + len; + + return auth_buffer_size; +} + +/** + * Returns if setup mode is enabled / disabled. + */ +static int is_setup_mode(void) +{ + struct secvar_node *setup; + u8 val; + + setup = find_secvar((char *)"SetupMode", 10, &variable_bank); + memset(&val, 0, sizeof(u8)); + memcpy(&val, setup->var->data, sizeof(val)); + printf("setup mode value is %d\n", val); + if (val == 1) + return true; + else + return false; + + return false; +} + +/** + * Update the variable with the new value. + */ +static int add_to_variable_bank(struct secvar *secvar, void *data, uint64_t dsize) +{ + struct secvar_node *node; + + node = find_secvar(secvar->key, secvar->key_len, &variable_bank); + if (!node) + return OPAL_INTERNAL_ERROR; + + node->var->data_size = dsize; + memset(node->var->data, 0, sizeof(node->var->data)); + memcpy(node->var->data, data, dsize); + + return 0; +} + +/** + * Verifies the PKCS7 signature on the signed data. + * This function is currently commented because of its dependency on the + * crypto library(mbedtls + pkcs7). + */ +/** +static int verify_update(void *auth_buffer, unsigned char *newcert, + uint64_t new_data_size, struct secvar *avar) +{ + struct efi_variable_authentication_2 *auth; + struct pkcs7 *pkcs7; + int len = 0; + int signing_cert_size = 0; + unsigned char *signing_cert; + unsigned char *x509_buf; + mbedtls_x509_crt x509; + int rc = 0; + + auth = (struct efi_variable_authentication_2 *) auth_buffer; + + len = get_pkcs7_len(auth); + + pkcs7 = malloc(sizeof(struct pkcs7)); + memset(pkcs7, 0, sizeof(struct pkcs7)); + + rc = pkcs7_parse_message( + (const unsigned char *)auth->auth_info.cert_data, + (const unsigned int)len, pkcs7); + + printf("----Load the signing certificate from the keystore----"); + + signing_cert_size = esl_get_cert_size(avar->data); + signing_cert = malloc(signing_cert_size); + memset(signing_cert, 0, signing_cert_size); + esl_get_cert(avar->data, &signing_cert); + + printf("\n"); + printf("----Print the signing certificate used for verification----\n"); + printf("\n"); + + mbedtls_x509_crt_init(&x509); + rc = mbedtls_x509_crt_parse(&x509, signing_cert, signing_cert_size); + if(rc) { + printf("X509 certificate parsing failed %04x\n", rc); + return rc; + } + + x509_buf = malloc(2048); + memset(x509_buf, 0, sizeof(x509_buf)); + mbedtls_x509_crt_info(x509_buf, 2048, "CRT:", &x509); + printf("%s \n", x509_buf); + + printf("----Verify the signature on the new ESL using the signing public key----\n"); + rc = verify_buf(signing_cert, signing_cert_size, newcert, new_data_size, + pkcs7->signed_data.signers.sig.p, + pkcs7->signed_data.signers.sig.len); + + if (rc) + printf("Signature Verification failed %02x\n", rc); + else + printf("Signature Verification passed\n"); + + return rc; +} +**/ + +/** + * Create the single buffer (name, vendor guid, attributes,timestamp and + * newdata) which was originally signed by the user + */ +static int concatenate_data_tobehashed(struct secvar *unode, + unsigned char *auth_buffer, + unsigned char *new_data, + uint64_t new_data_size, + unsigned char **buffer, + uint64_t *buffer_size) +{ + unsigned char *tbh_buffer; + int tbh_buffer_size; + int size = 0; + + tbh_buffer_size = sizeof(struct efi_time) + + unode->metadata_size + + new_data_size; + tbh_buffer = malloc(tbh_buffer_size); + + memset(tbh_buffer, 0, tbh_buffer_size); + memcpy(tbh_buffer + size, unode->metadata, unode->metadata_size); + size = size + unode->metadata_size; + memcpy(tbh_buffer + size, auth_buffer, sizeof(struct efi_time)); + size = size + sizeof(struct efi_time); + memcpy(tbh_buffer + size, new_data, new_data_size); + size = size + new_data_size; + + *buffer = malloc(size); + memset(*buffer, 0, size); + memcpy(*buffer, tbh_buffer, size); + *buffer_size = size; + + return 0; +} + +static int edk2_compat_process(void) +{ + unsigned char *auth_buffer; + uint64_t auth_buffer_size; + uint64_t new_data_size = 0; + unsigned char *dbcert = NULL; + struct secvar_node *anode = NULL; + struct secvar_node *node = NULL; + unsigned char *tbhbuffer; + uint64_t tbhbuffersize; + int rc; + bool setupmode = is_setup_mode(); + + printf("setup mode value is %d\n", setupmode); + + /* Loop through each command in the update bank. + * If any command fails, it just loops out of the update bank. + * It should also clear the update bank. That logic is TODO. + */ + list_for_each(&update_bank, node, link) { + printf("update for the variable %s\n",node->var->key); + + /* Submitted data is auth_descriptor_2 + new ESL data + * Extract the size of auth_descriptor_2 + */ + auth_buffer_size = get_auth_buffer_size(node->var->data); + auth_buffer = malloc(auth_buffer_size); + memset(auth_buffer, 0, auth_buffer_size); + memcpy(auth_buffer, node->var->data, auth_buffer_size); + + if (node->var->data_size < auth_buffer_size) + return OPAL_PARAMETER; + + /* Calculate the size of new ESL data */ + new_data_size = node->var->data_size - auth_buffer_size; + dbcert = malloc(new_data_size); + memset(dbcert, 0, new_data_size); + memcpy(dbcert, node->var->data + auth_buffer_size, new_data_size); + + if (setupmode) + printf("Inside setup mode\n"); + + if (!setupmode) { + printf("Inside user mode\n"); + + /* If the update is for PK, verify it with existing PK */ + if (memcmp(node->var->key,"PK",node->var->key_len) == 0) { + anode = find_secvar((char *)"PK", 3, + &variable_bank); + if (anode && (anode->var->data_size == 0)) + return OPAL_SECVAR_AUTH_FAILED; + } + + /* If the update is for KEK/DB, verify it with PK */ + if ((memcmp(node->var->key,"KEK", node->var->key_len) == 0) + || (memcmp(node->var->key, "db", + node->var->key_len) == 0)) { + anode = find_secvar((char *)"PK", 3, + &variable_bank); + if ((anode && (anode->var->data_size == 0)) + && (memcmp(node->var->key, + "KEK", + node->var->key_len) == 0)) { + printf("validation of %s failed\n", node->var->key); + return OPAL_SECVAR_AUTH_FAILED; + } + } + + /* If the update is for db, and previous verification + * via PK fails, check if it is signed by any of the + * KEKs + */ + if (memcmp(node->var->key, "db", + node->var->key_len) == 0) { + anode = find_secvar((char *)"KEK", 4, + &variable_bank); + if (anode && (anode->var->data_size == 0)) { + printf("validation of %s failed\n", node->var->key); + return OPAL_SECVAR_AUTH_FAILED; + } + } + + /* Create the buffer on which signature was generated */ + rc = concatenate_data_tobehashed(node->var, + auth_buffer, dbcert, + new_data_size, + &tbhbuffer, + &tbhbuffersize); + + /* Verify the signature */ + //rc = verify_update(auth_buffer, tbhbuffer, + // tbhbuffersize, anode->var); + if (rc) + return OPAL_SECVAR_AUTH_FAILED; + + } + + /* + * If reached here means, signature is verified so update the + * value in the variable bank + */ + add_to_variable_bank(node->var, dbcert, new_data_size); + + /* If the PK is updated, update the secure boot state of the + * system */ + if (memcmp(node->var->key, "PK", + node->var->key_len) == 0) + update_secureboot_state(); + + /* Delete the command processed */ + list_del(&node->link); + printf("variable list length is %d\n", list_length(&variable_bank)); + } + + return rc; +} + +static int edk2_compat_post_process(void) +{ + //Update the PNOR and TPM hashes. + //Do the Platform Auth + return 0; +}; + +static int edk2_compat_validate(struct secvar *var) +{ + + //Checks if the update is for supported + //Non-volatile secure variales + if (memcmp(var->key, "PK", 3) == 0) + return 1; + if (memcmp(var->key, "KEK", 4) == 0) + return 1; + if (memcmp(var->key, "db", 3) == 0) + return 1; + + //Some more checks needs to be added. + //Do we want to add GUID check ? + //Do we want to check here that the auth descriptor + //has PKCS7 signed data. It implies we should open the data here + //and parse through it. Is that ok ? + + return 0; +}; + +struct secvar_backend_driver edk2_compatible_v1 = { + .pre_process = edk2_compat_pre_process, + .process = edk2_compat_process, + .post_process = edk2_compat_post_process, + .validate = edk2_compat_validate, + .compatible = "ibm,edk2-compat-v1", + .version = 1, +}; diff --git a/libstb/secvar/backend/edk2/edk2.h b/libstb/secvar/backend/edk2-compat/edk2.h similarity index 100% rename from libstb/secvar/backend/edk2/edk2.h rename to libstb/secvar/backend/edk2-compat/edk2.h diff --git a/libstb/secvar/secvar.h b/libstb/secvar/secvar.h index eb4f4558..00cb4d29 100644 --- a/libstb/secvar/secvar.h +++ b/libstb/secvar/secvar.h @@ -25,6 +25,9 @@ #define SECVAR_MAX_METADATA_SIZE 1024 #define SECVAR_MAX_DATA_SIZE 2048 +//secvar specific error codes +#define OPAL_SECVAR_AUTH_FAILED 0x01 + enum { SECVAR_VARIABLE_BANK, SECVAR_UPDATE_BANK, From patchwork Tue Jun 25 22:02:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1122338 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 45YKx76ptsz9s3C for ; Wed, 26 Jun 2019 08:06:03 +1000 (AEST) 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 45YKx75GS6zDqVP for ; Wed, 26 Jun 2019 08:06:03 +1000 (AEST) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) 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 45YKs73YC6zDqNn for ; Wed, 26 Jun 2019 08:02:35 +1000 (AEST) Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x5PM1mUW066254 for ; Tue, 25 Jun 2019 18:02:33 -0400 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0a-001b2d01.pphosted.com with ESMTP id 2tbrtj7hfm-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Tue, 25 Jun 2019 18:02:33 -0400 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Tue, 25 Jun 2019 23:02:30 +0100 Received: from b06avi18626390.portsmouth.uk.ibm.com (9.149.26.192) by e06smtp04.uk.ibm.com (192.168.101.134) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Tue, 25 Jun 2019 23:02:28 +0100 Received: from d06av25.portsmouth.uk.ibm.com (d06av25.portsmouth.uk.ibm.com [9.149.105.61]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x5PM2HoS37618068 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Tue, 25 Jun 2019 22:02:17 GMT Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 4DCA811C052; Tue, 25 Jun 2019 22:02:27 +0000 (GMT) Received: from d06av25.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9BA0E11C04A; Tue, 25 Jun 2019 22:02:26 +0000 (GMT) Received: from yorha.austin.ibm.com (unknown [9.41.178.196]) by d06av25.portsmouth.uk.ibm.com (Postfix) with ESMTP; Tue, 25 Jun 2019 22:02:26 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Tue, 25 Jun 2019 17:02:15 -0500 X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190625220215.27134-1-erichte@linux.ibm.com> References: <20190625220215.27134-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19062522-0016-0000-0000-0000028C54D5 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19062522-0017-0000-0000-000032E9C96D Message-Id: <20190625220215.27134-10-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-06-25_14:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=815 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906250173 Subject: [Skiboot] [RFC PATCH v2 9/9] witherspoon: enable secvar for witherspoon platform 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" Secure variable support needs to be enabled for each platform, and each platform needs to select which storage and backend drivers to use (or alternatively implement their own). This patch adds secure variable support to the witherspoon platform. Signed-off-by: Eric Richter --- platforms/astbmc/witherspoon.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/platforms/astbmc/witherspoon.c b/platforms/astbmc/witherspoon.c index 52971ecf..f3e2378f 100644 --- a/platforms/astbmc/witherspoon.c +++ b/platforms/astbmc/witherspoon.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "astbmc.h" #include "ast.h" @@ -475,6 +476,11 @@ static void npu2_phb_nvlink_dt(struct phb *npuphb) } } +static int witherspoon_secvar_init(void) +{ + return secvar_main(secboot_p9_driver, edk2_compatible_v1); +} + static void witherspoon_exit(void) { struct dt_node *np; @@ -512,4 +518,5 @@ DECLARE_PLATFORM(witherspoon) = { .pci_get_slot_info = dt_slot_get_slot_info, .ocapi = &witherspoon_ocapi, .npu2_device_detect = witherspoon_npu2_device_detect, + .secvar_init = witherspoon_secvar_init, };