From patchwork Wed Dec 30 13:57:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 355264 Delivered-To: patch@linaro.org Received: by 2002:a02:85a7:0:0:0:0:0 with SMTP id d36csp11351376jai; Wed, 30 Dec 2020 05:59:50 -0800 (PST) X-Google-Smtp-Source: ABdhPJwyuMSonFHi1XYYZBUHmPIAB/Oy8thl46/0IjQ5BgyfhhtFkSQNrmdySJTeaV2ifkJ2m1UP X-Received: by 2002:a05:6402:d08:: with SMTP id eb8mr51522563edb.271.1609336790152; Wed, 30 Dec 2020 05:59:50 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1609336790; cv=none; d=google.com; s=arc-20160816; b=BVpgs6W5PZ2HpX8rZzCttDBA3jY2wFaqwIgC5UWa0vjL38PzOMZEjOSRPqUwlNACR2 o02GWfN9UT51gKVJgm1XmzTCVR8HsPaBbBuoieNG5QXLztjDOEzBbYlr4TIeAuL1O4I1 jqgdigCKT63k7xjvhJjL+tPPfoUzl7ECxiJY39qcxUv6ow7K0RrQvifYnR70NHyj3CFp A37YCTP2ISV/zRkk6RI1Sz9xmRIhh7Hf8pGHdJcP+FEibB5rELszz45YB4W4ZX3VzfOY JdcsiKKLYvH7kRHI5OsOvmnVv+SgqejK+zT3GWJznXW/5cZLulCSNzVI4EVywHplFcpg Z1pQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from; bh=L5EAl5Fv+++NEmBUaap1HmK6im69zRli01gIAbgF1Jo=; b=Fx+Eznqt9wqLdLlCRftch1H9nXxNp6kMvAJV0YbU0wcBrQSx/pf1Gh9eVnAmqOJUDm A3Ip5zS6QDgOKoI+9gNyHtr4wFey7ehzslxNG0A48KnZRM0xNcqtWt4GoR6EUYjmrldQ u9UISsQkWvIVnP4xVeJBgisPN4zchM+ZXVt+cJ5+OwDiy0Mnya8uDd2FBaujRCjOMlej f6fYx5XrMWN3wpXOB+Pza40aoD4GEChceZwE1jDtpcDzaCXXorHLd0Jz59GLg8wPnEtn xJn95zfySNJmCtS8fEH3ipXXk3P7HXg6701UizhwwscYlr0vgEp/ccAYo7AV4lsSefcB SYiA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id i7si27482868ejo.480.2020.12.30.05.59.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 30 Dec 2020 05:59:50 -0800 (PST) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 892428261B; Wed, 30 Dec 2020 14:58:45 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by phobos.denx.de (Postfix, from userid 109) id C955C82617; Wed, 30 Dec 2020 14:58:11 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, SPF_HELO_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by phobos.denx.de (Postfix) with ESMTP id EEBA1825D2 for ; Wed, 30 Dec 2020 14:58:05 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=fail smtp.mailfrom=sughosh.ganu@linaro.org Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 732C5101E; Wed, 30 Dec 2020 05:58:05 -0800 (PST) Received: from a076522.blr.arm.com (a076522.blr.arm.com [10.162.16.44]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id D0BC13F6CF; Wed, 30 Dec 2020 05:58:02 -0800 (PST) From: Sughosh Ganu To: u-boot@lists.denx.de Cc: Takahiro Akashi , Heinrich Schuchardt , Alexander Graf , Lukasz Majewski , Tuomas Tynkkynen , Tom Rini , Ilias Apalodimas , Sughosh Ganu Subject: [PATCH v4 11/14] efi: capsule: Add support for uefi capsule authentication Date: Wed, 30 Dec 2020 19:27:09 +0530 Message-Id: <20201230135712.5289-12-sughosh.ganu@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201230135712.5289-1-sughosh.ganu@linaro.org> References: <20201230135712.5289-1-sughosh.ganu@linaro.org> X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.34 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.102.3 at phobos.denx.de X-Virus-Status: Clean Add support for authenticating uefi capsules. Most of the signature verification functionality is shared with the uefi secure boot feature. The root certificate containing the public key used for the signature verification is stored as part of the device tree blob. The root certificate is stored as an efi signature list(esl) file -- this file contains the x509 certificate which is the root certificate. Signed-off-by: Sughosh Ganu --- Changes since V3: None board/emulation/common/Makefile | 1 + board/emulation/common/qemu_capsule.c | 48 ++++++++++ include/efi_api.h | 18 ++++ include/efi_loader.h | 6 ++ lib/efi_loader/Kconfig | 17 ++++ lib/efi_loader/efi_capsule.c | 122 ++++++++++++++++++++++++++ lib/efi_loader/efi_signature.c | 4 +- 7 files changed, 214 insertions(+), 2 deletions(-) create mode 100644 board/emulation/common/qemu_capsule.c -- 2.17.1 diff --git a/board/emulation/common/Makefile b/board/emulation/common/Makefile index c5b452e7e3..7ed447a69d 100644 --- a/board/emulation/common/Makefile +++ b/board/emulation/common/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_SYS_MTDPARTS_RUNTIME) += qemu_mtdparts.o obj-$(CONFIG_SET_DFU_ALT_INFO) += qemu_dfu.o +obj-$(CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT) += qemu_capsule.o diff --git a/board/emulation/common/qemu_capsule.c b/board/emulation/common/qemu_capsule.c new file mode 100644 index 0000000000..f1d403501a --- /dev/null +++ b/board/emulation/common/qemu_capsule.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020 Linaro Limited + */ + +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len) +{ + const void *fdt_blob = gd->fdt_blob; + const void *blob; + const char *cnode_name = "capsule-key"; + const char *snode_name = "signature"; + int sig_node; + int len; + + sig_node = fdt_subnode_offset(fdt_blob, 0, snode_name); + if (sig_node < 0) { + EFI_PRINT("Unable to get signature node offset\n"); + return -FDT_ERR_NOTFOUND; + } + + blob = fdt_getprop(fdt_blob, sig_node, cnode_name, &len); + + if (!blob || len < 0) { + EFI_PRINT("Unable to get capsule-key value\n"); + *pkey = NULL; + *pkey_len = 0; + return -FDT_ERR_NOTFOUND; + } + + *pkey = (void *)blob; + *pkey_len = len; + + return 0; +} + +bool efi_capsule_auth_enabled(void) +{ + return env_get("capsule_authentication_enabled") != NULL ? + true : false; +} diff --git a/include/efi_api.h b/include/efi_api.h index e82d4ca9ff..ecb43a0607 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1812,6 +1812,24 @@ struct efi_variable_authentication_2 { struct win_certificate_uefi_guid auth_info; } __attribute__((__packed__)); +/** + * efi_firmware_image_authentication - Capsule authentication method + * descriptor + * + * This structure describes an authentication information for + * a capsule with IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED set + * and should be included as part of the capsule. + * Only EFI_CERT_TYPE_PKCS7_GUID is accepted. + * + * @monotonic_count: Count to prevent replay + * @auth_info: Authentication info + */ +struct efi_firmware_image_authentication { + uint64_t monotonic_count; + struct win_certificate_uefi_guid auth_info; +} __attribute__((__packed__)); + + /** * efi_signature_data - A format of signature * diff --git a/include/efi_loader.h b/include/efi_loader.h index 73c3c4b85a..fb3e974aa1 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -817,6 +817,8 @@ struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name); bool efi_secure_boot_enabled(void); +bool efi_capsule_auth_enabled(void); + bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, WIN_CERTIFICATE **auth, size_t *auth_len); @@ -844,6 +846,10 @@ efi_status_t EFIAPI efi_query_capsule_caps( u64 *maximum_capsule_size, u32 *reset_type); +efi_status_t efi_capsule_authenticate(const void *capsule, + efi_uintn_t capsule_size, + void **image, efi_uintn_t *image_size); + #define EFI_CAPSULE_DIR L"\\EFI\\UpdateCapsule\\" /* Hook at initialization */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 073d90c802..297b2a2a7d 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -139,6 +139,23 @@ config EFI_CAPSULE_FIRMWARE_MANAGEMENT Select this option if you want to enable capsule-based firmware update using Firmware Management Protocol. +config EFI_CAPSULE_AUTHENTICATE + bool "Update Capsule authentication" + depends on EFI_CAPSULE_FIRMWARE + depends on EFI_CAPSULE_ON_DISK + depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT + select SHA256 + select RSA + select RSA_VERIFY + select RSA_VERIFY_WITH_PKEY + select X509_CERTIFICATE_PARSER + select PKCS7_MESSAGE_PARSER + select PKCS7_VERIFY + default n + help + Select this option if you want to enable capsule + authentication + config EFI_CAPSULE_FIRMWARE_FIT bool "FMP driver for FIT image" depends on EFI_CAPSULE_FIRMWARE_MANAGEMENT diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index ea22ee7968..d9a7bbd509 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -14,6 +14,10 @@ #include #include +#include +#include +#include + const efi_guid_t efi_guid_capsule_report = EFI_CAPSULE_REPORT_GUID; static const efi_guid_t efi_guid_firmware_management_capsule_id = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; @@ -191,6 +195,124 @@ skip: return NULL; } +#if defined(CONFIG_EFI_CAPSULE_AUTHENTICATE) + +const efi_guid_t efi_guid_capsule_root_cert_guid = + EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; + +__weak int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len) +{ + /* The platform is supposed to provide + * a method for getting the public key + * stored in the form of efi signature + * list + */ + return 0; +} + +efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_size, + void **image, efi_uintn_t *image_size) +{ + u8 *buf; + int ret; + void *fdt_pkey, *pkey; + efi_uintn_t pkey_len; + uint64_t monotonic_count; + struct efi_signature_store *truststore; + struct pkcs7_message *capsule_sig; + struct efi_image_regions *regs; + struct efi_firmware_image_authentication *auth_hdr; + efi_status_t status; + + status = EFI_SECURITY_VIOLATION; + capsule_sig = NULL; + truststore = NULL; + regs = NULL; + + /* Sanity checks */ + if (capsule == NULL || capsule_size == 0) + goto out; + + auth_hdr = (struct efi_firmware_image_authentication *)capsule; + if (capsule_size < sizeof(*auth_hdr)) + goto out; + + if (auth_hdr->auth_info.hdr.dwLength <= + offsetof(struct win_certificate_uefi_guid, cert_data)) + goto out; + + if (guidcmp(&auth_hdr->auth_info.cert_type, &efi_guid_cert_type_pkcs7)) + goto out; + + *image = (uint8_t *)capsule + sizeof(auth_hdr->monotonic_count) + + auth_hdr->auth_info.hdr.dwLength; + *image_size = capsule_size - auth_hdr->auth_info.hdr.dwLength - + sizeof(auth_hdr->monotonic_count); + memcpy(&monotonic_count, &auth_hdr->monotonic_count, + sizeof(monotonic_count)); + + /* data to be digested */ + regs = calloc(sizeof(*regs) + sizeof(struct image_region) * 2, 1); + if (!regs) + goto out; + + regs->max = 2; + efi_image_region_add(regs, (uint8_t *)*image, + (uint8_t *)*image + *image_size, 1); + + efi_image_region_add(regs, (uint8_t *)&monotonic_count, + (uint8_t *)&monotonic_count + sizeof(monotonic_count), + 1); + + capsule_sig = efi_parse_pkcs7_header(auth_hdr->auth_info.cert_data, + auth_hdr->auth_info.hdr.dwLength + - sizeof(auth_hdr->auth_info), + &buf); + if (IS_ERR(capsule_sig)) { + debug("Parsing variable's pkcs7 header failed\n"); + capsule_sig = NULL; + goto out; + } + + ret = efi_get_public_key_data(&fdt_pkey, &pkey_len); + if (ret < 0) + goto out; + + pkey = malloc(pkey_len); + if (!pkey) + goto out; + + memcpy(pkey, fdt_pkey, pkey_len); + truststore = efi_build_signature_store(pkey, pkey_len); + if (!truststore) + goto out; + + /* verify signature */ + if (efi_signature_verify(regs, capsule_sig, truststore, NULL)) { + debug("Verified\n"); + } else { + debug("Verifying variable's signature failed\n"); + goto out; + } + + status = EFI_SUCCESS; + +out: + efi_sigstore_free(truststore); + pkcs7_free_message(capsule_sig); + free(regs); + + return status; +} +#else +efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_size, + void **image, efi_uintn_t *image_size) +{ + return EFI_UNSUPPORTED; +} +#endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */ + + /** * efi_capsule_update_firmware - update firmware from capsule * @capsule_data: Capsule diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index 87525bdc80..c7ec275414 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -26,7 +26,7 @@ const efi_guid_t efi_guid_cert_x509 = EFI_CERT_X509_GUID; const efi_guid_t efi_guid_cert_x509_sha256 = EFI_CERT_X509_SHA256_GUID; const efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; -#ifdef CONFIG_EFI_SECURE_BOOT +#if defined(CONFIG_EFI_SECURE_BOOT) || defined(CONFIG_EFI_CAPSULE_AUTHENTICATE) static u8 pkcs7_hdr[] = { /* SEQUENCE */ 0x30, 0x82, 0x05, 0xc7, @@ -846,4 +846,4 @@ struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name) return efi_build_signature_store(db, db_size); } -#endif /* CONFIG_EFI_SECURE_BOOT */ +#endif /* CONFIG_EFI_SECURE_BOOT || CONFIG_EFI_CAPSULE_AUTHENTICATE */