From patchwork Sat Oct 26 09:45:43 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184595 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) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 470bhz25Rfz9sPc for ; Sat, 26 Oct 2019 20:46:27 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bhz0HQDzDqpR for ; Sat, 26 Oct 2019 20:46:27 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 470bhl3KGXzDqlZ for ; Sat, 26 Oct 2019 20:46:14 +1100 (AEDT) Received: from pps.filterd (m0098394.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x9Q9bNq1083894 for ; Sat, 26 Oct 2019 05:46:11 -0400 Received: from e06smtp07.uk.ibm.com (e06smtp07.uk.ibm.com [195.75.94.103]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvjn8hkm5-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:10 -0400 Received: from localhost by e06smtp07.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:08 +0100 Received: from b06avi18878370.portsmouth.uk.ibm.com (9.149.26.194) by e06smtp07.uk.ibm.com (192.168.101.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Sat, 26 Oct 2019 10:46:07 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06avi18878370.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9k5vC40501602 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:05 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 84F9F4C058; Sat, 26 Oct 2019 09:46:05 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B10D64C044; Sat, 26 Oct 2019 09:46:04 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:04 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:43 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0028-0000-0000-000003AFC455 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0029-0000-0000-00002471FC8A Message-Id: <20191026094553.26635-2-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 01/11] 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. 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 V3: - remove the metadata secvar field - add probe_secvar() to bump compatible flag - add device tree property for backend-agnostic secure mode setting - remove backend minor version field - remove static data allocation in secvar struct V4: - add alloc_secvar helpers - removed ibm,secureboot version bump to v3 - secvars now store their allocated size seperate from the data size (to permit overallocating) - split device tree functions into their own file - device tree changes: - secvar now a child of ibm,opal - compatible is "ibm,secvar-v1", backend creates its own node - secure-mode is now a boolean os-secure-enforcing property - storage and backends now have their own nodes Signed-off-by: Eric Richter --- core/init.c | 4 + include/platform.h | 2 + include/secvar.h | 43 +++++++++ libstb/Makefile.inc | 3 +- libstb/secvar/Makefile.inc | 14 +++ libstb/secvar/backend/Makefile.inc | 11 +++ libstb/secvar/secvar.h | 60 +++++++++++++ libstb/secvar/secvar_devtree.c | 136 +++++++++++++++++++++++++++++ libstb/secvar/secvar_devtree.h | 15 ++++ libstb/secvar/secvar_main.c | 89 +++++++++++++++++++ libstb/secvar/secvar_util.c | 106 ++++++++++++++++++++++ libstb/secvar/storage/Makefile.inc | 11 +++ 12 files changed, 493 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_devtree.c create mode 100644 libstb/secvar/secvar_devtree.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/core/init.c b/core/init.c index cc1fdbc4..e6efb600 100644 --- a/core/init.c +++ b/core/init.c @@ -1211,6 +1211,10 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) secureboot_init(); trustedboot_init(); + /* Secure variables init, handled by platform */ + if (platform.secvar_init) + platform.secvar_init(); + /* * BMC platforms load version information from flash after * secure/trustedboot init. diff --git a/include/platform.h b/include/platform.h index 0b043856..412f8fc8 100644 --- a/include/platform.h +++ b/include/platform.h @@ -210,6 +210,8 @@ struct platform { uint32_t len); int (*nvram_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..ae262616 --- /dev/null +++ b/include/secvar.h @@ -0,0 +1,43 @@ +/* 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); + char compatible[32]; + uint64_t max_var_size; +}; + +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 +}; + + +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..e1e6e5c7 --- /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_devtree.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..cddd6d45 --- /dev/null +++ b/libstb/secvar/secvar.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: Apache-2.0 +/* Copyright 2013-2019 IBM Corp. */ + +#ifndef _SECVAR_H_ +#define _SECVAR_H_ + +#include +#include +#include + +#define SECVAR_MAX_KEY_LEN 1024 + +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 + uint64_t size; // How much space was allocated for data +}; + +#define SECVAR_FLAG_VOLATILE 0x1 // Instructs storage driver to ignore variable on writes +#define SECVAR_FLAG_SECURE_STORAGE 0x2 // Hint for storage driver to select storage location + +struct secvar { + uint64_t key_len; + uint64_t data_size; + char key[SECVAR_MAX_KEY_LEN]; + char data[0]; +}; + + +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; + +// Check for secvar support, update secureboot DT compatible if so +int probe_secvar(void); + +// Helper functions +void clear_bank_list(struct list_head *bank); +struct secvar_node *alloc_secvar(uint64_t size); +int realloc_secvar(struct secvar_node *node, uint64_t size); +struct secvar_node *find_secvar(const char *key, uint64_t key_len, struct list_head *bank); +int is_key_empty(const char *key, uint64_t key_len); +int list_length(struct list_head *bank); + +#endif diff --git a/libstb/secvar/secvar_devtree.c b/libstb/secvar/secvar_devtree.c new file mode 100644 index 00000000..9cd12a15 --- /dev/null +++ b/libstb/secvar/secvar_devtree.c @@ -0,0 +1,136 @@ +#include +#include +#include "secvar.h" +#include "secvar_devtree.h" + +struct dt_node *secvar_node; +struct dt_node *secvar_backend_node; +struct dt_node *secvar_storage_node; + +int secvar_set_secure_mode(void) +{ + struct dt_property *prop; + + if (!secvar_node) + return -1; + + prop = (struct dt_property *) dt_find_property(secvar_node, "os-secure-enforcing"); + if (prop) + return 0; + + prop = dt_add_property(secvar_node, "os-secure-enforcing", 0, 0); + if (!prop) + return -2; + + return 0; +} + +void secvar_init_devnode(void) +{ + struct dt_node *sb_root; + + sb_root = dt_find_by_path(dt_root, "/ibm,opal/"); + + secvar_node = dt_new(sb_root, "secvar"); + + dt_add_property_string(secvar_node, "compatible", "ibm,secvar-v1"); + + secvar_backend_node = dt_new(secvar_node, "backend"); + secvar_storage_node = dt_new(secvar_node, "storage"); + + dt_add_property_string(secvar_backend_node, "compatible", secvar_backend.compatible); + dt_add_property_string(secvar_storage_node, "compatible", secvar_storage.compatible); + + dt_add_property_u64(secvar_storage_node, "max-var-size", secvar_storage.max_var_size); +} + +void secvar_set_status(const char *status) +{ + struct dt_property *stat_prop; + if (!secvar_node) + return; // Fail boot? + + stat_prop = (struct dt_property *) dt_find_property(secvar_node, "status"); + + if (stat_prop) + strcpy(stat_prop->prop, status); + else + dt_add_property_string(secvar_node, "status", status); + // Fail boot if not successful? +} + + +void secvar_set_update_status(uint64_t val) +{ + struct dt_property *stat_prop; + if (!secvar_node) + return; // Fail boot? + + stat_prop = (struct dt_property *) dt_find_property(secvar_backend_node, "update-status"); + + if (stat_prop) + memcpy(stat_prop->prop, &val, sizeof(val)); + else + dt_add_property(secvar_backend_node, "update-status", &val, sizeof(val)); +} + + +void secvar_dt_backend_set_prop_string(const char *prop, const char *val) +{ + struct dt_property *p; + + if (!secvar_backend_node) + return; + + p = (struct dt_property *) dt_find_property(secvar_backend_node, prop); + + if (p) + memcpy(p->prop, val, strlen(val)); + else + dt_add_property_string(secvar_backend_node, prop, val); +} + +void secvar_dt_backend_set_prop_u64(const char *prop, uint64_t val) +{ + struct dt_property *p; + + if (!secvar_backend_node) + return; + + p = (struct dt_property *) dt_find_property(secvar_backend_node, prop); + + if (p) + memcpy(p->prop, &val, sizeof(val)); + else + dt_add_property_u64(secvar_backend_node, prop, val); +} + +void secvar_dt_storage_set_prop_string(const char *prop, const char *val) +{ + struct dt_property *p; + + if (!secvar_storage_node) + return; + + p = (struct dt_property *) dt_find_property(secvar_storage_node, prop); + + if (p) + memcpy(p->prop, val, strlen(val)); + else + dt_add_property_string(secvar_backend_node, prop, val); +} + +void secvar_dt_storage_set_prop_u64(const char *prop, uint64_t val) +{ + struct dt_property *p; + + if (!secvar_storage_node) + return; + + p = (struct dt_property *) dt_find_property(secvar_storage_node, prop); + + if (p) + memcpy(p->prop, &val, sizeof(val)); + else + dt_add_property_u64(secvar_backend_node, prop, val); +} diff --git a/libstb/secvar/secvar_devtree.h b/libstb/secvar/secvar_devtree.h new file mode 100644 index 00000000..8ba516f0 --- /dev/null +++ b/libstb/secvar/secvar_devtree.h @@ -0,0 +1,15 @@ +#ifndef _SECVAR_DEVTREE_H_ +#define _SECVAR_DEVTREE_H_ + +int secvar_set_secure_mode(void); +void secvar_init_devnode(void); + +void secvar_set_status(const char *status); +void secvar_set_update_status(uint64_t val); + +void secvar_dt_backend_set_prop_string(const char *prop, const char *val); +void secvar_dt_backend_set_prop_u64(const char *prop, uint64_t val); +void secvar_dt_storage_set_prop_string(const char *prop, const char *val); +void secvar_dt_storage_set_prop_u64(const char *prop, uint64_t val); + +#endif diff --git a/libstb/secvar/secvar_main.c b/libstb/secvar/secvar_main.c new file mode 100644 index 00000000..e40d10bb --- /dev/null +++ b/libstb/secvar/secvar_main.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: Apache-2.0 +/* Copyright 2019 IBM Corp. */ + +#ifndef pr_fmt +#define pr_fmt(fmt) "SECVAR: " fmt +#endif + +#include +#include +#include +#include "secvar.h" +#include "secvar_devtree.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}; + + +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_init_devnode(); + + 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; + + 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(); + secvar_set_update_status(rc); + if (rc == OPAL_SUCCESS) { + 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; + } + + // Last point of possible base secvar failure + secvar_set_status("okay"); + + if (secvar_backend.post_process) + rc = secvar_backend.post_process(); + if (rc) + goto out; + + return OPAL_SUCCESS; +fail: + secvar_set_status("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..2955a07c --- /dev/null +++ b/libstb/secvar/secvar_util.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: Apache-2.0 +/* Copyright 2019 IBM Corp. */ + +#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->var); + } + + free(node); + } +} + +struct secvar_node *alloc_secvar(uint64_t size) +{ + struct secvar_node *ret; + + ret = zalloc(sizeof(struct secvar_node)); + if (!ret) + return NULL; + + ret->var = zalloc(sizeof(struct secvar) + size); + if (!ret->var) { + free(ret); + return NULL; + } + + ret->size = size; + + return ret; +} + +int realloc_secvar(struct secvar_node *node, uint64_t size) +{ + void *tmp; + + if (node->size >= size) + return 0; + + tmp = zalloc(sizeof(struct secvar) + size); + if (!tmp) + return -1; + + memcpy(tmp, node->var, sizeof(struct secvar) + node->size); + free(node->var); + node->var = tmp; + + return 0; +} + +struct secvar_node *find_secvar(const 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(const 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 Sat Oct 26 09:45:44 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184597 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 470bjv2WY8z9s7T for ; Sat, 26 Oct 2019 20:47:15 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bjv1DYRzDqlm for ; Sat, 26 Oct 2019 20:47:15 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 470bhm2ctQzDqlZ for ; Sat, 26 Oct 2019 20:46:16 +1100 (AEDT) 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 x9Q9bKZF049538 for ; Sat, 26 Oct 2019 05:46:13 -0400 Received: from e06smtp02.uk.ibm.com (e06smtp02.uk.ibm.com [195.75.94.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvja0a477-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:12 -0400 Received: from localhost by e06smtp02.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:10 +0100 Received: from b06avi18626390.portsmouth.uk.ibm.com (9.149.26.192) 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) Sat, 26 Oct 2019 10:46:08 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9jXR635586552 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:45:33 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 79A854C04A; Sat, 26 Oct 2019 09:46:06 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id C41334C058; Sat, 26 Oct 2019 09:46:05 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:05 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:44 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0008-0000-0000-00000327CA04 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0009-0000-0000-00004A47036D Message-Id: <20191026094553.26635-3-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 02/11] secvar_tpmnv: add high-level tpm nv index abstraction for secvar X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: nayna@linux.ibm.com Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Multiple components, like the storage driver or backend driver, need to store information in the one reserved TPM NV index. This abstraction provides a method for components to share the index space without stomping on each other's data, and without them needing to understand anything about the other. This is probably an overengineered solution to the problem, but the intent is to keep the drivers as isolated from one another as possible. Signed-off-by: Eric Richter --- libstb/secvar/Makefile.inc | 2 +- libstb/secvar/secvar_tpmnv.c | 167 +++++++++++++++++++++++++++++++++++ libstb/secvar/secvar_tpmnv.h | 11 +++ 3 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 libstb/secvar/secvar_tpmnv.c create mode 100644 libstb/secvar/secvar_tpmnv.h diff --git a/libstb/secvar/Makefile.inc b/libstb/secvar/Makefile.inc index e1e6e5c7..e36186b5 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_devtree.c +SECVAR_SRCS = secvar_main.c secvar_util.c secvar_devtree.c secvar_tpmnv.c SECVAR_OBJS = $(SECVAR_SRCS:%.c=%.o) SECVAR = $(SECVAR_DIR)/built-in.a diff --git a/libstb/secvar/secvar_tpmnv.c b/libstb/secvar/secvar_tpmnv.c new file mode 100644 index 00000000..2da8a92b --- /dev/null +++ b/libstb/secvar/secvar_tpmnv.c @@ -0,0 +1,167 @@ +#include +#include +#include "secvar_tpmnv.h" +//#include + +#define TPM_SECVAR_NV_INDEX 0x01c10191 + +struct tpm_nv_id { + uint32_t id; + uint32_t size; + char data[0]; +}; + +struct tpm_nv { + uint32_t magic_num; + uint32_t version; + struct tpm_nv_id vars[0]; +}; + +int tpm_ready = 0; +struct tpm_nv *tpm_image; +size_t tpm_nv_size = 0; + +// Here just for size purposes, delete when using TSS +#define SECBOOT_VARIABLE_BANK_SIZE 32000 +#define SECBOOT_UPDATE_BANK_SIZE 32000 +#define SECBOOT_VARIABLE_BANK_NUM 2 +#ifndef _secboot_header_ // stupid fix for the test, delete with the rest +struct secboot_header { + uint32_t magic_number; + uint8_t version; + uint8_t reserved[3]; // Fix alignment +} __packed; +struct secboot { + struct secboot_header header; + char bank[SECBOOT_VARIABLE_BANK_NUM][SECBOOT_VARIABLE_BANK_SIZE]; + char update[SECBOOT_UPDATE_BANK_SIZE]; +} __packed; +#endif + + +static int secvar_tpmnv_init(void) +{ + if (tpm_ready) + return 0; + + // Check if defined, if so, load + // and set tpm_nv_size + // TSS_NV_Define_Space + // TSS_NV_Read + + tpm_nv_size = 1024; + + tpm_image = zalloc(tpm_nv_size); + if (!tpm_image) + return -1; + + // TEMP use pnor space for now, stored after the secboot sections + if (platform.secboot_read(tpm_image, sizeof(struct secboot), tpm_nv_size)) + return -1; + + tpm_ready = 1; + + return 0; +} + + +static struct tpm_nv_id *find_tpmnv_id(uint32_t id) +{ + struct tpm_nv_id *cur; + + for (cur = tpm_image->vars; + (char *) cur < ((char *) tpm_image) + tpm_nv_size; + cur += sizeof(struct tpm_nv_id) + cur->size) { + if (cur->id == 0) + return NULL; + if (cur->id == id) + return cur; + } + + return NULL; +} + + +// "Allocate" space within the secvar tpm +int secvar_tpmnv_alloc(uint32_t id, int32_t size) +{ + struct tpm_nv_id *cur; + + if (!tpm_ready && secvar_tpmnv_init()) + return -1; + + for (cur = tpm_image->vars; + (char *) cur < ((char *) tpm_image) + tpm_nv_size; + cur += sizeof(struct tpm_nv_id) + cur->size) { + if (cur->id == 0) + goto allocate; + if (cur->id == id) + return 0; // Already allocated + } + +allocate: + // Special case: size of -1 gives remaining space + if (size == -1) { + cur->id = id; + cur->size = tpm_nv_size - (cur - tpm_image->vars); + } + + if ((((char *) cur) + size) - (char *) tpm_image > tpm_nv_size) + return -2; + + cur->id = id; + cur->size = size; + + return 0; +} + + +int secvar_tpmnv_read(uint32_t id, void *buf, size_t size, size_t off) +{ + struct tpm_nv_id *var; + + if (!tpm_ready && secvar_tpmnv_init()) + return -1; + + var = find_tpmnv_id(id); + if (!var) + return -1; + + size = MIN(size, var->size); + memcpy(buf + off, var->data, size); + + return 0; +} + + +int secvar_tpmnv_write(uint32_t id, void *buf, size_t size, size_t off) +{ + struct tpm_nv_id *var; + + if (!tpm_ready && secvar_tpmnv_init()) + return -1; + + var = find_tpmnv_id(id); + if (!var) + return -1; + + size = MIN(size, var->size); + memcpy(var->data, buf + off, size); + // TSS_NV_Write(TPM_SECVAR_NV_INDEX, var->data, size + sizeof(struct tpm_nv_id), tpm_image - var) + + platform.secboot_write(sizeof(struct secboot), tpm_image, tpm_nv_size); + return 0; +} + +uint32_t secvar_tpmnv_size(uint32_t id) +{ + struct tpm_nv_id *var; + + if (!tpm_ready && secvar_tpmnv_init()) + return -1; + + var = find_tpmnv_id(id); + if (!var) + return 0; + return var->size; +} diff --git a/libstb/secvar/secvar_tpmnv.h b/libstb/secvar/secvar_tpmnv.h new file mode 100644 index 00000000..3b4a620e --- /dev/null +++ b/libstb/secvar/secvar_tpmnv.h @@ -0,0 +1,11 @@ +#ifndef _SECVAR_TPMNV_H_ +#define _SECVAR_TPMNV_H_ +#include + +int secvar_tpmnv_alloc(uint32_t id, int32_t size); +int secvar_tpmnv_read(uint32_t id, void *buf, size_t size, size_t off); +int secvar_tpmnv_write(uint32_t id, void *buf, size_t size, size_t off); +uint32_t secvar_tpmnv_size(uint32_t id); + +#endif + From patchwork Sat Oct 26 09:45:45 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184599 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 470bkX4z9Tz9s7T for ; Sat, 26 Oct 2019 20:47:48 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bkX3NZpzDqq0 for ; Sat, 26 Oct 2019 20:47:48 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 470bhm3GY3zDqlf for ; Sat, 26 Oct 2019 20:46:16 +1100 (AEDT) Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x9Q9bXDQ011896 for ; Sat, 26 Oct 2019 05:46:13 -0400 Received: from e06smtp02.uk.ibm.com (e06smtp02.uk.ibm.com [195.75.94.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvgfcvse4-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:13 -0400 Received: from localhost by e06smtp02.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:11 +0100 Received: from b06cxnps4075.portsmouth.uk.ibm.com (9.149.109.197) 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) Sat, 26 Oct 2019 10:46:09 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9k7vR57540818 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:07 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 6D4A24C040; Sat, 26 Oct 2019 09:46:07 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id B85DF4C04A; Sat, 26 Oct 2019 09:46:06 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:06 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:45 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0008-0000-0000-00000327CA05 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0009-0000-0000-00004A47036E Message-Id: <20191026094553.26635-4-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 03/11] 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_next() - opal_secvar_enqueue_update() opal_secvar_get() retrieves the data blob associated with a given key. The data buffer may be set to NULL to only query for variable size. 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 V3: - remove metadata from API parameters - remove opal_secvar_get_size - change enqueue to replace an update with a repeat name, rather than enqueueing the duplicate - change enqueue to unstage an update matching a key if size is zero - make all key parameters const where possible - rename key_size to key_buf_size in _get_next - fix leaking node when enqueue could not allocate the secvar V4: - enqueue update now uses secvar alloc/realloc - use storage-defined max var size instead of hardcoded constant Signed-off-by: Eric Richter --- ccan/list/list.h | 38 +++++++++ include/opal-api.h | 5 +- libstb/secvar/Makefile.inc | 2 +- libstb/secvar/secvar_api.c | 158 +++++++++++++++++++++++++++++++++++++ 4 files changed, 201 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 ad913bfa..60f4b850 100644 --- a/include/opal-api.h +++ b/include/opal-api.h @@ -222,7 +222,10 @@ #define OPAL_MPIPL_UPDATE 173 #define OPAL_MPIPL_REGISTER_TAG 174 #define OPAL_MPIPL_QUERY_TAG 175 -#define OPAL_LAST 175 +#define OPAL_SECVAR_GET 176 +#define OPAL_SECVAR_GET_NEXT 177 +#define OPAL_SECVAR_ENQUEUE_UPDATE 178 +#define OPAL_LAST 178 #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 e36186b5..737b77d2 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_devtree.c secvar_tpmnv.c +SECVAR_SRCS = secvar_main.c secvar_util.c secvar_devtree.c secvar_tpmnv.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..02954590 --- /dev/null +++ b/libstb/secvar/secvar_api.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: Apache-2.0 +/* Copyright 2019 IBM Corp. */ + +#ifndef pr_fmt +#define pr_fmt(fmt) "SECVAR_API: " fmt +#endif + +#include +#include "secvar.h" + + +static int64_t opal_secvar_get(const char *key, uint64_t key_len, 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; + // Data size must be set, data is optional for size query + if (!data_size) + return OPAL_PARAMETER; + + node = find_secvar(key, key_len, &variable_bank); + + if (!node) + return OPAL_EMPTY; // Variable not found, bail early + + if (!data) + rc = OPAL_SUCCESS; + else 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, 4); + + +static int64_t opal_secvar_get_next(char *key, uint64_t *key_len, uint64_t key_buf_size) +{ + struct secvar_node *node; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!key_len) + return OPAL_PARAMETER; + if (key_buf_size == 0) + return OPAL_PARAMETER; + if (*key_len > SECVAR_MAX_KEY_LEN) + return OPAL_PARAMETER; + if (*key_len > key_buf_size) + return OPAL_PARAMETER; + if (!key) + return OPAL_PARAMETER; + + if (!is_key_empty(key, *key_len)) { + node = find_secvar(key, *key_len, &variable_bank); + if (!node) + return OPAL_PARAMETER; + + node = list_next(&variable_bank, node, link); + } else + node = list_top(&variable_bank, struct secvar_node, link); + + if (!node) + return OPAL_EMPTY; + + if (key_buf_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(const char *key, uint64_t key_len, void *data, uint64_t data_size) +{ + struct secvar_node *node; + + if (!secvar_enabled) + return OPAL_UNSUPPORTED; + if (!secvar_ready) + return OPAL_RESOURCE; + if (!secvar_storage.write_bank) + return OPAL_HARDWARE; + if (!key) + return OPAL_PARAMETER; + if (key_len == 0) + return OPAL_PARAMETER; + if (key_len > SECVAR_MAX_KEY_LEN) + return OPAL_PARAMETER; + if ((!data) && (data_size != 0)) + return OPAL_PARAMETER; + if (data_size > secvar_storage.max_var_size) + return OPAL_PARAMETER; + + // Key should not be empty + if (is_key_empty(key, key_len)) + return OPAL_PARAMETER; + + node = find_secvar(key, key_len, &update_bank); + + // Unstage an update + if (data_size == 0) { + if (!node) + return OPAL_EMPTY; + + if (node->var) + free(node->var); + list_del(&node->link); + free(node); + goto out; + } + + if (node) { + list_del(&node->link); + // Realloc var if too small + if (node->size < data_size) { + if (realloc_secvar(node, data_size)) + return OPAL_NO_MEM; + } + else + memset(node->var, 0x00, sizeof(struct secvar) + node->var->data_size); + } else { + node = alloc_secvar(data_size); + if (!node) + return OPAL_NO_MEM; + } + + 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; + + list_add_tail(&update_bank, &node->link); + +out: + secvar_storage.write_bank(&update_bank, SECVAR_UPDATE_BANK); + + return OPAL_SUCCESS; +} +opal_call(OPAL_SECVAR_ENQUEUE_UPDATE, opal_secvar_enqueue_update, 4); From patchwork Sat Oct 26 09:45:46 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184598 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 470bkD1VjGz9s7T for ; Sat, 26 Oct 2019 20:47:32 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bkD0Pf8zDqqW for ; Sat, 26 Oct 2019 20:47:32 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 470bhm3y18zDqld for ; Sat, 26 Oct 2019 20:46:16 +1100 (AEDT) Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x9Q9bUCk130974 for ; Sat, 26 Oct 2019 05:46:14 -0400 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvhsr2wrw-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:13 -0400 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:11 +0100 Received: from b06cxnps4076.portsmouth.uk.ibm.com (9.149.109.198) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Sat, 26 Oct 2019 10:46:10 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9k8nn36438266 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:08 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 604654C04A; Sat, 26 Oct 2019 09:46:08 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AD1E64C040; Sat, 26 Oct 2019 09:46:07 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:07 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:46 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0020-0000-0000-0000037ECEE6 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0021-0000-0000-000021D51EC3 Message-Id: <20191026094553.26635-5-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 04/11] 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. V3: - removed metadata - removed get_size - updated _get semantics for size queries - added/expanded device tree properties V4: - updated for new device tree changes Signed-off-by: Eric Richter --- doc/device-tree/ibm,secureboot.rst | 10 ++ doc/device-tree/secvar.rst | 84 +++++++++++++ doc/opal-api/opal-secvar.rst | 192 +++++++++++++++++++++++++++++ 3 files changed, 286 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..ddf15b38 --- /dev/null +++ b/doc/device-tree/secvar.rst @@ -0,0 +1,84 @@ +.. _device-tree/ibm,opal/secvar: + +secvar +====== + +The ``secvar`` node provides secure variable information for the secure +boot of the target OS. + +Required properties +------------------- + +.. code-block:: none + + status: set to "fail" if the secure variables could not + be initialized, validated, or some other + hardware problem. + + 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. See table below. + TODO: This probably belongs in the backend node. + + os-secure-enforcing: If this property exists, the system is in + considered to be in "OS secure mode". Kexec + images should be signature checked, etc. + + backend: This node contains any backend-specific + information, and is maintained by the backend driver. + + storage: This node contains any storage-specific + information, and is mainted by the storage driver. + + max-var-size: This property must be exposed as a child of the + storage driver, and determines how large a + variable can be. + +Example +------- + +.. code-block:: dts + + secvar { + compatible = "ibm,secvar-v1"; + status = "okay"; + os-secure-enforcing = <0x0>; + update-status = <0x0>; + storage { + compatible = "ibm,secboot-tpm-v1"; + status = "okay"; + max-var-size = <0x1000>; + } + backend { + compatible = "ibm,edk2-compat-v1"; + status = "okay"; + } + }; + +Update Status +------------- + +The update status property should be set by the backend driver to a value +that best fits its error condition. The following table defines the +general intent of each error code, check backend specific documentation +for more detail. + ++-----------------+-----------------------------------------------+ +| update-status | Generic Reason | ++-----------------|-----------------------------------------------+ +| OPAL_SUCCESS | Updates were found and processed successfully | ++-----------------|-----------------------------------------------+ +| OPAL_EMPTY | No updates were found, none processed | ++-----------------|-----------------------------------------------+ +| OPAL_PARAMETER | Unable to parse data in the update section | ++-----------------|-----------------------------------------------+ +| OPAL_PERMISSION | Update failed to apply, possible auth failure | ++-----------------|-----------------------------------------------+ +| OPAL_HARDWARE | Misc. storage-related error | ++-----------------|-----------------------------------------------+ +| OPAL_RESOURCE | Out of space (somewhere) | ++-----------------|-----------------------------------------------+ +| OPAL_NO_MEM | Out of memory | ++-----------------+-----------------------------------------------+ + diff --git a/doc/opal-api/opal-secvar.rst b/doc/opal-api/opal-secvar.rst new file mode 100644 index 00000000..f07c570a --- /dev/null +++ b/doc/opal-api/opal-secvar.rst @@ -0,0 +1,192 @@ +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 176 + +``OPAL_SECVAR_GET`` call retrieves a data blob associated with the supplied +key. + + +Parameters +---------- +:: + + char *key + uint64_t key_len + 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 + +``data`` + return buffer to store the data blob of the requested variable if +a match was found. May be set to NULL to only query the size into +``data_size`` + +``data_size`` + reference to the size of the ``data`` buffer. OPAL sets this to +the size of the requested variable if found. + + +Return Values +------------- + +``OPAL_SUCCESS`` + the requested data blob was copied successfully. ``data`` was NULL, +and the ``data_size`` value was set successfully + +``OPAL_PARAMETER`` + ``key`` is NULL. + ``key_len`` is zero. + ``data_size`` is NULL. + +``OPAL_EMPTY`` + no variable with the supplied ``key`` was found + +``OPAL_PARTIAL`` + the buffer size provided in ``data_size`` was insufficient. +``data_size`` 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_NEXT +==================== +:: + + #define OPAL_SECVAR_GET_NEXT 177 + +``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_buf_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_buf_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 178 + +``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 *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 + +``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``, ``data_size`` is larger than the maximum size + +``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 Sat Oct 26 09:45:47 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184600 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 470bks3xZfz9s7T for ; Sat, 26 Oct 2019 20:48:05 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bks2sq4zDqtK for ; Sat, 26 Oct 2019 20:48:05 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 470bhm63JMzDqlg for ; Sat, 26 Oct 2019 20:46:16 +1100 (AEDT) Received: from pps.filterd (m0098396.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x9Q9bMhH011316 for ; Sat, 26 Oct 2019 05:46:14 -0400 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvgfcvsef-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:14 -0400 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:12 +0100 Received: from b06cxnps3074.portsmouth.uk.ibm.com (9.149.109.194) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Sat, 26 Oct 2019 10:46:11 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps3074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9k9rB24707186 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:09 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 7D6BD4C044; Sat, 26 Oct 2019 09:46:09 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 9FB094C04A; Sat, 26 Oct 2019 09:46:08 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:08 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:47 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0020-0000-0000-0000037ECEE7 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0021-0000-0000-000021D51EC5 Message-Id: <20191026094553.26635-6-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 05/11] secvar/test: add rudimentary secvar API unit testing 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 adds an initial port of the userspace unit tests for exercising the API that were originally developed out of tree. Future revisions will adjust the naming schemes and general formatting to match that of other tests within skiboot. Signed-off-by: Eric Richter --- libstb/secvar/test/Makefile.check | 46 +++++++ libstb/secvar/test/secvar-test-enqueue.c | 160 +++++++++++++++++++++++ libstb/secvar/test/secvar-test-getvar.c | 112 ++++++++++++++++ libstb/secvar/test/secvar-test-nextvar.c | 132 +++++++++++++++++++ libstb/secvar/test/secvar-test-void.c | 24 ++++ libstb/secvar/test/secvar_api_test.c | 92 +++++++++++++ libstb/secvar/test/secvar_common_test.c | 64 +++++++++ 7 files changed, 630 insertions(+) create mode 100644 libstb/secvar/test/Makefile.check create mode 100644 libstb/secvar/test/secvar-test-enqueue.c create mode 100644 libstb/secvar/test/secvar-test-getvar.c create mode 100644 libstb/secvar/test/secvar-test-nextvar.c create mode 100644 libstb/secvar/test/secvar-test-void.c create mode 100644 libstb/secvar/test/secvar_api_test.c create mode 100644 libstb/secvar/test/secvar_common_test.c diff --git a/libstb/secvar/test/Makefile.check b/libstb/secvar/test/Makefile.check new file mode 100644 index 00000000..0b172039 --- /dev/null +++ b/libstb/secvar/test/Makefile.check @@ -0,0 +1,46 @@ +# -*-Makefile-*- +SECVAR_TEST_DIR = libstb/secvar/test +#SUBDIRS = $(SECVAR_TEST_DIR) + +SECVAR_TEST = $(patsubst %.c, %, $(wildcard $(SECVAR_TEST_DIR)/secvar-test-*.c)) + +HOSTCFLAGS+=-I . -I include + +.PHONY : secvar-check +secvar-check: $(SECVAR_TEST:%=%-check) $(SECVAR_TEST:%=%-gcov-run) +secvar-check: $(SECVAR_TEST_NOSTUB:%=%-check) $(SECVAR_TEST_NOSTUB:%=%-gcov-run) + +.PHONY : secvar-coverage +secvar-coverage: $(SECVAR_TEST:%=%-gcov-run) +secvar-coverage: $(SECVAR_TEST_NOSTUB:%=%-gcov-run) + +check: secvar-check +coverage: secvar-coverage + +# TODO: create pnor image for only tests that need it +$(SECVAR_TEST:%=%-gcov-run) : %-run: % + @dd if=/dev/zero of=secboot.img bs=128k count=1 2> /dev/null + $(call QTEST, TEST-COVERAGE ,$< , $<) + @$(RM) -f secboot.img + +$(SECVAR_TEST:%=%-check) : %-check: % + @dd if=/dev/zero of=secboot.img bs=128k count=1 2> /dev/null + $(call QTEST, RUN-TEST ,$(VALGRIND) $<, $<) + @$(RM) -f secboot.img + +$(SECVAR_TEST) : core/test/stubs.o + +$(SECVAR_TEST) : % : %.c + $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) -O0 -g -I include -I . -I libfdt -o $@ $< core/test/stubs.o, $<) + +$(SECVAR_TEST:%=%-gcov): %-gcov : %.c % + $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) $(HOSTGCOVCFLAGS) -I include -I . -I libfdt -lgcov -o $@ $< core/test/stubs.o, $<) + +-include $(wildcard libstb/secvar/test/*.d) + +clean: secvar-test-clean + +secvar-test-clean: + $(RM) -f libstb/secvar/test/*.[od] $(SECVAR_TEST) $(SECVAR_TEST:%=%-gcov) + $(RM) -f libstb/secvar/test/*.gcda libstb/secvar/test/*.gcno + $(RM) -f secboot.img diff --git a/libstb/secvar/test/secvar-test-enqueue.c b/libstb/secvar/test/secvar-test-enqueue.c new file mode 100644 index 00000000..92b6a024 --- /dev/null +++ b/libstb/secvar/test/secvar-test-enqueue.c @@ -0,0 +1,160 @@ +/* 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. + */ +#include "secvar_api_test.c" + +const char *secvar_test_name = "enqueue"; + +// Stub storage function, enqueue only cares that this succeeds +static int temp_write_bank(struct list_head *bank, int section) +{ + (void) bank, (void) section; + return OPAL_SUCCESS; +} + +int run_test(void) +{ + int64_t rc; + + struct secvar_node *node; + char key[1024] = {0}; + + uint64_t data_size = 128; + char *data = zalloc(data_size); + + secvar_storage.max_var_size = 1024; + + /*** Bad cases first this time ***/ + // No write bank hook set + secvar_storage.write_bank = NULL; + memcpy(key, "meow", 4); // ascii + rc = secvar_enqueue(key, 4, data, data_size); + ASSERT(rc == OPAL_HARDWARE); + + // Set a stub bank writer, so the rest runs ok + secvar_storage.write_bank = temp_write_bank; + + // Parameter checks + // null key + rc = secvar_enqueue(NULL, 5, data, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // key is empty + memset(key, 0, sizeof(key)); + rc = secvar_enqueue(key, 5, data, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // keylen is zero + rc = secvar_enqueue(key, 0, data, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // keylen is excessive + rc = secvar_enqueue(key, 5000, data, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // null data + rc = secvar_enqueue(key, 5, NULL, data_size); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // data_size is excessive + rc = secvar_enqueue(key, 5, data, 50000); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // data_size is zero + rc = secvar_enqueue(key, 5, data, 0); + ASSERT(rc == OPAL_PARAMETER); + ASSERT(list_empty(&update_bank)); + + // secvar is disabled + secvar_enabled = 0; + rc = secvar_enqueue(key, 5, data, data_size); + ASSERT(rc == OPAL_UNSUPPORTED); + secvar_enabled = 1; + + // secvar is not ready + secvar_ready = 0; + rc = secvar_enqueue(key, 5, data, data_size); + ASSERT(rc == OPAL_RESOURCE); + secvar_ready = 1; + + + /*** Good cases ***/ + // TODO: add data? + memcpy(key, "test", 4); // ascii + rc = secvar_enqueue(key, 4, data, data_size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 1); + + memcpy(key, "f\0o\0o\0b\0a\0r\0", 6*2); // "unicode" + rc = secvar_enqueue(key, 6*2, data, data_size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 2); + + memcpy(key, "meep", 4); + rc = secvar_enqueue(key, 4, data, data_size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 3); // should not increase + + // Re-add the same variable + memcpy(key, "meep", 4); + rc = secvar_enqueue(key, 4, data, data_size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 3); // should not increase + node = list_tail(&update_bank, struct secvar_node, link); + ASSERT(!memcmp(node->var->key, key, 4)) // should be at end + + // Unstage the variable update + rc = secvar_enqueue(key, 4, NULL, 0); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(list_length(&update_bank) == 2); + + // Unstage a bogus variable update + rc = secvar_enqueue("nada", 4, NULL, 0); + ASSERT(rc == OPAL_EMPTY); + ASSERT(list_length(&update_bank) == 2); + + + // Empty the in-memory cache, and reload from "pnor" + // Removed to drop dependency on a storage backend + // Probably not actually necessary to test, that's the + // job of the storage backend tests + /* + clear_bank_list(&update_bank); + ASSERT(list_empty(&update_bank)); + secvar_storage.load_bank(&update_bank, SECVAR_UPDATE_BANK); + printf("list_length = %d\n", list_length(&update_bank)); + ASSERT(list_length(&update_bank) == 2); + + node = list_top(&update_bank, struct secvar_node, link); + ASSERT(node); + ASSERT(!memcmp(node->var->key, "test", 4)); + node = list_next(&update_bank, node, link); + ASSERT(node); + ASSERT(!memcmp(node->var->key, "f\0o\0o\0b\0a\0r\0", 6*2)); + */ + + /*** ONE more bad case... ***/ + + free(data); + + return 0; + +} diff --git a/libstb/secvar/test/secvar-test-getvar.c b/libstb/secvar/test/secvar-test-getvar.c new file mode 100644 index 00000000..74d63f73 --- /dev/null +++ b/libstb/secvar/test/secvar-test-getvar.c @@ -0,0 +1,112 @@ +/* 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. + */ +#include "secvar_api_test.c" + +const char *secvar_test_name = "getvar"; + +// Run tests on the less obvious features of secvar_get +// Includes: +// - Partial reads +// - Size queries (NULL buffer) +//int run_test_helper(uint64_t bank_enum) +int run_test(void) +{ + int64_t rc; + + uint64_t size = 4; + char *temp = zalloc(100); + char key[1024] = {0}; + + struct secvar_node *node = zalloc(sizeof(struct secvar_node)); + struct secvar *var = zalloc(sizeof(struct secvar) + 1024); // over-allocate for now, this should be rewritten + size_t data_size = sizeof("foobar"); + char *data = zalloc(data_size); + uint64_t key_len = 4; + memcpy(data, "foobar", data_size); + + memcpy(key, "test", 4); + + // List should be empty at start + rc = secvar_get(key, key_len, data, &data_size); + ASSERT(rc == OPAL_EMPTY); + ASSERT(list_length(&variable_bank) == 0); + + // Manually add variables, and check get_variable call + var->key_len = key_len; + memcpy(var->key, key, key_len); + var->data_size = data_size; + memcpy(var->data, data, data_size); + + node->var = var; + list_add_tail(&variable_bank, &node->link); + + ASSERT(list_length(&variable_bank) == 1); + + // TEST ONLY DATA + // Test actual variable get + size = data_size; + rc = secvar_get(key, key_len, temp, &size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(0 == memcmp("foobar", var->data, size)); + + // Test buffer too small + size = data_size / 2; + memset(temp, 0, 100); + rc = secvar_get(key, key_len, temp, &size); + ASSERT(rc == OPAL_PARTIAL); + + size = 0; + rc = secvar_get(key, key_len, temp, &size); + ASSERT(rc == OPAL_PARTIAL); + ASSERT(size == data_size); + + // Test size query w/ no data + size = 0; + rc = secvar_get(key, key_len, NULL, &size); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(size == data_size); + + /**** Error/Bad param cases ****/ + // NULL key + rc = secvar_get(NULL, key_len, data, &data_size); + ASSERT(rc == OPAL_PARAMETER); + // zero key_len + rc = secvar_get(key, 0, data, &data_size); + ASSERT(rc == OPAL_PARAMETER); + // NULL size, valid data + rc = secvar_get(key, key_len, data, NULL); + ASSERT(rc == OPAL_PARAMETER); + + secvar_enabled = 0; + rc = secvar_get(key, key_len, data, &data_size); + ASSERT(rc == OPAL_UNSUPPORTED); + secvar_enabled = 1; + + secvar_ready = 0; + rc = secvar_get(key, key_len, data, &data_size); + ASSERT(rc == OPAL_RESOURCE); + secvar_ready = 1; + + list_del(&node->link); + + free(var); + free(node); + free(data); + free(temp); + + return 0; +} + diff --git a/libstb/secvar/test/secvar-test-nextvar.c b/libstb/secvar/test/secvar-test-nextvar.c new file mode 100644 index 00000000..79859195 --- /dev/null +++ b/libstb/secvar/test/secvar-test-nextvar.c @@ -0,0 +1,132 @@ +/* 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. + */ +#include "secvar_api_test.c" + +const char *secvar_test_name = "nextvar"; + +int run_test(void) +{ + int64_t rc; + + struct secvar *tmpvar; + struct secvar_node *tmpnode; + + char key[1024] = {0}; + uint64_t key_len = 16; + + + // Load up the bank with some variables. + // If these fail, we have bigger issues. + ASSERT(list_length(&variable_bank) == 0); + tmpvar = zalloc(sizeof(struct secvar) + 6); + tmpnode = zalloc(sizeof(struct secvar_node)); + memcpy(tmpvar->key, "test1", 6); // ascii w/ null + tmpvar->key_len = 6; + tmpnode->var = tmpvar; + list_add_tail(&variable_bank, &tmpnode->link); + ASSERT(list_length(&variable_bank) == 1); + + tmpvar = zalloc(sizeof(struct secvar) + 5); + tmpnode = zalloc(sizeof(struct secvar_node)); + memcpy(tmpvar->key, "test2", 5); // ascii w/o null + tmpvar->key_len = 5; + tmpnode->var = tmpvar; + list_add_tail(&variable_bank, &tmpnode->link); + ASSERT(list_length(&variable_bank) == 2); + + tmpvar = zalloc(sizeof(struct secvar) + 5*2); + tmpnode = zalloc(sizeof(struct secvar_node)); + memcpy(tmpvar->key, L"test3", 5*2); // wide char "unicode" + tmpvar->key_len = 10; + tmpnode->var = tmpvar; + list_add_tail(&variable_bank, &tmpnode->link); + ASSERT(list_length(&variable_bank) == 3); + + // Test sequential nexts + // first item + memset(key, 0, sizeof(key)); + key_len = 0; + rc = secvar_get_next(key, &key_len, sizeof(key)); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(key_len == 6); + ASSERT(!memcmp(key, "test1", key_len)); + + // second item + rc = secvar_get_next(key, &key_len, sizeof(key)); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(key_len == 5); + ASSERT(!memcmp(key, "test2", key_len)); + + // last item + rc = secvar_get_next(key, &key_len, sizeof(key)); + ASSERT(rc == OPAL_SUCCESS); + ASSERT(key_len == 5*2); + ASSERT(!memcmp(key, L"test3", key_len)); + + // end-of-list + rc = secvar_get_next(key, &key_len, sizeof(key)); + ASSERT(rc == OPAL_EMPTY); + + + memset(key, 0, sizeof(key)); + /*** Time for a break to test bad parameters ***/ + // null key + rc = secvar_get_next(NULL, &key_len, 1024); + ASSERT(rc == OPAL_PARAMETER); + // Size too small + key_len = 0; + rc = secvar_get_next(key, &key_len, 1); + ASSERT(rc == OPAL_PARTIAL); + ASSERT(key_len == 6); + // Supplied key length is larger than the buffer + key_len = 6; + rc = secvar_get_next(key, &key_len, 1); + ASSERT(rc == OPAL_PARAMETER); + + // NULL key_len pointer + rc = secvar_get_next(key, NULL, 1024); + ASSERT(rc == OPAL_PARAMETER); + + // NULL key_len pointer + key_len = ~0; + rc = secvar_get_next(key, &key_len, 1024); + ASSERT(rc == OPAL_PARAMETER); + + // zero key_len + key_len = 0; + rc = secvar_get_next(key, &key_len, 0); + ASSERT(rc == OPAL_PARAMETER); + + // Non-existing previous variable + key_len = 1024; + memcpy(key, L"foobar", 7*2); + rc = secvar_get_next(key, &key_len, 1024); + ASSERT(rc == OPAL_PARAMETER); + + secvar_enabled = 0; + rc = secvar_get_next(key, &key_len, 1024); + ASSERT(rc == OPAL_UNSUPPORTED); + secvar_enabled = 1; + + secvar_ready = 0; + rc = secvar_get_next(key, &key_len, 1024); + ASSERT(rc == OPAL_RESOURCE); + secvar_ready = 1; + + clear_bank_list(&variable_bank); + + return 0; +} diff --git a/libstb/secvar/test/secvar-test-void.c b/libstb/secvar/test/secvar-test-void.c new file mode 100644 index 00000000..45b8f449 --- /dev/null +++ b/libstb/secvar/test/secvar-test-void.c @@ -0,0 +1,24 @@ +/* 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. + */ +#include "secvar_api_test.c" + +const char *secvar_test_name = "void"; + +int run_test() +{ + // Do nothing... ensure testing framework is...working. + return 0; +} diff --git a/libstb/secvar/test/secvar_api_test.c b/libstb/secvar/test/secvar_api_test.c new file mode 100644 index 00000000..3b06c030 --- /dev/null +++ b/libstb/secvar/test/secvar_api_test.c @@ -0,0 +1,92 @@ +/* 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. + */ +#include "secvar_common_test.c" + + +// Hack to include the code we actually want to test here... +#include "../secvar_api.c" +#include "../secvar_util.c" + +// Stuff from secvar_main that we need, but not enough to +// include that file +int secvar_enabled = 0; +int secvar_ready = 0; + + +/**** Helper wrappers, so the caller doesn't have to cast ****/ + +static int64_t secvar_get(const char *k_key, uint64_t k_key_len, void *k_data, uint64_t *k_data_size) +{ + return opal_secvar_get( k_key, + k_key_len, + k_data, + k_data_size); +} + +static int64_t secvar_get_next(char *k_key, uint64_t *k_key_len, uint64_t k_key_size) +{ + + return opal_secvar_get_next( k_key, + k_key_len, + k_key_size); +} + + + +static int64_t secvar_enqueue(const char *k_key, uint64_t k_key_len, void *k_data, uint64_t k_data_size) +{ + return opal_secvar_enqueue_update(k_key, + k_key_len, + k_data, + k_data_size); + +} + + + +// Entry point +// TODO: do some real argparsing +int main(int argc, char **argv) +{ + int ret; + + (void) secvar_get; + (void) secvar_get_next; + (void) secvar_enqueue; + (void) argc; + (void) argv; + + secvar_enabled = 1; + + list_head_init(&variable_bank); + list_head_init(&update_bank); + + secvar_ready = 1; + + printf("Running test '%s'...", secvar_test_name); + ret = run_test(); + if (ret) + printf(COLOR_RED "FAILED" COLOR_RESET "\n"); + else + printf(COLOR_GREEN "OK" COLOR_RESET "\n"); + + // Clean up for the test cases + clear_bank_list(&variable_bank); + clear_bank_list(&update_bank); + + return ret; +} + diff --git a/libstb/secvar/test/secvar_common_test.c b/libstb/secvar/test/secvar_common_test.c new file mode 100644 index 00000000..896f63d2 --- /dev/null +++ b/libstb/secvar/test/secvar_common_test.c @@ -0,0 +1,64 @@ +/* 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. + */ +#define SECBOOT_FILE "secboot.img" +#define SECBOOT_SIZE 128000 + +#include +#include +#include +#include +#include +#include +#include + +// Force p9 +enum proc_gen proc_gen = proc_gen_p9; + +// Replace memalign with regular old malloc +#define memalign(a, b) malloc(b) +#define zalloc(a) calloc(1, a) + + + +struct list_head variable_bank; +struct list_head update_bank; + +struct secvar_storage_driver secvar_storage; + + +// For log file output instead of stdout +FILE *outfile; + +#ifndef NO_COLOR +#define COLOR_RED "\033[0;31m" +#define COLOR_GREEN "\033[1;32m" +#define COLOR_RESET "\033[0m" +#else +#define COLOR_RED "" +#define COLOR_GREEN "" +#define COLOR_RESET "" +#endif + +// Helper functions and macros to make test case writing easier + +// Semi-configurable assert, can use to jump to a clean up step on fail +#define ASSERT_POST(a,b) if(!(a)){fprintf(stdout, "Assert '%s' failed at %s:%d...", #a, __FILE__, __LINE__);b;} +#define ASSERT(a) ASSERT_POST(a, return 1) + +// To be defined by test case +int run_test(void); +const char *secvar_test_name; + From patchwork Sat Oct 26 09:45:48 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184601 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 470bl94HKdz9sPc for ; Sat, 26 Oct 2019 20:48:21 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bl85dDgzDqtp for ; Sat, 26 Oct 2019 20:48:20 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 470bhp0dMPzDqlZ for ; Sat, 26 Oct 2019 20:46:17 +1100 (AEDT) Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x9Q9bMBm130504 for ; Sat, 26 Oct 2019 05:46:16 -0400 Received: from e06smtp02.uk.ibm.com (e06smtp02.uk.ibm.com [195.75.94.98]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvhsr2wsp-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:16 -0400 Received: from localhost by e06smtp02.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:14 +0100 Received: from b06cxnps3075.portsmouth.uk.ibm.com (9.149.109.195) 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) Sat, 26 Oct 2019 10:46:12 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9kA9J45219878 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:10 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AF65E4C044; Sat, 26 Oct 2019 09:46:10 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id BC8B24C046; Sat, 26 Oct 2019 09:46:09 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:09 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:48 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0008-0000-0000-00000327CA06 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0009-0000-0000-00004A47036F Message-Id: <20191026094553.26635-7-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 06/11] 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 7fbfca22..5fbc395a 100644 --- a/core/flash.c +++ b/core/flash.c @@ -59,6 +59,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; @@ -93,6 +97,91 @@ bool flash_unregister(void) return true; } +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; @@ -182,6 +271,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; @@ -332,6 +461,7 @@ static void setup_system_flash(struct flash *flash, struct dt_node *node, prlog(PR_INFO, "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 412f8fc8..cdc64e0a 100644 --- a/include/platform.h +++ b/include/platform.h @@ -212,6 +212,10 @@ struct platform { int (*secvar_init)(void); + 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 Sat Oct 26 09:45:49 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184604 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 470bm45xGBz9s7T for ; Sat, 26 Oct 2019 20:49:08 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bm44jztzDqxM for ; Sat, 26 Oct 2019 20:49:08 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 470bhr4Z9NzDqlZ for ; Sat, 26 Oct 2019 20:46:20 +1100 (AEDT) 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 x9Q9bZJK049731 for ; Sat, 26 Oct 2019 05:46:18 -0400 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvja0a4aa-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:18 -0400 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:16 +0100 Received: from b06cxnps4074.portsmouth.uk.ibm.com (9.149.109.196) 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) Sat, 26 Oct 2019 10:46:13 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps4074.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9kBpN53870804 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:11 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id AD4CB4C050; Sat, 26 Oct 2019 09:46:11 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id F00874C040; Sat, 26 Oct 2019 09:46:10 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:10 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:49 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0016-0000-0000-000002BDCC22 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0017-0000-0000-0000331F1875 Message-Id: <20191026094553.26635-8-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 07/11] 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. 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. The driver alternates writes between the two variable sections, so that the final switch from one set of variables to the next can be as atomic as possible by flipping an "active bit" stored in TPM NV. PNOR space provides no lock protection, so prior to writing the variable bank, a sha256 hash is calculated and stored in TPM NV. This hash is checked against when loading the variables from PNOR to ensure consistency -- otherwise a failure is reported, no keys are loaded (which should cause skiroot to refuse to boot if secure boot support is enabled). NOTE: This version of the patch does not actually utilize the TPM NV index space. Instead, it uses a chunk of PNOR space just after the regular secboot partition. V2: - properly set DYN_ALLOC flag after loading from pnor - fixed "out of space" condition check in pnor writes V4: - renamed to secboot_tpm - implement base tpm storage logic - calculates hash on writes, verifies hash on reads - alternate writing to two banks - use alloc_secvar instead of malloc - determines max variable size - add basic unit tests for exposed driver functions Signed-off-by: Eric Richter --- include/secvar.h | 1 + libstb/secvar/storage/Makefile.inc | 2 +- libstb/secvar/storage/secboot_tpm.c | 309 +++++++++++++++++++ libstb/secvar/test/secvar-test-secboot-tpm.c | 134 ++++++++ 4 files changed, 445 insertions(+), 1 deletion(-) create mode 100644 libstb/secvar/storage/secboot_tpm.c create mode 100644 libstb/secvar/test/secvar-test-secboot-tpm.c diff --git a/include/secvar.h b/include/secvar.h index ae262616..cdc9b37d 100644 --- a/include/secvar.h +++ b/include/secvar.h @@ -37,6 +37,7 @@ struct secvar_backend_driver { char compatible[32]; // String to use for compatible in secvar node }; +extern struct secvar_storage_driver secboot_tpm_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..60d08ad9 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_tpm.c SECVAR_STORAGE_OBJS = $(SECVAR_STORAGE_SRCS:%.c=%.o) SECVAR_STORAGE = $(SECVAR_STORAGE_DIR)/built-in.a diff --git a/libstb/secvar/storage/secboot_tpm.c b/libstb/secvar/storage/secboot_tpm.c new file mode 100644 index 00000000..38e51383 --- /dev/null +++ b/libstb/secvar/storage/secboot_tpm.c @@ -0,0 +1,309 @@ +/* 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 +#include "../secvar.h" +#include "../secvar_tpmnv.h" + +//#define CYCLE_BIT(b) (((((b-1)%SECBOOT_VARIABLE_BANK_NUM)+1)%SECBOOT_VARIABLE_BANK_NUM)+1) +#define CYCLE_BIT(b) (b^0x1) + +// Arbitrarily defined via RNG +#define TPMNV_ID_ACTIVE_BIT 0x97faf1e2 +#define TPMNV_ID_HASH_BANK_0 0x7c579c31 +#define TPMNV_ID_HASH_BANK_1 0x9a296ce0 + +#define GET_HASH_BANK_ID(bit) ((bit)?TPMNV_ID_HASH_BANK_1:TPMNV_ID_HASH_BANK_0) + +// TODO: Determine reasonable values for these, or have platform set it? +#define SECBOOT_VARIABLE_BANK_SIZE 32000 +#define SECBOOT_UPDATE_BANK_SIZE 32000 + +#define SECBOOT_VARIABLE_BANK_NUM 2 + +// Because mbedtls doesn't define this? +#define SHA256_DIGEST_LENGTH 32 + + +/* 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 bank[SECBOOT_VARIABLE_BANK_NUM][SECBOOT_VARIABLE_BANK_SIZE]; + char update[SECBOOT_UPDATE_BANK_SIZE]; +} __packed; +#define _secboot_header_ // TODO: delete this with tss, move to header if long term + +struct secboot *secboot_image; + + +static void calc_bank_hash(char *target_hash, char *source_buf, uint64_t size) +{ + mbedtls_sha256_context ctx; + + mbedtls_sha256_init(&ctx); + mbedtls_sha256_update_ret(&ctx, source_buf, size); + mbedtls_sha256_finish_ret(&ctx, target_hash); +} + +static int secboot_format(void) +{ + char bank_hash[SHA256_DIGEST_LENGTH]; + + 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; + + // Write the empty hash to the tpm so loads work in the future + calc_bank_hash(bank_hash, secboot_image->bank[0], SECBOOT_VARIABLE_BANK_SIZE); + secvar_tpmnv_write(TPMNV_ID_HASH_BANK_0, bank_hash, SHA256_DIGEST_LENGTH, 0); + + 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, int flags) +{ + struct secvar_node *node; + char *tmp = target; + + if (!bank) + return -1; + if (!target) + return -1; + + list_for_each(bank, node, link) { + if (node->flags != flags) + continue; + + // Bail early if we are out of storage space + if ((target - tmp) + sizeof(struct secvar) + node->var->data_size > target_size) { + return -1; + } + + memcpy(target, node->var, sizeof(struct secvar) + node->var->data_size); + + target += sizeof(struct secvar) + node->var->data_size; + } + + return 0; +} + + +static int secboot_write_to_pnor(struct list_head *bank, char *target, size_t max_size) +{ + if (!platform.secboot_write) { + prlog(PR_ERR, "Failed to write: platform.secboot_write not set\n"); + return -1; + } + + memset(target, 0, max_size); + + return secboot_serialize_bank(bank, target, max_size, 0); +} + + +static int secboot_load_from_pnor(struct list_head *bank, char *source, size_t max_size) +{ + char *src; + struct secvar_node *tmp; + struct secvar *hdr; + + src = source; + + while (src < (source + max_size)) { + // Load in the header first to get the size, and check if we are at the end + hdr = (struct secvar *) src; + if (hdr->key_len == 0) { + break; + } + + tmp = alloc_secvar(hdr->data_size); + if (!tmp) { + prlog(PR_ERR, "Could not allocate memory for loading secvar from image\n"); + return -1; + } + + memcpy(tmp->var, src, sizeof(struct secvar) + hdr->data_size); + + list_add_tail(bank, &tmp->link); + src += sizeof(struct secvar) + hdr->data_size; + } + + return 0; +} + + +static int secboot_tpm_write_bank(struct list_head *bank, int section) +{ + int rc; + uint64_t bit; + char bank_hash[SHA256_DIGEST_LENGTH]; + + secvar_tpmnv_read(TPMNV_ID_ACTIVE_BIT, &bit, sizeof(bit), 0); + + bit = CYCLE_BIT(bit); + + switch(section) { + case SECVAR_VARIABLE_BANK: + // Calculate the bank hash, and write to TPM NV + rc = secboot_serialize_bank(bank, secboot_image->bank[bit], SECBOOT_VARIABLE_BANK_SIZE, 0); + calc_bank_hash(bank_hash, secboot_image->bank[bit], SECBOOT_VARIABLE_BANK_SIZE); + rc = secvar_tpmnv_write(GET_HASH_BANK_ID(bit), bank_hash, SHA256_DIGEST_LENGTH, 0); + + // Write new variable bank to pnor + rc = platform.secboot_write(0, secboot_image, sizeof(struct secboot)); + + // Flip the bit, and write to TPM NV + rc = secvar_tpmnv_write(TPMNV_ID_ACTIVE_BIT, &bit, sizeof(bit), 0); + break; + case SECVAR_UPDATE_BANK: + rc = secboot_write_to_pnor(bank, secboot_image->update, SECBOOT_UPDATE_BANK_SIZE); + rc = platform.secboot_write(0, secboot_image, sizeof(struct secboot)); + break; + default: + rc = OPAL_HARDWARE; + } + + return rc; +} + + +static int secboot_tpm_load_variable_bank(struct list_head *bank) +{ + char bank_hash[SHA256_DIGEST_LENGTH]; + char tpm_bank_hash[SHA256_DIGEST_LENGTH]; + uint64_t bit; + + secvar_tpmnv_read(TPMNV_ID_ACTIVE_BIT, &bit, sizeof(bit), 0); + secvar_tpmnv_read(GET_HASH_BANK_ID(bit), tpm_bank_hash, SHA256_DIGEST_LENGTH, 0); + + calc_bank_hash(bank_hash, secboot_image->bank[bit], SECBOOT_VARIABLE_BANK_SIZE); + if (memcmp(bank_hash, tpm_bank_hash, SHA256_DIGEST_LENGTH)) + return OPAL_PERMISSION; // Tampered pnor space detected, abandon ship + + return secboot_load_from_pnor(bank, secboot_image->bank[bit], SECBOOT_VARIABLE_BANK_SIZE); +} + + +static int secboot_tpm_load_bank(struct list_head *bank, int section) +{ + switch(section) { + case SECVAR_VARIABLE_BANK: + return secboot_tpm_load_variable_bank(bank); + case SECVAR_UPDATE_BANK: + return secboot_load_from_pnor(bank, secboot_image->update, SECBOOT_UPDATE_BANK_SIZE); + default: + return OPAL_HARDWARE; + } + + return OPAL_HARDWARE; +} + + +static int secboot_tpm_store_init(void) +{ + int rc; + unsigned secboot_size; + + // Already initialized + if (secboot_image) + return 0; + + if (!platform.secboot_info) + return -1; + + prlog(PR_DEBUG, "Initializing for pnor+tpm based platform\n"); + + rc = secvar_tpmnv_alloc(TPMNV_ID_ACTIVE_BIT, sizeof(uint64_t)); + rc |= secvar_tpmnv_alloc(TPMNV_ID_HASH_BANK_0, SHA256_DIGEST_LENGTH); + rc |= secvar_tpmnv_alloc(TPMNV_ID_HASH_BANK_1, SHA256_DIGEST_LENGTH); + if (rc) { + prlog(PR_ERR, "unable to alloc or find the tpmnv space\n"); + return -1; + } + + rc = platform.secboot_info(&secboot_size); + if (rc) { + prlog(PR_ERR, "error %d retrieving keystore info\n", rc); + 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 */ + rc = platform.secboot_read(secboot_image, 0, sizeof(struct secboot)); + if (rc) { + prlog(PR_ERR, "failed to read the secboot partition, rc=%d\n", rc); + goto out_free; + } + + if (secboot_image->header.magic_number != SECBOOT_MAGIC_NUMBER) { + prlog(PR_INFO, "Formatting secboot partition...\n"); + rc = secboot_format(); + if (rc) { + 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_tpm_driver = { + .load_bank = secboot_tpm_load_bank, + .write_bank = secboot_tpm_write_bank, + .store_init = secboot_tpm_store_init, + .compatible = "ibm,secboot-tpm-v1", + .max_var_size = 4096, // Arbitrary, probably could be larger +}; diff --git a/libstb/secvar/test/secvar-test-secboot-tpm.c b/libstb/secvar/test/secvar-test-secboot-tpm.c new file mode 100644 index 00000000..9a433f92 --- /dev/null +++ b/libstb/secvar/test/secvar-test-secboot-tpm.c @@ -0,0 +1,134 @@ +#include "secvar_common_test.c" +#include "../storage/secboot_tpm.c" +#include "../../crypto/mbedtls/library/sha256.c" +#include "../../crypto/mbedtls/library/platform_util.c" +#include "../secvar_tpmnv.c" +#include "../secvar_util.c" + +char *secboot_buffer; + +#define ARBITRARY_SECBOOT_SIZE 128000 + +const char *secvar_test_name = "secboot_tpm"; + +static int secboot_read(void *dst, uint32_t src, uint32_t len) +{ + memcpy(dst, secboot_buffer + src, len); + return 0; +} + +static int secboot_write(uint32_t dst, void *src, uint32_t len) +{ + memcpy(secboot_buffer + dst, src, len); + return 0; +} + +static int secboot_info(uint32_t *total_size) +{ + *total_size = ARBITRARY_SECBOOT_SIZE; + return 0; +} + +struct platform platform; + +int run_test(void) +{ + int rc; + struct secvar_node *tmp; + + platform.secboot_read = secboot_read; + platform.secboot_write = secboot_write; + platform.secboot_info = secboot_info; + + secboot_buffer = zalloc(ARBITRARY_SECBOOT_SIZE); + + // Initialize and format the storage + rc = secboot_tpm_store_init(); + ASSERT(OPAL_SUCCESS == rc); + + // Load the just-formatted empty section + rc = secboot_tpm_load_bank(&variable_bank, SECVAR_VARIABLE_BANK); + ASSERT(OPAL_SUCCESS == rc); + ASSERT(0 == list_length(&variable_bank)); + + // Add some test variables + tmp = alloc_secvar(8); + tmp->var->key_len = 5; + memcpy(tmp->var->key, "test", 5); + tmp->var->data_size = 8; + memcpy(tmp->var->data, "testdata", 8); + list_add_tail(&variable_bank, &tmp->link); + + tmp = alloc_secvar(8); + tmp->var->key_len = 4; + memcpy(tmp->var->key, "foo", 4); + tmp->var->data_size = 8; + memcpy(tmp->var->data, "moredata", 8); + list_add_tail(&variable_bank, &tmp->link); + + // Write the bank + rc = secboot_tpm_write_bank(&variable_bank, SECVAR_VARIABLE_BANK); + ASSERT(OPAL_SUCCESS == rc); + // should write to bank 1 first + ASSERT(secboot_image->bank[1][0] != 0); + ASSERT(secboot_image->bank[0][0] == 0); + + // Clear the variable list + clear_bank_list(&variable_bank); + ASSERT(0 == list_length(&variable_bank)); + + // Load the bank + rc = secboot_tpm_load_bank(&variable_bank, SECVAR_VARIABLE_BANK); + ASSERT(OPAL_SUCCESS == rc); + ASSERT(2 == list_length(&variable_bank)); + + // Change a variable + tmp = list_top(&variable_bank, struct secvar_node, link); + memcpy(tmp->var->data, "somethin", 8); + + // Write the bank + rc = secboot_tpm_write_bank(&variable_bank, SECVAR_VARIABLE_BANK); + ASSERT(OPAL_SUCCESS == rc); + // should have data in both now + ASSERT(secboot_image->bank[0][0] != 0); + ASSERT(secboot_image->bank[1][0] != 0); + + clear_bank_list(&variable_bank); + + // Tamper with pnor, hash check should catch this + secboot_image->bank[0][0] = ~secboot_image->bank[0][0]; + + rc = secboot_tpm_load_bank(&variable_bank, SECVAR_VARIABLE_BANK); + ASSERT(rc != OPAL_SUCCESS); // TODO: permission? + + // Fix it back... + secboot_image->bank[0][0] = ~secboot_image->bank[0][0]; + + // Should be ok again + rc = secboot_tpm_load_bank(&variable_bank, SECVAR_VARIABLE_BANK); + ASSERT(rc == OPAL_SUCCESS); + + clear_bank_list(&variable_bank); + free(secboot_buffer); + + return 0; +} + +int main(void) +{ + int rc = 0; + + list_head_init(&variable_bank); + + rc = run_test(); + + if (rc) + printf(COLOR_RED "FAILED" COLOR_RESET "\n"); + else + printf(COLOR_GREEN "OK" COLOR_RESET "\n"); + + free(tpm_image); + free(secboot_image); + + return rc; +} From patchwork Sat Oct 26 09:45:50 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184602 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 470blX5VyPz9s7T for ; Sat, 26 Oct 2019 20:48:40 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470blX44JSzDqsQ for ; Sat, 26 Oct 2019 20:48:40 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com; envelope-from=erichte@linux.ibm.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com [148.163.156.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 470bhr5np8zDqld for ; Sat, 26 Oct 2019 20:46:20 +1100 (AEDT) Received: from pps.filterd (m0187473.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x9Q9bMBs130504 for ; Sat, 26 Oct 2019 05:46:19 -0400 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvhsr2wtx-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:18 -0400 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:17 +0100 Received: from b06avi18878370.portsmouth.uk.ibm.com (9.149.26.194) 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) Sat, 26 Oct 2019 10:46:14 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06avi18878370.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9kCH745482394 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:12 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A33D24C044; Sat, 26 Oct 2019 09:46:12 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id ED1A74C04E; Sat, 26 Oct 2019 09:46:11 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:11 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:50 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0016-0000-0000-000002BDCC23 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0017-0000-0000-0000331F1876 Message-Id: <20191026094553.26635-9-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 08/11] crypto: add mbedtls build integration via git submodule 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 requires more crypto support than skiboot currently has. Since mbedtls' x509, etc implementations have rather tight dependencies which prevent easy cherry picking (unlike the existing sha512.c), it is easier to integrate and maintain the whole mbedtls library as a submodule. Signed-off-by: Eric Richter --- .gitmodules | 4 ++ Makefile.main | 1 + libstb/Makefile.inc | 5 +- libstb/crypto/Makefile.inc | 20 +++++++ libstb/crypto/mbedtls | 1 + libstb/crypto/mbedtls-config.h | 98 ++++++++++++++++++++++++++++++++++ 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 .gitmodules create mode 100644 libstb/crypto/Makefile.inc create mode 160000 libstb/crypto/mbedtls create mode 100644 libstb/crypto/mbedtls-config.h diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..78998dae --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "libstb/crypto/mbedtls"] + path = libstb/crypto/mbedtls + url = https://github.com/ARMmbed/mbedtls + branch = mbedtls-2.16 diff --git a/Makefile.main b/Makefile.main index 2d60bbbf..31e3018d 100644 --- a/Makefile.main +++ b/Makefile.main @@ -356,6 +356,7 @@ clean: $(RM) include/asm-offsets.h version.c .version $(RM) skiboot.info external/gard/gard.info external/pflash/pflash.info $(RM) extract-gcov $(TARGET).lid.stb $(TARGET).lid.xz.stb + $(MAKE) -C libstb/crypto/mbedtls clean distclean: clean $(RM) *~ $(SUBDIRS:%=%/*~) include/*~ diff --git a/libstb/Makefile.inc b/libstb/Makefile.inc index d3f68496..c727518c 100644 --- a/libstb/Makefile.inc +++ b/libstb/Makefile.inc @@ -12,8 +12,11 @@ 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 +include $(SRC)/$(LIBSTB_DIR)/crypto/Makefile.inc -$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(SECVAR) $(MBEDTLS) +CPPFLAGS += -I$(SRC)/$(LIBSTB_DIR)/crypto/mbedtls/include + +$(LIBSTB): $(LIBSTB_OBJS:%=$(LIBSTB_DIR)/%) $(DRIVERS) $(TSS) $(SECVAR) $(CRYPTO) libstb/create-container: libstb/create-container.c libstb/container-utils.c $(call Q, HOSTCC ,$(HOSTCC) $(HOSTCFLAGS) \ diff --git a/libstb/crypto/Makefile.inc b/libstb/crypto/Makefile.inc new file mode 100644 index 00000000..1e153ed2 --- /dev/null +++ b/libstb/crypto/Makefile.inc @@ -0,0 +1,20 @@ +CRYPTO_DIR = $(LIBSTB_DIR)/crypto + +SUBDIRS += $(CRYPTO_DIR) + +MBEDTLS=$(SRC)/$(LIBSTB_DIR)/crypto/mbedtls/library/libmbedcrypto.a +MBEDTLS+= $(SRC)/$(LIBSTB_DIR)/crypto/mbedtls/library/libmbedx509.a + +MBEDTLS_CFLAGS = $(CFLAGS) +MBEDTLS_CFLAGS += -I$(SRC)/$(LIBSTB_DIR) +MBEDTLS_CFLAGS += -I$(SRC)/$(LIBSTB_DIR)/crypto -DMBEDTLS_CONFIG_FILE='' +MBEDTLS_CFLAGS += -Wno-suggest-attribute=const +MBEDTLS_CFLAGS += -I$(SRC)/$(LIBSTB_DIR)/crypto/mbedtls/include +MBEDTLS_CFLAGS += $(CPPFLAGS) + +$(MBEDTLS): + @$(MAKE) -C $(SRC)/$(LIBSTB_DIR)/crypto/mbedtls/library/ CFLAGS="$(MBEDTLS_CFLAGS)" CC=$(CC) AR=$(AR) libmbedcrypto.a libmbedx509.a + +CRYPTO = $(CRYPTO_DIR)/built-in.a + +$(CRYPTO): $(MBEDTLS) diff --git a/libstb/crypto/mbedtls b/libstb/crypto/mbedtls new file mode 160000 index 00000000..d81c11b8 --- /dev/null +++ b/libstb/crypto/mbedtls @@ -0,0 +1 @@ +Subproject commit d81c11b8ab61fd5b2da8133aa73c5fe33a0633eb diff --git a/libstb/crypto/mbedtls-config.h b/libstb/crypto/mbedtls-config.h new file mode 100644 index 00000000..edf4acc2 --- /dev/null +++ b/libstb/crypto/mbedtls-config.h @@ -0,0 +1,98 @@ +/** + * \file config-no-entropy.h + * + * \brief Minimal configuration of features that do not require an entropy source + */ +/* + * Copyright (C) 2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * Minimal configuration of features that do not require an entropy source + * Distinguishing reatures: + * - no entropy module + * - no TLS protocol implementation available due to absence of an entropy + * source + * + * See README.txt for usage instructions. + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +/* System support */ +#define MBEDTLS_HAVE_ASM +#define MBEDTLS_HAVE_TIME + +/* mbed TLS feature support */ +#define MBEDTLS_CIPHER_MODE_CBC +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define MBEDTLS_ECP_NIST_OPTIM +#define MBEDTLS_ECDSA_DETERMINISTIC +#define MBEDTLS_PK_RSA_ALT_SUPPORT +#define MBEDTLS_PKCS1_V15 +#define MBEDTLS_PKCS1_V21 +#define MBEDTLS_SELF_TEST +#define MBEDTLS_VERSION_FEATURES +#define MBEDTLS_X509_CHECK_KEY_USAGE +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/* mbed TLS modules */ +#define MBEDTLS_AES_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#define MBEDTLS_CCM_C +#define MBEDTLS_CIPHER_C +#define MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ERROR_C +#define MBEDTLS_GCM_C +#define MBEDTLS_MD_C +#define MBEDTLS_OID_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_RSA_C +#define MBEDTLS_SHA256_C +#define MBEDTLS_SHA512_C +#define MBEDTLS_X509_USE_C +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_CRL_PARSE_C +//#define MBEDTLS_CMAC_C + +/* Settings to reduce/remove warnings */ +#define MBEDTLS_MPI_WINDOW_SIZE 3 // (max/default is 6) Increase for speed, may introduce warnings +#define MBEDTLS_MPI_MAX_SIZE 512 // (default is 1024) increase for more bits in user-MPIs +#define SIZE_MAX 65535 // this might need to be in libc? + +/* Disableable to mitigate warnings */ +#define MBEDTLS_ASN1_WRITE_C // Expects SIZE_MAX +#define MBEDTLS_VERSION_C // Possible 'const' function +#define MBEDTLS_HMAC_DRBG_C + +/* Miscellaneous options and fixes*/ +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_NO_UDBL_DIVISION // Disabled due to unsupported operation + +#endif /* MBEDTLS_CONFIG_H */ From patchwork Sat Oct 26 09:45:51 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184603 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 470blp5flZz9sPc for ; Sat, 26 Oct 2019 20:48:54 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470blp4SCmzDqsd for ; Sat, 26 Oct 2019 20:48:54 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.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 470bhr4CqdzDqkG for ; Sat, 26 Oct 2019 20:46:20 +1100 (AEDT) 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 x9Q9bt6Z095892 for ; Sat, 26 Oct 2019 05:46:18 -0400 Received: from e06smtp04.uk.ibm.com (e06smtp04.uk.ibm.com [195.75.94.100]) by mx0b-001b2d01.pphosted.com with ESMTP id 2vvjbe20ph-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:18 -0400 Received: from localhost by e06smtp04.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:16 +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) Sat, 26 Oct 2019 10:46:15 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06avi18626390.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9je4D36110808 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:45:40 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 954A44C04E; Sat, 26 Oct 2019 09:46:13 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E199E4C04A; Sat, 26 Oct 2019 09:46:12 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:12 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:51 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0016-0000-0000-000002BDCC25 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0017-0000-0000-0000331F1877 Message-Id: <20191026094553.26635-10-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 09/11] crypto: add out-of-tree mbedtls pkcs7 parser 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 This patch adds a pkcs7 parser for mbedtls that hasn't yet gone upstream. Once/if that implementation is accepted, this patch can be removed. Signed-off-by: Eric Richter --- libstb/crypto/Makefile.inc | 4 +- libstb/crypto/pkcs7/Makefile.inc | 10 + libstb/crypto/pkcs7/pkcs7.c | 476 +++++++++++++++++++++++++++++++ libstb/crypto/pkcs7/pkcs7.h | 176 ++++++++++++ 4 files changed, 665 insertions(+), 1 deletion(-) create mode 100644 libstb/crypto/pkcs7/Makefile.inc create mode 100644 libstb/crypto/pkcs7/pkcs7.c create mode 100644 libstb/crypto/pkcs7/pkcs7.h diff --git a/libstb/crypto/Makefile.inc b/libstb/crypto/Makefile.inc index 1e153ed2..954bd66d 100644 --- a/libstb/crypto/Makefile.inc +++ b/libstb/crypto/Makefile.inc @@ -15,6 +15,8 @@ MBEDTLS_CFLAGS += $(CPPFLAGS) $(MBEDTLS): @$(MAKE) -C $(SRC)/$(LIBSTB_DIR)/crypto/mbedtls/library/ CFLAGS="$(MBEDTLS_CFLAGS)" CC=$(CC) AR=$(AR) libmbedcrypto.a libmbedx509.a +include $(CRYPTO_DIR)/pkcs7/Makefile.inc + CRYPTO = $(CRYPTO_DIR)/built-in.a -$(CRYPTO): $(MBEDTLS) +$(CRYPTO): $(MBEDTLS) $(PKCS7) diff --git a/libstb/crypto/pkcs7/Makefile.inc b/libstb/crypto/pkcs7/Makefile.inc new file mode 100644 index 00000000..6acf6c68 --- /dev/null +++ b/libstb/crypto/pkcs7/Makefile.inc @@ -0,0 +1,10 @@ + +PKCS7_DIR = libstb/crypto/pkcs7 + +SUBDIRS += $(PKCS7_DIR) + +PKCS7_SRCS = pkcs7.c +PKCS7_OBJS = $(PKCS7_SRCS:%.c=%.o) +PKCS7 = $(PKCS7_DIR)/built-in.a + +$(PKCS7): $(PKCS7_OBJS:%=$(PKCS7_DIR)/%) diff --git a/libstb/crypto/pkcs7/pkcs7.c b/libstb/crypto/pkcs7/pkcs7.c new file mode 100644 index 00000000..c5ed897d --- /dev/null +++ b/libstb/crypto/pkcs7/pkcs7.c @@ -0,0 +1,476 @@ +/* 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. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include +#else +#include MBEDTLS_CONFIG_FILE +#endif +//#if defined(MBEDTLS_PKCS7_USE_C) + +#include +#include +#include "pkcs7.h" +#include +#include + +#include +#include +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_printf printf +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include +#endif +#if defined(MBEDTLS_HAVE_TIME_DATE) +#include +#include +#endif + +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain DER encoded data. + * A terminating null byte is always appended. + */ + +#if 0 +int mbedtls_pkcs7_load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + fclose( f ); + return( MBEDTLS_ERR_PKCS7_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + + mbedtls_platform_zeroize( *buf, *n + 1 ); + mbedtls_free( *buf ); + + return( MBEDTLS_ERR_PKCS7_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + return( 0 ); +} +#endif + +/** + * Initializes the pkcs7 structure. + */ +void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 ) +{ + memset( pkcs7, 0, sizeof( mbedtls_pkcs7 ) ); +} + + +static int pkcs7_get_next_content_len( unsigned char **p, unsigned char *end, size_t *len ) +{ + int ret; + + if ( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + return ( 0 ); +} + +/** + * version Version + * Version ::= INTEGER + **/ +static int pkcs7_get_version( unsigned char **p, unsigned char *end, int *ver ) +{ + int ret; + + if ( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + return ( 0 ); +} + +/** + * ContentInfo ::= SEQUENCE { + * contentType ContentType, + * content + * [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + **/ +static int pkcs7_get_content_info_type( unsigned char **p, unsigned char *end, mbedtls_pkcs7_buf *pkcs7 ) +{ + size_t len = 0; + int ret; + + ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE ); + if ( ret ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_OID ); + if ( ret ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + pkcs7->tag = MBEDTLS_ASN1_OID; + pkcs7->len = len; + pkcs7->p = *p; + + return ret; +} + +/** + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * This is from x509.h + **/ +static int pkcs7_get_digest_algorithm( unsigned char **p, unsigned char *end, mbedtls_x509_buf *alg ) +{ + int ret; + + if ( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG + ret ); + + return ( 0 ); +} + +/** + * DigestAlgorithmIdentifiers :: SET of DigestAlgorithmIdentifier + **/ +static int pkcs7_get_digest_algorithm_set( unsigned char **p, unsigned char *end, + mbedtls_x509_buf *alg ) +{ + size_t len = 0; + int ret; + + ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SET ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + end = *p + len; + + /** For now, it assumes there is only one digest algorithm specified **/ + ret = mbedtls_asn1_get_alg_null( p, end, alg ); + if ( ret ) + return ret; + + return ( 0 ); +} + +/** + * certificates :: SET OF ExtendedCertificateOrCertificate, + * ExtendedCertificateOrCertificate ::= CHOICE { + * certificate Certificate -- x509, + * extendedCertificate[0] IMPLICIT ExtendedCertificate } + **/ +static int pkcs7_get_certificates( unsigned char **buf, size_t buflen, + mbedtls_x509_crt *certs ) +{ + int ret; + + if ( ( ret = mbedtls_x509_crt_parse( certs, *buf, buflen ) ) != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + return ( 0 ); +} + +/** + * EncryptedDigest ::= OCTET STRING + **/ +static int pkcs7_get_signature( unsigned char **p, unsigned char *end, + mbedtls_pkcs7_buf *signature ) +{ + int ret; + size_t len = 0; + + ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_OCTET_STRING); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + signature->tag = MBEDTLS_ASN1_OCTET_STRING; + signature->len = len; + signature->p = *p; + + return ( 0 ); +} + +/** + * SignerInfo ::= SEQUENCE { + * version Version; + * issuerAndSerialNumber IssuerAndSerialNumber, + * digestAlgorithm DigestAlgorithmIdentifier, + * authenticatedAttributes + * [0] IMPLICIT Attributes OPTIONAL, + * digestEncryptionAlgorithm DigestEncryptionAlgorithmIdentifier, + * encryptedDigest EncryptedDigest, + * unauthenticatedAttributes + * [1] IMPLICIT Attributes OPTIONAL, + **/ +static int pkcs7_get_signers_info_set( unsigned char **p, unsigned char *end, + mbedtls_pkcs7_signer_info *signers_set ) +{ + unsigned char *end_set; + int ret; + size_t len = 0; + + ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SET ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + end_set = *p + len; + + ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + ret = mbedtls_asn1_get_int( p, end_set, &signers_set->version ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + signers_set->issuer_raw.p = *p; + + ret = mbedtls_asn1_get_tag( p, end_set, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + ret = mbedtls_x509_get_name( p, *p + len, &signers_set->issuer ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + signers_set->issuer_raw.len = *p - signers_set->issuer_raw.p; + + ret = mbedtls_x509_get_serial( p, end_set, &signers_set->serial ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + ret = pkcs7_get_digest_algorithm( p, end_set, + &signers_set->alg_identifier ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + ret = pkcs7_get_digest_algorithm( p, end_set, + &signers_set->sig_alg_identifier ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + ret = pkcs7_get_signature( p, end, &signers_set->sig ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + signers_set->next = NULL; + + return ( 0 ); +} + +/** + * SignedData ::= SEQUENCE { + * version Version, + * digestAlgorithms DigestAlgorithmIdentifiers, + * contentInfo ContentInfo, + * certificates + * [0] IMPLICIT ExtendedCertificatesAndCertificates + * OPTIONAL, + * crls + * [0] IMPLICIT CertificateRevocationLists OPTIONAL, + * signerInfos SignerInfos } + */ +static int pkcs7_get_signed_data( unsigned char *buf, size_t buflen, + mbedtls_pkcs7_signed_data *signed_data ) +{ + unsigned char *p = buf; + unsigned char *end = buf + buflen; + size_t len = 0; + int ret; + + ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_CONSTRUCTED + | MBEDTLS_ASN1_SEQUENCE ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_INVALID_FORMAT + ret ); + + /* Get version of signed data */ + ret = pkcs7_get_version( &p, end, &signed_data->version ); + if ( ret != 0 ) + return ( ret ); + + /* If version != 1, return invalid version */ + if ( signed_data->version != MBEDTLS_PKCS7_SUPPORTED_VERSION ) { + mbedtls_printf("Invalid version\n"); + return ( MBEDTLS_ERR_PKCS7_INVALID_VERSION ); + } + + /* Get digest algorithm */ + ret = pkcs7_get_digest_algorithm_set( &p, end, + &signed_data->digest_alg_identifiers ); + if ( ret != 0 ) { + mbedtls_printf("error getting digest algorithms\n"); + return ( ret ); + } + + if ( signed_data->digest_alg_identifiers.len != strlen( MBEDTLS_OID_DIGEST_ALG_SHA256 ) ) + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG ); + + if ( memcmp( signed_data->digest_alg_identifiers.p, MBEDTLS_OID_DIGEST_ALG_SHA256, + signed_data->digest_alg_identifiers.len ) ) { + mbedtls_fprintf(stdout, "Digest Algorithm other than SHA256 is not supported\n"); + return ( MBEDTLS_ERR_PKCS7_INVALID_ALG ); + } + + /* Do not expect any content */ + ret = pkcs7_get_content_info_type( &p, end, &signed_data->content.oid ); + if ( ret != 0 ) + return ( MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA ); + + if ( memcmp( signed_data->content.oid.p, MBEDTLS_OID_PKCS7_DATA, + signed_data->content.oid.len ) ) { + mbedtls_printf("Invalid PKCS7 data\n"); + return ( MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA ) ; + } + + p = p + signed_data->content.oid.len; + + ret = pkcs7_get_next_content_len( &p, end, &len ); + if ( ret != 0 ) + return ( ret ); + + /* Get certificates */ + mbedtls_x509_crt_init( &signed_data->certs ); + ret = pkcs7_get_certificates( &p, len, &signed_data->certs ); + if ( ret != 0 ) + return ( ret ) ; + + p = p + len; + + /* Get signers info */ + ret = pkcs7_get_signers_info_set( &p, end, &signed_data->signers ); + if ( ret != 0 ) + return ( ret ); + + return ( ret ); +} + +int mbedtls_pkcs7_parse_der( const unsigned char *buf, const int buflen, + mbedtls_pkcs7 *pkcs7 ) +{ + unsigned char *start; + unsigned char *end; + size_t len = 0; + int ret; + + /* use internal buffer for parsing */ + start = ( unsigned char * )buf; + end = start + buflen; + + ret = pkcs7_get_content_info_type( &start, end, &pkcs7->content_type_oid ); + if ( ret != 0 ) + goto out; + + if ( ( !memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENVELOPED_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_DIGESTED_DATA, + pkcs7->content_type_oid.len ) ) + || ( !memcmp(pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_ENCRYPTED_DATA, + pkcs7->content_type_oid.len ) ) ) { + mbedtls_printf("Unsupported PKCS7 data type\n"); + ret = MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE; + goto out; + } + + if ( ( memcmp( pkcs7->content_type_oid.p, MBEDTLS_OID_PKCS7_SIGNED_DATA, + pkcs7->content_type_oid.len ) ) ) { + mbedtls_printf("Invalid PKCS7 data type\n"); + ret = MBEDTLS_ERR_PKCS7_INVALID_ALG; + goto out; + } + mbedtls_printf("Content type is SignedData, continue...\n"); + + start = start + pkcs7->content_type_oid.len; + + ret = pkcs7_get_next_content_len( &start, end, &len ); + if ( ret != 0 ) + goto out; + + ret = pkcs7_get_signed_data( start, len, &pkcs7->signed_data ); + if ( ret != 0 ) + goto out; + +out: + return ( ret ); +} + +int mbedtls_pkcs7_signed_data_verify( mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *data, int datalen ) +{ + + int ret; + unsigned char hash[32]; + mbedtls_pk_context pk_cxt = cert->pk; + const mbedtls_md_info_t *md_info = + mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); + + mbedtls_md( md_info, data, datalen, hash ); + ret = mbedtls_pk_verify( &pk_cxt, MBEDTLS_MD_SHA256,hash, 32, pkcs7->signed_data.signers.sig.p, pkcs7->signed_data.signers.sig.len ); + + printf("rc is %02x\n", ret); + + return ( ret ); +} + +//#endif diff --git a/libstb/crypto/pkcs7/pkcs7.h b/libstb/crypto/pkcs7/pkcs7.h new file mode 100644 index 00000000..1aacd6ef --- /dev/null +++ b/libstb/crypto/pkcs7/pkcs7.h @@ -0,0 +1,176 @@ +/** + * \file pkcs7.h + * + * \brief PKCS7 generic defines and structures + */ +/* + * Copyright (C) 2019, IBM Corp, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS7_H +#define MBEDTLS_PKCS7_H + +//#if !defined(MBEDTLS_CONFIG_FILE) +//#include "config.h" +//#else +//#include MBEDTLS_CONFIG_FILE +//#endif + +#include "mbedtls/asn1.h" +#include "mbedtls/x509.h" +#include "mbedtls/x509_crt.h" + +/** + * \name PKCS7 Error codes + * \{ + */ +#define MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE -0x7080 /**< Unavailable feature, e.g. anything other than signed data. */ +#define MBEDTLS_ERR_PKCS7_UNKNOWN_OID -0x7100 /**< Requested OID is unknown. */ +#define MBEDTLS_ERR_PKCS7_INVALID_FORMAT -0x7180 /**< The CRT/CRL format is invalid, e.g. different type expected. */ +#define MBEDTLS_ERR_PKCS7_INVALID_VERSION -0x7200 /**< The PKCS7 version element is invalid. */ +#define MBEDTLS_ERR_PKCS7_INVALID_ALG -0x7280 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_PKCS7_INVALID_SIG_ALG -0x7300 /**< Signature algorithm (oid) is unsupported. */ +#define MBEDTLS_ERR_PKCS7_SIG_MISMATCH -0x7380 /**< Signature verification fails. (see \c ::mbedtls_x509_crt sig_oid) */ +#define MBEDTLS_ERR_PKCS7_BAD_INPUT_DATA -0x7400 /**< Input invalid. */ +#define MBEDTLS_ERR_PKCS7_ALLOC_FAILED -0x7480 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_PKCS7_FILE_IO_ERROR -0x7500 /**< File Read/Write Error */ +/* \} name */ + + +/** + * \name PKCS7 Supported Version + * \{ + */ +#define MBEDTLS_PKCS7_SUPPORTED_VERSION 0x01 +/* \} name */ + + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef mbedtls_asn1_buf mbedtls_pkcs7_buf; + +/** + * Container for ASN1 named information objects. + * It allows for Relative Distinguished Names (e.g. cn=localhost,ou=code,etc.). + */ +typedef mbedtls_asn1_named_data mbedtls_pkcs7_name; + +/** + * Container for a sequence of ASN.1 items + */ +typedef mbedtls_asn1_sequence mbedtls_pkcs7_sequence; + +/** + * Structure holding PKCS7 signer info + */ +typedef struct mbedtls_pkcs7_signer_info { + int version; + mbedtls_x509_buf serial; + mbedtls_x509_name issuer; + mbedtls_x509_buf issuer_raw; + mbedtls_x509_buf alg_identifier; + mbedtls_x509_buf sig_alg_identifier; + mbedtls_x509_buf sig; + struct mbedtls_pkcs7_signer_info *next; +} +mbedtls_pkcs7_signer_info; + +/** + * Structure holding attached data as part of PKCS7 signed data format + */ +typedef struct mbedtls_pkcs7_data { + mbedtls_pkcs7_buf oid; + mbedtls_pkcs7_buf data; +} +mbedtls_pkcs7_data; + +/** + * Structure holding the signed data section + */ +typedef struct mbedtls_pkcs7_signed_data { + int version; + mbedtls_pkcs7_buf digest_alg_identifiers; + struct mbedtls_pkcs7_data content; + mbedtls_x509_crt certs; + mbedtls_x509_crl crl; + struct mbedtls_pkcs7_signer_info signers; +} +mbedtls_pkcs7_signed_data; + +/** + * Structure holding PKCS7 structure, only signed data for now + */ +typedef struct mbedtls_pkcs7 { + mbedtls_pkcs7_buf content_type_oid; + struct mbedtls_pkcs7_signed_data signed_data; +} +mbedtls_pkcs7; + +void mbedtls_pkcs7_init( mbedtls_pkcs7 *pkcs7 ); + +int mbedtls_pkcs7_parse_der(const unsigned char *buf, const int buflen, mbedtls_pkcs7 *pkcs7); + +int mbedtls_pkcs7_signed_data_verify(mbedtls_pkcs7 *pkcs7, mbedtls_x509_crt *cert, const unsigned char *data, int datalen); + +int mbedtls_pkcs7_load_file( const char *path, unsigned char **buf, size_t *n ); + +#if defined(MBEDTLS_SELF_TEST) + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_x509_self_test( int verbose ); + +#endif /* MBEDTLS_SELF_TEST */ + +#define MBEDTLS_X509_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +#ifdef __cplusplus +} +#endif + +/* + * PKCS#7 OIDs + */ +#define MBEDTLS_OID_PKCS7 MBEDTLS_OID_PKCS "\x07" /**< pkcs-7 */ + +#define MBEDTLS_OID_PKCS7_DATA MBEDTLS_OID_PKCS7 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_SIGNED_DATA MBEDTLS_OID_PKCS7 "\x02" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_ENVELOPED_DATA MBEDTLS_OID_PKCS7 "\x03" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_SIGNED_AND_ENVELOPED_DATA MBEDTLS_OID_PKCS7 "\x04" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_DIGESTED_DATA MBEDTLS_OID_PKCS7 "\x05" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS7_ENCRYPTED_DATA MBEDTLS_OID_PKCS7 "\x06" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ + + + + +#endif /* pkcs7.h */ From patchwork Sat Oct 26 09:45:52 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184605 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 470bmL6S1rz9s7T for ; Sat, 26 Oct 2019 20:49:22 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bmL53S1zDqxs for ; Sat, 26 Oct 2019 20:49:22 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.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 470bht4N8FzDqlf for ; Sat, 26 Oct 2019 20:46:21 +1100 (AEDT) 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 x9Q9bXsO043371 for ; Sat, 26 Oct 2019 05:46:19 -0400 Received: from e06smtp05.uk.ibm.com (e06smtp05.uk.ibm.com [195.75.94.101]) by mx0a-001b2d01.pphosted.com with ESMTP id 2vvj10ajj1-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:19 -0400 Received: from localhost by e06smtp05.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:17 +0100 Received: from b06cxnps4075.portsmouth.uk.ibm.com (9.149.109.197) by e06smtp05.uk.ibm.com (192.168.101.135) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; (version=TLSv1/SSLv3 cipher=AES256-GCM-SHA384 bits=256/256) Sat, 26 Oct 2019 10:46:16 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps4075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9kE6M52166832 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:14 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8B9AD4C044; Sat, 26 Oct 2019 09:46:14 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id D63B34C050; Sat, 26 Oct 2019 09:46:13 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:13 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:52 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0020-0000-0000-0000037ECEE9 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0021-0000-0000-000021D51EC6 Message-Id: <20191026094553.26635-11-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 10/11] 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. 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 V4: - added draft document for general concepts - stores PK in the tpm - empty variables don't attempt to preallocate space - many malloc->zalloc changes - removed hard coded example variables - removed most printfs, converted some to prlog - updated for new pkcs7 implementation - removed unnecessary "SecureBoot", and "SecureMode" variables, handled by devtree entry [1] https://github.com/tianocore/edk2-staging.git Signed-off-by: Nayna Jain --- doc/secvar/edk2.rst | 49 ++ include/secvar.h | 1 + libstb/secvar/backend/Makefile.inc | 4 +- .../secvar/backend/edk2-compat/edk2-compat.c | 555 ++++++++++++++++++ libstb/secvar/backend/edk2-compat/edk2.h | 249 ++++++++ 5 files changed, 857 insertions(+), 1 deletion(-) create mode 100644 doc/secvar/edk2.rst create mode 100644 libstb/secvar/backend/edk2-compat/edk2-compat.c create mode 100644 libstb/secvar/backend/edk2-compat/edk2.h diff --git a/doc/secvar/edk2.rst b/doc/secvar/edk2.rst new file mode 100644 index 00000000..e0c29457 --- /dev/null +++ b/doc/secvar/edk2.rst @@ -0,0 +1,49 @@ +.. _secvar/edk2: + +Skiboot edk2-compatible Secure Variable Backend +=============================================== + +Overview +-------- + +The edk2 secure variable backend for skiboot borrows from edk2 concepts +such as the three key hierarchy (PK, KEK, and db), and a similar +structure. In general, variable updates must be signed with a key +of a higher level. So, updates to the db must be signed with a key stored +in the KEK; updates to the KEK must be signed with the PK. Updates to the +PK must be signed with the previous PK (if any). + +Variables are stored in the efi signature list format, and updates are a +signed variant that includes an authentication header. + +If no PK is currently enrolled, the system is considered to be in "Setup +Mode". Any key can be enrolled without signature checks. However, once a +PK is enrolled, the system switches to "User Mode", and each update must +now be signed according to the hierarchy. Furthermore, when in "User +Mode", the backend initialized the ``os-secure-mode`` device tree flag, +signaling to the kernel that we are in secure mode. + +Updates are processed sequentially, in the order that they were provided +in the update queue. If any update fails to validate, appears to be +malformed, or any other error occurs, NO updates will not be applied. +This includes updates that may have successfully applied prior to the +error. The system will continue in an error state, reporting the error +reason via the ``update-status`` device tree property. + +P9 Special Case for the Platform Key +------------------------------------ + +Due to the powerful nature of the platform key and the lack of lockable +flash, the edk2 backend will store the PK in TPM NV rather than PNOR on +P9 systems. (TODO expand on this) + +Update Status Return Codes +-------------------------- + +TODO, edk2 driver needs to actually return these properly first + + +Device Tree Bindings +-------------------- + +TODO diff --git a/include/secvar.h b/include/secvar.h index cdc9b37d..87365445 100644 --- a/include/secvar.h +++ b/include/secvar.h @@ -38,6 +38,7 @@ struct secvar_backend_driver { }; extern struct secvar_storage_driver secboot_tpm_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..34ce59a9 100644 --- a/libstb/secvar/backend/Makefile.inc +++ b/libstb/secvar/backend/Makefile.inc @@ -4,8 +4,10 @@ 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 +SUBDIRS += $(SECVAR_BACKEND_DIR)/edk2-compat + $(SECVAR_BACKEND): $(SECVAR_BACKEND_OBJS:%=$(SECVAR_BACKEND_DIR)/%) 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..f767b90a --- /dev/null +++ b/libstb/secvar/backend/edk2-compat/edk2-compat.c @@ -0,0 +1,555 @@ +/* + * 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 "libstb/crypto/pkcs7/pkcs7.h" +#include "edk2.h" +#include "opal-api.h" +#include "../../secvar.h" +#include "../../secvar_devtree.h" +#include "../../secvar_tpmnv.h" + +#define TPMNV_ID_EDK2_PK 0xd1e81f2c + +static int esl_get_cert_size(unsigned char *buf) +{ + EFI_SIGNATURE_LIST list; + uint32_t sigsize; + + 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; + + 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; +} + + +/* + * PK needs to be stored in the TPMNV space if on p9 + * We store it using the form , the + * extra secvar headers are unnecessary + */ +static int edk2_p9_load_pk(void) +{ + struct secvar_node *pkvar; + uint64_t size; + int rc; + + // Ensure it exists + rc = secvar_tpmnv_alloc(TPMNV_ID_EDK2_PK, -1); + + // Peek to get the size + rc = secvar_tpmnv_read(TPMNV_ID_EDK2_PK, &size, sizeof(size), 0); + if (OPAL_EMPTY) + return 0; + else if (rc) + return -1; + + if (size > secvar_storage.max_var_size) + return OPAL_RESOURCE; + + pkvar = alloc_secvar(size); + pkvar->var->data_size = size; + pkvar->flags |= SECVAR_FLAG_VOLATILE; + + rc = secvar_tpmnv_read(TPMNV_ID_EDK2_PK, pkvar->var->data, pkvar->var->data_size, sizeof(pkvar->var->data_size)); + if (rc) + return -1; + + list_add_tail(&variable_bank, &pkvar->link); +} + +static int edk2_p9_write_pk(void) +{ + char *tmp; + int32_t tmpsize; + struct secvar_node *pkvar; + + pkvar = find_secvar("PK", 3, &variable_bank); + + // Should not happen + if (!pkvar) + return OPAL_INTERNAL_ERROR; + + // Reset the pk flag to volatile on p9 + pkvar->flags |= SECVAR_FLAG_VOLATILE; + + tmpsize = secvar_tpmnv_size(TPMNV_ID_EDK2_PK); + if (!tmpsize) + return OPAL_RESOURCE; + if (tmpsize < pkvar->var->data_size + sizeof(pkvar->var->data_size)) + return OPAL_RESOURCE; + + tmp = zalloc(tmpsize); + + memcpy(tmp, &pkvar->var->data_size, sizeof(pkvar->var->data_size)); + tmp += sizeof(pkvar->var->data_size); + memcpy(tmp, pkvar->var->data, pkvar->var->data_size); + + return secvar_tpmnv_write(TPMNV_ID_EDK2_PK, tmp, tmpsize, 0); +} + +/** + * Initializes supported variables as empty if not loaded from + * storage. Variables are initialized as volatile if not found. + * Updates should clear this flag. + * + * 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; + + // If we are on p9, we need to load the PK from TPM NV space + if (proc_gen == proc_gen_p9) + edk2_p9_load_pk(); + + pkvar = find_secvar((char *)"PK", 3, &variable_bank); + if (!pkvar) { + pkvar = alloc_secvar(0); + if (!pkvar) + return OPAL_NO_MEM; + + memcpy(pkvar->var->key, "PK", 3); + pkvar->var->key_len = 3; + pkvar->flags |= SECVAR_FLAG_VOLATILE; + list_add_tail(&variable_bank, &pkvar->link); + } + + kekvar = find_secvar((char *)"KEK", 4, &variable_bank); + if (!kekvar) { + kekvar = alloc_secvar(0); + if (!kekvar) + return OPAL_NO_MEM; + + memcpy(kekvar->var->key, "KEK", 4); + kekvar->var->key_len = 4; + kekvar->flags |= SECVAR_FLAG_VOLATILE; + list_add_tail(&variable_bank, &kekvar->link); + } + + dbvar = find_secvar((char *)"db", 3, &variable_bank); + if (!dbvar) { + dbvar = alloc_secvar(0); + if (!dbvar) + return OPAL_NO_MEM; + + memcpy(dbvar->var->key, "db", 3); + dbvar->var->key_len = 3; + dbvar->flags |= SECVAR_FLAG_VOLATILE; + list_add_tail(&variable_bank, &dbvar->link); + } + + + return OPAL_SUCCESS; +}; + +/** + * 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(uuid_t) + + len; + + return auth_buffer_size; +} + +/** + * Returns true if we are in Setup Mode + * + * Setup Mode is active if we have no PK. + * Otherwise, we are in deployed mode. + */ +static int is_setup_mode(void) +{ + struct secvar_node *setup; + + setup = find_secvar((char *)"PK", 3, &variable_bank); + + // Not sure why this wouldn't exist + if (!setup) + return 1; + + return !setup->var->data_size; +} + +/** + * 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; + + // Expand the secvar allocated memory if needed + if (node->size < dsize) + if (realloc_secvar(node, dsize)) + return OPAL_NO_MEM; + + node->var->data_size = dsize; + memcpy(node->var->data, data, dsize); + node->flags &= ~SECVAR_FLAG_VOLATILE; // Clear the volatile bit when updated + + return 0; +} + +/** + * Verifies the PKCS7 signature on the signed data. + */ +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 mbedtls_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 = auth_buffer; + + len = get_pkcs7_len(auth); + + pkcs7 = malloc(sizeof(struct mbedtls_pkcs7)); + mbedtls_pkcs7_init(pkcs7); + + rc = mbedtls_pkcs7_parse_der( + (const unsigned char *)auth->auth_info.cert_data, + (const unsigned int)len, pkcs7); + + signing_cert_size = esl_get_cert_size(avar->data); + signing_cert = zalloc(signing_cert_size); + esl_get_cert(avar->data, signing_cert); + + mbedtls_x509_crt_init(&x509); + rc = mbedtls_x509_crt_parse(&x509, signing_cert, signing_cert_size); + if(rc) { + prlog(PR_INFO, "X509 certificate parsing failed %04x\n", rc); + return rc; + } + + x509_buf = zalloc(2048); + mbedtls_x509_crt_info(x509_buf, 2048, "CRT:", &x509); + + rc = mbedtls_pkcs7_signed_data_verify(pkcs7, &x509, newcert, new_data_size); + + free(pkcs7); + + return rc; +} + +static char *utf8_to_ucs2(const char *key, const char keylen) +{ + int i; + char *str; + str = malloc(keylen * 2); + + for (i = 0; i < keylen*2; key++) { + str[i++] = *key; + str[i++] = '\0'; + } + return str; +} + +/** + * Create the single buffer (name, vendor guid, attributes,timestamp and + * newdata) which was originally signed by the user + */ +static int concatenate_data_tobehashed( unsigned char *key, unsigned char *new_data, + uint64_t new_data_size, + unsigned char **buffer, + uint64_t *buffer_size) +{ + unsigned char *tbh_buffer; + int tbh_buffer_size; + struct efi_time timestamp; + int size = 0; + int varlen = 0; + char *wkey; + uint32_t attr = 0x00000000; + //uuid_t guid = PLATFORM_SECVAR_ID; + char guid[16] = {0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09}; + //uuid_t guid = UUID_INIT(0x11111111, 0x2222, 0x3333, 0x44, 0x44, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc); + + memset(×tamp, 0, sizeof(struct efi_time)); + + // Convert utf8 name to ucs2 width + varlen = strlen(key) * 2; + wkey = utf8_to_ucs2(key, strlen(key)+1); + + /** + * Hash is generated on: + * variablename || vendorguid || attributes || timestamp || newcontent + */ + + tbh_buffer_size = sizeof(struct efi_time) + varlen + UUID_SIZE + sizeof(attr) + new_data_size; + + tbh_buffer = malloc(tbh_buffer_size); + + memcpy(tbh_buffer + size, wkey, varlen); + size = size + varlen; + memcpy(tbh_buffer + size, &guid, sizeof(guid)); + size = size + sizeof(guid); + memcpy(tbh_buffer + size, &attr, sizeof(attr)); + size = size + sizeof(attr); + memcpy(tbh_buffer + size, ×tamp , 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); + memcpy(*buffer, tbh_buffer, size); + *buffer_size = size; + + free(wkey); + + 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; + int pk_updated = 0; + bool setupmode = is_setup_mode(); + + prlog(PR_DEBUG, "Setup mode = %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. + */ + list_for_each(&update_bank, node, link) { + + /* 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 = zalloc(auth_buffer_size); + memcpy(auth_buffer, node->var->data, auth_buffer_size); + + if (node->var->data_size < auth_buffer_size) { + rc = OPAL_PARAMETER; + goto out; + } + + /* Calculate the size of new ESL data */ + new_data_size = node->var->data_size - auth_buffer_size; + dbcert = zalloc(new_data_size); + memcpy(dbcert, node->var->data + auth_buffer_size, new_data_size); + + if (!setupmode) { + + /* 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)) { + rc = -1; + goto out; + } + } + + /* 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)) { + prlog(PR_INFO, "validation of %s failed\n", node->var->key); + rc = -1; + goto out; + } + } + + /* 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)) { + prlog(PR_INFO, "validation of %s failed\n", node->var->key); + rc = -1; + goto out; + } + } + + /* Create the buffer on which signature was generated */ + rc = concatenate_data_tobehashed(node->var->key, + dbcert, + new_data_size, + &tbhbuffer, + &tbhbuffersize); + + /* Verify the signature */ + rc = verify_update(auth_buffer, tbhbuffer, + tbhbuffersize, anode->var); + if (rc) + goto out; + + } + + /* + * 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 at the end of processing */ + if (memcmp(node->var->key, "PK", + node->var->key_len) == 0) { + pk_updated = 1; + } + } + + if (pk_updated) { + secvar_set_secure_mode(); + + // Store the updated pk in TPMNV on p9 to be safe + if (proc_gen == proc_gen_p9) + edk2_p9_write_pk(); + } + +out: + clear_bank_list(&update_bank); + + return rc; +} + + +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: + // - check guid + // - check auth struct + // - possibly check signature? can't add but can validate + + return 0; +}; + +struct secvar_backend_driver edk2_compatible_v1 = { + .pre_process = edk2_compat_pre_process, + .process = edk2_compat_process, + .validate = edk2_compat_validate, + .compatible = "ibm,edk2-compat-v1", +}; diff --git a/libstb/secvar/backend/edk2-compat/edk2.h b/libstb/secvar/backend/edk2-compat/edk2.h new file mode 100644 index 00000000..e36718c7 --- /dev/null +++ b/libstb/secvar/backend/edk2-compat/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 UUID_SIZE 16 + +typedef struct { + u8 b[UUID_SIZE]; +} uuid_t; + +#define UUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ + ((uuid_t) {{ ((a) >> 24) & 0xff, ((a) >> 16) & 0xff, ((a) >> 8) & 0xff, (a) & 0xff, ((b) >> 8) & 0xff, (b) & 0xff, \ + ((c) >> 8) & 0xff, (c) & 0xff,(d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) \ + }}); + +#define PLATFORM_SECVAR_ID \ +UUID_INIT(0x8be4df61,0x93ca,0x11d2,0xaa, 0x0d,0x00,0xe0,0x98,0x03,0x2b,0x8c) + +#define SECVAR_ATTRIBUTES 0x0029 + +/// +/// 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_RSA2048_GUID \ + (UUID_INIT) (0x3c5766e8, 0x269c, 0x4e34, 0xaa, 0x14, 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6) + +#define EFI_CERT_TYPE_PKCS7_GUID \ + (UUID_INIT)(0x4aafd29d, 0x68df, 0x49ee, 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 + +/* + * 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. + /// + uuid_t 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. + /// + uuid_t 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. + */ + uuid_t 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 Sat Oct 26 09:45:53 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Richter X-Patchwork-Id: 1184606 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 470bmf1k4Tz9s7T for ; Sat, 26 Oct 2019 20:49:38 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.ibm.com Received: from bilbo.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 470bmf0fjGzDqlm for ; Sat, 26 Oct 2019 20:49:38 +1100 (AEDT) X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=linux.ibm.com (client-ip=148.163.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 470bhw47kzzDqkG for ; Sat, 26 Oct 2019 20:46:24 +1100 (AEDT) Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.27/8.16.0.27) with SMTP id x9Q9bMA2140733 for ; Sat, 26 Oct 2019 05:46:21 -0400 Received: from e06smtp02.uk.ibm.com (e06smtp02.uk.ibm.com [195.75.94.98]) by mx0b-001b2d01.pphosted.com with ESMTP id 2vvg9pcwsv-1 (version=TLSv1.2 cipher=AES256-GCM-SHA384 bits=256 verify=NOT) for ; Sat, 26 Oct 2019 05:46:21 -0400 Received: from localhost by e06smtp02.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Sat, 26 Oct 2019 10:46:20 +0100 Received: from b06cxnps4076.portsmouth.uk.ibm.com (9.149.109.198) 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) Sat, 26 Oct 2019 10:46:17 +0100 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps4076.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id x9Q9kFaj47317058 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Sat, 26 Oct 2019 09:46:15 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id A27F34C046; Sat, 26 Oct 2019 09:46:15 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CAED24C044; Sat, 26 Oct 2019 09:46:14 +0000 (GMT) Received: from ceres.ibmuc.com (unknown [9.80.231.2]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP; Sat, 26 Oct 2019 09:46:14 +0000 (GMT) From: Eric Richter To: skiboot@lists.ozlabs.org Date: Sat, 26 Oct 2019 04:45:53 -0500 X-Mailer: git-send-email 2.21.0 In-Reply-To: <20191026094553.26635-1-erichte@linux.ibm.com> References: <20191026094553.26635-1-erichte@linux.ibm.com> MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 19102609-0008-0000-0000-00000327CA0A X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 19102609-0009-0000-0000-00004A470373 Message-Id: <20191026094553.26635-12-erichte@linux.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10434:, , definitions=2019-10-26_02:, , 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=827 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1908290000 definitions=main-1910260100 Subject: [Skiboot] [PATCH v4 11/11] 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 8aaed975..5fcb4fb4 100644 --- a/platforms/astbmc/witherspoon.c +++ b/platforms/astbmc/witherspoon.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "astbmc.h" #include "ast.h" @@ -481,6 +482,11 @@ static void witherspoon_finalise_dt(bool is_reboot) } } +static int witherspoon_secvar_init(void) +{ + return secvar_main(secboot_tpm_driver, edk2_compatible_v1); +} + /* The only difference between these is the PCI slot handling */ DECLARE_PLATFORM(witherspoon) = { @@ -502,4 +508,5 @@ DECLARE_PLATFORM(witherspoon) = { .ocapi = &witherspoon_ocapi, .npu2_device_detect = witherspoon_npu2_device_detect, .op_display = op_display_lpc, + .secvar_init = witherspoon_secvar_init, };