diff -Nru u-boot-2022.01+dfsg/debian/changelog u-boot-2022.01+dfsg/debian/changelog --- u-boot-2022.01+dfsg/debian/changelog 2023-07-20 17:42:59.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/changelog 2023-09-18 11:02:43.000000000 +0800 @@ -1,3 +1,11 @@ +u-boot (2022.01+dfsg-2ubuntu2.5) jammy; urgency=medium + + * Support mkeficapsule command to generate capsule file (LP: #2036406) + * mkeficapsule with the patches applied matches U-Boot v2022.04. + * Update test script related to efi_capsule + + -- Aristo Chen Mon, 18 Sep 2023 11:02:43 +0800 + u-boot (2022.01+dfsg-2ubuntu2.4) jammy; urgency=medium * Rebuild against updated OpenSBI (LP: #2026588) diff -Nru u-boot-2022.01+dfsg/debian/control u-boot-2022.01+dfsg/debian/control --- u-boot-2022.01+dfsg/debian/control 2022-11-18 19:11:50.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/control 2023-09-18 11:02:43.000000000 +0800 @@ -19,6 +19,7 @@ libc6:armhf [armhf] , libc6:armel [armel] , libc6:riscv64 [riscv64] , + libgnutls28-dev, libpython3-dev:native [linux-any], libssl-dev, libssl-dev:native, @@ -27,6 +28,7 @@ python3-distutils [linux-any], python3-pkg-resources [linux-any], swig [linux-any], + uuid-dev, lzop [armhf], Build-Depends-Indep: # For u-boot-qemu targets @@ -309,3 +311,4 @@ - dumpimage - mksunxiboot - mkenvimage + - mkeficapsule diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0001-tools-mkeficapsule-output-messages-to-stderr-instead.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0001-tools-mkeficapsule-output-messages-to-stderr-instead.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0001-tools-mkeficapsule-output-messages-to-stderr-instead.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0001-tools-mkeficapsule-output-messages-to-stderr-instead.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,121 @@ +From 28250daba1cca7abce0889e017589563d8a6ddae Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Tue, 18 Jan 2022 13:39:44 +0900 +Subject: [PATCH 1/1] tools: mkeficapsule: output messages to stderr instead of + stdout + +All the error messages should be printed out to stderr. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Heinrich Schuchardt +--- + tools/mkeficapsule.c | 27 ++++++++++++++------------- + 1 file changed, 14 insertions(+), 13 deletions(-) + +diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c +index 4995ba4e..b22b61a9 100644 +--- a/tools/mkeficapsule.c ++++ b/tools/mkeficapsule.c +@@ -81,21 +81,22 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + + g = fopen(bin, "r"); + if (!g) { +- printf("cannot open %s\n", bin); ++ fprintf(stderr, "cannot open %s\n", bin); + return -1; + } + if (stat(bin, &bin_stat) < 0) { +- printf("cannot determine the size of %s\n", bin); ++ fprintf(stderr, "cannot determine the size of %s\n", bin); + goto err_1; + } + data = malloc(bin_stat.st_size); + if (!data) { +- printf("cannot allocate memory: %zx\n", (size_t)bin_stat.st_size); ++ fprintf(stderr, "cannot allocate memory: %zx\n", ++ (size_t)bin_stat.st_size); + goto err_1; + } + f = fopen(path, "w"); + if (!f) { +- printf("cannot open %s\n", path); ++ fprintf(stderr, "cannot open %s\n", path); + goto err_2; + } + header.capsule_guid = efi_guid_fm_capsule; +@@ -109,7 +110,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + + size = fwrite(&header, 1, sizeof(header), f); + if (size < sizeof(header)) { +- printf("write failed (%zx)\n", size); ++ fprintf(stderr, "write failed (%zx)\n", size); + goto err_3; + } + +@@ -118,13 +119,13 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + capsule.payload_item_count = 1; + size = fwrite(&capsule, 1, sizeof(capsule), f); + if (size < (sizeof(capsule))) { +- printf("write failed (%zx)\n", size); ++ fprintf(stderr, "write failed (%zx)\n", size); + goto err_3; + } + offset = sizeof(capsule) + sizeof(u64); + size = fwrite(&offset, 1, sizeof(offset), f); + if (size < sizeof(offset)) { +- printf("write failed (%zx)\n", size); ++ fprintf(stderr, "write failed (%zx)\n", size); + goto err_3; + } + +@@ -141,17 +142,17 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + + size = fwrite(&image, 1, sizeof(image), f); + if (size < sizeof(image)) { +- printf("write failed (%zx)\n", size); ++ fprintf(stderr, "write failed (%zx)\n", size); + goto err_3; + } + size = fread(data, 1, bin_stat.st_size, g); + if (size < bin_stat.st_size) { +- printf("read failed (%zx)\n", size); ++ fprintf(stderr, "read failed (%zx)\n", size); + goto err_3; + } + size = fwrite(data, 1, bin_stat.st_size, f); + if (size < bin_stat.st_size) { +- printf("write failed (%zx)\n", size); ++ fprintf(stderr, "write failed (%zx)\n", size); + goto err_3; + } + +@@ -194,7 +195,7 @@ int main(int argc, char **argv) + switch (c) { + case 'f': + if (file) { +- printf("Image already specified\n"); ++ fprintf(stderr, "Image already specified\n"); + return -1; + } + file = optarg; +@@ -202,7 +203,7 @@ int main(int argc, char **argv) + break; + case 'r': + if (file) { +- printf("Image already specified\n"); ++ fprintf(stderr, "Image already specified\n"); + return -1; + } + file = optarg; +@@ -234,7 +235,7 @@ int main(int argc, char **argv) + + if (create_fwbin(argv[optind], file, guid, index, instance) + < 0) { +- printf("Creating firmware capsule failed\n"); ++ fprintf(stderr, "Creating firmware capsule failed\n"); + exit(EXIT_FAILURE); + } + +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0002-tools-mkeficapsule-rework-the-code-a-little-bit.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0002-tools-mkeficapsule-rework-the-code-a-little-bit.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0002-tools-mkeficapsule-rework-the-code-a-little-bit.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0002-tools-mkeficapsule-rework-the-code-a-little-bit.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,320 @@ +From 4d6c92cadfbb56fdf1f468393c4710f2ef212f4f Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Tue, 18 Jan 2022 13:39:45 +0900 +Subject: [PATCH 1/1] tools: mkeficapsule: rework the code a little bit + +Abstract common routines to make the code easily understandable. +No functional change. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +--- + tools/mkeficapsule.c | 239 ++++++++++++++++++++++++++++++------------- + 1 file changed, 167 insertions(+), 72 deletions(-) + +diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c +index b22b61a9..243fd6e4 100644 +--- a/tools/mkeficapsule.c ++++ b/tools/mkeficapsule.c +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -51,33 +52,36 @@ static struct option options[] = { + static void print_usage(void) + { + printf("Usage: %s [options] \n" +- "Options:\n" +- +- "\t-f, --fit new FIT image file\n" +- "\t-r, --raw new raw image file\n" +- "\t-i, --index update image index\n" +- "\t-I, --instance update hardware instance\n" +- "\t-h, --help print a help message\n", +- tool_name); ++ "Options:\n" ++ ++ "\t-f, --fit new FIT image file\n" ++ "\t-r, --raw new raw image file\n" ++ "\t-i, --index update image index\n" ++ "\t-I, --instance update hardware instance\n" ++ "\t-h, --help print a help message\n", ++ tool_name); + } + +-static int create_fwbin(char *path, char *bin, efi_guid_t *guid, +- unsigned long index, unsigned long instance) ++/** ++ * read_bin_file - read a firmware binary file ++ * @bin: Path to a firmware binary file ++ * @data: Pointer to pointer of allocated buffer ++ * @bin_size: Size of allocated buffer ++ * ++ * Read out a content of binary, @bin, into @data. ++ * A caller should free @data. ++ * ++ * Return: ++ * * 0 - on success ++ * * -1 - on failure ++ */ ++static int read_bin_file(char *bin, void **data, off_t *bin_size) + { +- struct efi_capsule_header header; +- struct efi_firmware_management_capsule_header capsule; +- struct efi_firmware_management_capsule_image_header image; +- FILE *f, *g; ++ FILE *g; + struct stat bin_stat; +- u8 *data; ++ void *buf; + size_t size; +- u64 offset; +- +-#ifdef DEBUG +- printf("For output: %s\n", path); +- printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); +- printf("\tindex: %ld\n\tinstance: %ld\n", index, instance); +-#endif ++ int ret = 0; + + g = fopen(bin, "r"); + if (!g) { +@@ -86,19 +90,123 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + } + if (stat(bin, &bin_stat) < 0) { + fprintf(stderr, "cannot determine the size of %s\n", bin); +- goto err_1; ++ ret = -1; ++ goto err; ++ } ++ if (bin_stat.st_size > SIZE_MAX) { ++ fprintf(stderr, "file size is too large for malloc: %s\n", bin); ++ ret = -1; ++ goto err; + } +- data = malloc(bin_stat.st_size); +- if (!data) { ++ buf = malloc(bin_stat.st_size); ++ if (!buf) { + fprintf(stderr, "cannot allocate memory: %zx\n", + (size_t)bin_stat.st_size); +- goto err_1; ++ ret = -1; ++ goto err; ++ } ++ ++ size = fread(buf, 1, bin_stat.st_size, g); ++ if (size < bin_stat.st_size) { ++ fprintf(stderr, "read failed (%zx)\n", size); ++ ret = -1; ++ goto err; + } ++ ++ *data = buf; ++ *bin_size = bin_stat.st_size; ++err: ++ fclose(g); ++ ++ return ret; ++} ++ ++/** ++ * write_capsule_file - write a capsule file ++ * @bin: FILE stream ++ * @data: Pointer to data ++ * @bin_size: Size of data ++ * ++ * Write out data, @data, with the size @bin_size. ++ * ++ * Return: ++ * * 0 - on success ++ * * -1 - on failure ++ */ ++static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg) ++{ ++ size_t size_written; ++ ++ size_written = fwrite(data, 1, size, f); ++ if (size_written < size) { ++ fprintf(stderr, "%s: write failed (%zx != %zx)\n", msg, ++ size_written, size); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++/** ++ * create_fwbin - create an uefi capsule file ++ * @path: Path to a created capsule file ++ * @bin: Path to a firmware binary to encapsulate ++ * @guid: GUID of related FMP driver ++ * @index: Index number in capsule ++ * @instance: Instance number in capsule ++ * @mcount: Monotonic count in authentication information ++ * @private_file: Path to a private key file ++ * @cert_file: Path to a certificate file ++ * ++ * This function actually does the job of creating an uefi capsule file. ++ * All the arguments must be supplied. ++ * If either @private_file ror @cert_file is NULL, the capsule file ++ * won't be signed. ++ * ++ * Return: ++ * * 0 - on success ++ * * -1 - on failure ++ */ ++static int create_fwbin(char *path, char *bin, efi_guid_t *guid, ++ unsigned long index, unsigned long instance) ++{ ++ struct efi_capsule_header header; ++ struct efi_firmware_management_capsule_header capsule; ++ struct efi_firmware_management_capsule_image_header image; ++ FILE *f; ++ void *data; ++ off_t bin_size; ++ u64 offset; ++ int ret; ++ ++#ifdef DEBUG ++ printf("For output: %s\n", path); ++ printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); ++ printf("\tindex: %ld\n\tinstance: %ld\n", index, instance); ++#endif ++ ++ f = NULL; ++ data = NULL; ++ ret = -1; ++ ++ /* ++ * read a firmware binary ++ */ ++ if (read_bin_file(bin, &data, &bin_size)) ++ goto err; ++ ++ /* ++ * write a capsule file ++ */ + f = fopen(path, "w"); + if (!f) { + fprintf(stderr, "cannot open %s\n", path); +- goto err_2; ++ goto err; + } ++ ++ /* ++ * capsule file header ++ */ + header.capsule_guid = efi_guid_fm_capsule; + header.header_size = sizeof(header); + /* TODO: The current implementation ignores flags */ +@@ -106,70 +214,57 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + header.capsule_image_size = sizeof(header) + + sizeof(capsule) + sizeof(u64) + + sizeof(image) +- + bin_stat.st_size; +- +- size = fwrite(&header, 1, sizeof(header), f); +- if (size < sizeof(header)) { +- fprintf(stderr, "write failed (%zx)\n", size); +- goto err_3; +- } ++ + bin_size; ++ if (write_capsule_file(f, &header, sizeof(header), ++ "Capsule header")) ++ goto err; + ++ /* ++ * firmware capsule header ++ * This capsule has only one firmware capsule image. ++ */ + capsule.version = 0x00000001; + capsule.embedded_driver_count = 0; + capsule.payload_item_count = 1; +- size = fwrite(&capsule, 1, sizeof(capsule), f); +- if (size < (sizeof(capsule))) { +- fprintf(stderr, "write failed (%zx)\n", size); +- goto err_3; +- } ++ if (write_capsule_file(f, &capsule, sizeof(capsule), ++ "Firmware capsule header")) ++ goto err; ++ + offset = sizeof(capsule) + sizeof(u64); +- size = fwrite(&offset, 1, sizeof(offset), f); +- if (size < sizeof(offset)) { +- fprintf(stderr, "write failed (%zx)\n", size); +- goto err_3; +- } ++ if (write_capsule_file(f, &offset, sizeof(offset), ++ "Offset to capsule image")) ++ goto err; + ++ /* ++ * firmware capsule image header ++ */ + image.version = 0x00000003; + memcpy(&image.update_image_type_id, guid, sizeof(*guid)); + image.update_image_index = index; + image.reserved[0] = 0; + image.reserved[1] = 0; + image.reserved[2] = 0; +- image.update_image_size = bin_stat.st_size; ++ image.update_image_size = bin_size; + image.update_vendor_code_size = 0; /* none */ + image.update_hardware_instance = instance; + image.image_capsule_support = 0; ++ if (write_capsule_file(f, &image, sizeof(image), ++ "Firmware capsule image header")) ++ goto err; + +- size = fwrite(&image, 1, sizeof(image), f); +- if (size < sizeof(image)) { +- fprintf(stderr, "write failed (%zx)\n", size); +- goto err_3; +- } +- size = fread(data, 1, bin_stat.st_size, g); +- if (size < bin_stat.st_size) { +- fprintf(stderr, "read failed (%zx)\n", size); +- goto err_3; +- } +- size = fwrite(data, 1, bin_stat.st_size, f); +- if (size < bin_stat.st_size) { +- fprintf(stderr, "write failed (%zx)\n", size); +- goto err_3; +- } +- +- fclose(f); +- fclose(g); +- free(data); +- +- return 0; ++ /* ++ * firmware binary ++ */ ++ if (write_capsule_file(f, data, bin_size, "Firmware binary")) ++ goto err; + +-err_3: +- fclose(f); +-err_2: ++ ret = 0; ++err: ++ if (f) ++ fclose(f); + free(data); +-err_1: +- fclose(g); + +- return -1; ++ return ret; + } + + /* +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0003-tools-mkeficapsule-dont-use-malloc.h.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0003-tools-mkeficapsule-dont-use-malloc.h.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0003-tools-mkeficapsule-dont-use-malloc.h.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0003-tools-mkeficapsule-dont-use-malloc.h.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,28 @@ +From c099a07133af22f4295c3dbc0c52cd4c3af0e7fc Mon Sep 17 00:00:00 2001 +From: Heinrich Schuchardt +Date: Sat, 5 Feb 2022 20:10:03 +0100 +Subject: [PATCH 1/1] tools: mkeficapsule: dont use malloc.h + +malloc() functions are declared via stdlib.h. Including malloc.h can lead +to build errors e.g. on OS-X. + +Signed-off-by: Heinrich Schuchardt +--- + tools/mkeficapsule.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c +index 243fd6e4..d6e3725e 100644 +--- a/tools/mkeficapsule.c ++++ b/tools/mkeficapsule.c +@@ -5,7 +5,6 @@ + */ + + #include +-#include + #include + #include + #include +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0004-CI-enforce-packages-upgrade-for-Msys2-on-Windows.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0004-CI-enforce-packages-upgrade-for-Msys2-on-Windows.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0004-CI-enforce-packages-upgrade-for-Msys2-on-Windows.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0004-CI-enforce-packages-upgrade-for-Msys2-on-Windows.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,40 @@ +From b86e72e83674cfdbfb1870bcdd8f53e41edd00d9 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 17:24:23 +0900 +Subject: [PATCH 1/1] CI: enforce packages upgrade for Msys2 on Windows + +We need to install libgnutls-devel package to build the host tool, +mkeficapsule, and as of now, there seems to be a depencency conflict +in the current msys2 installer; + + :: installing libp11-kit (0.24.1-1) breaks dependency \ + 'libp11-kit=0.23.22' required by p11-kit + +To resolve this conflict, however, the initial "pacman -Syyuu" in +'tools_only_windows' job is not enough. Another "pacman -Su" will +enforce all the out-of-date packages being upgraded. +(Probably the first "-Syyuu" can be changed to "-Syu".) + +See the installation steps in + https://www.msys2.org/ + +Signed-off-by: AKASHI Takahiro +--- + .azure-pipelines.yml | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml +index 8801ff7d..462b019e 100644 +--- a/.azure-pipelines.yml ++++ b/.azure-pipelines.yml +@@ -21,6 +21,7 @@ jobs: + - script: | + sfx.exe -y -o%CD:~0,2%\ + %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Syyuu" ++ %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Su" + displayName: 'Update MSYS2' + - script: | + %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm --needed -Sy make gcc bison flex diffutils openssl-devel" +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0005-tools-build-mkeficapsule-with-tools-only_defconfig.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0005-tools-build-mkeficapsule-with-tools-only_defconfig.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0005-tools-build-mkeficapsule-with-tools-only_defconfig.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0005-tools-build-mkeficapsule-with-tools-only_defconfig.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,59 @@ +From 1d1c46297be1f6ba124b7fe5e2050bacd2e649c4 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:34 +0900 +Subject: [PATCH 1/1] tools: build mkeficapsule with tools-only_defconfig + +Add CONFIG_TOOLS_MKEFICAPSULE. Then we want to always build mkeficapsule +if tools-only_defconfig is used. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +--- + configs/tools-only_defconfig | 1 + + tools/Kconfig | 8 ++++++++ + tools/Makefile | 3 +-- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig +index f482c9a1..5427797d 100644 +--- a/configs/tools-only_defconfig ++++ b/configs/tools-only_defconfig +@@ -31,3 +31,4 @@ CONFIG_I2C_EDID=y + # CONFIG_VIRTIO_MMIO is not set + # CONFIG_VIRTIO_PCI is not set + # CONFIG_VIRTIO_SANDBOX is not set ++CONFIG_TOOLS_MKEFICAPSULE=y +diff --git a/tools/Kconfig b/tools/Kconfig +index 91ce8ae3..117c921d 100644 +--- a/tools/Kconfig ++++ b/tools/Kconfig +@@ -90,4 +90,12 @@ config TOOLS_SHA512 + help + Enable SHA512 support in the tools builds + ++config TOOLS_MKEFICAPSULE ++ bool "Build efimkcapsule command" ++ default y if EFI_CAPSULE_ON_DISK ++ help ++ This command allows users to create a UEFI capsule file and, ++ optionally sign that file. If you want to enable UEFI capsule ++ update feature on your target, you certainly need this. ++ + endmenu +diff --git a/tools/Makefile b/tools/Makefile +index b3941f92..ef50e650 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -238,8 +238,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 ++hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule + + # We build some files with extra pedantic flags to try to minimize things + # that won't build on some weird host compiler -- though there are lots of +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0006-tools-mkeficapsule-add-firmware-image-signing.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0006-tools-mkeficapsule-add-firmware-image-signing.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0006-tools-mkeficapsule-add-firmware-image-signing.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0006-tools-mkeficapsule-add-firmware-image-signing.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,731 @@ +From ac1ddd2f4de55b6c131d0e643b06a8e5284e13e3 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:35 +0900 +Subject: [PATCH 1/1] tools: mkeficapsule: add firmware image signing + +With this enhancement, mkeficapsule will be able to sign a capsule +file when it is created. A signature added will be used later +in the verification at FMP's SetImage() call. + +To do that, we need specify additional command parameters: + -monotonic-cout : monotonic count + -private-key : private key file + -certificate : certificate file +Only when all of those parameters are given, a signature will be added +to a capsule file. + +Users are expected to maintain and increment the monotonic count at +every time of the update for each firmware image. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +Acked-by: Ilias Apalodimas +--- + .azure-pipelines.yml | 2 +- + tools/Makefile | 1 + + tools/eficapsule.h | 116 +++++++++++++ + tools/mkeficapsule.c | 381 +++++++++++++++++++++++++++++++++++++++---- + 4 files changed, 465 insertions(+), 35 deletions(-) + create mode 100644 tools/eficapsule.h + +diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml +index 462b019e..ffb1146a 100644 +--- a/.azure-pipelines.yml ++++ b/.azure-pipelines.yml +@@ -24,7 +24,7 @@ jobs: + %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Su" + displayName: 'Update MSYS2' + - script: | +- %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm --needed -Sy make gcc bison flex diffutils openssl-devel" ++ %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm --needed -Sy make gcc bison flex diffutils openssl-devel libgnutls-devel" + displayName: 'Install Toolchain' + - script: | + echo make tools-only_defconfig tools-only NO_SDL=1 > build-tools.sh +diff --git a/tools/Makefile b/tools/Makefile +index ef50e650..4fd3d486 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -238,6 +238,7 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs + hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler + HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include + ++HOSTLDLIBS_mkeficapsule += -lgnutls + hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule + + # We build some files with extra pedantic flags to try to minimize things +diff --git a/tools/eficapsule.h b/tools/eficapsule.h +new file mode 100644 +index 00000000..69c9c58c +--- /dev/null ++++ b/tools/eficapsule.h +@@ -0,0 +1,116 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright 2021 Linaro Limited ++ * Author: AKASHI Takahiro ++ * ++ * derived from efi.h and efi_api.h to make the file POSIX-compliant ++ */ ++ ++#ifndef _EFI_CAPSULE_H ++#define _EFI_CAPSULE_H ++ ++#include ++ ++/* ++ * Gcc's predefined attributes are not recognized by clang. ++ */ ++#ifndef __packed ++#define __packed __attribute__((__packed__)) ++#endif ++ ++#ifndef __aligned ++#define __aligned(x) __attribute__((__aligned__(x))) ++#endif ++ ++typedef struct { ++ uint8_t b[16]; ++} efi_guid_t __aligned(8); ++ ++#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ ++ {{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \ ++ ((a) >> 24) & 0xff, \ ++ (b) & 0xff, ((b) >> 8) & 0xff, \ ++ (c) & 0xff, ((c) >> 8) & 0xff, \ ++ (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) } } ++ ++#define EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID \ ++ EFI_GUID(0x6dcbd5ed, 0xe82d, 0x4c44, 0xbd, 0xa1, \ ++ 0x71, 0x94, 0x19, 0x9a, 0xd9, 0x2a) ++ ++#define EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID \ ++ EFI_GUID(0xae13ff2d, 0x9ad4, 0x4e25, 0x9a, 0xc8, \ ++ 0x6d, 0x80, 0xb3, 0xb2, 0x21, 0x47) ++ ++#define EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID \ ++ EFI_GUID(0xe2bb9c06, 0x70e9, 0x4b14, 0x97, 0xa3, \ ++ 0x5a, 0x79, 0x13, 0x17, 0x6e, 0x3f) ++ ++#define EFI_CERT_TYPE_PKCS7_GUID \ ++ EFI_GUID(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9, \ ++ 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7) ++ ++/* flags */ ++#define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000 ++ ++struct efi_capsule_header { ++ efi_guid_t capsule_guid; ++ uint32_t header_size; ++ uint32_t flags; ++ uint32_t capsule_image_size; ++} __packed; ++ ++struct efi_firmware_management_capsule_header { ++ uint32_t version; ++ uint16_t embedded_driver_count; ++ uint16_t payload_item_count; ++ uint32_t item_offset_list[]; ++} __packed; ++ ++/* image_capsule_support */ ++#define CAPSULE_SUPPORT_AUTHENTICATION 0x0000000000000001 ++ ++struct efi_firmware_management_capsule_image_header { ++ uint32_t version; ++ efi_guid_t update_image_type_id; ++ uint8_t update_image_index; ++ uint8_t reserved[3]; ++ uint32_t update_image_size; ++ uint32_t update_vendor_code_size; ++ uint64_t update_hardware_instance; ++ uint64_t image_capsule_support; ++} __packed; ++ ++/** ++ * win_certificate_uefi_guid - A certificate that encapsulates ++ * a GUID-specific signature ++ * ++ * @hdr: Windows certificate header, cf. WIN_CERTIFICATE ++ * @cert_type: Certificate type ++ */ ++struct win_certificate_uefi_guid { ++ struct { ++ uint32_t dwLength; ++ uint16_t wRevision; ++ uint16_t wCertificateType; ++ } hdr; ++ efi_guid_t cert_type; ++} __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; ++} __packed; ++ ++#endif /* _EFI_CAPSULE_H */ +diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c +index d6e3725e..4b7fe15c 100644 +--- a/tools/mkeficapsule.c ++++ b/tools/mkeficapsule.c +@@ -5,6 +5,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -15,21 +16,13 @@ + #include + #include + +-typedef __u8 u8; +-typedef __u16 u16; +-typedef __u32 u32; +-typedef __u64 u64; +-typedef __s16 s16; +-typedef __s32 s32; ++#include + +-#define aligned_u64 __aligned_u64 ++#include ++#include ++#include + +-#ifndef __packed +-#define __packed __attribute__((packed)) +-#endif +- +-#include +-#include ++#include "eficapsule.h" + + static const char *tool_name = "mkeficapsule"; + +@@ -38,12 +31,19 @@ efi_guid_t efi_guid_image_type_uboot_fit = + EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID; + efi_guid_t efi_guid_image_type_uboot_raw = + EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; ++efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; ++ ++static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; + + static struct option options[] = { + {"fit", required_argument, NULL, 'f'}, + {"raw", required_argument, NULL, 'r'}, + {"index", required_argument, NULL, 'i'}, + {"instance", required_argument, NULL, 'I'}, ++ {"private-key", required_argument, NULL, 'p'}, ++ {"certificate", required_argument, NULL, 'c'}, ++ {"monotonic-count", required_argument, NULL, 'm'}, ++ {"dump-sig", no_argument, NULL, 'd'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0}, + }; +@@ -57,10 +57,40 @@ static void print_usage(void) + "\t-r, --raw new raw image file\n" + "\t-i, --index update image index\n" + "\t-I, --instance update hardware instance\n" ++ "\t-p, --private-key private key file\n" ++ "\t-c, --certificate signer's certificate file\n" ++ "\t-m, --monotonic-count monotonic count\n" ++ "\t-d, --dump_sig dump signature (*.p7)\n" + "\t-h, --help print a help message\n", + tool_name); + } + ++/** ++ * auth_context - authentication context ++ * @key_file: Path to a private key file ++ * @cert_file: Path to a certificate file ++ * @image_data: Pointer to firmware data ++ * @image_size: Size of firmware data ++ * @auth: Authentication header ++ * @sig_data: Signature data ++ * @sig_size: Size of signature data ++ * ++ * Data structure used in create_auth_data(). @key_file through ++ * @image_size are input parameters. @auth, @sig_data and @sig_size ++ * are filled in by create_auth_data(). ++ */ ++struct auth_context { ++ char *key_file; ++ char *cert_file; ++ uint8_t *image_data; ++ size_t image_size; ++ struct efi_firmware_image_authentication auth; ++ uint8_t *sig_data; ++ size_t sig_size; ++}; ++ ++static int dump_sig; ++ + /** + * read_bin_file - read a firmware binary file + * @bin: Path to a firmware binary file +@@ -74,7 +104,7 @@ static void print_usage(void) + * * 0 - on success + * * -1 - on failure + */ +-static int read_bin_file(char *bin, void **data, off_t *bin_size) ++static int read_bin_file(char *bin, uint8_t **data, off_t *bin_size) + { + FILE *g; + struct stat bin_stat; +@@ -146,6 +176,205 @@ static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg) + return 0; + } + ++/** ++ * create_auth_data - compose authentication data in capsule ++ * @auth_context: Pointer to authentication context ++ * ++ * Fill up an authentication header (.auth) and signature data (.sig_data) ++ * in @auth_context, using library functions from openssl. ++ * All the parameters in @auth_context must be filled in by a caller. ++ * ++ * Return: ++ * * 0 - on success ++ * * -1 - on failure ++ */ ++static int create_auth_data(struct auth_context *ctx) ++{ ++ gnutls_datum_t cert; ++ gnutls_datum_t key; ++ off_t file_size; ++ gnutls_privkey_t pkey; ++ gnutls_x509_crt_t x509; ++ gnutls_pkcs7_t pkcs7; ++ gnutls_datum_t data; ++ gnutls_datum_t signature; ++ int ret; ++ ++ ret = read_bin_file(ctx->cert_file, &cert.data, &file_size); ++ if (ret < 0) ++ return -1; ++ if (file_size > UINT_MAX) ++ return -1; ++ cert.size = file_size; ++ ++ ret = read_bin_file(ctx->key_file, &key.data, &file_size); ++ if (ret < 0) ++ return -1; ++ if (ret < 0) ++ return -1; ++ if (file_size > UINT_MAX) ++ return -1; ++ key.size = file_size; ++ ++ /* ++ * For debugging, ++ * gnutls_global_set_time_function(mytime); ++ * gnutls_global_set_log_function(tls_log_func); ++ * gnutls_global_set_log_level(6); ++ */ ++ ++ ret = gnutls_privkey_init(&pkey); ++ if (ret < 0) { ++ fprintf(stderr, "error in gnutls_privkey_init(): %s\n", ++ gnutls_strerror(ret)); ++ return -1; ++ } ++ ++ ret = gnutls_x509_crt_init(&x509); ++ if (ret < 0) { ++ fprintf(stderr, "error in gnutls_x509_crt_init(): %s\n", ++ gnutls_strerror(ret)); ++ return -1; ++ } ++ ++ /* load a private key */ ++ ret = gnutls_privkey_import_x509_raw(pkey, &key, GNUTLS_X509_FMT_PEM, ++ 0, 0); ++ if (ret < 0) { ++ fprintf(stderr, ++ "error in gnutls_privkey_import_x509_raw(): %s\n", ++ gnutls_strerror(ret)); ++ return -1; ++ } ++ ++ /* load x509 certificate */ ++ ret = gnutls_x509_crt_import(x509, &cert, GNUTLS_X509_FMT_PEM); ++ if (ret < 0) { ++ fprintf(stderr, "error in gnutls_x509_crt_import(): %s\n", ++ gnutls_strerror(ret)); ++ return -1; ++ } ++ ++ /* generate a PKCS #7 structure */ ++ ret = gnutls_pkcs7_init(&pkcs7); ++ if (ret < 0) { ++ fprintf(stderr, "error in gnutls_pkcs7_init(): %s\n", ++ gnutls_strerror(ret)); ++ return -1; ++ } ++ ++ /* sign */ ++ /* ++ * Data should have ++ * * firmware image ++ * * monotonic count ++ * in this order! ++ * See EDK2's FmpAuthenticatedHandlerRsa2048Sha256() ++ */ ++ data.size = ctx->image_size + sizeof(ctx->auth.monotonic_count); ++ data.data = malloc(data.size); ++ if (!data.data) { ++ fprintf(stderr, "allocating memory (0x%x) failed\n", data.size); ++ return -1; ++ } ++ memcpy(data.data, ctx->image_data, ctx->image_size); ++ memcpy(data.data + ctx->image_size, &ctx->auth.monotonic_count, ++ sizeof(ctx->auth.monotonic_count)); ++ ++ ret = gnutls_pkcs7_sign(pkcs7, x509, pkey, &data, NULL, NULL, ++ GNUTLS_DIG_SHA256, ++ /* GNUTLS_PKCS7_EMBED_DATA? */ ++ GNUTLS_PKCS7_INCLUDE_CERT | ++ GNUTLS_PKCS7_INCLUDE_TIME); ++ if (ret < 0) { ++ fprintf(stderr, "error in gnutls_pkcs7)sign(): %s\n", ++ gnutls_strerror(ret)); ++ return -1; ++ } ++ ++ /* export */ ++ ret = gnutls_pkcs7_export2(pkcs7, GNUTLS_X509_FMT_DER, &signature); ++ if (ret < 0) { ++ fprintf(stderr, "error in gnutls_pkcs7_export2: %s\n", ++ gnutls_strerror(ret)); ++ return -1; ++ } ++ ctx->sig_data = signature.data; ++ ctx->sig_size = signature.size; ++ ++ /* fill auth_info */ ++ ctx->auth.auth_info.hdr.dwLength = sizeof(ctx->auth.auth_info) ++ + ctx->sig_size; ++ ctx->auth.auth_info.hdr.wRevision = WIN_CERT_REVISION_2_0; ++ ctx->auth.auth_info.hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID; ++ memcpy(&ctx->auth.auth_info.cert_type, &efi_guid_cert_type_pkcs7, ++ sizeof(efi_guid_cert_type_pkcs7)); ++ ++ /* ++ * For better clean-ups, ++ * gnutls_pkcs7_deinit(pkcs7); ++ * gnutls_privkey_deinit(pkey); ++ * gnutls_x509_crt_deinit(x509); ++ * free(cert.data); ++ * free(key.data); ++ * if error ++ * gnutls_free(signature.data); ++ */ ++ ++ return 0; ++} ++ ++/** ++ * dump_signature - dump out a signature ++ * @path: Path to a capsule file ++ * @signature: Signature data ++ * @sig_size: Size of signature data ++ * ++ * Signature data pointed to by @signature will be saved into ++ * a file whose file name is @path with ".p7" suffix. ++ * ++ * Return: ++ * * 0 - on success ++ * * -1 - on failure ++ */ ++static int dump_signature(const char *path, uint8_t *signature, size_t sig_size) ++{ ++ char *sig_path; ++ FILE *f; ++ size_t size; ++ int ret = -1; ++ ++ sig_path = malloc(strlen(path) + 3 + 1); ++ if (!sig_path) ++ return ret; ++ ++ sprintf(sig_path, "%s.p7", path); ++ f = fopen(sig_path, "w"); ++ if (!f) ++ goto err; ++ ++ size = fwrite(signature, 1, sig_size, f); ++ if (size == sig_size) ++ ret = 0; ++ ++ fclose(f); ++err: ++ free(sig_path); ++ return ret; ++} ++ ++/** ++ * free_sig_data - free out signature data ++ * @ctx: Pointer to authentication context ++ * ++ * Free signature data allocated in create_auth_data(). ++ */ ++static void free_sig_data(struct auth_context *ctx) ++{ ++ if (ctx->sig_size) ++ gnutls_free(ctx->sig_data); ++} ++ + /** + * create_fwbin - create an uefi capsule file + * @path: Path to a created capsule file +@@ -167,23 +396,25 @@ static int write_capsule_file(FILE *f, void *data, size_t size, const char *msg) + * * -1 - on failure + */ + static int create_fwbin(char *path, char *bin, efi_guid_t *guid, +- unsigned long index, unsigned long instance) ++ unsigned long index, unsigned long instance, ++ uint64_t mcount, char *privkey_file, char *cert_file) + { + struct efi_capsule_header header; + struct efi_firmware_management_capsule_header capsule; + struct efi_firmware_management_capsule_image_header image; ++ struct auth_context auth_context; + FILE *f; +- void *data; ++ uint8_t *data; + off_t bin_size; +- u64 offset; ++ uint64_t offset; + int ret; + + #ifdef DEBUG +- printf("For output: %s\n", path); +- printf("\tbin: %s\n\ttype: %pUl\n", bin, guid); +- printf("\tindex: %ld\n\tinstance: %ld\n", index, instance); ++ fprintf(stderr, "For output: %s\n", path); ++ fprintf(stderr, "\tbin: %s\n\ttype: %pUl\n", bin, guid); ++ fprintf(stderr, "\tindex: %lu\n\tinstance: %lu\n", index, instance); + #endif +- ++ auth_context.sig_size = 0; + f = NULL; + data = NULL; + ret = -1; +@@ -194,6 +425,27 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + if (read_bin_file(bin, &data, &bin_size)) + goto err; + ++ /* first, calculate signature to determine its size */ ++ if (privkey_file && cert_file) { ++ auth_context.key_file = privkey_file; ++ auth_context.cert_file = cert_file; ++ auth_context.auth.monotonic_count = mcount; ++ auth_context.image_data = data; ++ auth_context.image_size = bin_size; ++ ++ if (create_auth_data(&auth_context)) { ++ fprintf(stderr, "Signing firmware image failed\n"); ++ goto err; ++ } ++ ++ if (dump_sig && ++ dump_signature(path, auth_context.sig_data, ++ auth_context.sig_size)) { ++ fprintf(stderr, "Creating signature file failed\n"); ++ goto err; ++ } ++ } ++ + /* + * write a capsule file + */ +@@ -211,9 +463,12 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + /* TODO: The current implementation ignores flags */ + header.flags = CAPSULE_FLAGS_PERSIST_ACROSS_RESET; + header.capsule_image_size = sizeof(header) +- + sizeof(capsule) + sizeof(u64) ++ + sizeof(capsule) + sizeof(uint64_t) + + sizeof(image) + + bin_size; ++ if (auth_context.sig_size) ++ header.capsule_image_size += sizeof(auth_context.auth) ++ + auth_context.sig_size; + if (write_capsule_file(f, &header, sizeof(header), + "Capsule header")) + goto err; +@@ -229,7 +484,7 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + "Firmware capsule header")) + goto err; + +- offset = sizeof(capsule) + sizeof(u64); ++ offset = sizeof(capsule) + sizeof(uint64_t); + if (write_capsule_file(f, &offset, sizeof(offset), + "Offset to capsule image")) + goto err; +@@ -244,13 +499,32 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + image.reserved[1] = 0; + image.reserved[2] = 0; + image.update_image_size = bin_size; ++ if (auth_context.sig_size) ++ image.update_image_size += sizeof(auth_context.auth) ++ + auth_context.sig_size; + image.update_vendor_code_size = 0; /* none */ + image.update_hardware_instance = instance; + image.image_capsule_support = 0; ++ if (auth_context.sig_size) ++ image.image_capsule_support |= CAPSULE_SUPPORT_AUTHENTICATION; + if (write_capsule_file(f, &image, sizeof(image), + "Firmware capsule image header")) + goto err; + ++ /* ++ * signature ++ */ ++ if (auth_context.sig_size) { ++ if (write_capsule_file(f, &auth_context.auth, ++ sizeof(auth_context.auth), ++ "Authentication header")) ++ goto err; ++ ++ if (write_capsule_file(f, auth_context.sig_data, ++ auth_context.sig_size, "Signature")) ++ goto err; ++ } ++ + /* + * firmware binary + */ +@@ -261,28 +535,43 @@ static int create_fwbin(char *path, char *bin, efi_guid_t *guid, + err: + if (f) + fclose(f); ++ free_sig_data(&auth_context); + free(data); + + return ret; + } + +-/* +- * Usage: +- * $ mkeficapsule -f ++/** ++ * main - main entry function of mkeficapsule ++ * @argc: Number of arguments ++ * @argv: Array of pointers to arguments ++ * ++ * Create an uefi capsule file, optionally signing it. ++ * Parse all the arguments and pass them on to create_fwbin(). ++ * ++ * Return: ++ * * 0 - on success ++ * * -1 - on failure + */ + int main(int argc, char **argv) + { + char *file; + efi_guid_t *guid; + unsigned long index, instance; ++ uint64_t mcount; ++ char *privkey_file, *cert_file; + int c, idx; + + file = NULL; + guid = NULL; + index = 0; + instance = 0; ++ mcount = 0; ++ privkey_file = NULL; ++ cert_file = NULL; ++ dump_sig = 0; + for (;;) { +- c = getopt_long(argc, argv, "f:r:i:I:v:h", options, &idx); ++ c = getopt_long(argc, argv, opts_short, options, &idx); + if (c == -1) + break; + +@@ -290,7 +579,7 @@ int main(int argc, char **argv) + case 'f': + if (file) { + fprintf(stderr, "Image already specified\n"); +- return -1; ++ exit(EXIT_FAILURE); + } + file = optarg; + guid = &efi_guid_image_type_uboot_fit; +@@ -298,7 +587,7 @@ int main(int argc, char **argv) + case 'r': + if (file) { + fprintf(stderr, "Image already specified\n"); +- return -1; ++ exit(EXIT_FAILURE); + } + file = optarg; + guid = &efi_guid_image_type_uboot_raw; +@@ -309,14 +598,38 @@ int main(int argc, char **argv) + case 'I': + instance = strtoul(optarg, NULL, 0); + break; ++ case 'p': ++ if (privkey_file) { ++ fprintf(stderr, ++ "Private Key already specified\n"); ++ exit(EXIT_FAILURE); ++ } ++ privkey_file = optarg; ++ break; ++ case 'c': ++ if (cert_file) { ++ fprintf(stderr, ++ "Certificate file already specified\n"); ++ exit(EXIT_FAILURE); ++ } ++ cert_file = optarg; ++ break; ++ case 'm': ++ mcount = strtoul(optarg, NULL, 0); ++ break; ++ case 'd': ++ dump_sig = 1; ++ break; + case 'h': + print_usage(); +- return 0; ++ exit(EXIT_SUCCESS); + } + } + +- /* need an output file */ +- if (argc != optind + 1) { ++ /* check necessary parameters */ ++ if ((argc != optind + 1) || !file || ++ ((privkey_file && !cert_file) || ++ (!privkey_file && cert_file))) { + print_usage(); + exit(EXIT_FAILURE); + } +@@ -327,8 +640,8 @@ int main(int argc, char **argv) + exit(EXIT_SUCCESS); + } + +- if (create_fwbin(argv[optind], file, guid, index, instance) +- < 0) { ++ if (create_fwbin(argv[optind], file, guid, index, instance, ++ mcount, privkey_file, cert_file) < 0) { + fprintf(stderr, "Creating firmware capsule failed\n"); + exit(EXIT_FAILURE); + } +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0007-tools-mkeficapsule-add-man-page.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0007-tools-mkeficapsule-add-man-page.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0007-tools-mkeficapsule-add-man-page.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0007-tools-mkeficapsule-add-man-page.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,136 @@ +From 2500647f8cb68878950c75a367421a6b7d9d902f Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:36 +0900 +Subject: [PATCH 1/1] tools: mkeficapsule: add man page + +Add a man page for mkeficapsule command. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +Acked-by: Ilias Apalodimas +--- + MAINTAINERS | 1 + + doc/mkeficapsule.1 | 99 ++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 100 insertions(+) + create mode 100644 doc/mkeficapsule.1 + +diff --git a/MAINTAINERS b/MAINTAINERS +index 90666ce3..2b73feff 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -726,6 +726,7 @@ S: Maintained + T: git https://source.denx.de/u-boot/custodians/u-boot-efi.git + F: doc/api/efi.rst + F: doc/develop/uefi/* ++F: doc/mkeficapsule.1 + F: doc/usage/bootefi.rst + F: drivers/rtc/emul_rtc.c + F: include/capitalization.h +diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 +new file mode 100644 +index 00000000..680362f5 +--- /dev/null ++++ b/doc/mkeficapsule.1 +@@ -0,0 +1,99 @@ ++.\" SPDX-License-Identifier: GPL-2.0+ ++.\" Copyright (c) 2021, Linaro Limited ++.\" written by AKASHI Takahiro ++.TH MAEFICAPSULE 1 "May 2021" ++ ++.SH NAME ++mkeficapsule \- Generate EFI capsule file for U-Boot ++ ++.SH SYNOPSIS ++.B mkeficapsule ++.RI [ options "] " capsule-file ++ ++.SH "DESCRIPTION" ++.B mkeficapsule ++command is used to create an EFI capsule file for use with the U-Boot ++EFI capsule update. ++A capsule file may contain various type of firmware blobs which ++are to be applied to the system and must be placed in the specific ++directory on the UEFI system partition. ++An update will be automatically executed at next reboot. ++ ++Optionally, a capsule file can be signed with a given private key. ++In this case, the update will be authenticated by verifying the signature ++before applying. ++ ++.B mkeficapsule ++supports two different format of image files: ++.TP ++.I raw image ++format is a single binary blob of any type of firmware. ++ ++.TP ++.I FIT (Flattened Image Tree) image ++format is the same as used in the new uImage format and allows for ++multiple binary blobs in a single capsule file. ++This type of image file can be generated by ++.BR mkimage . ++ ++.SH "OPTIONS" ++One of ++.BR --fit " or " --raw ++option must be specified. ++ ++.TP ++.BI "-f\fR,\fB --fit " fit-image-file ++Specify a FIT image file ++ ++.TP ++.BI "-r\fR,\fB --raw " raw-image-file ++Specify a raw image file ++ ++.TP ++.BI "-i\fR,\fB --index " index ++Specify an image index ++ ++.TP ++.BI "-I\fR,\fB --instance " instance ++Specify a hardware instance ++ ++.TP ++.BR -h ", " --help ++Print a help message ++ ++.PP ++With signing, ++.BR --private-key ", " --certificate " and " --monotonic-count ++are all mandatory. ++ ++.TP ++.BI "-p\fR,\fB --private-key " private-key-file ++Specify signer's private key file in PEM ++ ++.TP ++.BI "-c\fR,\fB --certificate " certificate-file ++Specify signer's certificate file in EFI certificate list format ++ ++.TP ++.BI "-m\fR,\fB --monotonic-count " count ++Specify a monotonic count which is set to be monotonically incremented ++at every firmware update. ++ ++.TP ++.B "-d\fR,\fB --dump_sig" ++Dump signature data into *.p7 file ++ ++.PP ++.SH FILES ++.TP ++.I /EFI/UpdateCapsule ++The directory in which all capsule files be placed ++ ++.SH SEE ALSO ++.BR mkimage (1) ++ ++.SH AUTHORS ++Written by AKASHI Takahiro ++ ++.SH HOMEPAGE ++http://www.denx.de/wiki/U-Boot/WebHome +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0008-doc-update-UEFI-document-for-usage-of-mkeficapsule.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0008-doc-update-UEFI-document-for-usage-of-mkeficapsule.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0008-doc-update-UEFI-document-for-usage-of-mkeficapsule.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0008-doc-update-UEFI-document-for-usage-of-mkeficapsule.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,220 @@ +From 38b0e1237cd7da8d2a9ba958a363e4c7b9739896 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:37 +0900 +Subject: [PATCH 1/1] doc: update UEFI document for usage of mkeficapsule + +Now we can use mkeficapsule command instead of EDK-II's script +to create a signed capsule file. So update the instruction for +capsule authentication. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +Acked-by: Ilias Apalodimas +--- + doc/develop/uefi/uefi.rst | 151 +++++++++++++++++++------------------- + 1 file changed, 76 insertions(+), 75 deletions(-) + +diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst +index 43fb10f7..52a38c6b 100644 +--- a/doc/develop/uefi/uefi.rst ++++ b/doc/develop/uefi/uefi.rst +@@ -284,37 +284,56 @@ Support has been added for the UEFI capsule update feature which + enables updating the U-Boot image using the UEFI firmware management + protocol (FMP). The capsules are not passed to the firmware through + the UpdateCapsule runtime service. Instead, capsule-on-disk +-functionality is used for fetching the capsule from the EFI System +-Partition (ESP) by placing the capsule file under the +-\EFI\UpdateCapsule directory. +- +-The directory \EFI\UpdateCapsule is checked for capsules only within the +-EFI system partition on the device specified in the active boot option +-determined by reference to BootNext variable or BootOrder variable processing. +-The active Boot Variable is the variable with highest priority BootNext or +-within BootOrder that refers to a device found to be present. Boot variables +-in BootOrder but referring to devices not present are ignored when determining +-active boot variable. +-Before starting a capsule update make sure your capsules are installed in the +-correct ESP partition or set BootNext. ++functionality is used for fetching capsules from the EFI System ++Partition (ESP) by placing capsule files under the directory:: ++ ++ \EFI\UpdateCapsule ++ ++The directory is checked for capsules only within the ++EFI system partition on the device specified in the active boot option, ++which is determined by BootXXXX variable in BootNext, or if not, the highest ++priority one within BootOrder. Any BootXXXX variables referring to devices ++not present are ignored when determining the active boot option. ++ ++Please note that capsules will be applied in the alphabetic order of ++capsule file names. ++ ++Creating a capsule file ++*********************** ++ ++A capsule file can be created by using tools/mkeficapsule. ++To build this tool, enable:: ++ ++ CONFIG_TOOLS_MKEFICAPSULE=y ++ CONFIG_TOOLS_LIBCRYPTO=y ++ ++Run the following command ++ ++.. code-block:: console ++ ++ $ mkeficapsule \ ++ --index 1 --instance 0 \ ++ [--fit | --raw ] \ ++ + + Performing the update + ********************* + +-Since U-boot doesn't currently support SetVariable at runtime there's a Kconfig +-option (CONFIG_EFI_IGNORE_OSINDICATIONS) to disable the OsIndications variable +-check. If that option is enabled just copy your capsule to \EFI\UpdateCapsule. ++Put capsule files under the directory mentioned above. ++Then, following the UEFI specification, you'll need to set ++the EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED ++bit in OsIndications variable with + +-If that option is disabled, you'll need to set the OsIndications variable with:: ++.. code-block:: console + + => setenv -e -nv -bs -rt -v OsIndications =0x04 + +-Finally, the capsule update can be initiated either by rebooting the board, +-which is the preferred method, or by issuing the following command:: +- +- => efidebug capsule disk-update ++Since U-boot doesn't currently support SetVariable at runtime, its value ++won't be taken over across the reboot. If this is the case, you can skip ++this feature check with the Kconfig option (CONFIG_EFI_IGNORE_OSINDICATIONS) ++set. + +-**The efidebug command is should only be used during debugging/development.** ++Finally, the capsule update can be initiated by rebooting the board. + + Enabling Capsule Authentication + ******************************* +@@ -324,82 +343,64 @@ be updated by verifying the capsule signature. The capsule signature + is computed and prepended to the capsule payload at the time of + capsule generation. This signature is then verified by using the + public key stored as part of the X509 certificate. This certificate is +-in the form of an efi signature list (esl) file, which is embedded as +-part of U-Boot. ++in the form of an efi signature list (esl) file, which is embedded in ++a device tree. + + The capsule authentication feature can be enabled through the + following config, in addition to the configs listed above for capsule + update:: + + CONFIG_EFI_CAPSULE_AUTHENTICATE=y +- CONFIG_EFI_CAPSULE_KEY_PATH= + + The public and private keys used for the signing process are generated +-and used by the steps highlighted below:: ++and used by the steps highlighted below. + +- 1. Install utility commands on your host +- * OPENSSL ++1. Install utility commands on your host ++ * openssl + * efitools + +- 2. Create signing keys and certificate files on your host ++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 ++.. code-block:: console + +- $ openssl x509 -in CRT.crt -out CRT.cer -outform DER +- $ openssl x509 -inform DER -in CRT.cer -outform PEM -out CRT.pub.pem ++ $ 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 pkcs12 -export -out CRT.pfx -inkey CRT.key -in CRT.crt +- $ openssl pkcs12 -in CRT.pfx -nodes -out CRT.pem ++3. Run the following command to create and sign the capsule file + +-The capsule file can be generated by using the GenerateCapsule.py +-script in EDKII:: ++.. code-block:: console + +- $ ./BaseTools/BinWrappers/PosixLike/GenerateCapsule -e -o \ +- --monotonic-count --fw-version \ +- --lsv --guid \ +- e2bb9c06-70e9-4b14-97a3-5a7913176e3f --verbose \ +- --update-image-index --signer-private-cert \ +- /path/to/CRT.pem --trusted-public-cert \ +- /path/to/CRT.pub.pem --other-public-cert /path/to/CRT.pub.pem \ +- ++ $ mkeficapsule --monotonic-count 1 \ ++ --private-key CRT.key \ ++ --certificate CRT.crt \ ++ --index 1 --instance 0 \ ++ [--fit | --raw ] \ ++ + +-Place the capsule generated in the above step on the EFI System +-Partition under the EFI/UpdateCapsule directory ++4. Insert the signature list into a device tree in the following format:: + +-Testing on QEMU +-*************** ++ { ++ signature { ++ capsule-key = [ ]; ++ } ++ ... ++ } + +-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. ++You can do step-4 manually with + +-The capsule update feature is enabled with the following configuration +-settings:: ++.. code-block:: console + +- 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 ++ $ dtc -@ -I dts -O dtb -o signature.dtbo signature.dts ++ $ fdtoverlay -i orig.dtb -o new.dtb -v signature.dtbo + +-In addition, the following config needs to be disabled(QEMU ARM specific):: ++where signature.dts looks like:: + +- CONFIG_TFABOOT +- +-The capsule file can be generated by using the tools/mkeficapsule:: +- +- $ mkeficapsule --raw --index 1 ++ &{/} { ++ signature { ++ capsule-key = /incbin/("CRT.esl"); ++ }; ++ }; + + Executing the boot manager + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0009-test-py-efi_capsule-add-image-authentication-test.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0009-test-py-efi_capsule-add-image-authentication-test.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0009-test-py-efi_capsule-add-image-authentication-test.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0009-test-py-efi_capsule-add-image-authentication-test.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,397 @@ +From 438dde5e8b6859e9038c26294093840f9f49ffec Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:38 +0900 +Subject: [PATCH 1/1] test/py: efi_capsule: add image authentication test + +Add a couple of test cases against capsule image authentication +for capsule-on-disk, where only a signed capsule file with the verified +signature will be applied to the system. + +Due to the difficulty of embedding a public key (esl file) in U-Boot +binary during pytest setup time, all the keys/certificates are pre-created. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +Acked-by: Ilias Apalodimas +--- + .../py/tests/test_efi_capsule/capsule_defs.py | 5 + + test/py/tests/test_efi_capsule/conftest.py | 52 +++- + test/py/tests/test_efi_capsule/signature.dts | 10 + + .../test_capsule_firmware_signed.py | 254 ++++++++++++++++++ + 4 files changed, 318 insertions(+), 3 deletions(-) + create mode 100644 test/py/tests/test_efi_capsule/signature.dts + create mode 100644 test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py + +diff --git a/test/py/tests/test_efi_capsule/capsule_defs.py b/test/py/tests/test_efi_capsule/capsule_defs.py +index 4fd6353c..59b40f11 100644 +--- a/test/py/tests/test_efi_capsule/capsule_defs.py ++++ b/test/py/tests/test_efi_capsule/capsule_defs.py +@@ -3,3 +3,8 @@ + # Directories + CAPSULE_DATA_DIR = '/EFI/CapsuleTestData' + CAPSULE_INSTALL_DIR = '/EFI/UpdateCapsule' ++ ++# v1.5.1 or earlier of efitools has a bug in sha256 calculation, and ++# you need build a newer version on your own. ++# The path must terminate with '/' if it is not null. ++EFITOOLS_PATH = '' +diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py +index 6ad5608c..27c05971 100644 +--- a/test/py/tests/test_efi_capsule/conftest.py ++++ b/test/py/tests/test_efi_capsule/conftest.py +@@ -10,13 +10,13 @@ import pytest + from capsule_defs import * + + # +-# Fixture for UEFI secure boot test ++# Fixture for UEFI capsule test + # + +- + @pytest.fixture(scope='session') + def efi_capsule_data(request, u_boot_config): +- """Set up a file system to be used in UEFI capsule test. ++ """Set up a file system to be used in UEFI capsule and ++ authentication test. + + Args: + request: Pytest request object. +@@ -40,6 +40,36 @@ def efi_capsule_data(request, u_boot_config): + check_call('mkdir -p %s' % data_dir, shell=True) + check_call('mkdir -p %s' % install_dir, shell=True) + ++ capsule_auth_enabled = u_boot_config.buildconfig.get( ++ 'config_efi_capsule_authenticate') ++ if capsule_auth_enabled: ++ # Create private key (SIGNER.key) and certificate (SIGNER.crt) ++ check_call('cd %s; ' ++ 'openssl req -x509 -sha256 -newkey rsa:2048 ' ++ '-subj /CN=TEST_SIGNER/ -keyout SIGNER.key ' ++ '-out SIGNER.crt -nodes -days 365' ++ % data_dir, shell=True) ++ check_call('cd %s; %scert-to-efi-sig-list SIGNER.crt SIGNER.esl' ++ % (data_dir, EFITOOLS_PATH), shell=True) ++ ++ # Update dtb adding capsule certificate ++ check_call('cd %s; ' ++ 'cp %s/test/py/tests/test_efi_capsule/signature.dts .' ++ % (data_dir, u_boot_config.source_dir), shell=True) ++ check_call('cd %s; ' ++ 'dtc -@ -I dts -O dtb -o signature.dtbo signature.dts; ' ++ 'fdtoverlay -i %s/arch/sandbox/dts/test.dtb ' ++ '-o test_sig.dtb signature.dtbo' ++ % (data_dir, u_boot_config.build_dir), shell=True) ++ ++ # Create *malicious* private key (SIGNER2.key) and certificate ++ # (SIGNER2.crt) ++ check_call('cd %s; ' ++ 'openssl req -x509 -sha256 -newkey rsa:2048 ' ++ '-subj /CN=TEST_SIGNER/ -keyout SIGNER2.key ' ++ '-out SIGNER2.crt -nodes -days 365' ++ % data_dir, shell=True) ++ + # Create capsule files + # two regions: one for u-boot.bin and the other for u-boot.env + check_call('cd %s; echo -n u-boot:Old > u-boot.bin.old; echo -n u-boot:New > u-boot.bin.new; echo -n u-boot-env:Old -> u-boot.env.old; echo -n u-boot-env:New > u-boot.env.new' % data_dir, +@@ -56,6 +86,22 @@ def efi_capsule_data(request, u_boot_config): + check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 Test02' % + (data_dir, u_boot_config.build_dir), + shell=True) ++ if capsule_auth_enabled: ++ # firmware signed with proper key ++ check_call('cd %s; ' ++ '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' ++ '--private-key SIGNER.key --certificate SIGNER.crt ' ++ '--raw u-boot.bin.new Test11' ++ % (data_dir, u_boot_config.build_dir), ++ shell=True) ++ # firmware signed with *mal* key ++ check_call('cd %s; ' ++ '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' ++ '--private-key SIGNER2.key ' ++ '--certificate SIGNER2.crt ' ++ '--raw u-boot.bin.new Test12' ++ % (data_dir, u_boot_config.build_dir), ++ shell=True) + + # Create a disk image with EFI system partition + check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat %s %s' % +diff --git a/test/py/tests/test_efi_capsule/signature.dts b/test/py/tests/test_efi_capsule/signature.dts +new file mode 100644 +index 00000000..078cfc76 +--- /dev/null ++++ b/test/py/tests/test_efi_capsule/signature.dts +@@ -0,0 +1,10 @@ ++// SPDX-License-Identifier: GPL-2.0+ ++ ++/dts-v1/; ++/plugin/; ++ ++&{/} { ++ signature { ++ capsule-key = /incbin/("SIGNER.esl"); ++ }; ++}; +diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py +new file mode 100644 +index 00000000..593b032e +--- /dev/null ++++ b/test/py/tests/test_efi_capsule/test_capsule_firmware_signed.py +@@ -0,0 +1,254 @@ ++# SPDX-License-Identifier: GPL-2.0+ ++# Copyright (c) 2021, Linaro Limited ++# Author: AKASHI Takahiro ++# ++# U-Boot UEFI: Firmware Update (Signed capsule) Test ++ ++""" ++This test verifies capsule-on-disk firmware update ++with signed capsule files ++""" ++ ++import pytest ++from capsule_defs import CAPSULE_DATA_DIR, CAPSULE_INSTALL_DIR ++ ++@pytest.mark.boardspec('sandbox') ++@pytest.mark.buildconfigspec('efi_capsule_firmware_raw') ++@pytest.mark.buildconfigspec('efi_capsule_authenticate') ++@pytest.mark.buildconfigspec('dfu') ++@pytest.mark.buildconfigspec('dfu_sf') ++@pytest.mark.buildconfigspec('cmd_efidebug') ++@pytest.mark.buildconfigspec('cmd_fat') ++@pytest.mark.buildconfigspec('cmd_memory') ++@pytest.mark.buildconfigspec('cmd_nvedit_efi') ++@pytest.mark.buildconfigspec('cmd_sf') ++@pytest.mark.slow ++class TestEfiCapsuleFirmwareSigned(object): ++ def test_efi_capsule_auth1( ++ self, u_boot_config, u_boot_console, efi_capsule_data): ++ """ ++ Test Case 1 - Update U-Boot on SPI Flash, raw image format ++ 0x100000-0x150000: U-Boot binary (but dummy) ++ ++ If the capsule is properly signed, the authentication ++ should pass and the firmware be updated. ++ """ ++ disk_img = efi_capsule_data ++ with u_boot_console.log.section('Test Case 1-a, before reboot'): ++ output = u_boot_console.run_command_list([ ++ 'host bind 0 %s' % disk_img, ++ 'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi', ++ 'efidebug boot order 1', ++ 'env set -e -nv -bs -rt OsIndications =0x0000000000000004', ++ 'env set dfu_alt_info ' ++ '"sf 0:0=u-boot-bin raw 0x100000 ' ++ '0x50000;u-boot-env raw 0x150000 0x200000"', ++ 'env save']) ++ ++ # initialize content ++ output = u_boot_console.run_command_list([ ++ 'sf probe 0:0', ++ 'fatload host 0:1 4000000 %s/u-boot.bin.old' ++ % CAPSULE_DATA_DIR, ++ 'sf write 4000000 100000 10', ++ 'sf read 5000000 100000 10', ++ 'md.b 5000000 10']) ++ assert 'Old' in ''.join(output) ++ ++ # place a capsule file ++ output = u_boot_console.run_command_list([ ++ 'fatload host 0:1 4000000 %s/Test11' % CAPSULE_DATA_DIR, ++ 'fatwrite host 0:1 4000000 %s/Test11 $filesize' ++ % CAPSULE_INSTALL_DIR, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test11' in ''.join(output) ++ ++ # reboot ++ mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule' ++ u_boot_console.config.dtb = mnt_point + CAPSULE_DATA_DIR \ ++ + '/test_sig.dtb' ++ u_boot_console.restart_uboot() ++ ++ capsule_early = u_boot_config.buildconfig.get( ++ 'config_efi_capsule_on_disk_early') ++ with u_boot_console.log.section('Test Case 1-b, after reboot'): ++ if not capsule_early: ++ # make sure that dfu_alt_info exists even persistent variables ++ # are not available. ++ output = u_boot_console.run_command_list([ ++ 'env set dfu_alt_info ' ++ '"sf 0:0=u-boot-bin raw 0x100000 ' ++ '0x50000;u-boot-env raw 0x150000 0x200000"', ++ 'host bind 0 %s' % disk_img, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test11' in ''.join(output) ++ ++ # need to run uefi command to initiate capsule handling ++ output = u_boot_console.run_command( ++ 'env print -e Capsule0000') ++ ++ output = u_boot_console.run_command_list([ ++ 'host bind 0 %s' % disk_img, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test11' not in ''.join(output) ++ ++ output = u_boot_console.run_command_list([ ++ 'sf probe 0:0', ++ 'sf read 4000000 100000 10', ++ 'md.b 4000000 10']) ++ assert 'u-boot:New' in ''.join(output) ++ ++ def test_efi_capsule_auth2( ++ self, u_boot_config, u_boot_console, efi_capsule_data): ++ """ ++ Test Case 2 - Update U-Boot on SPI Flash, raw image format ++ 0x100000-0x150000: U-Boot binary (but dummy) ++ ++ If the capsule is signed but with an invalid key, ++ the authentication should fail and the firmware ++ not be updated. ++ """ ++ disk_img = efi_capsule_data ++ with u_boot_console.log.section('Test Case 2-a, before reboot'): ++ output = u_boot_console.run_command_list([ ++ 'host bind 0 %s' % disk_img, ++ 'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi', ++ 'efidebug boot order 1', ++ 'env set -e -nv -bs -rt OsIndications =0x0000000000000004', ++ 'env set dfu_alt_info ' ++ '"sf 0:0=u-boot-bin raw 0x100000 ' ++ '0x50000;u-boot-env raw 0x150000 0x200000"', ++ 'env save']) ++ ++ # initialize content ++ output = u_boot_console.run_command_list([ ++ 'sf probe 0:0', ++ 'fatload host 0:1 4000000 %s/u-boot.bin.old' ++ % CAPSULE_DATA_DIR, ++ 'sf write 4000000 100000 10', ++ 'sf read 5000000 100000 10', ++ 'md.b 5000000 10']) ++ assert 'Old' in ''.join(output) ++ ++ # place a capsule file ++ output = u_boot_console.run_command_list([ ++ 'fatload host 0:1 4000000 %s/Test12' % CAPSULE_DATA_DIR, ++ 'fatwrite host 0:1 4000000 %s/Test12 $filesize' ++ % CAPSULE_INSTALL_DIR, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test12' in ''.join(output) ++ ++ # reboot ++ mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule' ++ u_boot_console.config.dtb = mnt_point + CAPSULE_DATA_DIR \ ++ + '/test_sig.dtb' ++ u_boot_console.restart_uboot() ++ ++ capsule_early = u_boot_config.buildconfig.get( ++ 'config_efi_capsule_on_disk_early') ++ with u_boot_console.log.section('Test Case 2-b, after reboot'): ++ if not capsule_early: ++ # make sure that dfu_alt_info exists even persistent variables ++ # are not available. ++ output = u_boot_console.run_command_list([ ++ 'env set dfu_alt_info ' ++ '"sf 0:0=u-boot-bin raw 0x100000 ' ++ '0x50000;u-boot-env raw 0x150000 0x200000"', ++ 'host bind 0 %s' % disk_img, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test12' in ''.join(output) ++ ++ # need to run uefi command to initiate capsule handling ++ output = u_boot_console.run_command( ++ 'env print -e Capsule0000') ++ ++ # deleted any way ++ output = u_boot_console.run_command_list([ ++ 'host bind 0 %s' % disk_img, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test12' not in ''.join(output) ++ ++ # TODO: check CapsuleStatus in CapsuleXXXX ++ ++ output = u_boot_console.run_command_list([ ++ 'sf probe 0:0', ++ 'sf read 4000000 100000 10', ++ 'md.b 4000000 10']) ++ assert 'u-boot:Old' in ''.join(output) ++ ++ def test_efi_capsule_auth3( ++ self, u_boot_config, u_boot_console, efi_capsule_data): ++ """ ++ Test Case 3 - Update U-Boot on SPI Flash, raw image format ++ 0x100000-0x150000: U-Boot binary (but dummy) ++ ++ If the capsule is not signed, the authentication ++ should fail and the firmware not be updated. ++ """ ++ disk_img = efi_capsule_data ++ with u_boot_console.log.section('Test Case 3-a, before reboot'): ++ output = u_boot_console.run_command_list([ ++ 'host bind 0 %s' % disk_img, ++ 'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi', ++ 'efidebug boot order 1', ++ 'env set -e -nv -bs -rt OsIndications =0x0000000000000004', ++ 'env set dfu_alt_info ' ++ '"sf 0:0=u-boot-bin raw 0x100000 ' ++ '0x50000;u-boot-env raw 0x150000 0x200000"', ++ 'env save']) ++ ++ # initialize content ++ output = u_boot_console.run_command_list([ ++ 'sf probe 0:0', ++ 'fatload host 0:1 4000000 %s/u-boot.bin.old' ++ % CAPSULE_DATA_DIR, ++ 'sf write 4000000 100000 10', ++ 'sf read 5000000 100000 10', ++ 'md.b 5000000 10']) ++ assert 'Old' in ''.join(output) ++ ++ # place a capsule file ++ output = u_boot_console.run_command_list([ ++ 'fatload host 0:1 4000000 %s/Test02' % CAPSULE_DATA_DIR, ++ 'fatwrite host 0:1 4000000 %s/Test02 $filesize' ++ % CAPSULE_INSTALL_DIR, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test02' in ''.join(output) ++ ++ # reboot ++ mnt_point = u_boot_config.persistent_data_dir + '/test_efi_capsule' ++ u_boot_console.config.dtb = mnt_point + CAPSULE_DATA_DIR \ ++ + '/test_sig.dtb' ++ u_boot_console.restart_uboot() ++ ++ capsule_early = u_boot_config.buildconfig.get( ++ 'config_efi_capsule_on_disk_early') ++ with u_boot_console.log.section('Test Case 3-b, after reboot'): ++ if not capsule_early: ++ # make sure that dfu_alt_info exists even persistent variables ++ # are not available. ++ output = u_boot_console.run_command_list([ ++ 'env set dfu_alt_info ' ++ '"sf 0:0=u-boot-bin raw 0x100000 ' ++ '0x50000;u-boot-env raw 0x150000 0x200000"', ++ 'host bind 0 %s' % disk_img, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test02' in ''.join(output) ++ ++ # need to run uefi command to initiate capsule handling ++ output = u_boot_console.run_command( ++ 'env print -e Capsule0000') ++ ++ # deleted any way ++ output = u_boot_console.run_command_list([ ++ 'host bind 0 %s' % disk_img, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test02' not in ''.join(output) ++ ++ # TODO: check CapsuleStatus in CapsuleXXXX ++ ++ output = u_boot_console.run_command_list([ ++ 'sf probe 0:0', ++ 'sf read 4000000 100000 10', ++ 'md.b 4000000 10']) ++ assert 'u-boot:Old' in ''.join(output) +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0010-tools-mkeficapsule-allow-for-specifying-GUID-explici.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0010-tools-mkeficapsule-allow-for-specifying-GUID-explici.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0010-tools-mkeficapsule-allow-for-specifying-GUID-explici.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0010-tools-mkeficapsule-allow-for-specifying-GUID-explici.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,302 @@ +From bc240890ceb59e6cd56de114aba4d8d2c4cafaa5 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:39 +0900 +Subject: [PATCH 1/1] tools: mkeficapsule: allow for specifying GUID explicitly + +The existing options, "--fit" and "--raw," are only used to put a proper +GUID in a capsule header, where GUID identifies a particular FMP (Firmware +Management Protocol) driver which then would handle the firmware binary in +a capsule. In fact, mkeficapsule does the exact same job in creating +a capsule file whatever the firmware binary type is. + +To prepare for the future extension, the command syntax will be a bit +modified to allow users to specify arbitrary GUID for their own FMP driver. +OLD: + [--fit | --raw ] +NEW: + [--fit | --raw | --guid ] + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +--- + .azure-pipelines.yml | 4 +- + doc/develop/uefi/uefi.rst | 4 +- + doc/mkeficapsule.1 | 26 ++++++++---- + tools/Makefile | 2 +- + tools/mkeficapsule.c | 85 ++++++++++++++++++++++++++++----------- + 5 files changed, 86 insertions(+), 35 deletions(-) + +diff --git a/.azure-pipelines.yml b/.azure-pipelines.yml +index ffb1146a..718c06f1 100644 +--- a/.azure-pipelines.yml ++++ b/.azure-pipelines.yml +@@ -24,7 +24,7 @@ jobs: + %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Su" + displayName: 'Update MSYS2' + - script: | +- %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm --needed -Sy make gcc bison flex diffutils openssl-devel libgnutls-devel" ++ %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm --needed -Sy make gcc bison flex diffutils openssl-devel libgnutls-devel libutil-linux-devel" + displayName: 'Install Toolchain' + - script: | + echo make tools-only_defconfig tools-only NO_SDL=1 > build-tools.sh +@@ -41,7 +41,7 @@ jobs: + pool: + vmImage: $(macos_vm) + steps: +- - script: brew install make ++ - script: brew install make ossp-uuid + displayName: Brew install dependencies + - script: | + gmake tools-only_config tools-only NO_SDL=1 \ +diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst +index 52a38c6b..b7bf1356 100644 +--- a/doc/develop/uefi/uefi.rst ++++ b/doc/develop/uefi/uefi.rst +@@ -375,8 +375,8 @@ and used by the steps highlighted below. + --private-key CRT.key \ + --certificate CRT.crt \ + --index 1 --instance 0 \ +- [--fit | --raw ] \ +- ++ [--fit | --raw | --guid + + 4. Insert the signature list into a device tree in the following format:: + +diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1 +index 680362f5..8babb27e 100644 +--- a/doc/mkeficapsule.1 ++++ b/doc/mkeficapsule.1 +@@ -8,7 +8,7 @@ mkeficapsule \- Generate EFI capsule file for U-Boot + + .SH SYNOPSIS + .B mkeficapsule +-.RI [ options "] " capsule-file ++.RI [ options "] " image-blob " " capsule-file + + .SH "DESCRIPTION" + .B mkeficapsule +@@ -24,7 +24,7 @@ In this case, the update will be authenticated by verifying the signature + before applying. + + .B mkeficapsule +-supports two different format of image files: ++takes any type of image files, including: + .TP + .I raw image + format is a single binary blob of any type of firmware. +@@ -36,18 +36,30 @@ multiple binary blobs in a single capsule file. + This type of image file can be generated by + .BR mkimage . + ++.PP ++If you want to use other types than above two, you should explicitly ++specify a guid for the FMP driver. ++ + .SH "OPTIONS" + One of +-.BR --fit " or " --raw ++.BR --fit ", " --raw " or " --guid + option must be specified. + + .TP +-.BI "-f\fR,\fB --fit " fit-image-file +-Specify a FIT image file ++.BR -f ", " --fit ++Indicate that the blob is a FIT image file + + .TP +-.BI "-r\fR,\fB --raw " raw-image-file +-Specify a raw image file ++.BR -r ", " --raw ++Indicate that the blob is a raw image file ++ ++.TP ++.BI "-g\fR,\fB --guid " guid-string ++Specify guid for image blob type. The format is: ++ xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ++ ++The first three elements are in little endian, while the rest ++is in big endian. + + .TP + .BI "-i\fR,\fB --index " index +diff --git a/tools/Makefile b/tools/Makefile +index 4fd3d486..6184f6f0 100644 +--- a/tools/Makefile ++++ b/tools/Makefile +@@ -238,7 +238,7 @@ hostprogs-$(CONFIG_MIPS) += mips-relocs + hostprogs-$(CONFIG_ASN1_COMPILER) += asn1_compiler + HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include + +-HOSTLDLIBS_mkeficapsule += -lgnutls ++HOSTLDLIBS_mkeficapsule += -lgnutls -luuid + hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += 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 4b7fe15c..f7590e48 100644 +--- a/tools/mkeficapsule.c ++++ b/tools/mkeficapsule.c +@@ -15,7 +15,7 @@ + + #include + #include +- ++#include + #include + + #include +@@ -33,11 +33,12 @@ efi_guid_t efi_guid_image_type_uboot_raw = + EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID; + efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID; + +-static const char *opts_short = "f:r:i:I:v:p:c:m:dh"; ++static const char *opts_short = "frg:i:I:v:p:c:m:dh"; + + static struct option options[] = { +- {"fit", required_argument, NULL, 'f'}, +- {"raw", required_argument, NULL, 'r'}, ++ {"fit", no_argument, NULL, 'f'}, ++ {"raw", no_argument, NULL, 'r'}, ++ {"guid", required_argument, NULL, 'g'}, + {"index", required_argument, NULL, 'i'}, + {"instance", required_argument, NULL, 'I'}, + {"private-key", required_argument, NULL, 'p'}, +@@ -50,11 +51,12 @@ static struct option options[] = { + + static void print_usage(void) + { +- printf("Usage: %s [options] \n" ++ fprintf(stderr, "Usage: %s [options] \n" + "Options:\n" + +- "\t-f, --fit new FIT image file\n" +- "\t-r, --raw new raw image file\n" ++ "\t-f, --fit FIT image type\n" ++ "\t-r, --raw raw image type\n" ++ "\t-g, --guid guid for image blob type\n" + "\t-i, --index update image index\n" + "\t-I, --instance update hardware instance\n" + "\t-p, --private-key private key file\n" +@@ -541,6 +543,37 @@ err: + return ret; + } + ++/** ++ * convert_uuid_to_guid() - convert UUID to GUID ++ * @buf: UUID binary ++ * ++ * UUID and GUID have the same data structure, but their binary ++ * formats are different due to the endianness. See lib/uuid.c. ++ * Since uuid_parse() can handle only UUID, this function must ++ * be called to get correct data for GUID when parsing a string. ++ * ++ * The correct data will be returned in @buf. ++ */ ++void convert_uuid_to_guid(unsigned char *buf) ++{ ++ unsigned char c; ++ ++ c = buf[0]; ++ buf[0] = buf[3]; ++ buf[3] = c; ++ c = buf[1]; ++ buf[1] = buf[2]; ++ buf[2] = c; ++ ++ c = buf[4]; ++ buf[4] = buf[5]; ++ buf[5] = c; ++ ++ c = buf[6]; ++ buf[6] = buf[7]; ++ buf[7] = c; ++} ++ + /** + * main - main entry function of mkeficapsule + * @argc: Number of arguments +@@ -555,14 +588,13 @@ err: + */ + int main(int argc, char **argv) + { +- char *file; + efi_guid_t *guid; ++ unsigned char uuid_buf[16]; + unsigned long index, instance; + uint64_t mcount; + char *privkey_file, *cert_file; + int c, idx; + +- file = NULL; + guid = NULL; + index = 0; + instance = 0; +@@ -577,21 +609,34 @@ int main(int argc, char **argv) + + switch (c) { + case 'f': +- if (file) { +- fprintf(stderr, "Image already specified\n"); ++ if (guid) { ++ fprintf(stderr, ++ "Image type already specified\n"); + exit(EXIT_FAILURE); + } +- file = optarg; + guid = &efi_guid_image_type_uboot_fit; + break; + case 'r': +- if (file) { +- fprintf(stderr, "Image already specified\n"); ++ if (guid) { ++ fprintf(stderr, ++ "Image type already specified\n"); + exit(EXIT_FAILURE); + } +- file = optarg; + guid = &efi_guid_image_type_uboot_raw; + break; ++ case 'g': ++ if (guid) { ++ fprintf(stderr, ++ "Image type already specified\n"); ++ exit(EXIT_FAILURE); ++ } ++ if (uuid_parse(optarg, uuid_buf)) { ++ fprintf(stderr, "Wrong guid format\n"); ++ exit(EXIT_FAILURE); ++ } ++ convert_uuid_to_guid(uuid_buf); ++ guid = (efi_guid_t *)uuid_buf; ++ break; + case 'i': + index = strtoul(optarg, NULL, 0); + break; +@@ -627,20 +672,14 @@ int main(int argc, char **argv) + } + + /* check necessary parameters */ +- if ((argc != optind + 1) || !file || ++ if ((argc != optind + 2) || !guid || + ((privkey_file && !cert_file) || + (!privkey_file && cert_file))) { + print_usage(); + exit(EXIT_FAILURE); + } + +- /* need a fit image file or raw image file */ +- if (!file) { +- print_usage(); +- exit(EXIT_SUCCESS); +- } +- +- if (create_fwbin(argv[optind], file, guid, index, instance, ++ if (create_fwbin(argv[argc - 1], argv[argc - 2], guid, index, instance, + mcount, privkey_file, cert_file) < 0) { + fprintf(stderr, "Creating firmware capsule failed\n"); + exit(EXIT_FAILURE); +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0011-test-py-efi_capsule-align-with-the-syntax-change-of-.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0011-test-py-efi_capsule-align-with-the-syntax-change-of-.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0011-test-py-efi_capsule-align-with-the-syntax-change-of-.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0011-test-py-efi_capsule-align-with-the-syntax-change-of-.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,35 @@ +From 435c6806ee5268b4ca7cfc97a16d14bdef4b5cb8 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:40 +0900 +Subject: [PATCH 1/1] test/py: efi_capsule: align with the syntax change of + mkeficapsule + +Since the syntax of mkeficapsule was changed in the previous commit, +we need to modify command line arguments in a pytest script. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +--- + test/py/tests/test_efi_capsule/conftest.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py +index 27c05971..a5a25c53 100644 +--- a/test/py/tests/test_efi_capsule/conftest.py ++++ b/test/py/tests/test_efi_capsule/conftest.py +@@ -80,10 +80,10 @@ def efi_capsule_data(request, u_boot_config): + check_call('cd %s; %s/tools/mkimage -f uboot_bin_env.its uboot_bin_env.itb' % + (data_dir, u_boot_config.build_dir), + shell=True) +- check_call('cd %s; %s/tools/mkeficapsule --fit uboot_bin_env.itb --index 1 Test01' % ++ check_call('cd %s; %s/tools/mkeficapsule --index 1 --fit uboot_bin_env.itb Test01' % + (data_dir, u_boot_config.build_dir), + shell=True) +- check_call('cd %s; %s/tools/mkeficapsule --raw u-boot.bin.new --index 1 Test02' % ++ check_call('cd %s; %s/tools/mkeficapsule --index 1 --raw u-boot.bin.new Test02' % + (data_dir, u_boot_config.build_dir), + shell=True) + if capsule_auth_enabled: +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0012-test-py-efi_capsule-add-a-test-for-guid-option.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0012-test-py-efi_capsule-add-a-test-for-guid-option.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0012-test-py-efi_capsule-add-a-test-for-guid-option.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0012-test-py-efi_capsule-add-a-test-for-guid-option.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,107 @@ +From 2b814ae7b485816a438d870aba2753ab178505aa Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:41 +0900 +Subject: [PATCH 1/1] test/py: efi_capsule: add a test for "--guid" option + +This test scenario tests a new feature of mkeficapsule, "--guid" option, +which allows us to specify FMP driver's guid explicitly at the command +line. + +Signed-off-by: AKASHI Takahiro +--- + test/py/tests/test_efi_capsule/conftest.py | 3 + + .../test_efi_capsule/test_capsule_firmware.py | 67 +++++++++++++++++++ + 2 files changed, 70 insertions(+) + +diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py +index a5a25c53..9076087a 100644 +--- a/test/py/tests/test_efi_capsule/conftest.py ++++ b/test/py/tests/test_efi_capsule/conftest.py +@@ -86,6 +86,9 @@ def efi_capsule_data(request, u_boot_config): + check_call('cd %s; %s/tools/mkeficapsule --index 1 --raw u-boot.bin.new Test02' % + (data_dir, u_boot_config.build_dir), + shell=True) ++ check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid E2BB9C06-70E9-4B14-97A3-5A7913176E3F u-boot.bin.new Test03' % ++ (data_dir, u_boot_config.build_dir), ++ shell=True) + if capsule_auth_enabled: + # firmware signed with proper key + check_call('cd %s; ' +diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware.py b/test/py/tests/test_efi_capsule/test_capsule_firmware.py +index 9eeaae27..9cc97356 100644 +--- a/test/py/tests/test_efi_capsule/test_capsule_firmware.py ++++ b/test/py/tests/test_efi_capsule/test_capsule_firmware.py +@@ -247,3 +247,70 @@ class TestEfiCapsuleFirmwareFit(object): + 'sf read 4000000 100000 10', + 'md.b 4000000 10']) + assert 'u-boot:New' in ''.join(output) ++ ++ def test_efi_capsule_fw4( ++ self, u_boot_config, u_boot_console, efi_capsule_data): ++ """ ++ Test Case 4 - Test "--guid" option of mkeficapsule ++ The test scenario is the same as Case 3. ++ """ ++ disk_img = efi_capsule_data ++ with u_boot_console.log.section('Test Case 4-a, before reboot'): ++ output = u_boot_console.run_command_list([ ++ 'host bind 0 %s' % disk_img, ++ 'efidebug boot add -b 1 TEST host 0:1 /helloworld.efi -s ""', ++ 'efidebug boot order 1', ++ 'env set -e -nv -bs -rt OsIndications =0x0000000000000004', ++ 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', ++ 'env save']) ++ ++ # initialize content ++ output = u_boot_console.run_command_list([ ++ 'sf probe 0:0', ++ 'fatload host 0:1 4000000 %s/u-boot.bin.old' % CAPSULE_DATA_DIR, ++ 'sf write 4000000 100000 10', ++ 'sf read 5000000 100000 10', ++ 'md.b 5000000 10']) ++ assert 'Old' in ''.join(output) ++ ++ # place a capsule file ++ output = u_boot_console.run_command_list([ ++ 'fatload host 0:1 4000000 %s/Test03' % CAPSULE_DATA_DIR, ++ 'fatwrite host 0:1 4000000 %s/Test03 $filesize' % CAPSULE_INSTALL_DIR, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test03' in ''.join(output) ++ ++ # reboot ++ u_boot_console.restart_uboot() ++ ++ capsule_early = u_boot_config.buildconfig.get( ++ 'config_efi_capsule_on_disk_early') ++ with u_boot_console.log.section('Test Case 4-b, after reboot'): ++ if not capsule_early: ++ # make sure that dfu_alt_info exists even persistent variables ++ # are not available. ++ output = u_boot_console.run_command_list([ ++ 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', ++ 'host bind 0 %s' % disk_img, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test03' in ''.join(output) ++ ++ # need to run uefi command to initiate capsule handling ++ output = u_boot_console.run_command( ++ 'env print -e Capsule0000') ++ ++ output = u_boot_console.run_command_list(['efidebug capsule esrt']) ++ ++ # ensure that EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID is in the ESRT. ++ assert 'E2BB9C06-70E9-4B14-97A3-5A7913176E3F' in ''.join(output) ++ ++ output = u_boot_console.run_command_list([ ++ 'host bind 0 %s' % disk_img, ++ 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) ++ assert 'Test03' not in ''.join(output) ++ ++ output = u_boot_console.run_command_list([ ++ 'sf probe 0:0', ++ 'sf read 4000000 100000 10', ++ 'md.b 4000000 10']) ++ assert 'u-boot:New' in ''.join(output) +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0013-test-py-efi_capsule-check-the-results-in-case-of-CAP.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0013-test-py-efi_capsule-check-the-results-in-case-of-CAP.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0013-test-py-efi_capsule-check-the-results-in-case-of-CAP.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0013-test-py-efi_capsule-check-the-results-in-case-of-CAP.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,93 @@ +From d4a01fee63c6145b57eb544f2227b59bd8b43178 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 9 Feb 2022 19:10:42 +0900 +Subject: [PATCH 1/1] test/py: efi_capsule: check the results in case of + CAPSULE_AUTHENTICATE + +Before the capsule authentication is supported, this test script works +correctly, but with the feature enabled, most tests will fail due to +unsigned capsules. +So check the results depending on CAPSULE_AUTHENTICATE or not. + +Signed-off-by: AKASHI Takahiro +Reviewed-by: Simon Glass +--- + .../test_efi_capsule/test_capsule_firmware.py | 26 ++++++++++++++++--- + 1 file changed, 22 insertions(+), 4 deletions(-) + +diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware.py b/test/py/tests/test_efi_capsule/test_capsule_firmware.py +index 9cc97356..6e803f69 100644 +--- a/test/py/tests/test_efi_capsule/test_capsule_firmware.py ++++ b/test/py/tests/test_efi_capsule/test_capsule_firmware.py +@@ -148,6 +148,8 @@ class TestEfiCapsuleFirmwareFit(object): + + capsule_early = u_boot_config.buildconfig.get( + 'config_efi_capsule_on_disk_early') ++ capsule_auth = u_boot_config.buildconfig.get( ++ 'config_efi_capsule_authenticate') + with u_boot_console.log.section('Test Case 2-b, after reboot'): + if not capsule_early: + # make sure that dfu_alt_info exists even persistent variables +@@ -171,12 +173,18 @@ class TestEfiCapsuleFirmwareFit(object): + 'sf probe 0:0', + 'sf read 4000000 100000 10', + 'md.b 4000000 10']) +- assert 'u-boot:New' in ''.join(output) ++ if capsule_auth: ++ assert 'u-boot:Old' in ''.join(output) ++ else: ++ assert 'u-boot:New' in ''.join(output) + + output = u_boot_console.run_command_list([ + 'sf read 4000000 150000 10', + 'md.b 4000000 10']) +- assert 'u-boot-env:New' in ''.join(output) ++ if capsule_auth: ++ assert 'u-boot-env:Old' in ''.join(output) ++ else: ++ assert 'u-boot-env:New' in ''.join(output) + + def test_efi_capsule_fw3( + self, u_boot_config, u_boot_console, efi_capsule_data): +@@ -215,6 +223,8 @@ class TestEfiCapsuleFirmwareFit(object): + + capsule_early = u_boot_config.buildconfig.get( + 'config_efi_capsule_on_disk_early') ++ capsule_auth = u_boot_config.buildconfig.get( ++ 'config_efi_capsule_authenticate') + with u_boot_console.log.section('Test Case 3-b, after reboot'): + if not capsule_early: + # make sure that dfu_alt_info exists even persistent variables +@@ -246,7 +256,10 @@ class TestEfiCapsuleFirmwareFit(object): + 'sf probe 0:0', + 'sf read 4000000 100000 10', + 'md.b 4000000 10']) +- assert 'u-boot:New' in ''.join(output) ++ if capsule_auth: ++ assert 'u-boot:Old' in ''.join(output) ++ else: ++ assert 'u-boot:New' in ''.join(output) + + def test_efi_capsule_fw4( + self, u_boot_config, u_boot_console, efi_capsule_data): +@@ -285,6 +298,8 @@ class TestEfiCapsuleFirmwareFit(object): + + capsule_early = u_boot_config.buildconfig.get( + 'config_efi_capsule_on_disk_early') ++ capsule_auth = u_boot_config.buildconfig.get( ++ 'config_efi_capsule_authenticate') + with u_boot_console.log.section('Test Case 4-b, after reboot'): + if not capsule_early: + # make sure that dfu_alt_info exists even persistent variables +@@ -313,4 +328,7 @@ class TestEfiCapsuleFirmwareFit(object): + 'sf probe 0:0', + 'sf read 4000000 100000 10', + 'md.b 4000000 10']) +- assert 'u-boot:New' in ''.join(output) ++ if capsule_auth: ++ assert 'u-boot:Old' in ''.join(output) ++ else: ++ assert 'u-boot:New' in ''.join(output) +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0014-tools-mkeficapsule-remove-duplicated-code.patch u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0014-tools-mkeficapsule-remove-duplicated-code.patch --- u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0014-tools-mkeficapsule-remove-duplicated-code.patch 1970-01-01 08:00:00.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/mkeficapsule/0014-tools-mkeficapsule-remove-duplicated-code.patch 2023-09-18 11:02:43.000000000 +0800 @@ -0,0 +1,31 @@ +From d54092da1f952e37a9dbfb6eaf1ffc7bec88f877 Mon Sep 17 00:00:00 2001 +From: AKASHI Takahiro +Date: Wed, 16 Feb 2022 10:49:51 +0900 +Subject: [PATCH 1/1] tools: mkeficapsule: remove duplicated code + +That code is mistakenly duplicated due to copy-and-paste error. +Just remove it. + +Fixes: CID 348360 +Signed-off-by: AKASHI Takahiro +Reviewed-by: Heinrich Schuchardt +--- + tools/mkeficapsule.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c +index f7590e48..c118335b 100644 +--- a/tools/mkeficapsule.c ++++ b/tools/mkeficapsule.c +@@ -210,8 +210,6 @@ static int create_auth_data(struct auth_context *ctx) + cert.size = file_size; + + ret = read_bin_file(ctx->key_file, &key.data, &file_size); +- if (ret < 0) +- return -1; + if (ret < 0) + return -1; + if (file_size > UINT_MAX) +-- +2.34.1 + diff -Nru u-boot-2022.01+dfsg/debian/patches/series u-boot-2022.01+dfsg/debian/patches/series --- u-boot-2022.01+dfsg/debian/patches/series 2023-07-20 17:42:59.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/patches/series 2023-09-18 11:02:43.000000000 +0800 @@ -52,3 +52,19 @@ CVE-2022-33103.patch CVE-2022-33967.patch CVE-2022-34835.patch + +# For mkeficapsule command +mkeficapsule/0001-tools-mkeficapsule-output-messages-to-stderr-instead.patch +mkeficapsule/0002-tools-mkeficapsule-rework-the-code-a-little-bit.patch +mkeficapsule/0003-tools-mkeficapsule-dont-use-malloc.h.patch +mkeficapsule/0004-CI-enforce-packages-upgrade-for-Msys2-on-Windows.patch +mkeficapsule/0005-tools-build-mkeficapsule-with-tools-only_defconfig.patch +mkeficapsule/0006-tools-mkeficapsule-add-firmware-image-signing.patch +mkeficapsule/0007-tools-mkeficapsule-add-man-page.patch +mkeficapsule/0008-doc-update-UEFI-document-for-usage-of-mkeficapsule.patch +mkeficapsule/0009-test-py-efi_capsule-add-image-authentication-test.patch +mkeficapsule/0010-tools-mkeficapsule-allow-for-specifying-GUID-explici.patch +mkeficapsule/0011-test-py-efi_capsule-align-with-the-syntax-change-of-.patch +mkeficapsule/0012-test-py-efi_capsule-add-a-test-for-guid-option.patch +mkeficapsule/0013-test-py-efi_capsule-check-the-results-in-case-of-CAP.patch +mkeficapsule/0014-tools-mkeficapsule-remove-duplicated-code.patch diff -Nru u-boot-2022.01+dfsg/debian/u-boot-tools.install u-boot-2022.01+dfsg/debian/u-boot-tools.install --- u-boot-2022.01+dfsg/debian/u-boot-tools.install 2022-11-18 19:11:50.000000000 +0800 +++ u-boot-2022.01+dfsg/debian/u-boot-tools.install 2023-09-18 11:02:43.000000000 +0800 @@ -3,3 +3,4 @@ debian/build/tools/tools/mkenvimage usr/bin debian/build/tools/tools/mkimage usr/bin debian/build/tools/tools/mksunxiboot usr/bin +debian/build/tools/tools/mkeficapsule usr/bin