All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform
@ 2020-12-30 13:56 Sughosh Ganu
  2020-12-30 13:56 ` [PATCH v4 01/14] mkeficapsule: Add support for embedding public key in a dtb Sughosh Ganu
                   ` (13 more replies)
  0 siblings, 14 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:56 UTC (permalink / raw)
  To: u-boot

The capsule update feature is supported on a platform configuration
booting in a non-secure mode, i.e with -machine virt,secure=off option
set. This results in the platform booting u-boot directly without
the presence of trusted firmware(tf-a). Steps that need to be followed
for using this feature have been provided as part of the documentation.

Support has also been added for enabling the capsule authentication
feature. Capsule authentication, as defined by the uefi
specification is very much on similar lines to the logic used for
variable authentication. As a result, most of the signature
verification code already in use for variable authentication has been
used for capsule authentication.

Storage of the public key certificate, needed for the signature
verification process is in form of the efi signature list(esl)
structure.  This public key is stored on an overlay which is then
merged with the platform's base fdt at runtime. The public key esl
file can be embedded into the overlay dtb using the mkeficapsule
utility that has been added as part of the capsule update support
series by Takahiro Akashi. Steps needed for enabling capsule
authentication have been provided as part of the documentation.

This patch series needs to be applied on top of the capsule update
support patch series from Takahiro Akashi on the next branch.

Changes since V3:
* Move the selection of SYS_MTDPARTS_RUNTIME config to the board's
  Kconfig from lib/efi_loader/Kconfig, using imply.
* Move the selection of SET_DFU_ALT_INFO config to the board's Kconfig
  from lib/efi_loader/Kconfig, using imply.

Changes since V2:
* Enable building of board_late_init for both of the Qemu arm and
  arm64  variants
* Move the selection the CONFIG_BOARD_LATE_INIT to mach-qemu Kconfig
  file
* Move the functions to populate the mtdparts under
  board/emulation/common for allowing subsequent re-use by other Qemu
  arch based platforms
* Move the functions to populate the dfu_alt_info variable under
  board/emulation/common for allowing subsequent re-use by other Qemu
  arch based platforms
* Move the function for fetching the public key certficate from the
  platform's dtb under board/emulation/common directory.
* Move the function for checking the capsule_authentication_enabled
  env variable under board/emulation/common directory.
* Moved the capsule update related documentation for the Qemu
  platform to a new file under doc/board/emulation/ directory.
* Incorporated all typo review comments from Heinrich
* Put in a skeletal overlay dts file for reference, as was suggested
  by Heinrich

Changes since V1:
* Added support for embedding the public key cert in an overlay using
  the -O option
* The earlier patch was adding a call to pci_init in board_init. Moved
  the virtio_init call to board_late_init
* Change MTDPARTS_NOR[01] as config options instead of defining them in
  the qemu-arm.h config header.
* Enable CONFIG_SYS_MTDPARTS_RUNTIME with CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT
* Build set_dfu_alt_info and board_get_alt_info functions only if
  CONFIG_SET_DFU_ALT_INFO is defined
* Enable CONFIG_SET_DFU_ALT_INFO with
  CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT
* Detect the presence of the FMP Payload header at runtime instead of
  using a Kconfig option, as was suggested by Heinrich
* Change the documentation to reflect the usage of overlays for
  embedding the public key certs at runtime
* Fix the build for 'make htmldocs'


Sughosh Ganu (14):
  mkeficapsule: Add support for embedding public key in a dtb
  qemu: arm: Initialise virtio devices in board_late_init
  crypto: Fix the logic to calculate hash with authattributes set
  qemu: common: Add support for dynamic mtdparts for the platform
  qemu: common: Set dfu_alt_info variable for the platform
  fsp: Move and rename fsp_types.h file
  efi_loader: Add logic to parse EDKII specific fmp payload header
  dfu_mtd: Add provision to unlock mtd device
  efi_loader: Make the pkcs7 header parsing function an extern
  efi_loader: Re-factor code to build the signature store from efi
    signature list
  efi: capsule: Add support for uefi capsule authentication
  efi_loader: Enable uefi capsule authentication
  efidebug: capsule: Add a command to update capsule on disk
  qemu: arm64: Add documentation for capsule update

 arch/arm/mach-qemu/Kconfig                    |   2 +
 arch/x86/include/asm/fsp/fsp_support.h        |   3 +-
 board/emulation/common/Kconfig                |  15 ++
 board/emulation/common/Makefile               |   5 +
 board/emulation/common/qemu_capsule.c         |  48 ++++
 board/emulation/common/qemu_dfu.c             |  68 +++++
 board/emulation/common/qemu_mtdparts.c        |  82 ++++++
 board/emulation/qemu-arm/Kconfig              |   8 +
 board/emulation/qemu-arm/qemu-arm.c           |   5 +
 cmd/efidebug.c                                |  14 ++
 doc/board/emulation/index.rst                 |   1 +
 doc/board/emulation/qemu_capsule_update.rst   | 210 ++++++++++++++++
 drivers/dfu/dfu_mtd.c                         |  20 +-
 include/efi_api.h                             |  18 ++
 include/efi_loader.h                          |  12 +
 .../fsp/fsp_types.h => include/signatures.h   |   6 +-
 lib/crypto/pkcs7_verify.c                     |  37 ++-
 lib/efi_loader/Kconfig                        |  17 ++
 lib/efi_loader/efi_capsule.c                  | 122 +++++++++
 lib/efi_loader/efi_firmware.c                 |  77 +++++-
 lib/efi_loader/efi_signature.c                | 192 +++++++++++----
 lib/efi_loader/efi_variable.c                 |  93 +------
 tools/Makefile                                |   1 +
 tools/mkeficapsule.c                          | 233 +++++++++++++++++-
 24 files changed, 1125 insertions(+), 164 deletions(-)
 create mode 100644 board/emulation/common/Kconfig
 create mode 100644 board/emulation/common/Makefile
 create mode 100644 board/emulation/common/qemu_capsule.c
 create mode 100644 board/emulation/common/qemu_dfu.c
 create mode 100644 board/emulation/common/qemu_mtdparts.c
 create mode 100644 doc/board/emulation/qemu_capsule_update.rst
 rename arch/x86/include/asm/fsp/fsp_types.h => include/signatures.h (95%)

-- 
2.17.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 01/14] mkeficapsule: Add support for embedding public key in a dtb
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
@ 2020-12-30 13:56 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 02/14] qemu: arm: Initialise virtio devices in board_late_init Sughosh Ganu
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:56 UTC (permalink / raw)
  To: u-boot

Add options for embedding the public key esl(efi signature list) file
to the platform's dtb. The esl file is then retrieved and used for
authenticating the capsule to be used for updating firmare components
on the platform.

The esl file can now be embedded in the dtb by invoking the following
command
mkeficapsule -K <pub_key.esl> -D <dtb>

In the scenario where the esl file is to be embedded in an overlay,
this can be done through the following command
mkeficapsule -O -K <pub_key.esl> -D <dtb>

This will create a node named 'signature' in the dtb, and the esl file
will be stored as 'capsule-key'

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 tools/Makefile       |   1 +
 tools/mkeficapsule.c | 233 ++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 222 insertions(+), 12 deletions(-)

diff --git a/tools/Makefile b/tools/Makefile
index 66d9376803..6d7b48fb57 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -218,6 +218,7 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs
 hostprogs-$(CONFIG_ASN1_COMPILER)	+= asn1_compiler
 HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
 
+mkeficapsule-objs	:= mkeficapsule.o $(LIBFDT_OBJS)
 hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule
 
 # We build some files with extra pedantic flags to try to minimize things
diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c
index 3f8bc7009b..270943fc90 100644
--- a/tools/mkeficapsule.c
+++ b/tools/mkeficapsule.c
@@ -4,16 +4,22 @@
  *		Author: AKASHI Takahiro
  */
 
+#include <errno.h>
 #include <getopt.h>
 #include <malloc.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 #include <linux/types.h>
+
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include "fdt_host.h"
+
 typedef __u8 u8;
 typedef __u16 u16;
 typedef __u32 u32;
@@ -23,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
@@ -43,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},
 };
@@ -51,14 +63,183 @@ static void print_usage(void)
 {
 	printf("Usage: %s [options] <output file>\n"
 	       "Options:\n"
-	       "\t--fit <fit image>      new FIT image file\n"
-	       "\t--raw <raw image>      new raw image file\n"
-	       "\t--index <index>        update image index\n"
-	       "\t--instance <instance>  update hardware instance\n"
-	       "\t--help                 print a help message\n",
+
+	       "\t--fit <fit image>       new FIT image file\n"
+	       "\t--raw <raw image>       new raw image file\n"
+	       "\t--index <index>         update image index\n"
+	       "\t--instance <instance>   update hardware instance\n"
+	       "\t--public-key <key file> public key esl file\n"
+	       "\t--dtb <dtb file>        dtb file\n"
+	       "\t--overlay               the dtb file is an overlay\n"
+	       "\t--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 = 0;
+	int destfd = 0;
+	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));
+		goto err;
+	}
+
+	ret = fstat(srcfd, &pub_key);
+	if (ret == -1) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			__func__, pkey_file, strerror(errno));
+		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) || (errno != 0)) {
+		fprintf(stderr, "%s: Failed to mmap %s:%s\n",
+			__func__, pkey_file, strerror(errno));
+		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));
+		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));
+		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) || (errno != 0)) {
+		fprintf(stderr, "%s: Failed to mmap %s:%s\n",
+			__func__, dtb_file, strerror(errno));
+		goto err;
+	}
+
+	if (fdt_check_header(dptr)) {
+		fprintf(stderr, "%s: Invalid FDT header\n", __func__);
+		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));
+		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__);
+		goto err;
+	}
+
+	return 0;
+
+err:
+	if (sptr)
+		munmap(sptr, src_size);
+
+	if (dptr)
+		munmap(dptr, dtb.st_size);
+
+	if (srcfd >= 0)
+		close(srcfd);
+
+	if (destfd >= 0)
+		close(destfd);
+
+	return -1;
+}
+
 static int create_fwbin(char *path, char *bin, efi_guid_t *guid,
 			unsigned long index, unsigned long instance)
 {
@@ -173,16 +354,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;
 
@@ -209,22 +396,44 @@ 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 a output file */
-	if (argc != optind + 1) {
+	/* need a fit image file or raw image file */
+	if (!file && !pkey_file && !dtb_file) {
+		printf("%s: %d\n", __func__, __LINE__);
 		print_usage();
 		return -1;
 	}
 
-	/* need a fit image file or raw image file */
-	if (!file) {
-		print_usage();
-		return -1;
+	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");
+			return -1;
+		} else {
+			return 0;
+		}
 	}
 
 	if (create_fwbin(argv[optind], file, guid, index, instance)
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 02/14] qemu: arm: Initialise virtio devices in board_late_init
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
  2020-12-30 13:56 ` [PATCH v4 01/14] mkeficapsule: Add support for embedding public key in a dtb Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 03/14] crypto: Fix the logic to calculate hash with authattributes set Sughosh Ganu
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

On the qemu arm platform, the virtio devices are initialised in the
board_init function, which gets called before the initr_pci. With
this sequence, the virtio block devices on the pci bus are not
initialised. Move the initialisation of the virtio devices to
board_late_init which gets called after the call to initr_pci.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 arch/arm/mach-qemu/Kconfig          | 2 ++
 board/emulation/qemu-arm/qemu-arm.c | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/arch/arm/mach-qemu/Kconfig b/arch/arm/mach-qemu/Kconfig
index 588d2d3102..186c3582eb 100644
--- a/arch/arm/mach-qemu/Kconfig
+++ b/arch/arm/mach-qemu/Kconfig
@@ -16,12 +16,14 @@ choice
 config TARGET_QEMU_ARM_32BIT
 	bool "ARMv7-A, 32bit"
 	select ARCH_SUPPORT_PSCI
+	select BOARD_LATE_INIT
 	select CPU_V7A
 	select SYS_ARCH_TIMER
 
 config TARGET_QEMU_ARM_64BIT
 	bool "ARMv8, 64bit"
 	select ARM64
+	select BOARD_LATE_INIT
 
 endchoice
 
diff --git a/board/emulation/qemu-arm/qemu-arm.c b/board/emulation/qemu-arm/qemu-arm.c
index f18f2ed7da..aa68bef469 100644
--- a/board/emulation/qemu-arm/qemu-arm.c
+++ b/board/emulation/qemu-arm/qemu-arm.c
@@ -64,6 +64,11 @@ struct mm_region *mem_map = qemu_arm64_mem_map;
 #endif
 
 int board_init(void)
+{
+	return 0;
+}
+
+int board_late_init(void)
 {
 	/*
 	 * Make sure virtio bus is enumerated so that peripherals
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 03/14] crypto: Fix the logic to calculate hash with authattributes set
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
  2020-12-30 13:56 ` [PATCH v4 01/14] mkeficapsule: Add support for embedding public key in a dtb Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 02/14] qemu: arm: Initialise virtio devices in board_late_init Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 04/14] qemu: common: Add support for dynamic mtdparts for the platform Sughosh Ganu
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

RFC 2315 Section 9.3 describes the message digesting process. The
digest calculated depends on whether the authenticated attributes are
present. In case of a scenario where the authenticated attributes are
present, the message digest that gets signed and is part of the pkcs7
message is computed from the auth attributes rather than the contents
field.

Check if the auth attributes are present, and if set, use the auth
attributes to compute the hash that would be compared with the
encrypted hash on the pkcs7 message.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 lib/crypto/pkcs7_verify.c | 37 ++++++++++++++++++++++++++-----------
 1 file changed, 26 insertions(+), 11 deletions(-)

diff --git a/lib/crypto/pkcs7_verify.c b/lib/crypto/pkcs7_verify.c
index 320ba49f79..58683ef614 100644
--- a/lib/crypto/pkcs7_verify.c
+++ b/lib/crypto/pkcs7_verify.c
@@ -50,8 +50,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 	struct image_region regions[2];
 	int ret = 0;
 
-	/* The digest was calculated already. */
-	if (sig->digest)
+	/*
+	 * [RFC2315 9.3]
+	 * If the authenticated attributes are present,
+	 * the message-digest is calculated on the
+	 * attributes present in the
+	 * authenticatedAttributes field and not just
+	 * the contents field
+	 */
+	if (!sinfo->authattrs && sig->digest)
 		return 0;
 
 	if (!sinfo->sig->hash_algo)
@@ -63,17 +70,25 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
 	else
 		return -ENOPKG;
 
-	sig->digest = calloc(1, sig->digest_size);
-	if (!sig->digest) {
-		pr_warn("Sig %u: Out of memory\n", sinfo->index);
-		return -ENOMEM;
-	}
+	/*
+	 * Calculate the hash only if the data is present.
+	 * In case of authenticated variable and capsule,
+	 * the hash has already been calculated on the
+	 * efi_image_regions and populated
+	 */
+	if (pkcs7->data) {
+		sig->digest = calloc(1, sig->digest_size);
+		if (!sig->digest) {
+			pr_warn("Sig %u: Out of memory\n", sinfo->index);
+			return -ENOMEM;
+		}
 
-	regions[0].data = pkcs7->data;
-	regions[0].size = pkcs7->data_len;
+		regions[0].data = pkcs7->data;
+		regions[0].size = pkcs7->data_len;
 
-	/* Digest the message [RFC2315 9.3] */
-	hash_calculate(sinfo->sig->hash_algo, regions, 1, sig->digest);
+		/* Digest the message [RFC2315 9.3] */
+		hash_calculate(sinfo->sig->hash_algo, regions, 1, sig->digest);
+	}
 
 	/* However, if there are authenticated attributes, there must be a
 	 * message digest attribute amongst them which corresponds to the
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 04/14] qemu: common: Add support for dynamic mtdparts for the platform
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (2 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 03/14] crypto: Fix the logic to calculate hash with authattributes set Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 05/14] qemu: common: Set dfu_alt_info variable " Sughosh Ganu
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

Add support for setting the default values for mtd partitions on the
platform. This would be used for updating the firmware image using
uefi capsule update with the dfu mtd backend driver.

Currently, values have been defined for the qemu arm64 platform, with
default values defined for the mtd partitions based on the NOR
flash. This can be subsequently extended for other qemu architectures
which need mtdparts set.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since v3:
* Move the selection of SYS_MTDPARTS_RUNTIME config to the board's
  Kconfig from lib/efi_loader/Kconfig, using imply.

 board/emulation/common/Kconfig         | 15 +++++
 board/emulation/common/Makefile        |  3 +
 board/emulation/common/qemu_mtdparts.c | 82 ++++++++++++++++++++++++++
 board/emulation/qemu-arm/Kconfig       |  7 +++
 4 files changed, 107 insertions(+)
 create mode 100644 board/emulation/common/Kconfig
 create mode 100644 board/emulation/common/Makefile
 create mode 100644 board/emulation/common/qemu_mtdparts.c

diff --git a/board/emulation/common/Kconfig b/board/emulation/common/Kconfig
new file mode 100644
index 0000000000..4c15c8bcb8
--- /dev/null
+++ b/board/emulation/common/Kconfig
@@ -0,0 +1,15 @@
+config MTDPARTS_NOR0
+	string "mtd boot partition for nor0"
+	default "64m(u-boot)" if TARGET_QEMU_ARM_64BIT && !TFABOOT
+	depends on SYS_MTDPARTS_RUNTIME
+	help
+	  This define the partition of nor0 used to build mtparts dynamically
+	  for boot from nor0.
+
+config MTDPARTS_NOR1
+	string "mtd u-boot env partition for nor1"
+	default "64m(u-boot-env)" if TARGET_QEMU_ARM_64BIT && !TFABOOT
+	depends on SYS_MTDPARTS_RUNTIME
+	help
+	  This define the partition of nor1 used to build mtparts dynamically
+	  for the u-boot env stored on nor1.
diff --git a/board/emulation/common/Makefile b/board/emulation/common/Makefile
new file mode 100644
index 0000000000..de5c8d0c2a
--- /dev/null
+++ b/board/emulation/common/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-$(CONFIG_SYS_MTDPARTS_RUNTIME) += qemu_mtdparts.o
diff --git a/board/emulation/common/qemu_mtdparts.c b/board/emulation/common/qemu_mtdparts.c
new file mode 100644
index 0000000000..60212e97ac
--- /dev/null
+++ b/board/emulation/common/qemu_mtdparts.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020 Linaro Limited
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <mtd.h>
+
+#include <linux/string.h>
+
+#define MTDPARTS_LEN		256
+#define MTDIDS_LEN		128
+
+static void board_get_mtdparts(const char *dev, const char *partition,
+			       char *mtdids, char *mtdparts)
+{
+	/* mtdids: "<dev>=<dev>, ...." */
+	if (mtdids[0] != '\0')
+		strcat(mtdids, ",");
+	strcat(mtdids, dev);
+	strcat(mtdids, "=");
+	strcat(mtdids, dev);
+
+	/* mtdparts: "mtdparts=<dev>:<mtdparts_<dev>>;..." */
+	if (mtdparts[0] != '\0')
+		strncat(mtdparts, ";", MTDPARTS_LEN);
+	else
+		strcat(mtdparts, "mtdparts=");
+
+	strncat(mtdparts, dev, MTDPARTS_LEN);
+	strncat(mtdparts, ":", MTDPARTS_LEN);
+	strncat(mtdparts, partition, MTDPARTS_LEN);
+}
+
+void board_mtdparts_default(const char **mtdids, const char **mtdparts)
+{
+	struct mtd_info *mtd;
+	struct udevice *dev;
+	const char *mtd_partition;
+	static char parts[3 * MTDPARTS_LEN + 1];
+	static char ids[MTDIDS_LEN + 1];
+	static bool mtd_initialized;
+
+	if (mtd_initialized) {
+		*mtdids = ids;
+		*mtdparts = parts;
+		return;
+	}
+
+	memset(parts, 0, sizeof(parts));
+	memset(ids, 0, sizeof(ids));
+
+	/* Currently mtdparts is needed on Qemu ARM64 for capsule updates */
+	if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT) &&
+	    IS_ENABLED(CONFIG_TARGET_QEMU_ARM_64BIT)) {
+		/* probe all MTD devices */
+		for (uclass_first_device(UCLASS_MTD, &dev); dev;
+		     uclass_next_device(&dev)) {
+			debug("mtd device = %s\n", dev->name);
+		}
+
+		mtd = get_mtd_device_nm("nor0");
+		if (!IS_ERR_OR_NULL(mtd)) {
+			mtd_partition = CONFIG_MTDPARTS_NOR0;
+			board_get_mtdparts("nor0", mtd_partition, ids, parts);
+			put_mtd_device(mtd);
+		}
+
+		mtd = get_mtd_device_nm("nor1");
+		if (!IS_ERR_OR_NULL(mtd)) {
+			mtd_partition = CONFIG_MTDPARTS_NOR1;
+			board_get_mtdparts("nor1", mtd_partition, ids, parts);
+			put_mtd_device(mtd);
+		}
+	}
+
+	mtd_initialized = true;
+	*mtdids = ids;
+	*mtdparts = parts;
+	debug("%s:mtdids=%s & mtdparts=%s\n", __func__, ids, parts);
+}
diff --git a/board/emulation/qemu-arm/Kconfig b/board/emulation/qemu-arm/Kconfig
index 02ae4d9884..0108efebd3 100644
--- a/board/emulation/qemu-arm/Kconfig
+++ b/board/emulation/qemu-arm/Kconfig
@@ -11,3 +11,10 @@ config BOARD_SPECIFIC_OPTIONS # dummy
 	imply VIRTIO_BLK
 
 endif
+
+if TARGET_QEMU_ARM_64BIT && !TFABOOT
+config BOARD_SPECIFIC_OPTIONS
+	imply SYS_MTDPARTS_RUNTIME
+
+source "board/emulation/common/Kconfig"
+endif
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 05/14] qemu: common: Set dfu_alt_info variable for the platform
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (3 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 04/14] qemu: common: Add support for dynamic mtdparts for the platform Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 06/14] fsp: Move and rename fsp_types.h file Sughosh Ganu
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

The dfu framework uses the dfu_alt_info environment variable to get
information that is needed for performing the firmware update. Add
logic to set the dfu_alt_info for the qemu arm64 platform to reflect
the two mtd partitions created for the u-boot env and the firmware
image. This can be subsequently extended for other qemu architectures
which need this variable set.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3:
* Move the selection of SET_DFU_ALT_INFO config to the board's Kconfig
  from lib/efi_loader/Kconfig, using imply.

 board/emulation/common/Makefile   |  1 +
 board/emulation/common/qemu_dfu.c | 68 +++++++++++++++++++++++++++++++
 board/emulation/qemu-arm/Kconfig  |  1 +
 3 files changed, 70 insertions(+)
 create mode 100644 board/emulation/common/qemu_dfu.c

diff --git a/board/emulation/common/Makefile b/board/emulation/common/Makefile
index de5c8d0c2a..c5b452e7e3 100644
--- a/board/emulation/common/Makefile
+++ b/board/emulation/common/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0+
 
 obj-$(CONFIG_SYS_MTDPARTS_RUNTIME) += qemu_mtdparts.o
+obj-$(CONFIG_SET_DFU_ALT_INFO) += qemu_dfu.o
diff --git a/board/emulation/common/qemu_dfu.c b/board/emulation/common/qemu_dfu.c
new file mode 100644
index 0000000000..62234a7647
--- /dev/null
+++ b/board/emulation/common/qemu_dfu.c
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020 Linaro Limited
+ */
+
+#include <common.h>
+#include <dfu.h>
+#include <env.h>
+#include <memalign.h>
+#include <mtd.h>
+
+#define DFU_ALT_BUF_LEN		SZ_1K
+
+static void board_get_alt_info(struct mtd_info *mtd, char *buf)
+{
+	struct mtd_info *part;
+	bool first = true;
+	const char *name;
+	int len, partnum = 0;
+
+	name = mtd->name;
+	len = strlen(buf);
+
+	if (buf[0] != '\0')
+		len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, "&");
+	len += snprintf(buf + len, DFU_ALT_BUF_LEN - len,
+			"mtd %s=", name);
+
+	list_for_each_entry(part, &mtd->partitions, node) {
+		partnum++;
+		if (!first)
+			len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, ";");
+		first = false;
+
+		len += snprintf(buf + len, DFU_ALT_BUF_LEN - len,
+				"%s part %d",
+				part->name, partnum);
+	}
+}
+
+void set_dfu_alt_info(char *interface, char *devstr)
+{
+	struct mtd_info *mtd;
+
+	ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN);
+
+	if (env_get("dfu_alt_info"))
+		return;
+
+	memset(buf, 0, sizeof(buf));
+
+	/*
+	 * Currently dfu_alt_info is needed on Qemu ARM64 for
+	 * capsule updates
+	*/
+	if (IS_ENABLED(CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT) &&
+	    IS_ENABLED(CONFIG_TARGET_QEMU_ARM_64BIT)) {
+		/* probe all MTD devices */
+		mtd_probe_devices();
+
+		mtd = get_mtd_device_nm("nor0");
+		if (!IS_ERR_OR_NULL(mtd))
+			board_get_alt_info(mtd, buf);
+	}
+
+	env_set("dfu_alt_info", buf);
+	printf("dfu_alt_info set\n");
+}
diff --git a/board/emulation/qemu-arm/Kconfig b/board/emulation/qemu-arm/Kconfig
index 0108efebd3..fb8d38f5b8 100644
--- a/board/emulation/qemu-arm/Kconfig
+++ b/board/emulation/qemu-arm/Kconfig
@@ -15,6 +15,7 @@ endif
 if TARGET_QEMU_ARM_64BIT && !TFABOOT
 config BOARD_SPECIFIC_OPTIONS
 	imply SYS_MTDPARTS_RUNTIME
+	imply SET_DFU_ALT_INFO
 
 source "board/emulation/common/Kconfig"
 endif
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 06/14] fsp: Move and rename fsp_types.h file
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (4 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 05/14] qemu: common: Set dfu_alt_info variable " Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 07/14] efi_loader: Add logic to parse EDKII specific fmp payload header Sughosh Ganu
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

The fsp_types.h header file contains macros for building signatures of
different widths. These signature macros are architecture agnostic,
and can be used in all places which use signatures in a data
structure. Move and rename the fsp_types.h under the common include
header.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Bin Meng <bmeng.cn@gmail.com>
---

Changes since V3: None

This patch had been sent to the mailing list separately[1] and has
been reviewed by Simon Glass and Bin Meng and merged on the x86 tree.

[1] - https://lists.denx.de/pipermail/u-boot/2020-December/434849.html

 arch/x86/include/asm/fsp/fsp_support.h                      | 3 ++-
 .../x86/include/asm/fsp/fsp_types.h => include/signatures.h | 6 +++---
 2 files changed, 5 insertions(+), 4 deletions(-)
 rename arch/x86/include/asm/fsp/fsp_types.h => include/signatures.h (95%)

diff --git a/arch/x86/include/asm/fsp/fsp_support.h b/arch/x86/include/asm/fsp/fsp_support.h
index 29e511415c..3cd3e4fcf5 100644
--- a/arch/x86/include/asm/fsp/fsp_support.h
+++ b/arch/x86/include/asm/fsp/fsp_support.h
@@ -7,11 +7,12 @@
 #ifndef __FSP_SUPPORT_H__
 #define __FSP_SUPPORT_H__
 
+#include <signatures.h>
+
 #include <asm/fsp/fsp_bootmode.h>
 #include <asm/fsp/fsp_fv.h>
 #include <asm/fsp/fsp_hob.h>
 #include <asm/fsp/fsp_infoheader.h>
-#include <asm/fsp/fsp_types.h>
 #include <asm/fsp_arch.h>
 #include <asm/fsp/fsp_azalia.h>
 
diff --git a/arch/x86/include/asm/fsp/fsp_types.h b/include/signatures.h
similarity index 95%
rename from arch/x86/include/asm/fsp/fsp_types.h
rename to include/signatures.h
index 3d5b17ecf1..4042db1e00 100644
--- a/arch/x86/include/asm/fsp/fsp_types.h
+++ b/include/signatures.h
@@ -4,8 +4,8 @@
  * Copyright (C) 2014, Bin Meng <bmeng.cn@gmail.com>
  */
 
-#ifndef __FSP_TYPES_H__
-#define __FSP_TYPES_H__
+#ifndef __SIGNATURES_H__
+#define __SIGNATURES_H__
 
 /**
  * Returns a 16-bit signature built from 2 ASCII characters.
@@ -59,4 +59,4 @@
 #define SIGNATURE_64(A, B, C, D, E, F, G, H)	\
 	(SIGNATURE_32(A, B, C, D) | ((u64)(SIGNATURE_32(E, F, G, H)) << 32))
 
-#endif
+#endif /* __SIGNATURES_H__ */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 07/14] efi_loader: Add logic to parse EDKII specific fmp payload header
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (5 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 06/14] fsp: Move and rename fsp_types.h file Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 08/14] dfu_mtd: Add provision to unlock mtd device Sughosh Ganu
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

When building the capsule using scripts in edk2, a fmp header is
added on top of the binary payload. Add logic to detect presence of
the header. When present, the pointer to the image needs to be
adjusted as per the size of the header to point to the actual binary
payload.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 lib/efi_loader/efi_firmware.c | 41 +++++++++++++++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index 72c560dbc2..5d2ecde2f1 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -11,8 +11,30 @@
 #include <dfu.h>
 #include <efi_loader.h>
 #include <image.h>
+#include <signatures.h>
+
 #include <linux/list.h>
 
+#define FMP_PAYLOAD_HDR_SIGNATURE	SIGNATURE_32('M', 'S', 'S', '1')
+
+/**
+ * struct fmp_payload_header - EDK2 header for the FMP payload
+ *
+ * This structure describes the header which is preprended to the
+ * FMP payload by the edk2 capsule generation scripts.
+ *
+ * @signature:			Header signature used to identify the header
+ * @header_size:		Size of the structure
+ * @fw_version:			Firmware versions used
+ * @lowest_supported_version:	Lowest supported version
+ */
+struct fmp_payload_header {
+	u32 signature;
+	u32 header_size;
+	u32 fw_version;
+	u32 lowest_supported_version;
+};
+
 /* Place holder; not supported */
 static
 efi_status_t EFIAPI efi_firmware_get_image_unsupported(
@@ -379,12 +401,31 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
 	efi_status_t (*progress)(efi_uintn_t completion),
 	u16 **abort_reason)
 {
+	u32 fmp_hdr_signature;
+	struct fmp_payload_header *header;
+
 	EFI_ENTRY("%p %d %p %ld %p %p %p\n", this, image_index, image,
 		  image_size, vendor_code, progress, abort_reason);
 
 	if (!image)
 		return EFI_EXIT(EFI_INVALID_PARAMETER);
 
+	fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
+	header = (void *)image;
+
+	if (!memcmp(&header->signature, &fmp_hdr_signature,
+		    sizeof(fmp_hdr_signature))) {
+		/*
+		 * When building the capsule with the scripts in
+		 * edk2, a FMP header is inserted above the capsule
+		 * payload. Compensate for this header to get the
+		 * actual payload that is to be updated.
+		 */
+		image += header->header_size;
+		image_size -= header->header_size;
+
+	}
+
 	if (dfu_write_by_alt(image_index - 1, (void *)image, image_size,
 			     NULL, NULL))
 		return EFI_EXIT(EFI_DEVICE_ERROR);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 08/14] dfu_mtd: Add provision to unlock mtd device
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (6 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 07/14] efi_loader: Add logic to parse EDKII specific fmp payload header Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 09/14] efi_loader: Make the pkcs7 header parsing function an extern Sughosh Ganu
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

Prior to writing to an mtd device, mtd_erase is called. This call
fails in case the sector being erased is locked. Call mtd_unlock to
unlock the region which is to be erased and later written to. Lock the
region once the write to the region has completed.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 drivers/dfu/dfu_mtd.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c
index 36cd4e945b..b34975dbb0 100644
--- a/drivers/dfu/dfu_mtd.c
+++ b/drivers/dfu/dfu_mtd.c
@@ -21,7 +21,7 @@ static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size)
 static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
 			u64 offset, void *buf, long *len)
 {
-	u64 off, lim, remaining;
+	u64 off, lim, remaining, lock_ofs, lock_len;
 	struct mtd_info *mtd = dfu->data.mtd.info;
 	struct mtd_oob_ops io_op = {};
 	int ret = 0;
@@ -34,7 +34,7 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
 		return 0;
 	}
 
-	off = dfu->data.mtd.start + offset + dfu->bad_skip;
+	off = lock_ofs = dfu->data.mtd.start + offset + dfu->bad_skip;
 	lim = dfu->data.mtd.start + dfu->data.mtd.size;
 
 	if (off >= lim) {
@@ -56,12 +56,19 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
 	if (op == DFU_OP_WRITE) {
 		struct erase_info erase_op = {};
 
-		remaining = round_up(*len, mtd->erasesize);
+		remaining = lock_len = round_up(*len, mtd->erasesize);
 		erase_op.mtd = mtd;
 		erase_op.addr = off;
 		erase_op.len = mtd->erasesize;
 		erase_op.scrub = 0;
 
+		debug("Unlocking the mtd device\n");
+		ret = mtd_unlock(mtd, lock_ofs, lock_len);
+		if (ret && ret != -EOPNOTSUPP) {
+			printf("MTD device unlock failed\n");
+			return 0;
+		}
+
 		while (remaining) {
 			if (erase_op.addr + remaining > lim) {
 				printf("Limit reached 0x%llx while erasing at offset 0x%llx\n",
@@ -139,6 +146,13 @@ static int mtd_block_op(enum dfu_op op, struct dfu_entity *dfu,
 			io_op.len = mtd->writesize;
 	}
 
+	if (op == DFU_OP_WRITE) {
+		/* Write done, lock again */
+		debug("Locking the mtd device\n");
+		ret = mtd_lock(mtd, lock_ofs, lock_len);
+		if (ret && ret != -EOPNOTSUPP)
+			printf("MTD device lock failed\n");
+	}
 	return ret;
 }
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 09/14] efi_loader: Make the pkcs7 header parsing function an extern
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (7 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 08/14] dfu_mtd: Add provision to unlock mtd device Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 10/14] efi_loader: Re-factor code to build the signature store from efi signature list Sughosh Ganu
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

The pkcs7 header parsing functionality is pretty generic, and can be
used by other features like capsule authentication. Make the function
an extern, also changing it's name to efi_parse_pkcs7_header

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 include/efi_loader.h           |  4 ++
 lib/efi_loader/efi_signature.c | 85 +++++++++++++++++++++++++++++++
 lib/efi_loader/efi_variable.c  | 93 ++--------------------------------
 3 files changed, 93 insertions(+), 89 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 365f3d01dc..8807fcd913 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -818,6 +818,10 @@ 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,
+					     u8 **tmpbuf);
+
 /* runtime implementation of memcpy() */
 void efi_memcpy_runtime(void *dest, const void *src, size_t n);
 
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index 79dee27421..9ab071b611 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -27,6 +27,91 @@ 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
+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 payload
+ * @buf:	Pointer to payload's value
+ * @buflen:	Length of @buf
+ * @tmpbuf:	Pointer to temporary buffer
+ *
+ * Parse a signature embedded in payload'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
+ * A temporary buffer will be allocated if needed, and it should be
+ * kept valid during the authentication because some data in the buffer
+ * will be referenced by efi_signature_verify().
+ *
+ * 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 **tmpbuf)
+{
+	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);
+		if (IS_ERR(msg))
+			return NULL;
+		return msg;
+	}
+
+	/*
+	 * 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.
+	 */
+	EFI_PRINT("Makeshift prefix added to authentication data\n");
+	ebuflen = sizeof(pkcs7_hdr) + buflen;
+	if (ebuflen <= 0x7f) {
+		EFI_PRINT("Data is too short\n");
+		return NULL;
+	}
+
+	ebuf = malloc(ebuflen);
+	if (!ebuf) {
+		EFI_PRINT("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);
+
+	if (IS_ERR(msg)) {
+		free(ebuf);
+		return NULL;
+	}
+
+	*tmpbuf = ebuf;
+	return msg;
+}
 
 /**
  * efi_hash_regions - calculate a hash value
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 0c689cfb47..ba0874e9e7 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -24,91 +24,6 @@
 #include <asm/sections.h>
 
 #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
- * @tmpbuf:	Pointer to temporary buffer
- *
- * 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.
- * A temporary buffer will be allocated if needed, and it should be
- * kept valid during the authentication because some data in the buffer
- * will be referenced by efi_signature_verify().
- *
- * 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 **tmpbuf)
-{
-	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);
-		if (IS_ERR(msg))
-			return NULL;
-		return msg;
-	}
-
-	/*
-	 * 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.
-	 */
-	EFI_PRINT("Makeshift prefix added to authentication data\n");
-	ebuflen = sizeof(pkcs7_hdr) + buflen;
-	if (ebuflen <= 0x7f) {
-		EFI_PRINT("Data is too short\n");
-		return NULL;
-	}
-
-	ebuf = malloc(ebuflen);
-	if (!ebuf) {
-		EFI_PRINT("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);
-
-	if (IS_ERR(msg)) {
-		free(ebuf);
-		return NULL;
-	}
-
-	*tmpbuf = ebuf;
-	return msg;
-}
 
 /**
  * efi_variable_authenticate - authenticate a variable
@@ -215,10 +130,10 @@ static efi_status_t efi_variable_authenticate(u16 *variable,
 		goto err;
 
 	/* ebuf should be kept valid during the authentication */
-	var_sig = efi_variable_parse_signature(auth->auth_info.cert_data,
-					       auth->auth_info.hdr.dwLength
-						   - sizeof(auth->auth_info),
-					       &ebuf);
+	var_sig = efi_parse_pkcs7_header(auth->auth_info.cert_data,
+					 auth->auth_info.hdr.dwLength
+					 - sizeof(auth->auth_info),
+					 &ebuf);
 	if (!var_sig) {
 		EFI_PRINT("Parsing variable's signature failed\n");
 		goto err;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 10/14] efi_loader: Re-factor code to build the signature store from efi signature list
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (8 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 09/14] efi_loader: Make the pkcs7 header parsing function an extern Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 11/14] efi: capsule: Add support for uefi capsule authentication Sughosh Ganu
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

The efi_sigstore_parse_sigdb function reads the uefi authenticated
variable, stored in the signature database format and builds the
signature store structure. Factor out the code for building
the signature store. This can then be used by the capsule
authentication routine to build the signature store even when the
signature database is not stored as an uefi authenticated variable

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 include/efi_loader.h           |   2 +
 lib/efi_loader/efi_signature.c | 103 +++++++++++++++++++--------------
 2 files changed, 63 insertions(+), 42 deletions(-)

diff --git a/include/efi_loader.h b/include/efi_loader.h
index 8807fcd913..73c3c4b85a 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -811,6 +811,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_build_signature_store(void *sig_list,
+						      efi_uintn_t size);
 struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name);
 
 bool efi_secure_boot_enabled(void);
diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c
index 9ab071b611..87525bdc80 100644
--- a/lib/efi_loader/efi_signature.c
+++ b/lib/efi_loader/efi_signature.c
@@ -736,6 +736,63 @@ err:
 	return NULL;
 }
 
+/**
+ * efi_sigstore_parse_sigdb - parse the signature list and populate
+ * the signature store
+ *
+ * @sig_list:	Pointer to the signature list
+ * @size:	Size of the signature list
+ *
+ * Parse the efi signature list and instantiate a signature store
+ * structure.
+ *
+ * Return:	Pointer to signature store on success, NULL on error
+ */
+struct efi_signature_store *efi_build_signature_store(void *sig_list,
+						      efi_uintn_t size)
+{
+	struct efi_signature_list *esl;
+	struct efi_signature_store *sigstore = NULL, *siglist;
+
+	esl = sig_list;
+	while (size > 0) {
+		/* List must exist if there is remaining data. */
+		if (size < sizeof(*esl)) {
+			EFI_PRINT("Signature list in wrong format\n");
+			goto err;
+		}
+
+		if (size < esl->signature_list_size) {
+			EFI_PRINT("Signature list in wrong format\n");
+			goto err;
+		}
+
+		/* Parse a single siglist. */
+		siglist = efi_sigstore_parse_siglist(esl);
+		if (!siglist) {
+			EFI_PRINT("Parsing of signature list of failed\n");
+			goto err;
+		}
+
+		/* Append siglist */
+		siglist->next = sigstore;
+		sigstore = siglist;
+
+		/* Next */
+		size -= esl->signature_list_size;
+		esl = (void *)esl + esl->signature_list_size;
+	}
+	free(sig_list);
+
+	return sigstore;
+
+err:
+	efi_sigstore_free(sigstore);
+	free(sig_list);
+
+	return NULL;
+}
+
 /**
  * efi_sigstore_parse_sigdb - parse a signature database variable
  * @name:	Variable's name
@@ -747,8 +804,7 @@ err:
  */
 struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
 {
-	struct efi_signature_store *sigstore = NULL, *siglist;
-	struct efi_signature_list *esl;
+	struct efi_signature_store *sigstore = NULL;
 	const efi_guid_t *vendor;
 	void *db;
 	efi_uintn_t db_size;
@@ -784,47 +840,10 @@ struct efi_signature_store *efi_sigstore_parse_sigdb(u16 *name)
 	ret = EFI_CALL(efi_get_variable(name, vendor, NULL, &db_size, db));
 	if (ret != EFI_SUCCESS) {
 		EFI_PRINT("Getting variable, %ls, failed\n", name);
-		goto err;
-	}
-
-	/* Parse siglist list */
-	esl = db;
-	while (db_size > 0) {
-		/* List must exist if there is remaining data. */
-		if (db_size < sizeof(*esl)) {
-			EFI_PRINT("variable, %ls, in wrong format\n", name);
-			goto err;
-		}
-
-		if (db_size < esl->signature_list_size) {
-			EFI_PRINT("variable, %ls, in wrong format\n", name);
-			goto err;
-		}
-
-		/* Parse a single siglist. */
-		siglist = efi_sigstore_parse_siglist(esl);
-		if (!siglist) {
-			EFI_PRINT("Parsing signature list of %ls failed\n",
-				  name);
-			goto err;
-		}
-
-		/* Append siglist */
-		siglist->next = sigstore;
-		sigstore = siglist;
-
-		/* Next */
-		db_size -= esl->signature_list_size;
-		esl = (void *)esl + esl->signature_list_size;
+		free(db);
+		return NULL;
 	}
-	free(db);
-
-	return sigstore;
 
-err:
-	efi_sigstore_free(sigstore);
-	free(db);
-
-	return NULL;
+	return efi_build_signature_store(db, db_size);
 }
 #endif /* CONFIG_EFI_SECURE_BOOT */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 11/14] efi: capsule: Add support for uefi capsule authentication
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (9 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 10/14] efi_loader: Re-factor code to build the signature store from efi signature list Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 12/14] efi_loader: Enable " Sughosh Ganu
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

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 <sughosh.ganu@linaro.org>
---

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

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 <common.h>
+#include <efi_api.h>
+#include <efi_loader.h>
+#include <env.h>
+#include <fdtdec.h>
+
+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@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 <mapmem.h>
 #include <sort.h>
 
+#include <crypto/pkcs7.h>
+#include <crypto/pkcs7_parser.h>
+#include <linux/err.h>
+
 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 */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 12/14] efi_loader: Enable uefi capsule authentication
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (10 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 11/14] efi: capsule: Add support for uefi capsule authentication Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 13/14] efidebug: capsule: Add a command to update capsule on disk Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update Sughosh Ganu
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

Add support for enabling uefi capsule authentication. 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_HAVE_CAPSULE_SUPPORT=y
CONFIG_EFI_CAPSULE_ON_DISK=y
CONFIG_EFI_CAPSULE_FIRMWARE_MANAGEMENT=y
CONFIG_EFI_CAPSULE_FIRMWARE=y
CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y
CONFIG_EFI_CAPSULE_AUTHENTICATE=y

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 lib/efi_loader/efi_firmware.c | 36 ++++++++++++++++++++++++++++++++++-
 1 file changed, 35 insertions(+), 1 deletion(-)

diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index 5d2ecde2f1..5e401bbca2 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -184,9 +184,16 @@ static efi_status_t efi_get_dfu_info(
 		image_info[i].version_name = NULL; /* not supported */
 		image_info[i].size = 0;
 		image_info[i].attributes_supported =
-				IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+			IMAGE_ATTRIBUTE_IMAGE_UPDATABLE |
+			IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
 		image_info[i].attributes_setting =
 				IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+
+		/* Check if the capsule authentication is enabled */
+		if (env_get("capsule_authentication_enabled"))
+			image_info[0].attributes_setting |=
+				IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED;
+
 		image_info[i].lowest_supported_image_version = 0;
 		image_info[i].last_attempt_version = 0;
 		image_info[i].last_attempt_status = LAST_ATTEMPT_STATUS_SUCCESS;
@@ -403,6 +410,9 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
 {
 	u32 fmp_hdr_signature;
 	struct fmp_payload_header *header;
+	void *capsule_payload;
+	efi_status_t status;
+	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);
@@ -410,6 +420,30 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
 	if (!image)
 		return EFI_EXIT(EFI_INVALID_PARAMETER);
 
+	/* 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");
+			return EFI_EXIT(status);
+		} else if (status != EFI_SUCCESS) {
+			return EFI_EXIT(status);
+		}
+
+		debug("Capsule authentication successfull\n");
+		image = capsule_payload;
+		image_size = capsule_payload_size;
+	} else {
+		debug("Capsule authentication disabled. ");
+		debug("Updating capsule without authenticating.\n");
+	}
+
 	fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
 	header = (void *)image;
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 13/14] efidebug: capsule: Add a command to update capsule on disk
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (11 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 12/14] efi_loader: Enable " Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2020-12-30 13:57 ` [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update Sughosh Ganu
  13 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

Add a efidebug subcommand to initiate a firmware update using the efi
firmware management protocol(fmp) set_image routine.

The firmware update can be initiated through

'efidebug capsule disk-update'

This would locate the efi capsule file on the efi system partition,
and call the platform's set_image fmp routine to initiate the firmware
update.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 cmd/efidebug.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/cmd/efidebug.c b/cmd/efidebug.c
index fa9d7fe757..5fb7b1e3c6 100644
--- a/cmd/efidebug.c
+++ b/cmd/efidebug.c
@@ -79,6 +79,16 @@ static int do_efi_capsule_update(struct cmd_tbl *cmdtp, int flag,
 	return CMD_RET_SUCCESS;
 }
 
+static int do_efi_capsule_on_disk_update(struct cmd_tbl *cmdtp, int flag,
+					 int argc, char * const argv[])
+{
+	efi_status_t ret;
+
+	ret = efi_launch_capsules();
+
+	return ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
 /**
  * do_efi_capsule_show() - show capsule information
  *
@@ -207,6 +217,8 @@ static struct cmd_tbl cmd_efidebug_capsule_sub[] = {
 			 "", ""),
 	U_BOOT_CMD_MKENT(show, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_show,
 			 "", ""),
+	U_BOOT_CMD_MKENT(disk-update, 0, 0, do_efi_capsule_on_disk_update,
+			 "", ""),
 	U_BOOT_CMD_MKENT(result, CONFIG_SYS_MAXARGS, 1, do_efi_capsule_res,
 			 "", ""),
 };
@@ -1544,6 +1556,8 @@ static char efidebug_help_text[] =
 #ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
 	"efidebug capsule update [-v] <capsule address>\n"
 	"  - process a capsule\n"
+	"efidebug capsule disk-update\n"
+	"  - update a capsule from disk\n"
 	"efidebug capsule show <capsule address>\n"
 	"  - show capsule information\n"
 	"efidebug capsule result [<capsule result var>]\n"
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update
  2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
                   ` (12 preceding siblings ...)
  2020-12-30 13:57 ` [PATCH v4 13/14] efidebug: capsule: Add a command to update capsule on disk Sughosh Ganu
@ 2020-12-30 13:57 ` Sughosh Ganu
  2021-03-02 11:14   ` Heinrich Schuchardt
  13 siblings, 1 reply; 21+ messages in thread
From: Sughosh Ganu @ 2020-12-30 13:57 UTC (permalink / raw)
  To: u-boot

Add documentation highlighting the steps for using the uefi capsule
update feature for updating the u-boot firmware image.

Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
---

Changes since V3: None

 doc/board/emulation/index.rst               |   1 +
 doc/board/emulation/qemu_capsule_update.rst | 210 ++++++++++++++++++++
 2 files changed, 211 insertions(+)
 create mode 100644 doc/board/emulation/qemu_capsule_update.rst

diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst
index 1adefee155..a09ead1c35 100644
--- a/doc/board/emulation/index.rst
+++ b/doc/board/emulation/index.rst
@@ -10,3 +10,4 @@ Emulation
    qemu-mips
    qemu-riscv
    qemu-x86
+   qemu_capsule_update
diff --git a/doc/board/emulation/qemu_capsule_update.rst b/doc/board/emulation/qemu_capsule_update.rst
new file mode 100644
index 0000000000..9fec75f8f1
--- /dev/null
+++ b/doc/board/emulation/qemu_capsule_update.rst
@@ -0,0 +1,210 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (C) 2020, Linaro Limited
+
+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.
+
+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
+    CONFIG_EFI_CAPSULE_FMP_HEADER=y
+
+In addition, the following config needs to be disabled(QEMU ARM specific)::
+
+    CONFIG_TFABOOT
+
+The capsule file can be generated by using the GenerateCapsule.py
+script in EDKII::
+
+    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
+    <capsule_file_name> --fw-version <val> --lsv <val> --guid \
+    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose --update-image-index \
+    <val> --verbose <u-boot.bin>
+
+The above is a wrapper script(GenerateCapsule) which eventually calls
+the actual GenerateCapsule.py script.
+
+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,
+BootXXXX and OsIndications need to be set. The BootXXXX variable needs
+to be pointing to the EFI System Partition which contains the capsule
+file. The BootNext, BootXXXX and OsIndications variables can be set
+using the following commands::
+
+    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
+    => efidebug boot next 0
+    => setenv -e -nv -bs -rt -v OsIndications =0x04
+    => saveenv
+
+Finally, the capsule update can be initiated with the following
+command::
+
+    => efidebug capsule disk-update
+
+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 embedded as
+part of the platform's device tree blob using the mkeficapsule
+utility.
+
+On the QEMU virt platforms, the device-tree is generated on the fly
+based on the devices configured. This device tree is then passed on to
+the various software components booting on the platform, including
+U-Boot. Therefore, on the QEMU virt platform, the signatute is
+embedded on an overlay. This overlay is then applied at runtime to the
+base platform device-tree. Steps needed for embedding the esl file in
+the overlay are highlighted below.
+
+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 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 \
+      <capsule_file_name> --monotonic-count <val> --fw-version \
+      <val> --lsv <val> --guid \
+      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
+      --update-image-index <val> --signer-private-cert \
+      /path/to/CRT.pem --trusted-public-cert \
+      /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \
+      <u-boot.bin>
+
+Place the capsule generated in the above step on the EFI System
+Partition under the EFI/UpdateCapsule directory
+
+For embedding the public key certificate, the following steps need to
+be followed::
+
+    1. Generate a skeleton overlay dts file, with a single fragment
+       node and an empty __overlay__ node
+
+       A typical skeleton overlay file will look like this
+
+       /dts-v1/;
+       /plugin/;
+
+       / {
+               fragment at 0 {
+                       target-path = "/";
+                       __overlay__ {
+                       };
+               };
+       };
+
+
+    2. Convert the dts to a corresponding dtb with the following
+       command
+        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \
+        <dts_file>
+
+    3. Run the dtb file generated above through the mkeficapsule tool
+       in U-Boot
+        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>
+
+Running the above command results in the creation of a 'signature'
+node in the dtb, under which the public key is stored as a
+'capsule-key' property. The '-O' option is to be used since the
+public key certificate(esl) file is being embedded in an overlay.
+
+The dtb file embedded with the certificate is now to be placed on an
+EFI System Partition. This would then be loaded and "merged" with the
+base platform flattened device-tree(dtb) at runtime.
+
+Build U-Boot with the following steps(QEMU ARM64)::
+
+    $ make qemu_arm64_defconfig
+    $ make menuconfig
+        Disable CONFIG_TFABOOT
+        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE
+        Enable all configs needed for capsule update(listed above)
+    $ make all
+
+Boot the platform and perform the following steps on the U-Boot
+command line::
+
+    1. Enable capsule authentication by setting the following env
+       variable
+
+        => setenv capsule_authentication_enabled 1
+        => saveenv
+
+    2. Load the overlay dtb to memory and merge it with the base fdt
+
+        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>
+        => fdt addr $fdtcontroladdr
+        => fdt resize <size_of_ov_dtb_file>
+        => fdt apply <$fdtovaddr>
+
+    3. Set the following environment and UEFI boot variables
+
+        => setenv -e -nv -bs -rt -v OsIndications =0x04
+        => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
+        => efidebug boot next 0
+        => saveenv
+
+    4. Finally, the capsule update can be initiated with the following
+       command
+
+        => efidebug capsule disk-update
+
+On subsequent reboot, the platform should boot the updated U-Boot binary.
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update
  2020-12-30 13:57 ` [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update Sughosh Ganu
@ 2021-03-02 11:14   ` Heinrich Schuchardt
  2021-03-02 14:48     ` Sughosh Ganu
  0 siblings, 1 reply; 21+ messages in thread
From: Heinrich Schuchardt @ 2021-03-02 11:14 UTC (permalink / raw)
  To: u-boot

On 30.12.20 14:57, Sughosh Ganu wrote:
> Add documentation highlighting the steps for using the uefi capsule
> update feature for updating the u-boot firmware image.
>
> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> ---
>
> Changes since V3: None
>
>  doc/board/emulation/index.rst               |   1 +
>  doc/board/emulation/qemu_capsule_update.rst | 210 ++++++++++++++++++++
>  2 files changed, 211 insertions(+)
>  create mode 100644 doc/board/emulation/qemu_capsule_update.rst
>
> diff --git a/doc/board/emulation/index.rst b/doc/board/emulation/index.rst
> index 1adefee155..a09ead1c35 100644
> --- a/doc/board/emulation/index.rst
> +++ b/doc/board/emulation/index.rst
> @@ -10,3 +10,4 @@ Emulation
>     qemu-mips
>     qemu-riscv
>     qemu-x86
> +   qemu_capsule_update
> diff --git a/doc/board/emulation/qemu_capsule_update.rst b/doc/board/emulation/qemu_capsule_update.rst
> new file mode 100644
> index 0000000000..9fec75f8f1
> --- /dev/null
> +++ b/doc/board/emulation/qemu_capsule_update.rst
> @@ -0,0 +1,210 @@
> +.. SPDX-License-Identifier: GPL-2.0+
> +.. Copyright (C) 2020, Linaro Limited
> +
> +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.
> +
> +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
> +    CONFIG_EFI_CAPSULE_FMP_HEADER=y
> +
> +In addition, the following config needs to be disabled(QEMU ARM specific)::
> +
> +    CONFIG_TFABOOT
> +
> +The capsule file can be generated by using the GenerateCapsule.py
> +script in EDKII::
> +
> +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
> +    <capsule_file_name> --fw-version <val> --lsv <val> --guid \
> +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose --update-image-index \
> +    <val> --verbose <u-boot.bin>
> +
> +The above is a wrapper script(GenerateCapsule) which eventually calls
> +the actual GenerateCapsule.py script.
> +
> +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,
> +BootXXXX and OsIndications need to be set. The BootXXXX variable needs
> +to be pointing to the EFI System Partition which contains the capsule
> +file. The BootNext, BootXXXX and OsIndications variables can be set
> +using the following commands::
> +
> +    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
> +    => efidebug boot next 0
> +    => setenv -e -nv -bs -rt -v OsIndications =0x04
> +    => saveenv
> +
> +Finally, the capsule update can be initiated with the following
> +command::
> +
> +    => efidebug capsule disk-update
> +
> +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 embedded as
> +part of the platform's device tree blob using the mkeficapsule
> +utility.
> +
> +On the QEMU virt platforms, the device-tree is generated on the fly
> +based on the devices configured. This device tree is then passed on to
> +the various software components booting on the platform, including
> +U-Boot. Therefore, on the QEMU virt platform, the signatute is
> +embedded on an overlay. This overlay is then applied at runtime to the
> +base platform device-tree. Steps needed for embedding the esl file in
> +the overlay are highlighted below.
> +
> +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 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 \
> +      <capsule_file_name> --monotonic-count <val> --fw-version \
> +      <val> --lsv <val> --guid \
> +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
> +      --update-image-index <val> --signer-private-cert \
> +      /path/to/CRT.pem --trusted-public-cert \
> +      /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \
> +      <u-boot.bin>
> +
> +Place the capsule generated in the above step on the EFI System
> +Partition under the EFI/UpdateCapsule directory
> +
> +For embedding the public key certificate, the following steps need to
> +be followed::
> +
> +    1. Generate a skeleton overlay dts file, with a single fragment
> +       node and an empty __overlay__ node
> +
> +       A typical skeleton overlay file will look like this
> +
> +       /dts-v1/;
> +       /plugin/;
> +
> +       / {
> +               fragment at 0 {
> +                       target-path = "/";
> +                       __overlay__ {
> +                       };
> +               };
> +       };
> +
> +
> +    2. Convert the dts to a corresponding dtb with the following

Shouldn't this be dtbo?

> +       command
> +        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \
> +        <dts_file>
> +
> +    3. Run the dtb file generated above through the mkeficapsule tool
> +       in U-Boot
> +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>
> +
> +Running the above command results in the creation of a 'signature'
> +node in the dtb, under which the public key is stored as a
> +'capsule-key' property. The '-O' option is to be used since the
> +public key certificate(esl) file is being embedded in an overlay.
> +
> +The dtb file embedded with the certificate is now to be placed on an
> +EFI System Partition. This would then be loaded and "merged" with the
> +base platform flattened device-tree(dtb) at runtime.
> +
> +Build U-Boot with the following steps(QEMU ARM64)::
> +
> +    $ make qemu_arm64_defconfig
> +    $ make menuconfig
> +        Disable CONFIG_TFABOOT
> +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE
> +        Enable all configs needed for capsule update(listed above)
> +    $ make all
> +
> +Boot the platform and perform the following steps on the U-Boot
> +command line::
> +
> +    1. Enable capsule authentication by setting the following env
> +       variable
> +
> +        => setenv capsule_authentication_enabled 1
> +        => saveenv
> +
> +    2. Load the overlay dtb to memory and merge it with the base fdt
> +
> +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>
> +        => fdt addr $fdtcontroladdr
> +        => fdt resize <size_of_ov_dtb_file>
> +        => fdt apply <$fdtovaddr>

Having the public key on the disk means that any public key can be
placed here and we get zero security.

We need to build the public key into U-Boot.

Could you, please, investigate how we can adjust the build process
accordingly.

Best regards

Heinrich

> +
> +    3. Set the following environment and UEFI boot variables
> +
> +        => setenv -e -nv -bs -rt -v OsIndications =0x04
> +        => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
> +        => efidebug boot next 0
> +        => saveenv
> +
> +    4. Finally, the capsule update can be initiated with the following
> +       command
> +
> +        => efidebug capsule disk-update
> +
> +On subsequent reboot, the platform should boot the updated U-Boot binary.
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update
  2021-03-02 11:14   ` Heinrich Schuchardt
@ 2021-03-02 14:48     ` Sughosh Ganu
  2021-03-02 15:57       ` Heinrich Schuchardt
  0 siblings, 1 reply; 21+ messages in thread
From: Sughosh Ganu @ 2021-03-02 14:48 UTC (permalink / raw)
  To: u-boot

hi Heinrich,

On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> On 30.12.20 14:57, Sughosh Ganu wrote:
> > Add documentation highlighting the steps for using the uefi capsule
> > update feature for updating the u-boot firmware image.
> >
> > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org>
> > ---
> >
> > Changes since V3: None
> >
> >  doc/board/emulation/index.rst               |   1 +
> >  doc/board/emulation/qemu_capsule_update.rst | 210 ++++++++++++++++++++
> >  2 files changed, 211 insertions(+)
> >  create mode 100644 doc/board/emulation/qemu_capsule_update.rst
> >
> > diff --git a/doc/board/emulation/index.rst
> b/doc/board/emulation/index.rst
> > index 1adefee155..a09ead1c35 100644
> > --- a/doc/board/emulation/index.rst
> > +++ b/doc/board/emulation/index.rst
> > @@ -10,3 +10,4 @@ Emulation
> >     qemu-mips
> >     qemu-riscv
> >     qemu-x86
> > +   qemu_capsule_update
> > diff --git a/doc/board/emulation/qemu_capsule_update.rst
> b/doc/board/emulation/qemu_capsule_update.rst
> > new file mode 100644
> > index 0000000000..9fec75f8f1
> > --- /dev/null
> > +++ b/doc/board/emulation/qemu_capsule_update.rst
> > @@ -0,0 +1,210 @@
> > +.. SPDX-License-Identifier: GPL-2.0+
> > +.. Copyright (C) 2020, Linaro Limited
> > +
> > +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.
> > +
> > +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
> > +    CONFIG_EFI_CAPSULE_FMP_HEADER=y
> > +
> > +In addition, the following config needs to be disabled(QEMU ARM
> specific)::
> > +
> > +    CONFIG_TFABOOT
> > +
> > +The capsule file can be generated by using the GenerateCapsule.py
> > +script in EDKII::
> > +
> > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
> > +    <capsule_file_name> --fw-version <val> --lsv <val> --guid \
> > +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose --update-image-index
> \
> > +    <val> --verbose <u-boot.bin>
> > +
> > +The above is a wrapper script(GenerateCapsule) which eventually calls
> > +the actual GenerateCapsule.py script.
> > +
> > +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,
> > +BootXXXX and OsIndications need to be set. The BootXXXX variable needs
> > +to be pointing to the EFI System Partition which contains the capsule
> > +file. The BootNext, BootXXXX and OsIndications variables can be set
> > +using the following commands::
> > +
> > +    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
> > +    => efidebug boot next 0
> > +    => setenv -e -nv -bs -rt -v OsIndications =0x04
> > +    => saveenv
> > +
> > +Finally, the capsule update can be initiated with the following
> > +command::
> > +
> > +    => efidebug capsule disk-update
> > +
> > +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 embedded as
> > +part of the platform's device tree blob using the mkeficapsule
> > +utility.
> > +
> > +On the QEMU virt platforms, the device-tree is generated on the fly
> > +based on the devices configured. This device tree is then passed on to
> > +the various software components booting on the platform, including
> > +U-Boot. Therefore, on the QEMU virt platform, the signatute is
> > +embedded on an overlay. This overlay is then applied at runtime to the
> > +base platform device-tree. Steps needed for embedding the esl file in
> > +the overlay are highlighted below.
> > +
> > +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 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 \
> > +      <capsule_file_name> --monotonic-count <val> --fw-version \
> > +      <val> --lsv <val> --guid \
> > +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
> > +      --update-image-index <val> --signer-private-cert \
> > +      /path/to/CRT.pem --trusted-public-cert \
> > +      /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \
> > +      <u-boot.bin>
> > +
> > +Place the capsule generated in the above step on the EFI System
> > +Partition under the EFI/UpdateCapsule directory
> > +
> > +For embedding the public key certificate, the following steps need to
> > +be followed::
> > +
> > +    1. Generate a skeleton overlay dts file, with a single fragment
> > +       node and an empty __overlay__ node
> > +
> > +       A typical skeleton overlay file will look like this
> > +
> > +       /dts-v1/;
> > +       /plugin/;
> > +
> > +       / {
> > +               fragment at 0 {
> > +                       target-path = "/";
> > +                       __overlay__ {
> > +                       };
> > +               };
> > +       };
> > +
> > +
> > +    2. Convert the dts to a corresponding dtb with the following
>
> Shouldn't this be dtbo?
>
> > +       command
> > +        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \
> > +        <dts_file>
> > +
> > +    3. Run the dtb file generated above through the mkeficapsule tool
> > +       in U-Boot
> > +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>
> > +
> > +Running the above command results in the creation of a 'signature'
> > +node in the dtb, under which the public key is stored as a
> > +'capsule-key' property. The '-O' option is to be used since the
> > +public key certificate(esl) file is being embedded in an overlay.
> > +
> > +The dtb file embedded with the certificate is now to be placed on an
> > +EFI System Partition. This would then be loaded and "merged" with the
> > +base platform flattened device-tree(dtb) at runtime.
> > +
> > +Build U-Boot with the following steps(QEMU ARM64)::
> > +
> > +    $ make qemu_arm64_defconfig
> > +    $ make menuconfig
> > +        Disable CONFIG_TFABOOT
> > +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE
> > +        Enable all configs needed for capsule update(listed above)
> > +    $ make all
> > +
> > +Boot the platform and perform the following steps on the U-Boot
> > +command line::
> > +
> > +    1. Enable capsule authentication by setting the following env
> > +       variable
> > +
> > +        => setenv capsule_authentication_enabled 1
> > +        => saveenv
> > +
> > +    2. Load the overlay dtb to memory and merge it with the base fdt
> > +
> > +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>
> > +        => fdt addr $fdtcontroladdr
> > +        => fdt resize <size_of_ov_dtb_file>
> > +        => fdt apply <$fdtovaddr>
>
> Having the public key on the disk means that any public key can be
> placed here and we get zero security.
>

But that does not mean the authentication will succeed unless the private
key is compromised. Deleting or tampering the public key on the disk can
result in a denial of service attack, as the capsule authentication would
fail, but that is true even when the public key is embedded in u-boot --
the public key or the u-boot image can be tampered with, resulting in a
board brick. For countering this kind of denial of service attack, the
public key needs to be placed on a secure storage device, which cannot be
modified or removed from the normal world. Moreover, how is this different
to the placement of the signature database used for the uefi secure boot as
part of the uefi authenticated variables on a storage device that can be
accessed from the normal world.

-sughosh


>
> We need to build the public key into U-Boot.
>
> Could you, please, investigate how we can adjust the build process
> accordingly.
>
> Best regards
>
> Heinrich
>
> > +
> > +    3. Set the following environment and UEFI boot variables
> > +
> > +        => setenv -e -nv -bs -rt -v OsIndications =0x04
> > +        => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
> > +        => efidebug boot next 0
> > +        => saveenv
> > +
> > +    4. Finally, the capsule update can be initiated with the following
> > +       command
> > +
> > +        => efidebug capsule disk-update
> > +
> > +On subsequent reboot, the platform should boot the updated U-Boot
> binary.
> >
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update
  2021-03-02 14:48     ` Sughosh Ganu
@ 2021-03-02 15:57       ` Heinrich Schuchardt
  2021-03-02 16:39         ` Sughosh Ganu
  0 siblings, 1 reply; 21+ messages in thread
From: Heinrich Schuchardt @ 2021-03-02 15:57 UTC (permalink / raw)
  To: u-boot

On 02.03.21 15:48, Sughosh Ganu wrote:
> hi Heinrich,
>
> On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt <xypron.glpk@gmx.de
> <mailto:xypron.glpk@gmx.de>> wrote:
>
>     On 30.12.20 14:57, Sughosh Ganu wrote:
>     > Add documentation highlighting the steps for using the uefi capsule
>     > update feature for updating the u-boot firmware image.
>     >
>     > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org
>     <mailto:sughosh.ganu@linaro.org>>
>     > ---
>     >
>     > Changes since V3: None
>     >
>     >? doc/board/emulation/index.rst? ? ? ? ? ? ? ?|? ?1 +
>     >? doc/board/emulation/qemu_capsule_update.rst | 210
>     ++++++++++++++++++++
>     >? 2 files changed, 211 insertions(+)
>     >? create mode 100644 doc/board/emulation/qemu_capsule_update.rst
>     >
>     > diff --git a/doc/board/emulation/index.rst
>     b/doc/board/emulation/index.rst
>     > index 1adefee155..a09ead1c35 100644
>     > --- a/doc/board/emulation/index.rst
>     > +++ b/doc/board/emulation/index.rst
>     > @@ -10,3 +10,4 @@ Emulation
>     >? ? ?qemu-mips
>     >? ? ?qemu-riscv
>     >? ? ?qemu-x86
>     > +? ?qemu_capsule_update
>     > diff --git a/doc/board/emulation/qemu_capsule_update.rst
>     b/doc/board/emulation/qemu_capsule_update.rst
>     > new file mode 100644
>     > index 0000000000..9fec75f8f1
>     > --- /dev/null
>     > +++ b/doc/board/emulation/qemu_capsule_update.rst
>     > @@ -0,0 +1,210 @@
>     > +.. SPDX-License-Identifier: GPL-2.0+
>     > +.. Copyright (C) 2020, Linaro Limited
>     > +
>     > +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.
>     > +
>     > +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
>     > +? ? CONFIG_EFI_CAPSULE_FMP_HEADER=y
>     > +
>     > +In addition, the following config needs to be disabled(QEMU ARM
>     specific)::
>     > +
>     > +? ? CONFIG_TFABOOT
>     > +
>     > +The capsule file can be generated by using the GenerateCapsule.py
>     > +script in EDKII::
>     > +
>     > +? ? $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
>     > +? ? <capsule_file_name> --fw-version <val> --lsv <val> --guid \
>     > +? ? e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose
>     --update-image-index \
>     > +? ? <val> --verbose <u-boot.bin>
>     > +
>     > +The above is a wrapper script(GenerateCapsule) which eventually calls
>     > +the actual GenerateCapsule.py script.
>     > +
>     > +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,
>     > +BootXXXX and OsIndications need to be set. The BootXXXX variable
>     needs
>     > +to be pointing to the EFI System Partition which contains the capsule
>     > +file. The BootNext, BootXXXX and OsIndications variables can be set
>     > +using the following commands::
>     > +
>     > +? ? => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
>     > +? ? => efidebug boot next 0
>     > +? ? => setenv -e -nv -bs -rt -v OsIndications =0x04
>     > +? ? => saveenv
>     > +
>     > +Finally, the capsule update can be initiated with the following
>     > +command::
>     > +
>     > +? ? => efidebug capsule disk-update
>     > +
>     > +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 embedded as
>     > +part of the platform's device tree blob using the mkeficapsule
>     > +utility.
>     > +
>     > +On the QEMU virt platforms, the device-tree is generated on the fly
>     > +based on the devices configured. This device tree is then passed
>     on to
>     > +the various software components booting on the platform, including
>     > +U-Boot. Therefore, on the QEMU virt platform, the signatute is
>     > +embedded on an overlay. This overlay is then applied at runtime
>     to the
>     > +base platform device-tree. Steps needed for embedding the esl file in
>     > +the overlay are highlighted below.
>     > +
>     > +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 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 \
>     > +? ? ? <capsule_file_name> --monotonic-count <val> --fw-version \
>     > +? ? ? <val> --lsv <val> --guid \
>     > +? ? ? e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
>     > +? ? ? --update-image-index <val> --signer-private-cert \
>     > +? ? ? /path/to/CRT.pem --trusted-public-cert \
>     > +? ? ? /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \
>     > +? ? ? <u-boot.bin>
>     > +
>     > +Place the capsule generated in the above step on the EFI System
>     > +Partition under the EFI/UpdateCapsule directory
>     > +
>     > +For embedding the public key certificate, the following steps need to
>     > +be followed::
>     > +
>     > +? ? 1. Generate a skeleton overlay dts file, with a single fragment
>     > +? ? ? ?node and an empty __overlay__ node
>     > +
>     > +? ? ? ?A typical skeleton overlay file will look like this
>     > +
>     > +? ? ? ?/dts-v1/;
>     > +? ? ? ?/plugin/;
>     > +
>     > +? ? ? ?/ {
>     > +? ? ? ? ? ? ? ?fragment at 0 {
>     > +? ? ? ? ? ? ? ? ? ? ? ?target-path = "/";
>     > +? ? ? ? ? ? ? ? ? ? ? ?__overlay__ {
>     > +? ? ? ? ? ? ? ? ? ? ? ?};
>     > +? ? ? ? ? ? ? ?};
>     > +? ? ? ?};
>     > +
>     > +
>     > +? ? 2. Convert the dts to a corresponding dtb with the following
>
>     Shouldn't this be dtbo?
>
>     > +? ? ? ?command
>     > +? ? ? ? ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \
>     > +? ? ? ? <dts_file>
>     > +
>     > +? ? 3. Run the dtb file generated above through the mkeficapsule tool
>     > +? ? ? ?in U-Boot
>     > +? ? ? ? ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>
>     > +
>     > +Running the above command results in the creation of a 'signature'
>     > +node in the dtb, under which the public key is stored as a
>     > +'capsule-key' property. The '-O' option is to be used since the
>     > +public key certificate(esl) file is being embedded in an overlay.
>     > +
>     > +The dtb file embedded with the certificate is now to be placed on an
>     > +EFI System Partition. This would then be loaded and "merged" with the
>     > +base platform flattened device-tree(dtb) at runtime.
>     > +
>     > +Build U-Boot with the following steps(QEMU ARM64)::
>     > +
>     > +? ? $ make qemu_arm64_defconfig
>     > +? ? $ make menuconfig
>     > +? ? ? ? Disable CONFIG_TFABOOT
>     > +? ? ? ? Enable CONFIG_EFI_CAPSULE_AUTHENTICATE
>     > +? ? ? ? Enable all configs needed for capsule update(listed above)
>     > +? ? $ make all
>     > +
>     > +Boot the platform and perform the following steps on the U-Boot
>     > +command line::
>     > +
>     > +? ? 1. Enable capsule authentication by setting the following env
>     > +? ? ? ?variable
>     > +
>     > +? ? ? ? => setenv capsule_authentication_enabled 1
>     > +? ? ? ? => saveenv
>     > +
>     > +? ? 2. Load the overlay dtb to memory and merge it with the base fdt
>     > +
>     > +? ? ? ? => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>
>     > +? ? ? ? => fdt addr $fdtcontroladdr
>     > +? ? ? ? => fdt resize <size_of_ov_dtb_file>
>     > +? ? ? ? => fdt apply <$fdtovaddr>
>
>     Having the public key on the disk means that any public key can be
>     placed here and we get zero security.
>
>
> But that does not mean the authentication will succeed unless the
> private key is compromised. Deleting or tampering the public key on the
> disk can result in a denial of service attack, as the capsule
> authentication would fail, but that is true even when the public key is
> embedded in u-boot -- the public key or the u-boot image can be tampered
> with,?resulting in a board brick. For countering this kind of denial of
> service attack, the public key needs to be placed on a secure storage
> device, which cannot be modified or removed from the normal world.
> Moreover, how is this different to the placement of the signature
> database used for the uefi secure boot as part of the uefi authenticated
> variables on a storage device that can be accessed from the normal world.

The public key is what you use to verify that a capsule was signed by an
authorized party. Who controls the public keys used for capsule checking
can crack the device:

I just have to create a public/private key pair to sign my malware and
place both the public key and the malware capsule on the disk.

We should not allow public keys for capsules to be on disk.

TF-A checks BL33 (U-Boot). If the public key is part of BL33 then only
capsules signed with this trusted key can be installed.

An attacker can still change U-Boot in a way that TF-A will not load it
leading to a denial of service. But he cannot launch malware via capsules.

Best regards

Heinrich
>
>
>     We need to build the public key into U-Boot.
>
>     Could you, please, investigate how we can adjust the build process
>     accordingly.
>
>     Best regards
>
>     Heinrich
>
>     > +
>     > +? ? 3. Set the following environment and UEFI boot variables
>     > +
>     > +? ? ? ? => setenv -e -nv -bs -rt -v OsIndications =0x04
>     > +? ? ? ? => efidebug boot add 0 Boot0000 virtio 0:1
>     <capsule_file_name>
>     > +? ? ? ? => efidebug boot next 0
>     > +? ? ? ? => saveenv
>     > +
>     > +? ? 4. Finally, the capsule update can be initiated with the
>     following
>     > +? ? ? ?command
>     > +
>     > +? ? ? ? => efidebug capsule disk-update
>     > +
>     > +On subsequent reboot, the platform should boot the updated U-Boot
>     binary.
>     >
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update
  2021-03-02 15:57       ` Heinrich Schuchardt
@ 2021-03-02 16:39         ` Sughosh Ganu
  2021-03-02 17:06           ` Heinrich Schuchardt
  0 siblings, 1 reply; 21+ messages in thread
From: Sughosh Ganu @ 2021-03-02 16:39 UTC (permalink / raw)
  To: u-boot

On Tue, 2 Mar 2021 at 21:27, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> On 02.03.21 15:48, Sughosh Ganu wrote:
> > hi Heinrich,
> >
> > On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt <xypron.glpk@gmx.de
> > <mailto:xypron.glpk@gmx.de>> wrote:
> >
> >     On 30.12.20 14:57, Sughosh Ganu wrote:
> >     > Add documentation highlighting the steps for using the uefi capsule
> >     > update feature for updating the u-boot firmware image.
> >     >
> >     > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org
> >     <mailto:sughosh.ganu@linaro.org>>
> >     > ---
> >     >
> >     > Changes since V3: None
> >     >
> >     >  doc/board/emulation/index.rst               |   1 +
> >     >  doc/board/emulation/qemu_capsule_update.rst | 210
> >     ++++++++++++++++++++
> >     >  2 files changed, 211 insertions(+)
> >     >  create mode 100644 doc/board/emulation/qemu_capsule_update.rst
> >     >
> >     > diff --git a/doc/board/emulation/index.rst
> >     b/doc/board/emulation/index.rst
> >     > index 1adefee155..a09ead1c35 100644
> >     > --- a/doc/board/emulation/index.rst
> >     > +++ b/doc/board/emulation/index.rst
> >     > @@ -10,3 +10,4 @@ Emulation
> >     >     qemu-mips
> >     >     qemu-riscv
> >     >     qemu-x86
> >     > +   qemu_capsule_update
> >     > diff --git a/doc/board/emulation/qemu_capsule_update.rst
> >     b/doc/board/emulation/qemu_capsule_update.rst
> >     > new file mode 100644
> >     > index 0000000000..9fec75f8f1
> >     > --- /dev/null
> >     > +++ b/doc/board/emulation/qemu_capsule_update.rst
> >     > @@ -0,0 +1,210 @@
> >     > +.. SPDX-License-Identifier: GPL-2.0+
> >     > +.. Copyright (C) 2020, Linaro Limited
> >     > +
> >     > +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.
> >     > +
> >     > +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
> >     > +    CONFIG_EFI_CAPSULE_FMP_HEADER=y
> >     > +
> >     > +In addition, the following config needs to be disabled(QEMU ARM
> >     specific)::
> >     > +
> >     > +    CONFIG_TFABOOT
> >     > +
> >     > +The capsule file can be generated by using the GenerateCapsule.py
> >     > +script in EDKII::
> >     > +
> >     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
> >     > +    <capsule_file_name> --fw-version <val> --lsv <val> --guid \
> >     > +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose
> >     --update-image-index \
> >     > +    <val> --verbose <u-boot.bin>
> >     > +
> >     > +The above is a wrapper script(GenerateCapsule) which eventually
> calls
> >     > +the actual GenerateCapsule.py script.
> >     > +
> >     > +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,
> >     > +BootXXXX and OsIndications need to be set. The BootXXXX variable
> >     needs
> >     > +to be pointing to the EFI System Partition which contains the
> capsule
> >     > +file. The BootNext, BootXXXX and OsIndications variables can be
> set
> >     > +using the following commands::
> >     > +
> >     > +    => efidebug boot add 0 Boot0000 virtio 0:1 <capsule_file_name>
> >     > +    => efidebug boot next 0
> >     > +    => setenv -e -nv -bs -rt -v OsIndications =0x04
> >     > +    => saveenv
> >     > +
> >     > +Finally, the capsule update can be initiated with the following
> >     > +command::
> >     > +
> >     > +    => efidebug capsule disk-update
> >     > +
> >     > +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
> embedded as
> >     > +part of the platform's device tree blob using the mkeficapsule
> >     > +utility.
> >     > +
> >     > +On the QEMU virt platforms, the device-tree is generated on the
> fly
> >     > +based on the devices configured. This device tree is then passed
> >     on to
> >     > +the various software components booting on the platform, including
> >     > +U-Boot. Therefore, on the QEMU virt platform, the signatute is
> >     > +embedded on an overlay. This overlay is then applied at runtime
> >     to the
> >     > +base platform device-tree. Steps needed for embedding the esl
> file in
> >     > +the overlay are highlighted below.
> >     > +
> >     > +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 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 \
> >     > +      <capsule_file_name> --monotonic-count <val> --fw-version \
> >     > +      <val> --lsv <val> --guid \
> >     > +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
> >     > +      --update-image-index <val> --signer-private-cert \
> >     > +      /path/to/CRT.pem --trusted-public-cert \
> >     > +      /path/to/CRT.pub.pem --other-public-cert
> /path/to/CRT.pub.pem \
> >     > +      <u-boot.bin>
> >     > +
> >     > +Place the capsule generated in the above step on the EFI System
> >     > +Partition under the EFI/UpdateCapsule directory
> >     > +
> >     > +For embedding the public key certificate, the following steps
> need to
> >     > +be followed::
> >     > +
> >     > +    1. Generate a skeleton overlay dts file, with a single
> fragment
> >     > +       node and an empty __overlay__ node
> >     > +
> >     > +       A typical skeleton overlay file will look like this
> >     > +
> >     > +       /dts-v1/;
> >     > +       /plugin/;
> >     > +
> >     > +       / {
> >     > +               fragment at 0 {
> >     > +                       target-path = "/";
> >     > +                       __overlay__ {
> >     > +                       };
> >     > +               };
> >     > +       };
> >     > +
> >     > +
> >     > +    2. Convert the dts to a corresponding dtb with the following
> >
> >     Shouldn't this be dtbo?
> >
> >     > +       command
> >     > +        ./scripts/dtc/dtc -@ -I dts -O dtb -o <ov_dtb_file_name> \
> >     > +        <dts_file>
> >     > +
> >     > +    3. Run the dtb file generated above through the mkeficapsule
> tool
> >     > +       in U-Boot
> >     > +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>
> >     > +
> >     > +Running the above command results in the creation of a 'signature'
> >     > +node in the dtb, under which the public key is stored as a
> >     > +'capsule-key' property. The '-O' option is to be used since the
> >     > +public key certificate(esl) file is being embedded in an overlay.
> >     > +
> >     > +The dtb file embedded with the certificate is now to be placed on
> an
> >     > +EFI System Partition. This would then be loaded and "merged" with
> the
> >     > +base platform flattened device-tree(dtb) at runtime.
> >     > +
> >     > +Build U-Boot with the following steps(QEMU ARM64)::
> >     > +
> >     > +    $ make qemu_arm64_defconfig
> >     > +    $ make menuconfig
> >     > +        Disable CONFIG_TFABOOT
> >     > +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE
> >     > +        Enable all configs needed for capsule update(listed above)
> >     > +    $ make all
> >     > +
> >     > +Boot the platform and perform the following steps on the U-Boot
> >     > +command line::
> >     > +
> >     > +    1. Enable capsule authentication by setting the following env
> >     > +       variable
> >     > +
> >     > +        => setenv capsule_authentication_enabled 1
> >     > +        => saveenv
> >     > +
> >     > +    2. Load the overlay dtb to memory and merge it with the base
> fdt
> >     > +
> >     > +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>
> >     > +        => fdt addr $fdtcontroladdr
> >     > +        => fdt resize <size_of_ov_dtb_file>
> >     > +        => fdt apply <$fdtovaddr>
> >
> >     Having the public key on the disk means that any public key can be
> >     placed here and we get zero security.
> >
> >
> > But that does not mean the authentication will succeed unless the
> > private key is compromised. Deleting or tampering the public key on the
> > disk can result in a denial of service attack, as the capsule
> > authentication would fail, but that is true even when the public key is
> > embedded in u-boot -- the public key or the u-boot image can be tampered
> > with, resulting in a board brick. For countering this kind of denial of
> > service attack, the public key needs to be placed on a secure storage
> > device, which cannot be modified or removed from the normal world.
> > Moreover, how is this different to the placement of the signature
> > database used for the uefi secure boot as part of the uefi authenticated
> > variables on a storage device that can be accessed from the normal world.
>
> The public key is what you use to verify that a capsule was signed by an
> authorized party. Who controls the public keys used for capsule checking
> can crack the device:
>
> I just have to create a public/private key pair to sign my malware and
> place both the public key and the malware capsule on the disk.
>

But when tf-a verifies this this BL33 during boot, it would fail
authentication and would not boot that BL33 image. So it is the same as
denial of service, isn't it.

-sughosh


>
> We should not allow public keys for capsules to be on disk.
>
> TF-A checks BL33 (U-Boot). If the public key is part of BL33 then only
> capsules signed with this trusted key can be installed.
>
> An attacker can still change U-Boot in a way that TF-A will not load it
> leading to a denial of service. But he cannot launch malware via capsules.
>
> Best regards
>
> Heinrich
> >
> >
> >     We need to build the public key into U-Boot.
> >
> >     Could you, please, investigate how we can adjust the build process
> >     accordingly.
> >
> >     Best regards
> >
> >     Heinrich
> >
> >     > +
> >     > +    3. Set the following environment and UEFI boot variables
> >     > +
> >     > +        => setenv -e -nv -bs -rt -v OsIndications =0x04
> >     > +        => efidebug boot add 0 Boot0000 virtio 0:1
> >     <capsule_file_name>
> >     > +        => efidebug boot next 0
> >     > +        => saveenv
> >     > +
> >     > +    4. Finally, the capsule update can be initiated with the
> >     following
> >     > +       command
> >     > +
> >     > +        => efidebug capsule disk-update
> >     > +
> >     > +On subsequent reboot, the platform should boot the updated U-Boot
> >     binary.
> >     >
> >
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update
  2021-03-02 16:39         ` Sughosh Ganu
@ 2021-03-02 17:06           ` Heinrich Schuchardt
  2021-03-02 17:38             ` Sughosh Ganu
  0 siblings, 1 reply; 21+ messages in thread
From: Heinrich Schuchardt @ 2021-03-02 17:06 UTC (permalink / raw)
  To: u-boot

On 02.03.21 17:39, Sughosh Ganu wrote:
>
>
> On Tue, 2 Mar 2021 at 21:27, Heinrich Schuchardt <xypron.glpk@gmx.de
> <mailto:xypron.glpk@gmx.de>> wrote:
>
>     On 02.03.21 15:48, Sughosh Ganu wrote:
>     > hi Heinrich,
>     >
>     > On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt
>     <xypron.glpk at gmx.de <mailto:xypron.glpk@gmx.de>
>     > <mailto:xypron.glpk at gmx.de <mailto:xypron.glpk@gmx.de>>> wrote:
>     >
>     >? ? ?On 30.12.20 14:57, Sughosh Ganu wrote:
>     >? ? ?> Add documentation highlighting the steps for using the uefi
>     capsule
>     >? ? ?> update feature for updating the u-boot firmware image.
>     >? ? ?>
>     >? ? ?> Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org
>     <mailto:sughosh.ganu@linaro.org>
>     >? ? ?<mailto:sughosh.ganu at linaro.org <mailto:sughosh.ganu@linaro.org>>>
>     >? ? ?> ---
>     >? ? ?>
>     >? ? ?> Changes since V3: None
>     >? ? ?>
>     >? ? ?>? doc/board/emulation/index.rst? ? ? ? ? ? ? ?|? ?1 +
>     >? ? ?>? doc/board/emulation/qemu_capsule_update.rst | 210
>     >? ? ?++++++++++++++++++++
>     >? ? ?>? 2 files changed, 211 insertions(+)
>     >? ? ?>? create mode 100644 doc/board/emulation/qemu_capsule_update.rst
>     >? ? ?>
>     >? ? ?> diff --git a/doc/board/emulation/index.rst
>     >? ? ?b/doc/board/emulation/index.rst
>     >? ? ?> index 1adefee155..a09ead1c35 100644
>     >? ? ?> --- a/doc/board/emulation/index.rst
>     >? ? ?> +++ b/doc/board/emulation/index.rst
>     >? ? ?> @@ -10,3 +10,4 @@ Emulation
>     >? ? ?>? ? ?qemu-mips
>     >? ? ?>? ? ?qemu-riscv
>     >? ? ?>? ? ?qemu-x86
>     >? ? ?> +? ?qemu_capsule_update
>     >? ? ?> diff --git a/doc/board/emulation/qemu_capsule_update.rst
>     >? ? ?b/doc/board/emulation/qemu_capsule_update.rst
>     >? ? ?> new file mode 100644
>     >? ? ?> index 0000000000..9fec75f8f1
>     >? ? ?> --- /dev/null
>     >? ? ?> +++ b/doc/board/emulation/qemu_capsule_update.rst
>     >? ? ?> @@ -0,0 +1,210 @@
>     >? ? ?> +.. SPDX-License-Identifier: GPL-2.0+
>     >? ? ?> +.. Copyright (C) 2020, Linaro Limited
>     >? ? ?> +
>     >? ? ?> +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.
>     >? ? ?> +
>     >? ? ?> +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
>     >? ? ?> +? ? CONFIG_EFI_CAPSULE_FMP_HEADER=y
>     >? ? ?> +
>     >? ? ?> +In addition, the following config needs to be disabled(QEMU ARM
>     >? ? ?specific)::
>     >? ? ?> +
>     >? ? ?> +? ? CONFIG_TFABOOT
>     >? ? ?> +
>     >? ? ?> +The capsule file can be generated by using the
>     GenerateCapsule.py
>     >? ? ?> +script in EDKII::
>     >? ? ?> +
>     >? ? ?> +? ? $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \
>     >? ? ?> +? ? <capsule_file_name> --fw-version <val> --lsv <val> --guid \
>     >? ? ?> +? ? e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose
>     >? ? ?--update-image-index \
>     >? ? ?> +? ? <val> --verbose <u-boot.bin>
>     >? ? ?> +
>     >? ? ?> +The above is a wrapper script(GenerateCapsule) which
>     eventually calls
>     >? ? ?> +the actual GenerateCapsule.py script.
>     >? ? ?> +
>     >? ? ?> +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,
>     >? ? ?> +BootXXXX and OsIndications need to be set. The BootXXXX
>     variable
>     >? ? ?needs
>     >? ? ?> +to be pointing to the EFI System Partition which contains
>     the capsule
>     >? ? ?> +file. The BootNext, BootXXXX and OsIndications variables
>     can be set
>     >? ? ?> +using the following commands::
>     >? ? ?> +
>     >? ? ?> +? ? => efidebug boot add 0 Boot0000 virtio 0:1
>     <capsule_file_name>
>     >? ? ?> +? ? => efidebug boot next 0
>     >? ? ?> +? ? => setenv -e -nv -bs -rt -v OsIndications =0x04
>     >? ? ?> +? ? => saveenv
>     >? ? ?> +
>     >? ? ?> +Finally, the capsule update can be initiated with the following
>     >? ? ?> +command::
>     >? ? ?> +
>     >? ? ?> +? ? => efidebug capsule disk-update
>     >? ? ?> +
>     >? ? ?> +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
>     embedded as
>     >? ? ?> +part of the platform's device tree blob using the mkeficapsule
>     >? ? ?> +utility.
>     >? ? ?> +
>     >? ? ?> +On the QEMU virt platforms, the device-tree is generated on
>     the fly
>     >? ? ?> +based on the devices configured. This device tree is then
>     passed
>     >? ? ?on to
>     >? ? ?> +the various software components booting on the platform,
>     including
>     >? ? ?> +U-Boot. Therefore, on the QEMU virt platform, the signatute is
>     >? ? ?> +embedded on an overlay. This overlay is then applied at runtime
>     >? ? ?to the
>     >? ? ?> +base platform device-tree. Steps needed for embedding the
>     esl file in
>     >? ? ?> +the overlay are highlighted below.
>     >? ? ?> +
>     >? ? ?> +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 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 \
>     >? ? ?> +? ? ? <capsule_file_name> --monotonic-count <val>
>     --fw-version \
>     >? ? ?> +? ? ? <val> --lsv <val> --guid \
>     >? ? ?> +? ? ? e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
>     >? ? ?> +? ? ? --update-image-index <val> --signer-private-cert \
>     >? ? ?> +? ? ? /path/to/CRT.pem --trusted-public-cert \
>     >? ? ?> +? ? ? /path/to/CRT.pub.pem --other-public-cert
>     /path/to/CRT.pub.pem \
>     >? ? ?> +? ? ? <u-boot.bin>
>     >? ? ?> +
>     >? ? ?> +Place the capsule generated in the above step on the EFI System
>     >? ? ?> +Partition under the EFI/UpdateCapsule directory
>     >? ? ?> +
>     >? ? ?> +For embedding the public key certificate, the following
>     steps need to
>     >? ? ?> +be followed::
>     >? ? ?> +
>     >? ? ?> +? ? 1. Generate a skeleton overlay dts file, with a single
>     fragment
>     >? ? ?> +? ? ? ?node and an empty __overlay__ node
>     >? ? ?> +
>     >? ? ?> +? ? ? ?A typical skeleton overlay file will look like this
>     >? ? ?> +
>     >? ? ?> +? ? ? ?/dts-v1/;
>     >? ? ?> +? ? ? ?/plugin/;
>     >? ? ?> +
>     >? ? ?> +? ? ? ?/ {
>     >? ? ?> +? ? ? ? ? ? ? ?fragment at 0 {
>     >? ? ?> +? ? ? ? ? ? ? ? ? ? ? ?target-path = "/";
>     >? ? ?> +? ? ? ? ? ? ? ? ? ? ? ?__overlay__ {
>     >? ? ?> +? ? ? ? ? ? ? ? ? ? ? ?};
>     >? ? ?> +? ? ? ? ? ? ? ?};
>     >? ? ?> +? ? ? ?};
>     >? ? ?> +
>     >? ? ?> +
>     >? ? ?> +? ? 2. Convert the dts to a corresponding dtb with the
>     following
>     >
>     >? ? ?Shouldn't this be dtbo?
>     >
>     >? ? ?> +? ? ? ?command
>     >? ? ?> +? ? ? ? ./scripts/dtc/dtc -@ -I dts -O dtb -o
>     <ov_dtb_file_name> \
>     >? ? ?> +? ? ? ? <dts_file>
>     >? ? ?> +
>     >? ? ?> +? ? 3. Run the dtb file generated above through the
>     mkeficapsule tool
>     >? ? ?> +? ? ? ?in U-Boot
>     >? ? ?> +? ? ? ? ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>
>     >? ? ?> +
>     >? ? ?> +Running the above command results in the creation of a
>     'signature'
>     >? ? ?> +node in the dtb, under which the public key is stored as a
>     >? ? ?> +'capsule-key' property. The '-O' option is to be used since the
>     >? ? ?> +public key certificate(esl) file is being embedded in an
>     overlay.
>     >? ? ?> +
>     >? ? ?> +The dtb file embedded with the certificate is now to be
>     placed on an
>     >? ? ?> +EFI System Partition. This would then be loaded and
>     "merged" with the
>     >? ? ?> +base platform flattened device-tree(dtb) at runtime.
>     >? ? ?> +
>     >? ? ?> +Build U-Boot with the following steps(QEMU ARM64)::
>     >? ? ?> +
>     >? ? ?> +? ? $ make qemu_arm64_defconfig
>     >? ? ?> +? ? $ make menuconfig
>     >? ? ?> +? ? ? ? Disable CONFIG_TFABOOT
>     >? ? ?> +? ? ? ? Enable CONFIG_EFI_CAPSULE_AUTHENTICATE
>     >? ? ?> +? ? ? ? Enable all configs needed for capsule update(listed
>     above)
>     >? ? ?> +? ? $ make all
>     >? ? ?> +
>     >? ? ?> +Boot the platform and perform the following steps on the U-Boot
>     >? ? ?> +command line::
>     >? ? ?> +
>     >? ? ?> +? ? 1. Enable capsule authentication by setting the
>     following env
>     >? ? ?> +? ? ? ?variable
>     >? ? ?> +
>     >? ? ?> +? ? ? ? => setenv capsule_authentication_enabled 1
>     >? ? ?> +? ? ? ? => saveenv
>     >? ? ?> +
>     >? ? ?> +? ? 2. Load the overlay dtb to memory and merge it with the
>     base fdt
>     >? ? ?> +
>     >? ? ?> +? ? ? ? => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>
>     >? ? ?> +? ? ? ? => fdt addr $fdtcontroladdr
>     >? ? ?> +? ? ? ? => fdt resize <size_of_ov_dtb_file>
>     >? ? ?> +? ? ? ? => fdt apply <$fdtovaddr>
>     >
>     >? ? ?Having the public key on the disk means that any public key can be
>     >? ? ?placed here and we get zero security.
>     >
>     >
>     > But that does not mean the authentication will succeed unless the
>     > private key is compromised. Deleting or tampering the public key
>     on the
>     > disk can result in a denial of service attack, as the capsule
>     > authentication would fail, but that is true even when the public
>     key is
>     > embedded in u-boot -- the public key or the u-boot image can be
>     tampered
>     > with,?resulting in a board brick. For countering this kind of
>     denial of
>     > service attack, the public key needs to be placed on a secure storage
>     > device, which cannot be modified or removed from the normal world.
>     > Moreover, how is this different to the placement of the signature
>     > database used for the uefi secure boot as part of the uefi
>     authenticated
>     > variables on a storage device that can be accessed from the normal
>     world.
>
>     The public key is what you use to verify that a capsule was signed by an
>     authorized party. Who controls the public keys used for capsule checking
>     can crack the device:
>
>     I just have to create a public/private key pair to sign my malware and
>     place both the public key and the malware capsule on the disk.
>
>
> But when tf-a verifies this this BL33 during boot, it would fail
> authentication and would not boot that BL33 image. So it is the same as
> denial of service, isn't it.

You cannot stop denial of service, but you can stop malware.

That is why I don't want the public key used for capsule verification on
disk.

Best regards

Heinrich

>
> -sughosh
> ?
>
>
>     We should not allow public keys for capsules to be on disk.
>
>     TF-A checks BL33 (U-Boot). If the public key is part of BL33 then only
>     capsules signed with this trusted key can be installed.
>
>     An attacker can still change U-Boot in a way that TF-A will not load it
>     leading to a denial of service. But he cannot launch malware via
>     capsules.
>
>     Best regards
>
>     Heinrich
>     >
>     >
>     >? ? ?We need to build the public key into U-Boot.
>     >
>     >? ? ?Could you, please, investigate how we can adjust the build process
>     >? ? ?accordingly.
>     >
>     >? ? ?Best regards
>     >
>     >? ? ?Heinrich
>     >
>     >? ? ?> +
>     >? ? ?> +? ? 3. Set the following environment and UEFI boot variables
>     >? ? ?> +
>     >? ? ?> +? ? ? ? => setenv -e -nv -bs -rt -v OsIndications =0x04
>     >? ? ?> +? ? ? ? => efidebug boot add 0 Boot0000 virtio 0:1
>     >? ? ?<capsule_file_name>
>     >? ? ?> +? ? ? ? => efidebug boot next 0
>     >? ? ?> +? ? ? ? => saveenv
>     >? ? ?> +
>     >? ? ?> +? ? 4. Finally, the capsule update can be initiated with the
>     >? ? ?following
>     >? ? ?> +? ? ? ?command
>     >? ? ?> +
>     >? ? ?> +? ? ? ? => efidebug capsule disk-update
>     >? ? ?> +
>     >? ? ?> +On subsequent reboot, the platform should boot the updated
>     U-Boot
>     >? ? ?binary.
>     >? ? ?>
>     >
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update
  2021-03-02 17:06           ` Heinrich Schuchardt
@ 2021-03-02 17:38             ` Sughosh Ganu
  0 siblings, 0 replies; 21+ messages in thread
From: Sughosh Ganu @ 2021-03-02 17:38 UTC (permalink / raw)
  To: u-boot

On Tue, 2 Mar 2021 at 22:36, Heinrich Schuchardt <xypron.glpk@gmx.de> wrote:

> On 02.03.21 17:39, Sughosh Ganu wrote:
> >
> >
> > On Tue, 2 Mar 2021 at 21:27, Heinrich Schuchardt <xypron.glpk@gmx.de
> > <mailto:xypron.glpk@gmx.de>> wrote:
> >
> >     On 02.03.21 15:48, Sughosh Ganu wrote:
> >     > hi Heinrich,
> >     >
> >     > On Tue, 2 Mar 2021 at 16:45, Heinrich Schuchardt
> >     <xypron.glpk at gmx.de <mailto:xypron.glpk@gmx.de>
> >     > <mailto:xypron.glpk at gmx.de <mailto:xypron.glpk@gmx.de>>> wrote:
> >     >
> >     >     On 30.12.20 14:57, Sughosh Ganu wrote:
> >     >     > Add documentation highlighting the steps for using the uefi
> >     capsule
> >     >     > update feature for updating the u-boot firmware image.
> >     >     >
> >     >     > Signed-off-by: Sughosh Ganu <sughosh.ganu@linaro.org
> >     <mailto:sughosh.ganu@linaro.org>
> >     >     <mailto:sughosh.ganu@linaro.org <mailto:
> sughosh.ganu at linaro.org>>>
> >     >     > ---
> >     >     >
> >     >     > Changes since V3: None
> >     >     >
> >     >     >  doc/board/emulation/index.rst               |   1 +
> >     >     >  doc/board/emulation/qemu_capsule_update.rst | 210
> >     >     ++++++++++++++++++++
> >     >     >  2 files changed, 211 insertions(+)
> >     >     >  create mode 100644
> doc/board/emulation/qemu_capsule_update.rst
> >     >     >
> >     >     > diff --git a/doc/board/emulation/index.rst
> >     >     b/doc/board/emulation/index.rst
> >     >     > index 1adefee155..a09ead1c35 100644
> >     >     > --- a/doc/board/emulation/index.rst
> >     >     > +++ b/doc/board/emulation/index.rst
> >     >     > @@ -10,3 +10,4 @@ Emulation
> >     >     >     qemu-mips
> >     >     >     qemu-riscv
> >     >     >     qemu-x86
> >     >     > +   qemu_capsule_update
> >     >     > diff --git a/doc/board/emulation/qemu_capsule_update.rst
> >     >     b/doc/board/emulation/qemu_capsule_update.rst
> >     >     > new file mode 100644
> >     >     > index 0000000000..9fec75f8f1
> >     >     > --- /dev/null
> >     >     > +++ b/doc/board/emulation/qemu_capsule_update.rst
> >     >     > @@ -0,0 +1,210 @@
> >     >     > +.. SPDX-License-Identifier: GPL-2.0+
> >     >     > +.. Copyright (C) 2020, Linaro Limited
> >     >     > +
> >     >     > +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.
> >     >     > +
> >     >     > +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
> >     >     > +    CONFIG_EFI_CAPSULE_FMP_HEADER=y
> >     >     > +
> >     >     > +In addition, the following config needs to be disabled(QEMU
> ARM
> >     >     specific)::
> >     >     > +
> >     >     > +    CONFIG_TFABOOT
> >     >     > +
> >     >     > +The capsule file can be generated by using the
> >     GenerateCapsule.py
> >     >     > +script in EDKII::
> >     >     > +
> >     >     > +    $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e
> -o \
> >     >     > +    <capsule_file_name> --fw-version <val> --lsv <val>
> --guid \
> >     >     > +    e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose
> >     >     --update-image-index \
> >     >     > +    <val> --verbose <u-boot.bin>
> >     >     > +
> >     >     > +The above is a wrapper script(GenerateCapsule) which
> >     eventually calls
> >     >     > +the actual GenerateCapsule.py script.
> >     >     > +
> >     >     > +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,
> >     >     > +BootXXXX and OsIndications need to be set. The BootXXXX
> >     variable
> >     >     needs
> >     >     > +to be pointing to the EFI System Partition which contains
> >     the capsule
> >     >     > +file. The BootNext, BootXXXX and OsIndications variables
> >     can be set
> >     >     > +using the following commands::
> >     >     > +
> >     >     > +    => efidebug boot add 0 Boot0000 virtio 0:1
> >     <capsule_file_name>
> >     >     > +    => efidebug boot next 0
> >     >     > +    => setenv -e -nv -bs -rt -v OsIndications =0x04
> >     >     > +    => saveenv
> >     >     > +
> >     >     > +Finally, the capsule update can be initiated with the
> following
> >     >     > +command::
> >     >     > +
> >     >     > +    => efidebug capsule disk-update
> >     >     > +
> >     >     > +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
> >     embedded as
> >     >     > +part of the platform's device tree blob using the
> mkeficapsule
> >     >     > +utility.
> >     >     > +
> >     >     > +On the QEMU virt platforms, the device-tree is generated on
> >     the fly
> >     >     > +based on the devices configured. This device tree is then
> >     passed
> >     >     on to
> >     >     > +the various software components booting on the platform,
> >     including
> >     >     > +U-Boot. Therefore, on the QEMU virt platform, the signatute
> is
> >     >     > +embedded on an overlay. This overlay is then applied at
> runtime
> >     >     to the
> >     >     > +base platform device-tree. Steps needed for embedding the
> >     esl file in
> >     >     > +the overlay are highlighted below.
> >     >     > +
> >     >     > +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 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 \
> >     >     > +      <capsule_file_name> --monotonic-count <val>
> >     --fw-version \
> >     >     > +      <val> --lsv <val> --guid \
> >     >     > +      e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \
> >     >     > +      --update-image-index <val> --signer-private-cert \
> >     >     > +      /path/to/CRT.pem --trusted-public-cert \
> >     >     > +      /path/to/CRT.pub.pem --other-public-cert
> >     /path/to/CRT.pub.pem \
> >     >     > +      <u-boot.bin>
> >     >     > +
> >     >     > +Place the capsule generated in the above step on the EFI
> System
> >     >     > +Partition under the EFI/UpdateCapsule directory
> >     >     > +
> >     >     > +For embedding the public key certificate, the following
> >     steps need to
> >     >     > +be followed::
> >     >     > +
> >     >     > +    1. Generate a skeleton overlay dts file, with a single
> >     fragment
> >     >     > +       node and an empty __overlay__ node
> >     >     > +
> >     >     > +       A typical skeleton overlay file will look like this
> >     >     > +
> >     >     > +       /dts-v1/;
> >     >     > +       /plugin/;
> >     >     > +
> >     >     > +       / {
> >     >     > +               fragment at 0 {
> >     >     > +                       target-path = "/";
> >     >     > +                       __overlay__ {
> >     >     > +                       };
> >     >     > +               };
> >     >     > +       };
> >     >     > +
> >     >     > +
> >     >     > +    2. Convert the dts to a corresponding dtb with the
> >     following
> >     >
> >     >     Shouldn't this be dtbo?
> >     >
> >     >     > +       command
> >     >     > +        ./scripts/dtc/dtc -@ -I dts -O dtb -o
> >     <ov_dtb_file_name> \
> >     >     > +        <dts_file>
> >     >     > +
> >     >     > +    3. Run the dtb file generated above through the
> >     mkeficapsule tool
> >     >     > +       in U-Boot
> >     >     > +        ./tools/mkeficapsule -O <pub_key.esl> -D <ov_dtb>
> >     >     > +
> >     >     > +Running the above command results in the creation of a
> >     'signature'
> >     >     > +node in the dtb, under which the public key is stored as a
> >     >     > +'capsule-key' property. The '-O' option is to be used since
> the
> >     >     > +public key certificate(esl) file is being embedded in an
> >     overlay.
> >     >     > +
> >     >     > +The dtb file embedded with the certificate is now to be
> >     placed on an
> >     >     > +EFI System Partition. This would then be loaded and
> >     "merged" with the
> >     >     > +base platform flattened device-tree(dtb) at runtime.
> >     >     > +
> >     >     > +Build U-Boot with the following steps(QEMU ARM64)::
> >     >     > +
> >     >     > +    $ make qemu_arm64_defconfig
> >     >     > +    $ make menuconfig
> >     >     > +        Disable CONFIG_TFABOOT
> >     >     > +        Enable CONFIG_EFI_CAPSULE_AUTHENTICATE
> >     >     > +        Enable all configs needed for capsule update(listed
> >     above)
> >     >     > +    $ make all
> >     >     > +
> >     >     > +Boot the platform and perform the following steps on the
> U-Boot
> >     >     > +command line::
> >     >     > +
> >     >     > +    1. Enable capsule authentication by setting the
> >     following env
> >     >     > +       variable
> >     >     > +
> >     >     > +        => setenv capsule_authentication_enabled 1
> >     >     > +        => saveenv
> >     >     > +
> >     >     > +    2. Load the overlay dtb to memory and merge it with the
> >     base fdt
> >     >     > +
> >     >     > +        => fatload virtio 0:1 <$fdtovaddr> EFI/<ov_dtb_file>
> >     >     > +        => fdt addr $fdtcontroladdr
> >     >     > +        => fdt resize <size_of_ov_dtb_file>
> >     >     > +        => fdt apply <$fdtovaddr>
> >     >
> >     >     Having the public key on the disk means that any public key
> can be
> >     >     placed here and we get zero security.
> >     >
> >     >
> >     > But that does not mean the authentication will succeed unless the
> >     > private key is compromised. Deleting or tampering the public key
> >     on the
> >     > disk can result in a denial of service attack, as the capsule
> >     > authentication would fail, but that is true even when the public
> >     key is
> >     > embedded in u-boot -- the public key or the u-boot image can be
> >     tampered
> >     > with, resulting in a board brick. For countering this kind of
> >     denial of
> >     > service attack, the public key needs to be placed on a secure
> storage
> >     > device, which cannot be modified or removed from the normal world.
> >     > Moreover, how is this different to the placement of the signature
> >     > database used for the uefi secure boot as part of the uefi
> >     authenticated
> >     > variables on a storage device that can be accessed from the normal
> >     world.
> >
> >     The public key is what you use to verify that a capsule was signed
> by an
> >     authorized party. Who controls the public keys used for capsule
> checking
> >     can crack the device:
> >
> >     I just have to create a public/private key pair to sign my malware
> and
> >     place both the public key and the malware capsule on the disk.
> >
> >
> > But when tf-a verifies this this BL33 during boot, it would fail
> > authentication and would not boot that BL33 image. So it is the same as
> > denial of service, isn't it.
>
> You cannot stop denial of service, but you can stop malware.
>
> That is why I don't want the public key used for capsule verification on
> disk.
>

If we have a trusted boot flow[1], with tf-a authenticating the
BL33(u-boot) image before booting, how do we allow malware to boot on the
system.

-sughosh

[1] -
https://trustedfirmware-a.readthedocs.io/en/latest/design/trusted-board-boot.html


>
> Best regards
>
> Heinrich
>
> >
> > -sughosh
> >
> >
> >
> >     We should not allow public keys for capsules to be on disk.
> >
> >     TF-A checks BL33 (U-Boot). If the public key is part of BL33 then
> only
> >     capsules signed with this trusted key can be installed.
> >
> >     An attacker can still change U-Boot in a way that TF-A will not load
> it
> >     leading to a denial of service. But he cannot launch malware via
> >     capsules.
> >
> >     Best regards
> >
> >     Heinrich
> >     >
> >     >
> >     >     We need to build the public key into U-Boot.
> >     >
> >     >     Could you, please, investigate how we can adjust the build
> process
> >     >     accordingly.
> >     >
> >     >     Best regards
> >     >
> >     >     Heinrich
> >     >
> >     >     > +
> >     >     > +    3. Set the following environment and UEFI boot variables
> >     >     > +
> >     >     > +        => setenv -e -nv -bs -rt -v OsIndications =0x04
> >     >     > +        => efidebug boot add 0 Boot0000 virtio 0:1
> >     >     <capsule_file_name>
> >     >     > +        => efidebug boot next 0
> >     >     > +        => saveenv
> >     >     > +
> >     >     > +    4. Finally, the capsule update can be initiated with the
> >     >     following
> >     >     > +       command
> >     >     > +
> >     >     > +        => efidebug capsule disk-update
> >     >     > +
> >     >     > +On subsequent reboot, the platform should boot the updated
> >     U-Boot
> >     >     binary.
> >     >     >
> >     >
> >
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2021-03-02 17:38 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-12-30 13:56 [PATCH v4 00/14] qemu: arm64: Add support for uefi capsule update on qemu arm platform Sughosh Ganu
2020-12-30 13:56 ` [PATCH v4 01/14] mkeficapsule: Add support for embedding public key in a dtb Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 02/14] qemu: arm: Initialise virtio devices in board_late_init Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 03/14] crypto: Fix the logic to calculate hash with authattributes set Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 04/14] qemu: common: Add support for dynamic mtdparts for the platform Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 05/14] qemu: common: Set dfu_alt_info variable " Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 06/14] fsp: Move and rename fsp_types.h file Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 07/14] efi_loader: Add logic to parse EDKII specific fmp payload header Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 08/14] dfu_mtd: Add provision to unlock mtd device Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 09/14] efi_loader: Make the pkcs7 header parsing function an extern Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 10/14] efi_loader: Re-factor code to build the signature store from efi signature list Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 11/14] efi: capsule: Add support for uefi capsule authentication Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 12/14] efi_loader: Enable " Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 13/14] efidebug: capsule: Add a command to update capsule on disk Sughosh Ganu
2020-12-30 13:57 ` [PATCH v4 14/14] qemu: arm64: Add documentation for capsule update Sughosh Ganu
2021-03-02 11:14   ` Heinrich Schuchardt
2021-03-02 14:48     ` Sughosh Ganu
2021-03-02 15:57       ` Heinrich Schuchardt
2021-03-02 16:39         ` Sughosh Ganu
2021-03-02 17:06           ` Heinrich Schuchardt
2021-03-02 17:38             ` Sughosh Ganu

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.