From patchwork Thu Nov 26 18:41:07 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 333048 Delivered-To: patch@linaro.org Received: by 2002:a92:5e16:0:0:0:0:0 with SMTP id s22csp1543551ilb; Thu, 26 Nov 2020 10:44:16 -0800 (PST) X-Google-Smtp-Source: ABdhPJzKBuG0E0Ak7sLHOdRoEPrEYqmvtSftt0qOJiov2wT25mKauTI2C/ckmLWepLhOJnPl5m7+ X-Received: by 2002:a17:906:af6b:: with SMTP id os11mr3994384ejb.270.1606416256786; Thu, 26 Nov 2020 10:44:16 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1606416256; cv=none; d=google.com; s=arc-20160816; b=YBONM52aPNDHTQzRh0MguezY1uFtM7mCctXBUTkbNfPzp0jaugvHCdUvh3NiviEWfu IHhOv9GpmsZISMzgbqKZpcoT9sgFkfSLD2Ehzb/UBs3GMe4aJiVUP71MQHA3D8NIEmSN q8WjS28rKIBGsLncjVLrA5w+YTUENwhbBzZdV0d+XoM4pYjNd4KhCwgt5LNsojRSfXSB 0zyLhLenQ4je1SzzHxLFW+yB8/bioq6Y6knymVv91+NSPNU8QPtk7vMXgdlQL6V3FdZe atQ3p24LnZoG4+uCCGT7DllD+ER5SP/NX/iWs5TMS6fL5nJNjf4ImWi4U6x6Far6lBB4 Sqpw== 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=ShstwUGWlFqt657RfxLewjGa0ly08lsv31K4uQk2/So=; b=v1zD7nQyHzEWoU2WyRP8p08iVLGPdPW6eccwiVqH+8faOJBqG2m8PScIce7D7zLxzv 2JWH+FeD/uCHTxj4GuJmQLAb6+shRqVCtmNOTkUzutg1M7JdkqRmpLOXfCBFSh3U+8VB qb6RXI9hVvjaZxhPxAgNlLu8z3s+eb+26lIrYGcoJ24FIcISfhgpgmBQ137ZUp2vcT1o N6cqPwJd6By153LXQ7fE6AqtoTN/OK9FT/QD0Zdb1VDeUP9mdxA3By5F4TSEei73vgxK SZrCxGi2vY/uLX7jyszTzJto/suj/vTeD/PdyWJHjPLrO9IolBSWRhy5Otpxyp3Muj5c kTaw== 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 p89si3524048edp.328.2020.11.26.10.44.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 26 Nov 2020 10:44:16 -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 C6C2E8270E; Thu, 26 Nov 2020 19:42:49 +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 BAEC0826EA; Thu, 26 Nov 2020 19:42:25 +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=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, URIBL_BLOCKED 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 18210826EE for ; Thu, 26 Nov 2020 19:42:22 +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 50D4D1684; Thu, 26 Nov 2020 10:42:21 -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 98FBF3F23F; Thu, 26 Nov 2020 10:42:18 -0800 (PST) From: Sughosh Ganu To: u-boot@lists.denx.de Cc: Takahiro Akashi , Heinrich Schuchardt , Alexander Graf , Lukasz Majewski , Tuomas Tynkkynen , Tom Rini , Sughosh Ganu Subject: [PATCH 11/14] efi: capsule: Add support for uefi capsule authentication Date: Fri, 27 Nov 2020 00:11:07 +0530 Message-Id: <20201126184110.30521-12-sughosh.ganu@linaro.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20201126184110.30521-1-sughosh.ganu@linaro.org> References: <20201126184110.30521-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 --- board/emulation/qemu-arm/qemu-arm.c | 35 ++++++++ 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 +- 6 files changed, 200 insertions(+), 2 deletions(-) -- 2.17.1 diff --git a/board/emulation/qemu-arm/qemu-arm.c b/board/emulation/qemu-arm/qemu-arm.c index 8cad54c76f..5794d4c669 100644 --- a/board/emulation/qemu-arm/qemu-arm.c +++ b/board/emulation/qemu-arm/qemu-arm.c @@ -208,6 +208,41 @@ void flash_write32(u32 value, void *addr) #define DFU_ALT_BUF_LEN SZ_1K +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; +} + static void board_get_alt_info(struct mtd_info *mtd, char *buf) { struct mtd_info *part; diff --git a/include/efi_api.h b/include/efi_api.h index c7038f863a..bcf6de6629 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1808,6 +1808,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 8d8a6649b5..d311317fc1 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -809,6 +809,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); @@ -836,6 +838,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 55e4787e32..597ad6b2a7 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -145,6 +145,23 @@ config EFI_CAPSULE_FMP_HEADER Select this option if the capsule is built using the scripts in edk2. +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 f385e58378..ad2036fe93 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 */