From patchwork Thu Apr 30 17:36:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 239030 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Thu, 30 Apr 2020 23:06:23 +0530 Subject: [PATCH 1/8] semihosting: Change semihosting file operation functions into global symbols In-Reply-To: <20200430173630.15608-1-sughosh.ganu@linaro.org> References: <20200430173630.15608-1-sughosh.ganu@linaro.org> Message-ID: <20200430173630.15608-2-sughosh.ganu@linaro.org> Change the semihosting file operation functions into external symbols so that they can be called from outside the file. These functions would be required to be called for implementing firmware update functionality for the qemu arm64 platform. Signed-off-by: Sughosh Ganu --- arch/arm/lib/semihosting.c | 7 ++++--- include/semihosting.h | 13 +++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 include/semihosting.h diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c index 2658026cf4..3aeda1303a 100644 --- a/arch/arm/lib/semihosting.c +++ b/arch/arm/lib/semihosting.c @@ -13,6 +13,7 @@ */ #include #include +#include #define SYSOPEN 0x01 #define SYSCLOSE 0x02 @@ -43,7 +44,7 @@ static noinline long smh_trap(unsigned int sysnum, void *addr) * Open a file on the host. Mode is "r" or "rb" currently. Returns a file * descriptor or -1 on error. */ -static long smh_open(const char *fname, char *modestr) +long smh_open(const char *fname, char *modestr) { long fd; unsigned long mode; @@ -82,7 +83,7 @@ static long smh_open(const char *fname, char *modestr) /* * Read 'len' bytes of file into 'memp'. Returns 0 on success, else failure */ -static long smh_read(long fd, void *memp, size_t len) +long smh_read(long fd, void *memp, size_t len) { long ret; struct smh_read_s { @@ -116,7 +117,7 @@ static long smh_read(long fd, void *memp, size_t len) /* * Close the file using the file descriptor */ -static long smh_close(long fd) +long smh_close(long fd) { long ret; diff --git a/include/semihosting.h b/include/semihosting.h new file mode 100644 index 0000000000..f1bf419275 --- /dev/null +++ b/include/semihosting.h @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020, Linaro Limited + */ + +#if !defined _SEMIHOSTING_H_ +#define _SEMIHOSTING_H_ + +long smh_open(const char *fname, char *modestr); +long smh_read(long fd, void *memp, size_t len); +long smh_close(long fd); + +#endif /* _SEMIHOSTING_H_ */ From patchwork Thu Apr 30 17:36:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 239026 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Thu, 30 Apr 2020 23:06:24 +0530 Subject: [PATCH 2/8] semihosting: Add support for writing to a file In-Reply-To: <20200430173630.15608-1-sughosh.ganu@linaro.org> References: <20200430173630.15608-1-sughosh.ganu@linaro.org> Message-ID: <20200430173630.15608-3-sughosh.ganu@linaro.org> Add a function to enable writing to a file. Currently, support is added for writing to a binary file. This would be used for implementing the firmware update functionality for the qemu arm64 platform. Signed-off-by: Sughosh Ganu --- arch/arm/lib/semihosting.c | 41 ++++++++++++++++++++++++++++++++++++-- include/semihosting.h | 1 + 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/arch/arm/lib/semihosting.c b/arch/arm/lib/semihosting.c index 3aeda1303a..08181132d1 100644 --- a/arch/arm/lib/semihosting.c +++ b/arch/arm/lib/semihosting.c @@ -17,11 +17,18 @@ #define SYSOPEN 0x01 #define SYSCLOSE 0x02 +#define SYSWRITE 0x5 #define SYSREAD 0x06 #define SYSFLEN 0x0C -#define MODE_READ 0x0 -#define MODE_READBIN 0x1 +#define MODE_READ 0x0 +#define MODE_READBIN 0x1 +#define MODE_READPLUS 0x2 +#define MODE_READPLUSBIN 0x3 +#define MODE_WRITE 0x4 +#define MODE_WRITEBIN 0x5 +#define MODE_WRITEPLUS 0x6 +#define MODE_WRITEPLUSBIN 0x7 /* * Call the handler @@ -61,6 +68,8 @@ long smh_open(const char *fname, char *modestr) mode = MODE_READ; } else if (!(strcmp(modestr, "rb"))) { mode = MODE_READBIN; + } else if (!strcmp(modestr, "w+b")) { + mode = MODE_WRITEPLUSBIN; } else { printf("%s: ERROR mode \'%s\' not supported\n", __func__, modestr); @@ -114,6 +123,34 @@ long smh_read(long fd, void *memp, size_t len) return 0; } +/* + * Write 'len' bytes into the file referenced by the fd. Returns 0 on success, else + * a negavite value for failure + */ +long smh_write(long fd, void *memp, size_t len) +{ + long ret; + struct smh_write_s { + long fd; + void *memp; + size_t len; + } write; + + debug("%s: fd %ld, memp %p, len %zu\n", __func__, fd, memp, len); + + write.fd = fd; + write.memp = memp; + write.len = len; + + ret = smh_trap(SYSWRITE, &write); + + if (ret > 0) + printf("%s: ERROR ret %ld, fd %ld, len %zu, memp %p\n", + __func__, ret, fd, len, memp); + + return ret == 0 ? 0 : -1; +} + /* * Close the file using the file descriptor */ diff --git a/include/semihosting.h b/include/semihosting.h index f1bf419275..fa5cecddf2 100644 --- a/include/semihosting.h +++ b/include/semihosting.h @@ -8,6 +8,7 @@ long smh_open(const char *fname, char *modestr); long smh_read(long fd, void *memp, size_t len); +long smh_write(long fd, void *memp, size_t len); long smh_close(long fd); #endif /* _SEMIHOSTING_H_ */ From patchwork Thu Apr 30 17:36:25 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 239024 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Thu, 30 Apr 2020 23:06:25 +0530 Subject: [PATCH 3/8] qemu: arm64: Add support for efi firmware management protocol routines In-Reply-To: <20200430173630.15608-1-sughosh.ganu@linaro.org> References: <20200430173630.15608-1-sughosh.ganu@linaro.org> Message-ID: <20200430173630.15608-4-sughosh.ganu@linaro.org> Add support for the get_image_info and set_image routines, which are part of the efi firmware management protocol. The current implementation uses the set_image routine for updating the u-boot binary image for the qemu arm64 platform. This is supported using the capsule-on-disk feature of the uefi specification, wherein the firmware image to be updated is placed on the efi system partition as a efi capsule under EFI/UpdateCapsule/ directory. Support has been added for updating the u-boot image on platforms booting with arm trusted firmware(tf-a), where the u-boot image gets booted as the BL33 payload(bl33.bin). The feature can be enabled by the following config options CONFIG_EFI_CAPSULE_ON_DISK=y CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y Signed-off-by: Sughosh Ganu --- board/emulation/qemu-arm/Kconfig | 12 ++ board/emulation/qemu-arm/Makefile | 1 + board/emulation/qemu-arm/qemu_efi_fmp.c | 210 ++++++++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 board/emulation/qemu-arm/qemu_efi_fmp.c diff --git a/board/emulation/qemu-arm/Kconfig b/board/emulation/qemu-arm/Kconfig index 02ae4d9884..f1b2de8e41 100644 --- a/board/emulation/qemu-arm/Kconfig +++ b/board/emulation/qemu-arm/Kconfig @@ -11,3 +11,15 @@ config BOARD_SPECIFIC_OPTIONS # dummy imply VIRTIO_BLK endif + +if TARGET_QEMU_ARM_64BIT && TFABOOT + +config EFI_FIRMWARE_MANAGEMENT_PROTOCOL + bool "EFI Firmware Management protocol for Qemu arm64 platform" + depends on EFI_CAPSULE_ON_DISK + default n + help + Select this option for enabling firmware management protocol + for qemu arm64 platform + +endif diff --git a/board/emulation/qemu-arm/Makefile b/board/emulation/qemu-arm/Makefile index a22d1237ff..c95ac6d233 100644 --- a/board/emulation/qemu-arm/Makefile +++ b/board/emulation/qemu-arm/Makefile @@ -1,3 +1,4 @@ # SPDX-License-Identifier: GPL-2.0+ obj-y += qemu-arm.o +obj-$(CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL) += qemu_efi_fmp.o diff --git a/board/emulation/qemu-arm/qemu_efi_fmp.c b/board/emulation/qemu-arm/qemu_efi_fmp.c new file mode 100644 index 0000000000..9baea94e6c --- /dev/null +++ b/board/emulation/qemu-arm/qemu_efi_fmp.c @@ -0,0 +1,210 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include + +#define QEMU_UBOOT_IMAGE_INDEX 0x1 +#define QEMU_UBOOT_IMAGE 0x1 + +#define UBOOT_FILE "bl33.bin" + +#define EFI_FMP_QEMU_ARM64_UBOOT_CAPSULE_ID_GUID \ + EFI_GUID(0xfb90808a, 0xba9a, 0x4d42, 0xb9, 0xa2, \ + 0xa7, 0xa9, 0x37, 0x14, 0x4a, 0xee) + +/** + * qemu_arm64_fmp_get_image_info() - Implement get_image_info + * + * @this: instance of the efi_firmware_management_protocol + * @image_info_size: pointer to the size of image_info buffer + * @image_info: pointer to buffer which contains info on the + * image + * @desc_version: pointer to version number of the + * efi_firmware_image_descriptor + * @desc_count: pointer to the number of descriptors of the + * firmware images on the device + * @desc_size: pointer to the size of an individual descriptor + * @package_version: version for all firmware images on the device + * @package_version_name: string representing the package version name + * + * Implement the get_image_info function of the + * efi_firmware_management_protocol for the platform. + * + * Return: status code + */ +static efi_status_t EFIAPI qemu_arm64_fmp_get_image_info( + struct efi_firmware_management_protocol *this, + efi_uintn_t *image_info_size, + struct efi_firmware_image_descriptor *image_info, + u32 *desc_version, u8 *desc_count, + efi_uintn_t *desc_size, u32 *package_version, + u16 **package_version_name) +{ + efi_status_t status = EFI_SUCCESS; + u16 *image_id_name; + const char *image_name = "Qemu Aarch64 U-Boot"; + const efi_guid_t image_guid = EFI_FMP_QEMU_ARM64_UBOOT_CAPSULE_ID_GUID; + + EFI_ENTRY("%p %p %p %p %p %p %p %p\n", this, image_info_size, + image_info, desc_version, desc_count, desc_size, + package_version, package_version_name); + + /* Sanity checks */ + if (*image_info_size && !image_info) { + status = EFI_INVALID_PARAMETER; + goto back; + } + + if (*image_info_size && + (!desc_version || !desc_count || !desc_size)) { + status = EFI_INVALID_PARAMETER; + goto back; + } + + if (*image_info_size < sizeof(*image_info)) { + *image_info_size = sizeof(*image_info); + status = EFI_BUFFER_TOO_SMALL; + goto back; + } + + if (desc_version) + *desc_version = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION; + + *desc_count = 0x1; + *desc_size = sizeof(*image_info); + + if (package_version) + *package_version = 0xffffffff; + + if (package_version_name) + *package_version_name = NULL; + + image_info[0].image_type_id = image_guid; + image_info[0].image_id = QEMU_UBOOT_IMAGE; + + image_id_name = malloc(40); + utf8_utf16_strcpy(&image_id_name, image_name); + image_info[0].image_id_name = image_id_name; + + /* Todo: Get a mechanism to store version information */ + image_info[0]. version = 0x1; + image_info[0].version_name = NULL; + + /* Todo: Need to find a mechanism to get the image size */ + image_info[0].size = 0; + + image_info[0].attributes_supported = + EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; + image_info[0].attributes_setting = EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; + + image_info[0].lowest_supported_image_version = 1; + image_info[0].last_attempt_version = 0; + image_info[0].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS; + image_info[0].hardware_instance = 0; + +back: + return EFI_EXIT(status); +} + +/** + * qemu_arm64_fmp_set_image() - Implement set_image + * + * @this: instance of the efi_firmware_management_protocol + * @image_index: a unique number identifying the firmware image + * @image: pointer to the buffer containing the firmware + * image to be updated + * @image_size: pointer to size of the firmware image + * @vendor_code: pointer to the vendor specific update policy + * @completion: function pointer that can be invoked to report + * firmware update progress + * @abort_reason: string providing details if update is aborted + * + * Implement the set_image function of the efi_firmware_management_protocol + * for the platform. This updates the firmware image and authenticates the + * capsule, if authentication is enabled + * + * Return: status code + */ +static efi_status_t EFIAPI qemu_arm64_fmp_set_image( + struct efi_firmware_management_protocol *this, + u8 image_index, const void *image, + efi_uintn_t image_size, const void *vendor_code, + efi_status_t (*progress)(efi_uintn_t completion), + u16 **abort_reason) +{ + long fd, ret; + efi_status_t status = EFI_SUCCESS; + char *mode = "w+b"; + + EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image, + image_size, vendor_code, progress, abort_reason); + + /* + * Put a hack here to offset the size of + * the FMP_PAYLOAD_HEADER that gets added + * by the GenerateCapsule script in edk2. + */ + image += 0x10; + image_size -= 0x10; + + /* Do all the sanity checks first */ + if (!image) { + status = EFI_INVALID_PARAMETER; + goto back; + } + + if (image_size == 0) { + status = EFI_INVALID_PARAMETER; + goto back; + } + + if (image_index != QEMU_UBOOT_IMAGE_INDEX) { + status = EFI_INVALID_PARAMETER; + goto back; + } + + /* Do the update */ + fd = smh_open(UBOOT_FILE, mode); + if (fd == -1) { + printf("Unable to open the firmware image for writing\n"); + status = EFI_DEVICE_ERROR; + goto back; + } + + ret = smh_write(fd, (void *)image, image_size); + if (ret == -1) { + printf("Error writing to the firmware image!"); + smh_close(fd); + status = EFI_DEVICE_ERROR; + goto back; + } + + printf("Capsule Update Complete\n"); + smh_close(fd); +back: + return EFI_EXIT(status); +} + +const struct efi_firmware_management_protocol efi_qemu_arm64_fmp = { + .get_image_info = qemu_arm64_fmp_get_image_info, + .set_image = qemu_arm64_fmp_set_image, +}; + +efi_status_t arch_efi_load_capsule_drivers(void) +{ + efi_status_t ret; + + ret = EFI_CALL(efi_install_multiple_protocol_interfaces(&efi_root, + &efi_guid_firmware_management_protocol, + &efi_qemu_arm64_fmp, + NULL)); + + return ret; +} From patchwork Thu Apr 30 17:36:26 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 239028 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Thu, 30 Apr 2020 23:06:26 +0530 Subject: [PATCH 4/8] efi_loader: Allow parsing of miscellaneous signature database variables In-Reply-To: <20200430173630.15608-1-sughosh.ganu@linaro.org> References: <20200430173630.15608-1-sughosh.ganu@linaro.org> Message-ID: <20200430173630.15608-5-sughosh.ganu@linaro.org> The current function to parse the signature database(sigdb) only allows parsing of secure boot related sigdb variables, namely PK, KEK, db and dbx. Allow the function to parse any other sigdb variables. This would be useful for the capsule authenticate feature, which would be storing it's root certificate in a non secure-boot sigdb. This is done by passing the vendor guid as a function argument. Signed-off-by: Sughosh Ganu --- include/efi_loader.h | 3 ++- lib/efi_loader/efi_image_loader.c | 11 +++++++---- lib/efi_loader/efi_signature.c | 14 +++----------- lib/efi_loader/efi_variable.c | 9 ++++++--- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index ad99ab660f..b7638d5825 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -774,7 +774,8 @@ efi_status_t efi_image_region_add(struct efi_image_regions *regs, int nocheck); void efi_sigstore_free(struct efi_signature_store *sigstore); -struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name); +struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name, + const efi_guid_t *vendor); bool efi_secure_boot_enabled(void); diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c index 6c270ce94f..e07dc290a3 100644 --- a/lib/efi_loader/efi_image_loader.c +++ b/lib/efi_loader/efi_image_loader.c @@ -418,13 +418,15 @@ static bool efi_image_unsigned_authenticate(struct efi_image_regions *regs) struct efi_signature_store *db = NULL, *dbx = NULL; bool ret = false; - dbx = efi_sigstore_parse_sigdb(L"dbx"); + dbx = efi_sigstore_parse_sigdb(L"dbx", + &efi_guid_image_security_database); if (!dbx) { debug("Getting signature database(dbx) failed\n"); goto out; } - db = efi_sigstore_parse_sigdb(L"db"); + db = efi_sigstore_parse_sigdb(L"db", + &efi_guid_image_security_database); if (!db) { debug("Getting signature database(db) failed\n"); goto out; @@ -515,13 +517,14 @@ static bool efi_image_authenticate(void *efi, size_t efi_size) /* * verify signature using db and dbx */ - db = efi_sigstore_parse_sigdb(L"db"); + db = efi_sigstore_parse_sigdb(L"db", &efi_guid_image_security_database); if (!db) { debug("Getting signature database(db) failed\n"); goto err; } - dbx = efi_sigstore_parse_sigdb(L"dbx"); + dbx = efi_sigstore_parse_sigdb(L"dbx", + &efi_guid_image_security_database); if (!dbx) { debug("Getting signature database(dbx) failed\n"); goto err; diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index 658e3547da..bf6f39aab2 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -714,30 +714,22 @@ err: /** * efi_sigstore_parse_sigdb - parse a signature database variable * @name: Variable's name + * @vendor: Vendor guid * * Read in a value of signature database variable pointed to by * @name, parse it and instantiate a signature store structure. * * Return: Pointer to signature store on success, NULL on error */ -struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name) +struct efi_signature_store *efi_sigstore_parse_sigdb( + u16 *name, const efi_guid_t *vendor) { struct efi_signature_store *sigstore = NULL, *siglist; struct efi_signature_list *esl; - const efi_guid_t *vendor; void *db; efi_uintn_t db_size; efi_status_t ret; - if (!u16_strcmp(name, L"PK") || !u16_strcmp(name, L"KEK")) { - vendor = &efi_global_variable_guid; - } else if (!u16_strcmp(name, L"db") || !u16_strcmp(name, L"dbx")) { - vendor = &efi_guid_image_security_database; - } else { - debug("unknown signature database, %ls\n", name); - return NULL; - } - /* retrieve variable data */ db_size = 0; ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, NULL)); diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 7df881a74b..6c2dd82306 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -604,14 +604,17 @@ static efi_status_t efi_variable_authenticate(u16 *variable, if (u16_strcmp(variable, L"PK") == 0 || u16_strcmp(variable, L"KEK") == 0) { /* with PK */ - truststore = efi_sigstore_parse_sigdb(L"PK"); + truststore = efi_sigstore_parse_sigdb(L"PK", + &efi_global_variable_guid); if (!truststore) goto err; } else if (u16_strcmp(variable, L"db") == 0 || u16_strcmp(variable, L"dbx") == 0) { /* with PK and KEK */ - truststore = efi_sigstore_parse_sigdb(L"KEK"); - truststore2 = efi_sigstore_parse_sigdb(L"PK"); + truststore = efi_sigstore_parse_sigdb(L"KEK", + &efi_global_variable_guid); + truststore2 = efi_sigstore_parse_sigdb(L"PK", + &efi_global_variable_guid); if (!truststore) { if (!truststore2) From patchwork Thu Apr 30 17:36:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 239027 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Thu, 30 Apr 2020 23:06:27 +0530 Subject: [PATCH 5/8] efi_loader: Make the pkcs7 header parsing function an extern In-Reply-To: <20200430173630.15608-1-sughosh.ganu@linaro.org> References: <20200430173630.15608-1-sughosh.ganu@linaro.org> Message-ID: <20200430173630.15608-6-sughosh.ganu@linaro.org> The pkcs7 header parsing functionality is pretty generic, and can be used by other features like capsule authentication. Make the function as an extern, also changing it's name to efi_parse_pkcs7_header. Signed-off-by: Sughosh Ganu --- include/efi_loader.h | 2 + lib/efi_loader/efi_signature.c | 78 ++++++++++++++++++++++++++++++++ lib/efi_loader/efi_variable.c | 82 +--------------------------------- 3 files changed, 82 insertions(+), 80 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index b7638d5825..8d923451ce 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -781,6 +781,8 @@ bool efi_secure_boot_enabled(void); bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, WIN_CERTIFICATE **auth, size_t *auth_len); +struct pkcs7_message *efi_parse_pkcs7_header(const void *buf, size_t buflen); + #endif /* CONFIG_EFI_SECURE_BOOT */ #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index bf6f39aab2..9897f5418e 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -25,6 +25,84 @@ const efi_guid_t efi_guid_cert_x509_sha256 = EFI_CERT_X509_SHA256_GUID; #ifdef CONFIG_EFI_SECURE_BOOT +static u8 pkcs7_hdr[] = { + /* SEQUENCE */ + 0x30, 0x82, 0x05, 0xc7, + /* OID: pkcs7-signedData */ + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, + /* Context Structured? */ + 0xa0, 0x82, 0x05, 0xb8, +}; + +/** + * efi_parse_pkcs7_header - parse a signature in variable + * @buf: Pointer to the payload's value + * @buflen: Length of @buf + * + * Parse a signature embedded in variable's value and instantiate + * a pkcs7_message structure. Since pkcs7_parse_message() accepts only + * pkcs7's signedData, some header needed be prepended for correctly + * parsing authentication data, particularly for variable's. + * + * Return: Pointer to pkcs7_message structure on success, NULL on error + */ +struct pkcs7_message *efi_parse_pkcs7_header(const void *buf, size_t buflen) +{ + u8 *ebuf; + size_t ebuflen, len; + struct pkcs7_message *msg; + + /* + * This is the best assumption to check if the binary is + * already in a form of pkcs7's signedData. + */ + if (buflen > sizeof(pkcs7_hdr) && + !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) { + msg = pkcs7_parse_message(buf, buflen); + goto out; + } + + /* + * Otherwise, we should add a dummy prefix sequence for pkcs7 + * message parser to be able to process. + * NOTE: EDK2 also uses similar hack in WrapPkcs7Data() + * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c + * TODO: + * The header should be composed in a more refined manner. + */ + debug("Makeshift prefix added to authentication data\n"); + ebuflen = sizeof(pkcs7_hdr) + buflen; + if (ebuflen <= 0x7f) { + debug("Data is too short\n"); + return NULL; + } + + ebuf = malloc(ebuflen); + if (!ebuf) { + debug("Out of memory\n"); + return NULL; + } + + memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr)); + memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen); + len = ebuflen - 4; + ebuf[2] = (len >> 8) & 0xff; + ebuf[3] = len & 0xff; + len = ebuflen - 0x13; + ebuf[0x11] = (len >> 8) & 0xff; + ebuf[0x12] = len & 0xff; + + msg = pkcs7_parse_message(ebuf, ebuflen); + + free(ebuf); + +out: + if (IS_ERR(msg)) + return NULL; + + return msg; +} + /** * efi_hash_regions - calculate a hash value * @regs: List of regions diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 6c2dd82306..be34a2cadd 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -415,85 +415,7 @@ bool efi_secure_boot_enabled(void) return efi_secure_boot; } -#ifdef CONFIG_EFI_SECURE_BOOT -static u8 pkcs7_hdr[] = { - /* SEQUENCE */ - 0x30, 0x82, 0x05, 0xc7, - /* OID: pkcs7-signedData */ - 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, - /* Context Structured? */ - 0xa0, 0x82, 0x05, 0xb8, -}; - -/** - * efi_variable_parse_signature - parse a signature in variable - * @buf: Pointer to variable's value - * @buflen: Length of @buf - * - * Parse a signature embedded in variable's value and instantiate - * a pkcs7_message structure. Since pkcs7_parse_message() accepts only - * pkcs7's signedData, some header needed be prepended for correctly - * parsing authentication data, particularly for variable's. - * - * Return: Pointer to pkcs7_message structure on success, NULL on error - */ -static struct pkcs7_message *efi_variable_parse_signature(const void *buf, - size_t buflen) -{ - u8 *ebuf; - size_t ebuflen, len; - struct pkcs7_message *msg; - - /* - * This is the best assumption to check if the binary is - * already in a form of pkcs7's signedData. - */ - if (buflen > sizeof(pkcs7_hdr) && - !memcmp(&((u8 *)buf)[4], &pkcs7_hdr[4], 11)) { - msg = pkcs7_parse_message(buf, buflen); - goto out; - } - - /* - * Otherwise, we should add a dummy prefix sequence for pkcs7 - * message parser to be able to process. - * NOTE: EDK2 also uses similar hack in WrapPkcs7Data() - * in CryptoPkg/Library/BaseCryptLib/Pk/CryptPkcs7VerifyCommon.c - * TODO: - * The header should be composed in a more refined manner. - */ - debug("Makeshift prefix added to authentication data\n"); - ebuflen = sizeof(pkcs7_hdr) + buflen; - if (ebuflen <= 0x7f) { - debug("Data is too short\n"); - return NULL; - } - - ebuf = malloc(ebuflen); - if (!ebuf) { - debug("Out of memory\n"); - return NULL; - } - - memcpy(ebuf, pkcs7_hdr, sizeof(pkcs7_hdr)); - memcpy(ebuf + sizeof(pkcs7_hdr), buf, buflen); - len = ebuflen - 4; - ebuf[2] = (len >> 8) & 0xff; - ebuf[3] = len & 0xff; - len = ebuflen - 0x13; - ebuf[0x11] = (len >> 8) & 0xff; - ebuf[0x12] = len & 0xff; - - msg = pkcs7_parse_message(ebuf, ebuflen); - - free(ebuf); - -out: - if (IS_ERR(msg)) - return NULL; - - return msg; -} +#ifdef CONFIG_SECURE_BOOT /** * efi_variable_authenticate - authenticate a variable @@ -591,7 +513,7 @@ static efi_status_t efi_variable_authenticate(u16 *variable, /* variable's signature list */ if (auth->auth_info.hdr.dwLength < sizeof(auth->auth_info)) goto err; - var_sig = efi_variable_parse_signature(auth->auth_info.cert_data, + var_sig = efi_parse_pkcs7_header(auth->auth_info.cert_data, auth->auth_info.hdr.dwLength - sizeof(auth->auth_info)); if (IS_ERR(var_sig)) { From patchwork Thu Apr 30 17:36:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 239029 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Thu, 30 Apr 2020 23:06:28 +0530 Subject: [PATCH 6/8] efi: capsule: Add support for uefi capsule authentication In-Reply-To: <20200430173630.15608-1-sughosh.ganu@linaro.org> References: <20200430173630.15608-1-sughosh.ganu@linaro.org> Message-ID: <20200430173630.15608-7-sughosh.ganu@linaro.org> 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 an efi variable, similar to the variables used for uefi secure boot. 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 --- include/efi_api.h | 17 +++++ include/efi_loader.h | 8 ++- lib/efi_loader/Kconfig | 16 +++++ lib/efi_loader/efi_capsule.c | 126 +++++++++++++++++++++++++++++++++ lib/efi_loader/efi_signature.c | 4 +- 5 files changed, 167 insertions(+), 4 deletions(-) diff --git a/include/efi_api.h b/include/efi_api.h index e518ffa838..8dfa479db4 100644 --- a/include/efi_api.h +++ b/include/efi_api.h @@ -1794,6 +1794,23 @@ 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 8d923451ce..897710ae3f 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -708,7 +708,7 @@ void efi_deserialize_load_option(struct efi_load_option *lo, u8 *data); unsigned long efi_serialize_load_option(struct efi_load_option *lo, u8 **data); efi_status_t efi_bootmgr_load(efi_handle_t *handle); -#ifdef CONFIG_EFI_SECURE_BOOT +#if defined(CONFIG_EFI_SECURE_BOOT) || defined(CONFIG_EFI_CAPSULE_AUTHENTICATE) #include /** @@ -783,7 +783,7 @@ bool efi_image_parse(void *efi, size_t len, struct efi_image_regions **regp, WIN_CERTIFICATE **auth, size_t *auth_len); struct pkcs7_message *efi_parse_pkcs7_header(const void *buf, size_t buflen); -#endif /* CONFIG_EFI_SECURE_BOOT */ +#endif /* CONFIG_EFI_SECURE_BOOT || CONFIG_EFI_CAPSULE_AUTHENTICATE */ #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT /* Capsule update */ @@ -798,6 +798,10 @@ efi_status_t EFIAPI efi_query_capsule_caps( u32 *reset_type); #endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */ +efi_status_t efi_capsule_authenticate(const void *capsule, + efi_uintn_t capsule_size, + void **image, efi_uintn_t *image_size); + #ifdef CONFIG_EFI_CAPSULE_ON_DISK #define EFI_CAPSULE_DIR L"\\EFI\\UpdateCapsule\\" diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index ec2976ceba..245deabbed 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -110,6 +110,22 @@ config EFI_CAPSULE_FIT_DEVICE help Define storage device, say 1:1, for storing FIT image +config EFI_CAPSULE_AUTHENTICATE + bool "Update Capsule authentication" + depends on EFI_HAVE_CAPSULE_SUPPORT + depends on EFI_CAPSULE_ON_DISK + depends on EFI_FIRMWARE_MANAGEMENT_PROTOCOL + select SHA256 + select RSA + select RSA_VERIFY + select RSA_VERIFY_WITH_PKEY + select X509_CERTIFICATE_PARSER + select PKCS7_MESSAGE_PARSER + default n + help + Select this option if you want to enable capsule + authentication + config EFI_DEVICE_PATH_TO_TEXT bool "Device path to text protocol" default y diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index 931d363edc..a265d36ff0 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -12,6 +12,10 @@ #include #include #include +#include "../lib/crypto/pkcs7_parser.h" + +#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 = @@ -245,6 +249,128 @@ out: return ret; } + +#if defined(CONFIG_EFI_CAPSULE_AUTHENTICATE) + +const efi_guid_t efi_guid_capsule_root_cert_guid = + EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; + +__weak u16 *efi_get_truststore_name(void) +{ + return L"CRT"; +} + +__weak const efi_guid_t *efi_get_truststore_vendor(void) +{ + + return &efi_guid_capsule_root_cert_guid; +} + +/** + * efi_capsule_authenticate() - Authenticate a uefi capsule + * + * @capsule: Capsule file with the authentication + * header + * @capsule_size: Size of the entire capsule + * @image: pointer to the image payload minus the + * authentication header + * @image_size: size of the image payload + * + * Authenticate the capsule signature with the public key contained + * in the root certificate stored as an efi environment variable + * + * Return: EFI_SUCCESS on successfull authentication or + * EFI_SECURITY_VIOLATION on authentication failure + */ +efi_status_t efi_capsule_authenticate(const void *capsule, + efi_uintn_t capsule_size, + void **image, efi_uintn_t *image_size) +{ + 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)); + if (IS_ERR(capsule_sig)) { + debug("Parsing variable's pkcs7 header failed\n"); + capsule_sig = NULL; + goto out; + } + + truststore = efi_sigstore_parse_sigdb(efi_get_truststore_name(), + efi_get_truststore_vendor()); + if (!truststore) + goto out; + + /* verify signature */ + if (efi_signature_verify_with_sigdb(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 */ #else static efi_status_t efi_capsule_update_firmware( struct efi_capsule_header *capsule_data) diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index 9897f5418e..4c722e0da9 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -23,7 +23,7 @@ const efi_guid_t efi_guid_cert_rsa2048 = EFI_CERT_RSA2048_GUID; 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; -#ifdef CONFIG_EFI_SECURE_BOOT +#if defined(CONFIG_EFI_SECURE_BOOT) || defined(CONFIG_EFI_CAPSULE_AUTHENTICATE) static u8 pkcs7_hdr[] = { /* SEQUENCE */ @@ -871,4 +871,4 @@ err: return NULL; } -#endif /* CONFIG_EFI_SECURE_BOOT */ +#endif /* CONFIG_EFI_SECURE_BOOT || CONFIG_EFI_CAPSULE_AUTHENTICATE */ From patchwork Thu Apr 30 17:36:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 239032 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Thu, 30 Apr 2020 23:06:29 +0530 Subject: [PATCH 7/8] qemu: arm64: Add support for uefi capsule authentication In-Reply-To: <20200430173630.15608-1-sughosh.ganu@linaro.org> References: <20200430173630.15608-1-sughosh.ganu@linaro.org> Message-ID: <20200430173630.15608-8-sughosh.ganu@linaro.org> Add support for uefi capsule authentication feature for the qemu arm64 platform. This feature is enabled by setting the environment variable "capsule_authentication_enabled". The following configs are needed for enabling uefi capsule update and capsule authentication features on the platform. CONFIG_EFI_CAPSULE_ON_DISK=y CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y CONFIG_EFI_CAPSULE_AUTHENTICATE=y Signed-off-by: Sughosh Ganu --- board/emulation/qemu-arm/qemu_efi_fmp.c | 49 +++++++++++++++++++++---- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/board/emulation/qemu-arm/qemu_efi_fmp.c b/board/emulation/qemu-arm/qemu_efi_fmp.c index 9baea94e6c..b58843f8fb 100644 --- a/board/emulation/qemu-arm/qemu_efi_fmp.c +++ b/board/emulation/qemu-arm/qemu_efi_fmp.c @@ -101,9 +101,15 @@ static efi_status_t EFIAPI qemu_arm64_fmp_get_image_info( image_info[0].size = 0; image_info[0].attributes_supported = - EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; + EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE | + EFI_IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED; image_info[0].attributes_setting = EFI_IMAGE_ATTRIBUTE_IMAGE_UPDATABLE; + /* Check if the capsule authentication is enabled */ + if (env_get("capsule_authentication_enabled")) + image_info[0].attributes_setting |= + EFI_IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED; + image_info[0].lowest_supported_image_version = 1; image_info[0].last_attempt_version = 0; image_info[0].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS; @@ -142,17 +148,12 @@ static efi_status_t EFIAPI qemu_arm64_fmp_set_image( long fd, ret; efi_status_t status = EFI_SUCCESS; char *mode = "w+b"; + void *capsule_payload; + efi_uintn_t capsule_payload_size; EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image, image_size, vendor_code, progress, abort_reason); - /* - * Put a hack here to offset the size of - * the FMP_PAYLOAD_HEADER that gets added - * by the GenerateCapsule script in edk2. - */ - image += 0x10; - image_size -= 0x10; /* Do all the sanity checks first */ if (!image) { @@ -170,6 +171,38 @@ static efi_status_t EFIAPI qemu_arm64_fmp_set_image( goto back; } + /* Authenticate the capsule if authentication enabled */ + if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE) && + env_get("capsule_authentication_enabled")) { + capsule_payload = NULL; + capsule_payload_size = 0; + status = efi_capsule_authenticate(image, image_size, + &capsule_payload, + &capsule_payload_size); + + if (status == EFI_SECURITY_VIOLATION) { + printf("Capsule authentication check failed. Aborting update\n"); + goto back; + } else if (status != EFI_SUCCESS) { + goto back; + } + + debug("Capsule authentication successfull\n"); + image = capsule_payload; + image_size = capsule_payload_size; + } else { + debug("Capsule authentication disabled. "); + debug("Updating capsule without authenticating.\n"); + } + + /* + * Put a hack here to offset the size of + * the FMP_PAYLOAD_HEADER that gets added + * by the GenerateCapsule script in edk2. + */ + image += 0x10; + image_size -= 0x10; + /* Do the update */ fd = smh_open(UBOOT_FILE, mode); if (fd == -1) { From patchwork Thu Apr 30 17:36:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sughosh Ganu X-Patchwork-Id: 239031 List-Id: U-Boot discussion From: sughosh.ganu at linaro.org (Sughosh Ganu) Date: Thu, 30 Apr 2020 23:06:30 +0530 Subject: [PATCH 8/8] qemu: arm64: Add documentation for capsule update In-Reply-To: <20200430173630.15608-1-sughosh.ganu@linaro.org> References: <20200430173630.15608-1-sughosh.ganu@linaro.org> Message-ID: <20200430173630.15608-9-sughosh.ganu@linaro.org> Add documentation highlighting the steps for using the uefi capsule update feature for updating the u-boot firmware image. Signed-off-by: Sughosh Ganu --- doc/board/emulation/qemu-arm.rst | 112 +++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/doc/board/emulation/qemu-arm.rst b/doc/board/emulation/qemu-arm.rst index ca751d4af4..8649d593ed 100644 --- a/doc/board/emulation/qemu-arm.rst +++ b/doc/board/emulation/qemu-arm.rst @@ -80,3 +80,115 @@ can be enabled with the following command line parameters: -drive if=none,file=disk.img,id=mydisk -device nvme,drive=mydisk,serial=foo These have been tested in QEMU 2.9.0 but should work in at least 2.5.0 as well. + +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). Currently, support has been added for the arm64 +target booting with arm trusted firmware. The This feature is enabled +with the following configs:: + + CONFIG_EFI_CAPSULE_ON_DISK=y + CONFIG_EFI_FIRMWARE_MANAGEMENT_PROTOCOL=y + CONFIG_CMD_EFIDEBUG=y + +The capsule file can be generated by using the GenerateCapsule.py +script in edk2:: + + $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \ + --fw-version --lsv --guid \ + fb90808a-ba9a-4d42-b9a2-a7a937144aee --verbose --update-image-index \ + --verbose + + +As per the uefi specification, the capsule file needs to be placed on +the EFI System Partition, under the EFI/UpdateCapsule/ directory. The +EFI System Partition can be a virtio-blk-device. + +Before initiating the firmware update, the efi variables BootNext and +BootXXXX need to be set. The BootXXXX variable needs to be pointing to +the EFI System Partition which contains the capsule file. The +BootNext and BootXXXX variables can be set using the efidebug +command:: + + => efidebug boot add 0 Boot0000 virtio 0:1 + => efidebug boot next 0 + +The OsIndications efi variable needs to be set with the +EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED flag set:: + + => setenv -e -nv -bs -rt OsIndications =0x04 + => saveenv + +The capsule update function will be invoked on subsequent boot as part +of the main_loop function. The updated u-boot image will be booted on +subsequent boot. + + +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 stored as an +efi variable. + +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 + +The esl file can be generated as follows: + +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 + +3. Store the esl file generated above as an efi variable:: + + => fatload virtio 0:1 EFI/CRT.esl + => setenv -e -nv -bs -rt -i ,$filesize CRT + + => setenv capsule_authentication_enabled 1 + => setenv -e -nv -bs -rt OsIndication =0x04 + => saveenv + +Setting the environment variable capsule_authentication_enabled +enables the capsule authentication. + +4. The capsule file can be generated by using the GenerateCapsule.py + script in edk2:: + + $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \ + --monotonic-count --fw-version \ + --lsv --guid \ + fb90808a-ba9a-4d42-b9a2-a7a937144aee --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 \ + + +Once the capsule has been generated, use the same instructions as +mentioned above for placing the capsule on the EFI System Partition +and subsequently to initiate the update.