From a7e4f905d206d5895dab4bd38a8316e4f2fe15fe Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 2 Aug 2021 08:44:29 -0600 Subject: [PATCH 1/3] Revert "doc: Update CapsuleUpdate READMEs" This reverts commit 316ab801c0d91c02b21b8be1e3db7e69555364e9. Signed-off-by: Simon Glass --- doc/develop/uefi/uefi.rst | 124 -------------------------------------- 1 file changed, 124 deletions(-) diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index f17138f5c7..4f2b8b036d 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -277,130 +277,6 @@ Enable ``CONFIG_OPTEE``, ``CONFIG_CMD_OPTEE_RPMB`` and ``CONFIG_EFI_MM_COMM_TEE` [1] https://optee.readthedocs.io/en/latest/building/efi_vars/stmm.html -Enabling UEFI Capsule Update feature -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Support has been added for the UEFI capsule update feature which -enables updating the U-Boot image using the UEFI firmware management -protocol (FMP). The capsules are not passed to the firmware through -the UpdateCapsule runtime service. Instead, capsule-on-disk -functionality is used for fetching the capsule from the EFI System -Partition (ESP) by placing the capsule file under the -\EFI\UpdateCapsule directory. - -The directory \EFI\UpdateCapsule is checked for capsules only within the -EFI system partition on the device specified in the active boot option -determined by reference to BootNext variable or BootOrder variable processing. -The active Boot Variable is the variable with highest priority BootNext or -within BootOrder that refers to a device found to be present. Boot variables -in BootOrder but referring to devices not present are ignored when determining -active boot variable. -Before starting a capsule update make sure your capsules are installed in the -correct ESP partition or set BootNext. - -Performing the update -********************* - -Since U-boot doesn't currently support SetVariable at runtime there's a Kconfig -option (CONFIG_EFI_IGNORE_OSINDICATIONS) to disable the OsIndications variable -check. If that option is enabled just copy your capsule to \EFI\UpdateCapsule. - -If that option is disabled, you'll need to set the OsIndications variable with:: - - => setenv -e -nv -bs -rt -v OsIndications =0x04 - -Finally, the capsule update can be initiated either by rebooting the board, -which is the preferred method, or by issuing the following command:: - - => efidebug capsule disk-update - -**The efidebug command is should only be used during debugging/development.** - -Enabling Capsule Authentication -******************************* - -The UEFI specification defines a way of authenticating the capsule to -be updated by verifying the capsule signature. The capsule signature -is computed and prepended to the capsule payload at the time of -capsule generation. This signature is then verified by using the -public key stored as part of the X509 certificate. This certificate is -in the form of an efi signature list (esl) file, which is embedded as -part of U-Boot. - -The capsule authentication feature can be enabled through the -following config, in addition to the configs listed above for capsule -update:: - - CONFIG_EFI_CAPSULE_AUTHENTICATE=y - CONFIG_EFI_CAPSULE_KEY_PATH= - -The public and private keys used for the signing process are generated -and used by the steps highlighted below:: - - 1. Install utility commands on your host - * OPENSSL - * efitools - - 2. Create signing keys and certificate files on your host - - $ openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=CRT/ \ - -keyout CRT.key -out CRT.crt -nodes -days 365 - $ cert-to-efi-sig-list CRT.crt CRT.esl - - $ openssl x509 -in CRT.crt -out CRT.cer -outform DER - $ openssl x509 -inform DER -in CRT.cer -outform PEM -out CRT.pub.pem - - $ openssl pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt - $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem - -The capsule file can be generated by using the GenerateCapsule.py -script in EDKII:: - - $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \ - --monotonic-count --fw-version \ - --lsv --guid \ - e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \ - --update-image-index --signer-private-cert \ - /path/to/CRT.pem --trusted-public-cert \ - /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \ - - -Place the capsule generated in the above step on the EFI System -Partition under the EFI/UpdateCapsule directory - -Testing on QEMU -*************** - -Currently, support has been added on the QEMU ARM64 virt platform for -updating the U-Boot binary as a raw image when the platform is booted -in non-secure mode, i.e. with CONFIG_TFABOOT disabled. For this -configuration, the QEMU platform needs to be booted with -'secure=off'. The U-Boot binary placed on the first bank of the NOR -flash at offset 0x0. The U-Boot environment is placed on the second -NOR flash bank at offset 0x4000000. - -The capsule update feature is enabled with the following configuration -settings:: - - CONFIG_MTD=y - CONFIG_FLASH_CFI_MTD=y - CONFIG_CMD_MTDPARTS=y - CONFIG_CMD_DFU=y - CONFIG_DFU_MTD=y - CONFIG_PCI_INIT_R=y - CONFIG_EFI_CAPSULE_ON_DISK=y - CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y - CONFIG_EFI_CAPSULE_FIRMWARE=y - CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y - -In addition, the following config needs to be disabled(QEMU ARM specific):: - - CONFIG_TFABOOT - -The capsule file can be generated by using the tools/mkeficapsule:: - - $ mkeficapsule --raw --index 1 - Executing the boot manager ~~~~~~~~~~~~~~~~~~~~~~~~~~ From d428e81266a59974ade74c1ba019af39f23304ab Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 2 Aug 2021 08:44:30 -0600 Subject: [PATCH 2/3] Revert "mkeficapsule: Remove dtb related options" This reverts commit f86caab058ff062ce72b24cd1ab9ec1253cc1352. Signed-off-by: Simon Glass --- tools/mkeficapsule.c | 229 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 222 insertions(+), 7 deletions(-) diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 4995ba4e0c..de0a628988 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -4,17 +4,22 @@ * Author: AKASHI Takahiro */ +#include #include #include #include #include #include #include +#include #include +#include #include #include +#include "fdt_host.h" + typedef __u8 u8; typedef __u16 u16; typedef __u32 u32; @@ -24,6 +29,9 @@ typedef __s32 s32; #define aligned_u64 __aligned_u64 +#define SIGNATURE_NODENAME "signature" +#define OVERLAY_NODENAME "__overlay__" + #ifndef __packed #define __packed __attribute__((packed)) #endif @@ -44,6 +52,9 @@ static struct option options[] = { {"raw", required_argument, NULL, 'r'}, {"index", required_argument, NULL, 'i'}, {"instance", required_argument, NULL, 'I'}, + {"dtb", required_argument, NULL, 'D'}, + {"public key", required_argument, NULL, 'K'}, + {"overlay", no_argument, NULL, 'O'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, }; @@ -57,10 +68,187 @@ static void print_usage(void) "\t-r, --raw new raw image file\n" "\t-i, --index update image index\n" "\t-I, --instance update hardware instance\n" + "\t-K, --public-key public key esl file\n" + "\t-D, --dtb dtb file\n" + "\t-O, --overlay the dtb file is an overlay\n" "\t-h, --help print a help message\n", tool_name); } +static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size, + bool overlay) +{ + int parent; + int ov_node; + int frag_node; + int ret = 0; + + if (overlay) { + /* + * The signature would be stored in the + * first fragment node of the overlay + */ + frag_node = fdt_first_subnode(dptr, 0); + if (frag_node == -FDT_ERR_NOTFOUND) { + fprintf(stderr, + "Couldn't find the fragment node: %s\n", + fdt_strerror(frag_node)); + goto done; + } + + ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME); + if (ov_node == -FDT_ERR_NOTFOUND) { + fprintf(stderr, + "Couldn't find the __overlay__ node: %s\n", + fdt_strerror(ov_node)); + goto done; + } + } else { + ov_node = 0; + } + + parent = fdt_subnode_offset(dptr, ov_node, SIGNATURE_NODENAME); + if (parent == -FDT_ERR_NOTFOUND) { + parent = fdt_add_subnode(dptr, ov_node, SIGNATURE_NODENAME); + if (parent < 0) { + ret = parent; + if (ret != -FDT_ERR_NOSPACE) { + fprintf(stderr, + "Couldn't create signature node: %s\n", + fdt_strerror(parent)); + } + } + } + if (ret) + goto done; + + /* Write the key to the FDT node */ + ret = fdt_setprop(dptr, parent, "capsule-key", + sptr, key_size); + +done: + if (ret) + ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO; + + return ret; +} + +static int add_public_key(const char *pkey_file, const char *dtb_file, + bool overlay) +{ + int ret; + int srcfd = -1; + int destfd = -1; + void *sptr = NULL; + void *dptr = NULL; + off_t src_size; + struct stat pub_key; + struct stat dtb; + + /* Find out the size of the public key */ + srcfd = open(pkey_file, O_RDONLY); + if (srcfd == -1) { + fprintf(stderr, "%s: Can't open %s: %s\n", + __func__, pkey_file, strerror(errno)); + ret = -1; + goto err; + } + + ret = fstat(srcfd, &pub_key); + if (ret == -1) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + __func__, pkey_file, strerror(errno)); + ret = -1; + goto err; + } + + src_size = pub_key.st_size; + + /* mmap the public key esl file */ + sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0); + if (sptr == MAP_FAILED) { + fprintf(stderr, "%s: Failed to mmap %s:%s\n", + __func__, pkey_file, strerror(errno)); + ret = -1; + goto err; + } + + /* Open the dest FDT */ + destfd = open(dtb_file, O_RDWR); + if (destfd == -1) { + fprintf(stderr, "%s: Can't open %s: %s\n", + __func__, dtb_file, strerror(errno)); + ret = -1; + goto err; + } + + ret = fstat(destfd, &dtb); + if (ret == -1) { + fprintf(stderr, "%s: Can't stat %s: %s\n", + __func__, dtb_file, strerror(errno)); + goto err; + } + + dtb.st_size += src_size + 0x30; + if (ftruncate(destfd, dtb.st_size)) { + fprintf(stderr, "%s: Can't expand %s: %s\n", + __func__, dtb_file, strerror(errno)); + ret = -1; + goto err; + } + + errno = 0; + /* mmap the dtb file */ + dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, + destfd, 0); + if (dptr == MAP_FAILED) { + fprintf(stderr, "%s: Failed to mmap %s:%s\n", + __func__, dtb_file, strerror(errno)); + ret = -1; + goto err; + } + + if (fdt_check_header(dptr)) { + fprintf(stderr, "%s: Invalid FDT header\n", __func__); + ret = -1; + goto err; + } + + ret = fdt_open_into(dptr, dptr, dtb.st_size); + if (ret) { + fprintf(stderr, "%s: Cannot expand FDT: %s\n", + __func__, fdt_strerror(ret)); + ret = -1; + goto err; + } + + /* Copy the esl file to the expanded FDT */ + ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay); + if (ret < 0) { + fprintf(stderr, "%s: Unable to add public key to the FDT\n", + __func__); + ret = -1; + goto err; + } + + ret = 0; + +err: + if (sptr) + munmap(sptr, src_size); + + if (dptr) + munmap(dptr, dtb.st_size); + + if (srcfd != -1) + close(srcfd); + + if (destfd != -1) + close(destfd); + + return ret; +} + static int create_fwbin(char *path, char *bin, efi_guid_t *guid, unsigned long index, unsigned long instance) { @@ -178,16 +366,22 @@ err_1: int main(int argc, char **argv) { char *file; + char *pkey_file; + char *dtb_file; efi_guid_t *guid; unsigned long index, instance; int c, idx; + int ret; + bool overlay = false; file = NULL; + pkey_file = NULL; + dtb_file = NULL; guid = NULL; index = 0; instance = 0; for (;;) { - c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx); + c = getopt_long(argc, argv, "f:r:i:I:v:D:K:Oh", options, &idx); if (c == -1) break; @@ -214,22 +408,43 @@ int main(int argc, char **argv) case 'I': instance = strtoul(optarg, NULL, 0); break; + case 'K': + if (pkey_file) { + printf("Public Key already specified\n"); + return -1; + } + pkey_file = optarg; + break; + case 'D': + if (dtb_file) { + printf("DTB file already specified\n"); + return -1; + } + dtb_file = optarg; + break; + case 'O': + overlay = true; + break; case 'h': print_usage(); return 0; } } - /* need an output file */ - if (argc != optind + 1) { + /* need a fit image file or raw image file */ + if (!file && !pkey_file && !dtb_file) { print_usage(); exit(EXIT_FAILURE); } - /* need a fit image file or raw image file */ - if (!file) { - print_usage(); - exit(EXIT_SUCCESS); + if (pkey_file && dtb_file) { + ret = add_public_key(pkey_file, dtb_file, overlay); + if (ret == -1) { + printf("Adding public key to the dtb failed\n"); + exit(EXIT_FAILURE); + } else { + exit(EXIT_SUCCESS); + } } if (create_fwbin(argv[optind], file, guid, index, instance) From 47a25e81d35c8d801cae9089de90c9ffea083409 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 2 Aug 2021 08:44:31 -0600 Subject: [PATCH 3/3] Revert "efi_capsule: Move signature from DTB to .rodata" This was unfortunately applied despite much discussion about it beiong the wrong way to implement this feature. Revert it before too many other things are built on top of it. This reverts commit ddf67daac39de76d2697d587148f4c2cb768f492. Signed-off-by: Simon Glass --- board/emulation/common/Makefile | 1 + include/asm-generic/sections.h | 2 -- lib/efi_loader/Kconfig | 7 ------- lib/efi_loader/Makefile | 8 -------- lib/efi_loader/efi_capsule.c | 18 +++--------------- lib/efi_loader/efi_capsule_key.S | 17 ----------------- 6 files changed, 4 insertions(+), 49 deletions(-) delete mode 100644 lib/efi_loader/efi_capsule_key.S 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/include/asm-generic/sections.h b/include/asm-generic/sections.h index ec992b0c2e..267f1db73f 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -27,8 +27,6 @@ extern char __efi_helloworld_begin[]; extern char __efi_helloworld_end[]; extern char __efi_var_file_begin[]; extern char __efi_var_file_end[]; -extern char __efi_capsule_sig_begin[]; -extern char __efi_capsule_sig_end[]; /* Private data used by of-platdata devices/uclasses */ extern char __priv_data_start[], __priv_data_end[]; diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index 649ee57330..f48d9e8b51 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -215,13 +215,6 @@ config EFI_CAPSULE_AUTHENTICATE Select this option if you want to enable capsule authentication -config EFI_CAPSULE_KEY_PATH - string "Path to .esl cert for capsule authentication" - depends on EFI_CAPSULE_AUTHENTICATE - help - Provide the EFI signature list (esl) certificate used for capsule - authentication - config EFI_DEVICE_PATH_TO_TEXT bool "Device path to text protocol" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 08469d9cd9..fd344cea29 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -20,19 +20,11 @@ always += helloworld.efi targets += helloworld.o endif -ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y) -EFI_CAPSULE_KEY_PATH := $(subst $\",,$(CONFIG_EFI_CAPSULE_KEY_PATH)) -ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") -$(error .esl certificate not found. Configure your CONFIG_EFI_CAPSULE_KEY_PATH) -endif -endif - obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o obj-$(CONFIG_CMD_BOOTEFI_BOOTMGR) += efi_bootmgr.o obj-y += efi_boottime.o obj-y += efi_helper.o obj-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += efi_capsule.o -obj-$(CONFIG_EFI_CAPSULE_AUTHENTICATE) += efi_capsule_key.o obj-$(CONFIG_EFI_CAPSULE_FIRMWARE) += efi_firmware.o obj-y += efi_console.o obj-y += efi_device_path.o diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index 26990bc2df..b75e4bcba1 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include @@ -253,23 +252,12 @@ out: #if defined(CONFIG_EFI_CAPSULE_AUTHENTICATE) -static int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len) -{ - const void *blob = __efi_capsule_sig_begin; - const int len = __efi_capsule_sig_end - __efi_capsule_sig_begin; - - *pkey = (void *)blob; - *pkey_len = len; - - 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 *stored_pkey, *pkey; + void *fdt_pkey, *pkey; efi_uintn_t pkey_len; uint64_t monotonic_count; struct efi_signature_store *truststore; @@ -322,7 +310,7 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s goto out; } - ret = efi_get_public_key_data(&stored_pkey, &pkey_len); + ret = efi_get_public_key_data(&fdt_pkey, &pkey_len); if (ret < 0) goto out; @@ -330,7 +318,7 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s if (!pkey) goto out; - memcpy(pkey, stored_pkey, pkey_len); + memcpy(pkey, fdt_pkey, pkey_len); truststore = efi_build_signature_store(pkey, pkey_len); if (!truststore) goto out; diff --git a/lib/efi_loader/efi_capsule_key.S b/lib/efi_loader/efi_capsule_key.S deleted file mode 100644 index 58f00b8e4b..0000000000 --- a/lib/efi_loader/efi_capsule_key.S +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * .esl cert for capsule authentication - * - * Copyright (c) 2021, Ilias Apalodimas - */ - -#include - -.section .rodata.capsule_key.init,"a" -.balign 16 -.global __efi_capsule_sig_begin -__efi_capsule_sig_begin: -.incbin CONFIG_EFI_CAPSULE_KEY_PATH -__efi_capsule_sig_end: -.global __efi_capsule_sig_end -.balign 16