[PATCH v5 00/12] Integrate EFI capsule tasks into u-boot's build flow

This patchset aims to bring two capsule related tasks under the u-boot build flow.
One is the embedding of the public key into the platform's dtb. The public key is in the form of an EFI Signature List(ESL) file and is used for capsule authentication. This is being achieved by adding the signature node containing the capsule public key in the architecture's u-boot.dtsi file. Currently, the u-boot.dtsi file has been added for the sandbox and arm architectures. The path to the ESL file is being provided through a Kconfig symbol(CONFIG_EFI_CAPSULE_ESL_FILE).
Changes have also been made to the test flow so that the keys used for signing the capsule, and the ESL file, are generated prior to invoking the u-boot's build, which enables embedding the ESL file into the dtb as part of the u-boot build.
The other task is related to generation of capsules. Support is being added to generate capsules by specifying the capsule parameters in a config file. Calling the mkeficapsule tool then results in generation of the corresponding capsule files. The capsules can be generated as part of u-boot build, and this is being achieved through binman, by adding a capsule entry type. The capsules can be generated either by specifying the capsule parameters in a config file, or through specifying them as properties under the capsule entry node. If using the config file, the path to the config file is to be specified through a Kconfig symbol(CONFIG_EFI_CAPSULE_CFG_FILE).
Changes have also been made to the efi capsule update feature testing setup on the sandbox variants. Currently, the capsule files and the public key ESL file are generated after u-boot has been built. This logic has been changed so that the capsule input files along with the keys needed for capsule signing and authentication are generated prior to initiation of the u-boot build. The placement of all the files needed for generation of capsules, along with the generated capsule files is under the /tmp/capsules/ directory.
Currently, the capsule update feature is tested on the sandbox and sandbox_flattree variants in CI. The capsule generation through config file is enabled for the sandbox variant, with the sandbox_flattree variant generating capsules through the command-line parameters.
The document has been updated to reflect the above changes.
Changes since V4: * Rebase on top of current HEAD. * Pass the single command target names directly to the function instead of putting them in a separate list. * Fix multi line comment format. * Drop additional blank line. * Remove the check for CONFIG_EFI_HAVE_CAPSULE_SUPPORT from arm's u-boot.dtsi. * Wrap the help text in the EFI_CAPSULE_ESL_FILE config at 72 chars. * New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile. * Remove blank lines after function comments. * Fix a couple of typos. * Use single quotes for strings. * Put the GUIDs in variables with relevant names. * Declare certain values in local variables instead of member values. * Add comments for explaning the payload offsets in the capsule file. * Drop the test case for generating the capsule from the config file. * Define payload data for the capsule tests. * Add logic to find input and output files in capsule generation in the indir and outdir directories when absolute path is not passed. * Use a relative path for CONFIG_EFI_CAPSULE_CFG_FILE. * Remove logic to copy capsule config file to /tmp/capsules/ directory, as the capsule entry can handle relative paths. * Add a comment in the capsule config file for the image GUIDs being used. * Use lower case for image GUIDs. * Define macros for the image GUIDs being used for generating the capsules. * Use lower case for image GUIDs.
Sughosh Ganu (12): binman: bintool: Build a tool from a list of commands nuvoton: npcm845-evb: Add a newline at the end of file capsule: authenticate: Add capsule public key in platform's dtb doc: capsule: Document the new mechanism to embed ESL file into dtb tools: mkeficapsule: Add support for parsing capsule params from config file Dockerfile: capsule: Setup the files needed for capsule update testing binman: capsule: Add support for generating capsules doc: Add documentation to highlight capsule generation related updates test: py: Setup capsule files for testing test: capsule: Remove public key embed logic from capsule update test sandbox: capsule: Add a config file for generating capsules sandbox: capsule: Generate capsule related files through binman
arch/arm/dts/nuvoton-npcm845-evb.dts | 2 +- arch/arm/dts/u-boot.dtsi | 14 + arch/sandbox/dts/u-boot.dtsi | 288 ++++++++++++++ configs/sandbox_defconfig | 3 + configs/sandbox_flattree_defconfig | 1 + configs/sandbox_spl_defconfig | 1 + doc/develop/uefi/uefi.rst | 106 +++++- lib/efi_loader/Kconfig | 9 + lib/efi_loader/Makefile | 7 + test/py/conftest.py | 84 +++++ test/py/tests/test_efi_capsule/conftest.py | 164 +------- .../test_efi_capsule/sandbox_capsule_cfg.txt | 175 +++++++++ test/py/tests/test_efi_capsule/signature.dts | 10 - .../tests/test_efi_capsule/uboot_bin_env.its | 36 -- tools/Kconfig | 16 + tools/Makefile | 1 + tools/binman/bintool.py | 19 +- tools/binman/btool/mkeficapsule.py | 153 ++++++++ tools/binman/entries.rst | 42 +++ tools/binman/etype/capsule.py | 132 +++++++ tools/binman/ftest.py | 115 ++++++ tools/binman/test/307_capsule.dts | 19 + tools/binman/test/308_capsule_signed.dts | 21 ++ tools/binman/test/309_capsule_version.dts | 20 + tools/binman/test/310_capsule_missing_key.dts | 20 + .../binman/test/311_capsule_missing_index.dts | 18 + .../binman/test/312_capsule_missing_guid.dts | 17 + .../test/313_capsule_missing_payload.dts | 18 + tools/binman/test/314_capsule_missing.dts | 18 + tools/binman/test/files/capsule_cfg.txt | 6 + tools/docker/Dockerfile | 12 + tools/eficapsule.h | 115 ++++++ tools/mkeficapsule.c | 87 +++-- tools/mkeficapsule_parse.c | 352 ++++++++++++++++++ 34 files changed, 1845 insertions(+), 256 deletions(-) create mode 100644 arch/arm/dts/u-boot.dtsi create mode 100644 arch/sandbox/dts/u-boot.dtsi create mode 100644 test/py/tests/test_efi_capsule/sandbox_capsule_cfg.txt delete mode 100644 test/py/tests/test_efi_capsule/signature.dts delete mode 100644 test/py/tests/test_efi_capsule/uboot_bin_env.its create mode 100644 tools/binman/btool/mkeficapsule.py create mode 100644 tools/binman/etype/capsule.py create mode 100644 tools/binman/test/307_capsule.dts create mode 100644 tools/binman/test/308_capsule_signed.dts create mode 100644 tools/binman/test/309_capsule_version.dts create mode 100644 tools/binman/test/310_capsule_missing_key.dts create mode 100644 tools/binman/test/311_capsule_missing_index.dts create mode 100644 tools/binman/test/312_capsule_missing_guid.dts create mode 100644 tools/binman/test/313_capsule_missing_payload.dts create mode 100644 tools/binman/test/314_capsule_missing.dts create mode 100644 tools/binman/test/files/capsule_cfg.txt create mode 100644 tools/mkeficapsule_parse.c

Add support to build a tool from source with a list of commands. This is useful when a tool can be built with multiple commands instead of a single command.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: * Pass the single command target names directly to the function instead of putting them in a separate list.
tools/binman/bintool.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/tools/binman/bintool.py b/tools/binman/bintool.py index 0b0f56dbbb..3c4ad1adbb 100644 --- a/tools/binman/bintool.py +++ b/tools/binman/bintool.py @@ -328,7 +328,7 @@ class Bintool: return result.stdout
@classmethod - def build_from_git(cls, git_repo, make_target, bintool_path, flags=None): + def build_from_git(cls, git_repo, make_targets, bintool_path, flags=None): """Build a bintool from a git repo
This clones the repo in a temporary directory, builds it with 'make', @@ -336,7 +336,8 @@ class Bintool:
Args: git_repo (str): URL of git repo - make_target (str): Target to pass to 'make' to build the tool + make_targets (list of str): List of targets to pass to 'make' to build + the tool bintool_path (str): Relative path of the tool in the repo, after build is complete flags (list of str): Flags or variables to pass to make, or None @@ -350,12 +351,14 @@ class Bintool: tmpdir = tempfile.mkdtemp(prefix='binmanf.') print(f"- clone git repo '{git_repo}' to '{tmpdir}'") tools.run('git', 'clone', '--depth', '1', git_repo, tmpdir) - print(f"- build target '{make_target}'") - cmd = ['make', '-C', tmpdir, '-j', f'{multiprocessing.cpu_count()}', - make_target] - if flags: - cmd += flags - tools.run(*cmd) + for target in make_targets: + print(f"- build target '{target}'") + cmd = ['make', '-C', tmpdir, '-j', f'{multiprocessing.cpu_count()}', + target] + if flags: + cmd += flags + tools.run(*cmd) + fname = os.path.join(tmpdir, bintool_path) if not os.path.exists(fname): print(f"- File '{fname}' was not produced")

On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add support to build a tool from source with a list of commands. This is useful when a tool can be built with multiple commands instead of a single command.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Pass the single command target names directly to the function instead of putting them in a separate list.
tools/binman/bintool.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
Reviewed-by: Simon Glass sjg@chromium.org

Add a newline at the end of the dts, without which the build fails when including the u-boot.dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org Reviewed-by: Simon Glass sjg@chromium.org --- Changes since V4: None
arch/arm/dts/nuvoton-npcm845-evb.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/dts/nuvoton-npcm845-evb.dts b/arch/arm/dts/nuvoton-npcm845-evb.dts index 3cab7807e3..a93666cb41 100644 --- a/arch/arm/dts/nuvoton-npcm845-evb.dts +++ b/arch/arm/dts/nuvoton-npcm845-evb.dts @@ -354,4 +354,4 @@ &r1en_pins &r1oen_pins >; -}; \ No newline at end of file +};

On Tue, 25 Jul 2023 at 11:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add a newline at the end of the dts, without which the build fails when including the u-boot.dtsi file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
Changes since V4: None
arch/arm/dts/nuvoton-npcm845-evb.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm/dts/nuvoton-npcm845-evb.dts b/arch/arm/dts/nuvoton-npcm845-evb.dts index 3cab7807e3..a93666cb41 100644 --- a/arch/arm/dts/nuvoton-npcm845-evb.dts +++ b/arch/arm/dts/nuvoton-npcm845-evb.dts @@ -354,4 +354,4 @@ &r1en_pins &r1oen_pins >; -}; \ No newline at end of file
+};
2.34.1
Reviewed-by: Ilias Apalodimas ilias.apalodimas@linaro.org

The EFI capsule authentication logic in u-boot expects the public key in the form of an EFI Signature List(ESL) to be provided as part of the platform's dtb. Currently, the embedding of the ESL file into the dtb needs to be done manually.
Add a signature node in the u-boot dtsi file and include the public key through the capsule-key property. This file is per architecture, and is currently being added for sandbox and arm architectures. It will have to be added for other architectures which need to enable capsule authentication support.
The path to the ESL file is specified through the CONFIG_EFI_CAPSULE_ESL_FILE symbol.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: * Fix multi line comment format. * Drop additional blank line. * Remove the check for CONFIG_EFI_HAVE_CAPSULE_SUPPORT from arm's u-boot.dtsi. * Wrap the help text in the EFI_CAPSULE_ESL_FILE config at 72 chars.
arch/arm/dts/u-boot.dtsi | 14 ++++++++++++++ arch/sandbox/dts/u-boot.dtsi | 17 +++++++++++++++++ lib/efi_loader/Kconfig | 9 +++++++++ lib/efi_loader/Makefile | 7 +++++++ 4 files changed, 47 insertions(+) create mode 100644 arch/arm/dts/u-boot.dtsi create mode 100644 arch/sandbox/dts/u-boot.dtsi
diff --git a/arch/arm/dts/u-boot.dtsi b/arch/arm/dts/u-boot.dtsi new file mode 100644 index 0000000000..4f31da4521 --- /dev/null +++ b/arch/arm/dts/u-boot.dtsi @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/** + * Devicetree file with miscellaneous nodes that will be included + * at build time into the DTB. Currently being used for including + * capsule related information. + */ + +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE +/ { + signature { + capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE); + }; +}; +#endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */ diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi new file mode 100644 index 0000000000..60bd004937 --- /dev/null +++ b/arch/sandbox/dts/u-boot.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Devicetree file with miscellaneous nodes that will be included + * at build time into the DTB. Currently being used for including + * capsule related information. + * + */ + +#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT +/ { +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE + signature { + capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE); + }; +#endif +}; +#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */ diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index a22e47616f..0d559ff3a1 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -235,6 +235,15 @@ config EFI_CAPSULE_MAX Select the max capsule index value used for capsule report variables. This value is used to create CapsuleMax variable.
+config EFI_CAPSULE_ESL_FILE + string "Path to the EFI Signature List File" + default "" + depends on EFI_CAPSULE_AUTHENTICATE + help + Provides the absolute path to the EFI Signature List file which + will be embedded in the platform's device tree and used for + capsule authentication at the time of capsule update. + config EFI_DEVICE_PATH_TO_TEXT bool "Device path to text protocol" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 1a8c8d7cab..c52c9d27bd 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -89,3 +89,10 @@ obj-$(CONFIG_EFI_ECPT) += efi_conformance.o
EFI_VAR_SEED_FILE := $(subst $",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE) + +ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y) +EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_ESL_FILE)) +ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") +$(error .esl cerificate not found. Configure your CONFIG_EFI_CAPSULE_ESL_FILE) +endif +endif

Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The EFI capsule authentication logic in u-boot expects the public key in the form of an EFI Signature List(ESL) to be provided as part of the platform's dtb. Currently, the embedding of the ESL file into the dtb needs to be done manually.
Add a signature node in the u-boot dtsi file and include the public key through the capsule-key property. This file is per architecture, and is currently being added for sandbox and arm architectures. It will have to be added for other architectures which need to enable capsule authentication support.
The path to the ESL file is specified through the CONFIG_EFI_CAPSULE_ESL_FILE symbol.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Fix multi line comment format.
- Drop additional blank line.
- Remove the check for CONFIG_EFI_HAVE_CAPSULE_SUPPORT from arm's u-boot.dtsi.
- Wrap the help text in the EFI_CAPSULE_ESL_FILE config at 72 chars.
arch/arm/dts/u-boot.dtsi | 14 ++++++++++++++ arch/sandbox/dts/u-boot.dtsi | 17 +++++++++++++++++ lib/efi_loader/Kconfig | 9 +++++++++ lib/efi_loader/Makefile | 7 +++++++ 4 files changed, 47 insertions(+) create mode 100644 arch/arm/dts/u-boot.dtsi create mode 100644 arch/sandbox/dts/u-boot.dtsi
diff --git a/arch/arm/dts/u-boot.dtsi b/arch/arm/dts/u-boot.dtsi new file mode 100644 index 0000000000..4f31da4521 --- /dev/null +++ b/arch/arm/dts/u-boot.dtsi @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0+ +/**
- Devicetree file with miscellaneous nodes that will be included
- at build time into the DTB. Currently being used for including
- capsule related information.
- */
+#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE +/ {
signature {
capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE);
};
+}; +#endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */ diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi new file mode 100644 index 0000000000..60bd004937 --- /dev/null +++ b/arch/sandbox/dts/u-boot.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Devicetree file with miscellaneous nodes that will be included
- at build time into the DTB. Currently being used for including
- capsule related information.
- */
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT +/ { +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE
signature {
capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE);
};
+#endif +}; +#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
You missed my comment there. You should not need the outer #ifdef, but if you do, please combine them into one #if
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index a22e47616f..0d559ff3a1 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -235,6 +235,15 @@ config EFI_CAPSULE_MAX Select the max capsule index value used for capsule report variables. This value is used to create CapsuleMax variable.
+config EFI_CAPSULE_ESL_FILE
string "Path to the EFI Signature List File"
default ""
depends on EFI_CAPSULE_AUTHENTICATE
help
Provides the absolute path to the EFI Signature List file which
will be embedded in the platform's device tree and used for
capsule authentication at the time of capsule update.
config EFI_DEVICE_PATH_TO_TEXT bool "Device path to text protocol" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 1a8c8d7cab..c52c9d27bd 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -89,3 +89,10 @@ obj-$(CONFIG_EFI_ECPT) += efi_conformance.o
EFI_VAR_SEED_FILE := $(subst $",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE)
+ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y) +EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_ESL_FILE)) +ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") +$(error .esl cerificate not found. Configure your CONFIG_EFI_CAPSULE_ESL_FILE) +endif
+endif
2.34.1
Regards, Simon

hi Simon,
On Wed, 26 Jul 2023 at 04:22, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The EFI capsule authentication logic in u-boot expects the public key in the form of an EFI Signature List(ESL) to be provided as part of the platform's dtb. Currently, the embedding of the ESL file into the dtb needs to be done manually.
Add a signature node in the u-boot dtsi file and include the public key through the capsule-key property. This file is per architecture, and is currently being added for sandbox and arm architectures. It will have to be added for other architectures which need to enable capsule authentication support.
The path to the ESL file is specified through the CONFIG_EFI_CAPSULE_ESL_FILE symbol.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Fix multi line comment format.
- Drop additional blank line.
- Remove the check for CONFIG_EFI_HAVE_CAPSULE_SUPPORT from arm's u-boot.dtsi.
- Wrap the help text in the EFI_CAPSULE_ESL_FILE config at 72 chars.
<snip>
diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi new file mode 100644 index 0000000000..60bd004937 --- /dev/null +++ b/arch/sandbox/dts/u-boot.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Devicetree file with miscellaneous nodes that will be included
- at build time into the DTB. Currently being used for including
- capsule related information.
- */
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT +/ { +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE
signature {
capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE);
};
+#endif +}; +#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
You missed my comment there. You should not need the outer #ifdef, but if you do, please combine them into one #if
I did not miss your comment. The reason I have kept both the ifdefs is that we need to include stuff which is needed only when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled, and then the rest of the stuff is needed only when CONFIG_EFI_HAVE_CAPSULE_SUPPORT is enabled. Not having both the ifdefs would result in build failures. In the u-boot.dtsi included for the arm arch, I am using a single ifdef, since we are including only the signature node in that file.
-sughosh
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index a22e47616f..0d559ff3a1 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -235,6 +235,15 @@ config EFI_CAPSULE_MAX Select the max capsule index value used for capsule report variables. This value is used to create CapsuleMax variable.
+config EFI_CAPSULE_ESL_FILE
string "Path to the EFI Signature List File"
default ""
depends on EFI_CAPSULE_AUTHENTICATE
help
Provides the absolute path to the EFI Signature List file which
will be embedded in the platform's device tree and used for
capsule authentication at the time of capsule update.
config EFI_DEVICE_PATH_TO_TEXT bool "Device path to text protocol" default y diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile index 1a8c8d7cab..c52c9d27bd 100644 --- a/lib/efi_loader/Makefile +++ b/lib/efi_loader/Makefile @@ -89,3 +89,10 @@ obj-$(CONFIG_EFI_ECPT) += efi_conformance.o
EFI_VAR_SEED_FILE := $(subst $",,$(CONFIG_EFI_VAR_SEED_FILE)) $(obj)/efi_var_seed.o: $(srctree)/$(EFI_VAR_SEED_FILE)
+ifeq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),y) +EFI_CAPSULE_KEY_PATH := $(subst $",,$(CONFIG_EFI_CAPSULE_ESL_FILE)) +ifeq ("$(wildcard $(EFI_CAPSULE_KEY_PATH))","") +$(error .esl cerificate not found. Configure your CONFIG_EFI_CAPSULE_ESL_FILE) +endif
+endif
2.34.1
Regards, Simon

Hi Sughosh,
On Wed, 26 Jul 2023 at 02:57, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 04:22, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The EFI capsule authentication logic in u-boot expects the public key in the form of an EFI Signature List(ESL) to be provided as part of the platform's dtb. Currently, the embedding of the ESL file into the dtb needs to be done manually.
Add a signature node in the u-boot dtsi file and include the public key through the capsule-key property. This file is per architecture, and is currently being added for sandbox and arm architectures. It will have to be added for other architectures which need to enable capsule authentication support.
The path to the ESL file is specified through the CONFIG_EFI_CAPSULE_ESL_FILE symbol.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Fix multi line comment format.
- Drop additional blank line.
- Remove the check for CONFIG_EFI_HAVE_CAPSULE_SUPPORT from arm's u-boot.dtsi.
- Wrap the help text in the EFI_CAPSULE_ESL_FILE config at 72 chars.
<snip>
diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi new file mode 100644 index 0000000000..60bd004937 --- /dev/null +++ b/arch/sandbox/dts/u-boot.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Devicetree file with miscellaneous nodes that will be included
- at build time into the DTB. Currently being used for including
- capsule related information.
- */
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT +/ { +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE
signature {
capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE);
};
+#endif +}; +#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
You missed my comment there. You should not need the outer #ifdef, but if you do, please combine them into one #if
I did not miss your comment. The reason I have kept both the ifdefs is that we need to include stuff which is needed only when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled, and then the rest of the stuff is needed only when CONFIG_EFI_HAVE_CAPSULE_SUPPORT is enabled. Not having both the ifdefs would result in build failures. In the u-boot.dtsi included for the arm arch, I am using a single ifdef, since we are including only the signature node in that file.
Well having
/ { };
is harmless in all cases, I believe. So you should not need the outer one?
Regards, Simon [..]

hi Simon,
On Wed, 26 Jul 2023 at 19:56, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 26 Jul 2023 at 02:57, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 04:22, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The EFI capsule authentication logic in u-boot expects the public key in the form of an EFI Signature List(ESL) to be provided as part of the platform's dtb. Currently, the embedding of the ESL file into the dtb needs to be done manually.
Add a signature node in the u-boot dtsi file and include the public key through the capsule-key property. This file is per architecture, and is currently being added for sandbox and arm architectures. It will have to be added for other architectures which need to enable capsule authentication support.
The path to the ESL file is specified through the CONFIG_EFI_CAPSULE_ESL_FILE symbol.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Fix multi line comment format.
- Drop additional blank line.
- Remove the check for CONFIG_EFI_HAVE_CAPSULE_SUPPORT from arm's u-boot.dtsi.
- Wrap the help text in the EFI_CAPSULE_ESL_FILE config at 72 chars.
<snip>
diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi new file mode 100644 index 0000000000..60bd004937 --- /dev/null +++ b/arch/sandbox/dts/u-boot.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Devicetree file with miscellaneous nodes that will be included
- at build time into the DTB. Currently being used for including
- capsule related information.
- */
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT +/ { +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE
signature {
capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE);
};
+#endif +}; +#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
You missed my comment there. You should not need the outer #ifdef, but if you do, please combine them into one #if
I did not miss your comment. The reason I have kept both the ifdefs is that we need to include stuff which is needed only when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled, and then the rest of the stuff is needed only when CONFIG_EFI_HAVE_CAPSULE_SUPPORT is enabled. Not having both the ifdefs would result in build failures. In the u-boot.dtsi included for the arm arch, I am using a single ifdef, since we are including only the signature node in that file.
Well having
/ { };
is harmless in all cases, I believe. So you should not need the outer one?
Sorry, I missed out this comment earlier. So this would not be an empty node but contain the capsule generation nodes. This would result in capsules getting generated for the sandbox_vpl and sandbox_noinst variants which do not enable the capsule functionality.
-sughosh

Hi Sughosh,
On Tue, 1 Aug 2023 at 11:35, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 19:56, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 26 Jul 2023 at 02:57, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 04:22, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The EFI capsule authentication logic in u-boot expects the public key in the form of an EFI Signature List(ESL) to be provided as part of the platform's dtb. Currently, the embedding of the ESL file into the dtb needs to be done manually.
Add a signature node in the u-boot dtsi file and include the public key through the capsule-key property. This file is per architecture, and is currently being added for sandbox and arm architectures. It will have to be added for other architectures which need to enable capsule authentication support.
The path to the ESL file is specified through the CONFIG_EFI_CAPSULE_ESL_FILE symbol.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Fix multi line comment format.
- Drop additional blank line.
- Remove the check for CONFIG_EFI_HAVE_CAPSULE_SUPPORT from arm's u-boot.dtsi.
- Wrap the help text in the EFI_CAPSULE_ESL_FILE config at 72 chars.
<snip>
diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi new file mode 100644 index 0000000000..60bd004937 --- /dev/null +++ b/arch/sandbox/dts/u-boot.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Devicetree file with miscellaneous nodes that will be included
- at build time into the DTB. Currently being used for including
- capsule related information.
- */
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT +/ { +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE
signature {
capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE);
};
+#endif +}; +#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
You missed my comment there. You should not need the outer #ifdef, but if you do, please combine them into one #if
I did not miss your comment. The reason I have kept both the ifdefs is that we need to include stuff which is needed only when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled, and then the rest of the stuff is needed only when CONFIG_EFI_HAVE_CAPSULE_SUPPORT is enabled. Not having both the ifdefs would result in build failures. In the u-boot.dtsi included for the arm arch, I am using a single ifdef, since we are including only the signature node in that file.
Well having
/ { };
is harmless in all cases, I believe. So you should not need the outer one?
Sorry, I missed out this comment earlier. So this would not be an empty node but contain the capsule generation nodes. This would result in capsules getting generated for the sandbox_vpl and sandbox_noinst variants which do not enable the capsule functionality.
If that is all it is then I think it is fine to leave them in. Those builds won't care anyway.
Regards, Simon

hi Simon,
On Wed, 2 Aug 2023 at 18:22, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Tue, 1 Aug 2023 at 11:35, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 19:56, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Wed, 26 Jul 2023 at 02:57, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 04:22, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The EFI capsule authentication logic in u-boot expects the public key in the form of an EFI Signature List(ESL) to be provided as part of the platform's dtb. Currently, the embedding of the ESL file into the dtb needs to be done manually.
Add a signature node in the u-boot dtsi file and include the public key through the capsule-key property. This file is per architecture, and is currently being added for sandbox and arm architectures. It will have to be added for other architectures which need to enable capsule authentication support.
The path to the ESL file is specified through the CONFIG_EFI_CAPSULE_ESL_FILE symbol.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Fix multi line comment format.
- Drop additional blank line.
- Remove the check for CONFIG_EFI_HAVE_CAPSULE_SUPPORT from arm's u-boot.dtsi.
- Wrap the help text in the EFI_CAPSULE_ESL_FILE config at 72 chars.
<snip>
diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi new file mode 100644 index 0000000000..60bd004937 --- /dev/null +++ b/arch/sandbox/dts/u-boot.dtsi @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- Devicetree file with miscellaneous nodes that will be included
- at build time into the DTB. Currently being used for including
- capsule related information.
- */
+#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT +/ { +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE
signature {
capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE);
};
+#endif +}; +#endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */
You missed my comment there. You should not need the outer #ifdef, but if you do, please combine them into one #if
I did not miss your comment. The reason I have kept both the ifdefs is that we need to include stuff which is needed only when CONFIG_EFI_CAPSULE_AUTHENTICATE is enabled, and then the rest of the stuff is needed only when CONFIG_EFI_HAVE_CAPSULE_SUPPORT is enabled. Not having both the ifdefs would result in build failures. In the u-boot.dtsi included for the arm arch, I am using a single ifdef, since we are including only the signature node in that file.
Well having
/ { };
is harmless in all cases, I believe. So you should not need the outer one?
Sorry, I missed out this comment earlier. So this would not be an empty node but contain the capsule generation nodes. This would result in capsules getting generated for the sandbox_vpl and sandbox_noinst variants which do not enable the capsule functionality.
If that is all it is then I think it is fine to leave them in. Those builds won't care anyway.
Fair enough. Will drop the outer ifdef.
-sughosh
Regards, Simon

Update the document to specify how the EFI Signature List(ESL) file can be embedded into the platform's dtb as part of the u-boot build.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org Reviewed-by: Simon Glass sjg@chromium.org --- Changes since V4: None
doc/develop/uefi/uefi.rst | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index a7a41f2fac..b2854b52a6 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -522,20 +522,16 @@ and used by the steps highlighted below. ... }
-You can do step-4 manually with +You can perform step-4 by defining the Kconfig symbol +CONFIG_EFI_CAPSULE_ESL_FILE. Once this has been done, the signature +node can be added to the u-boot.dtsi file. For reference, check the +u-boot.dtsi file for the sandbox architecture. If this node has not +been added to the architecture's u-boot.dtsi file, this needs to be +done. The node has currently been added for the sandbox and arm +architectures' in the u-boot.dtsi file. Once the u-boot.dtsi file has +been added with the signature node, the esl file will automatically +get embedded into the platform's dtb as part of u-boot build.
-.. code-block:: console - - $ dtc -@ -I dts -O dtb -o signature.dtbo signature.dts - $ fdtoverlay -i orig.dtb -o new.dtb -v signature.dtbo - -where signature.dts looks like:: - - &{/} { - signature { - capsule-key = /incbin/("CRT.esl"); - }; - };
Anti-rollback Protection ************************

Add support for specifying the parameters needed for capsule generation through a config file, instead of passing them through command-line. Parameters for more than a single capsule file can be specified, resulting in generation of multiple capsules through a single invocation of the command.
This path is to be used for generating capsules through a make target, with the parameters being parsed from the config file.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: None
tools/Kconfig | 16 ++ tools/Makefile | 1 + tools/eficapsule.h | 115 ++++++++++++ tools/mkeficapsule.c | 87 +++++---- tools/mkeficapsule_parse.c | 352 +++++++++++++++++++++++++++++++++++++ 5 files changed, 540 insertions(+), 31 deletions(-) create mode 100644 tools/mkeficapsule_parse.c
diff --git a/tools/Kconfig b/tools/Kconfig index 6e23f44d55..88ea3567d0 100644 --- a/tools/Kconfig +++ b/tools/Kconfig @@ -98,6 +98,22 @@ config TOOLS_MKEFICAPSULE optionally sign that file. If you want to enable UEFI capsule update feature on your target, you certainly need this.
+config EFI_CAPSULE_CFG_FILE + string "Path to the EFI Capsule Config File" + default "" + help + Path to the EFI capsule config file which provides the + parameters needed to build capsule(s). Parameters can be + provided for multiple payloads resulting in corresponding + capsule images being generated. + +config EFI_USE_CAPSULE_CFG_FILE + bool "Use the config file for generating capsules" + help + Boolean option used to specify if the EFI capsules are to + be generated through parameters specified via the config + file or through command line. + menuconfig FSPI_CONF_HEADER bool "FlexSPI Header Configuration" help diff --git a/tools/Makefile b/tools/Makefile index 3d0c4b0dd6..eb129e3bb2 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -250,6 +250,7 @@ HOSTLDLIBS_mkeficapsule += \ HOSTLDLIBS_mkeficapsule += \ $(shell pkg-config --libs uuid 2> /dev/null || echo "-luuid") hostprogs-$(CONFIG_TOOLS_MKEFICAPSULE) += mkeficapsule +mkeficapsule-objs := mkeficapsule.o mkeficapsule_parse.o
mkfwumdata-objs := mkfwumdata.o generated/lib/crc32.o HOSTLDLIBS_mkfwumdata += -luuid diff --git a/tools/eficapsule.h b/tools/eficapsule.h index 2099a2e9b8..d455ac1d6f 100644 --- a/tools/eficapsule.h +++ b/tools/eficapsule.h @@ -52,6 +52,12 @@ typedef struct { /* flags */ #define CAPSULE_FLAGS_PERSIST_ACROSS_RESET 0x00010000
+enum capsule_type { + CAPSULE_NORMAL_BLOB = 0, + CAPSULE_ACCEPT, + CAPSULE_REVERT, +}; + struct efi_capsule_header { efi_guid_t capsule_guid; uint32_t header_size; @@ -113,6 +119,7 @@ struct efi_firmware_image_authentication { struct win_certificate_uefi_guid auth_info; } __packed;
+ /* fmp payload header */ #define SIGNATURE_16(A, B) ((A) | ((B) << 8)) #define SIGNATURE_32(A, B, C, D) \ @@ -143,4 +150,112 @@ struct fmp_payload_header_params { uint32_t fw_version; };
+/** + * struct efi_capsule_params - Capsule parameters + * @image_guid: Guid value of the payload input image + * @image_index: Image index value + * @hardware_instance: Hardware instance to be used for the image + * @fmp: FMP payload header used for storing firmware version + * @monotonic_count: Monotonic count value to be used for signed capsule + * @privkey_file: Path to private key used in capsule signing + * @cert_file: Path to public key certificate used in capsule signing + * @input_file: Path to payload input image + * @capsule_file: Path to the output capsule file + * @oemflags: Oemflags to be populated in the capsule header + * @capsule: Capsule Type, normal or accept or revert + */ +struct efi_capsule_params { + efi_guid_t *image_guid; + unsigned long image_index; + unsigned long hardware_instance; + struct fmp_payload_header_params fmp; + uint64_t monotonic_count; + char *privkey_file; + char *cert_file; + char *input_file; + char *capsule_file; + unsigned long oemflags; + enum capsule_type capsule; +}; + +/** + * capsule_with_cfg_file() - Generate capsule from config file + * @cfg_file: Path to the config file + * + * Parse the capsule parameters from the config file and use the + * parameters for generating one or more capsules. + * + * Return: None + * + */ +void capsule_with_cfg_file(const char *cfg_file); + +/** + * 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); + +/** + * create_empty_capsule() - Generate an empty capsule + * @path: Path to the empty capsule file to be generated + * @guid: Guid value of the image for which empty capsule is generated + * @fw_accept: Flag to specify whether to generate accept or revert capsule + * + * Generate an empty capsule, either an accept or a revert capsule to be + * used to flag acceptance or rejection of an earlier executed firmware + * update operation. Being used in the FWU Multi Bank firmware update + * feature. + * + * Return: 0 if OK, -ve on error + * + */ +int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept); + +/** + * 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 + * @fmp: FMP header params + * @mcount: Monotonic count in authentication information + * @private_file: Path to a private key file + * @cert_file: Path to a certificate file + * @oemflags: Capsule OEM Flags, bits 0-15 + * + * 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 + */ +int create_fwbin(char *path, char *bin, efi_guid_t *guid, + unsigned long index, unsigned long instance, + struct fmp_payload_header_params *fmp_ph_params, + uint64_t mcount, char *privkey_file, char *cert_file, + uint16_t oemflags); + +/** + * print_usage() - Print the command usage string + * + * Prints the standard command usage string. Called in the case + * of incorrect parameters being passed to the tool. + * + * Return: None + * + */ +void print_usage(void); + #endif /* _EFI_CAPSULE_H */ diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index 52be1f122e..4058813c98 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -29,13 +29,7 @@ static const char *tool_name = "mkeficapsule"; efi_guid_t efi_guid_fm_capsule = EFI_FIRMWARE_MANAGEMENT_CAPSULE_ID_GUID; efi_guid_t efi_guid_cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
-static const char *opts_short = "g:i:I:v:p:c:m:o:dhAR"; - -enum { - CAPSULE_NORMAL_BLOB = 0, - CAPSULE_ACCEPT, - CAPSULE_REVERT, -} capsule_type; +static const char *opts_short = "g:i:I:v:p:c:m:o:f:dhAR";
static struct option options[] = { {"guid", required_argument, NULL, 'g'}, @@ -49,11 +43,21 @@ static struct option options[] = { {"fw-accept", no_argument, NULL, 'A'}, {"fw-revert", no_argument, NULL, 'R'}, {"capoemflag", required_argument, NULL, 'o'}, + {"cfg-file", required_argument, NULL, 'f'}, {"help", no_argument, NULL, 'h'}, {NULL, 0, NULL, 0}, };
-static void print_usage(void) +/** + * print_usage() - Print the command usage string + * + * Prints the standard command usage string. Called in the case + * of incorrect parameters being passed to the tool. + * + * Return: None + * + */ +void print_usage(void) { fprintf(stderr, "Usage: %s [options] <image blob> <output file>\n" "Options:\n" @@ -69,6 +73,7 @@ static void print_usage(void) "\t-A, --fw-accept firmware accept capsule, requires GUID, no image blob\n" "\t-R, --fw-revert firmware revert capsule, takes no GUID, no image blob\n" "\t-o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff\n" + "\t-f, --cfg-file <config file> config file with capsule parameters\n" "\t-h, --help print a help message\n", tool_name); } @@ -388,6 +393,7 @@ static void free_sig_data(struct auth_context *ctx) * @guid: GUID of related FMP driver * @index: Index number in capsule * @instance: Instance number in capsule + * @fmp: FMP header params * @mcount: Monotonic count in authentication information * @private_file: Path to a private key file * @cert_file: Path to a certificate file @@ -402,11 +408,11 @@ static void free_sig_data(struct auth_context *ctx) * * 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 fmp_payload_header_params *fmp_ph_params, - uint64_t mcount, char *privkey_file, char *cert_file, - uint16_t oemflags) +int create_fwbin(char *path, char *bin, efi_guid_t *guid, + unsigned long index, unsigned long instance, + struct fmp_payload_header_params *fmp_ph_params, + uint64_t mcount, char *privkey_file, char *cert_file, + uint16_t oemflags) { struct efi_capsule_header header; struct efi_firmware_management_capsule_header capsule; @@ -604,7 +610,21 @@ void convert_uuid_to_guid(unsigned char *buf) buf[7] = c; }
-static int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept) +/** + * create_empty_capsule() - Generate an empty capsule + * @path: Path to the empty capsule file to be generated + * @guid: Guid value of the image for which empty capsule is generated + * @fw_accept: Flag to specify whether to generate accept or revert capsule + * + * Generate an empty capsule, either an accept or a revert capsule to be + * used to flag acceptance or rejection of an earlier executed firmware + * update operation. Being used in the FWU Multi Bank firmware update + * feature. + * + * Return: 0 if OK, -ve on error + * + */ +int create_empty_capsule(char *path, efi_guid_t *guid, bool fw_accept) { struct efi_capsule_header header = { 0 }; FILE *f = NULL; @@ -667,6 +687,8 @@ int main(int argc, char **argv) uint64_t mcount; unsigned long oemflags; char *privkey_file, *cert_file; + char *cfg_file; + enum capsule_type capsule; int c, idx; struct fmp_payload_header_params fmp_ph_params = { 0 };
@@ -676,8 +698,9 @@ int main(int argc, char **argv) mcount = 0; privkey_file = NULL; cert_file = NULL; + cfg_file = NULL; dump_sig = 0; - capsule_type = CAPSULE_NORMAL_BLOB; + capsule = CAPSULE_NORMAL_BLOB; oemflags = 0; for (;;) { c = getopt_long(argc, argv, opts_short, options, &idx); @@ -731,20 +754,20 @@ int main(int argc, char **argv) dump_sig = 1; break; case 'A': - if (capsule_type) { + if (capsule) { fprintf(stderr, "Select either of Accept or Revert capsule generation\n"); exit(1); } - capsule_type = CAPSULE_ACCEPT; + capsule = CAPSULE_ACCEPT; break; case 'R': - if (capsule_type) { + if (capsule) { fprintf(stderr, "Select either of Accept or Revert capsule generation\n"); exit(1); } - capsule_type = CAPSULE_REVERT; + capsule = CAPSULE_REVERT; break; case 'o': oemflags = strtoul(optarg, NULL, 0); @@ -754,6 +777,10 @@ int main(int argc, char **argv) exit(1); } break; + case 'f': + cfg_file = optarg; + capsule_with_cfg_file(cfg_file); + exit(EXIT_SUCCESS); default: print_usage(); exit(EXIT_SUCCESS); @@ -761,21 +788,21 @@ int main(int argc, char **argv) }
/* check necessary parameters */ - if ((capsule_type == CAPSULE_NORMAL_BLOB && - ((argc != optind + 2) || !guid || - ((privkey_file && !cert_file) || - (!privkey_file && cert_file)))) || - (capsule_type != CAPSULE_NORMAL_BLOB && - ((argc != optind + 1) || - ((capsule_type == CAPSULE_ACCEPT) && !guid) || - ((capsule_type == CAPSULE_REVERT) && guid)))) { + if ((capsule == CAPSULE_NORMAL_BLOB && + ((argc != optind + 2) || !guid || + ((privkey_file && !cert_file) || + (!privkey_file && cert_file)))) || + (capsule != CAPSULE_NORMAL_BLOB && + ((argc != optind + 1) || + (capsule == CAPSULE_ACCEPT && !guid) || + (capsule == CAPSULE_REVERT && guid)))) { print_usage(); exit(EXIT_FAILURE); }
- if (capsule_type != CAPSULE_NORMAL_BLOB) { + if (capsule != CAPSULE_NORMAL_BLOB) { if (create_empty_capsule(argv[argc - 1], guid, - capsule_type == CAPSULE_ACCEPT) < 0) { + capsule == CAPSULE_ACCEPT) < 0) { fprintf(stderr, "Creating empty capsule failed\n"); exit(EXIT_FAILURE); } @@ -785,6 +812,4 @@ int main(int argc, char **argv) fprintf(stderr, "Creating firmware capsule failed\n"); exit(EXIT_FAILURE); } - - exit(EXIT_SUCCESS); } diff --git a/tools/mkeficapsule_parse.c b/tools/mkeficapsule_parse.c new file mode 100644 index 0000000000..0b010706d5 --- /dev/null +++ b/tools/mkeficapsule_parse.c @@ -0,0 +1,352 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2023 Linaro Limited + */ + +/* + * The code in this file adds parsing ability to the mkeficapsule + * tool. This allows specifying parameters needed to build the capsule + * through the config file instead of specifying them on the command-line. + * Parameters can be specified for more than one payload, generating the + * corresponding capsule files. + * + * The parameters are specified in a "key:value" pair. All the parameters + * that are currently supported by the mkeficapsule tool can be specified + * in the config file. + * + * The example below shows four payloads. The first payload is an example + * of generating a signed capsule. The second payload is an example of + * generating an unsigned capsule. The third payload is an accept empty + * capsule, while the fourth payload is the revert empty capsule, used + * for the multi-bank firmware update feature. + * + * This functionality can be easily extended to generate a single capsule + * comprising multiple payloads. + + { + image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660 + hardware-instance: 0 + monotonic-count: 1 + payload: u-boot.bin + fw-version: 2 + image-index: 1 + private-key: /path/to/priv/key + pub-key-cert: /path/to/pub/key + capsule: u-boot.capsule + } + { + image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e + hardware-instance: 0 + payload: u-boot.itb + image-index: 2 + fw-version: 10 + oemflags: 0x8000 + capsule: fit.capsule + } + { + capsule-type: accept + image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e + capsule: accept.capsule + } + { + capsule-type: revert + capsule: revert.capsule + } +*/ + +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <uuid/uuid.h> + +#include "eficapsule.h" + +#define PARAMS_START "{" +#define PARAMS_END "}" + +#define PSTART 2 +#define PEND 3 + +#define MALLOC_FAIL_STR "Unable to allocate memory\n" + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +const char *capsule_params[] = { + "image-guid", "image-index", "private-key", + "pub-key-cert", "payload", "capsule", + "hardware-instance", "monotonic-count", + "capsule-type", "oemflags", "fw-version" }; + +static unsigned char params_start; +static unsigned char params_end; + +static void print_and_exit(const char *str) +{ + fprintf(stderr, "%s", str); + exit(EXIT_FAILURE); +} + +static int param_delim_checks(char *line, unsigned char *token) +{ + if (!strcmp(line, PARAMS_START)) { + if (params_start || !params_end) { + fprintf(stderr, "Earlier params processing still in progress. "); + fprintf(stderr, "Can't start processing a new params.\n"); + exit(EXIT_FAILURE); + } else { + params_start = 1; + params_end = 0; + *token = PSTART; + return 1; + } + } else if (!strcmp(line, PARAMS_END)) { + if (!params_start) { + fprintf(stderr, "Cannot put end braces without start braces. "); + fprintf(stderr, "Please check the documentation for reference config file syntax\n"); + exit(EXIT_FAILURE); + } else { + params_start = 0; + params_end = 1; + *token = PEND; + return 1; + } + } else if (!params_start) { + fprintf(stderr, "Params should be passed within braces. "); + fprintf(stderr, "Please check the documentation for reference config file syntax\n"); + exit(EXIT_FAILURE); + } + + return 0; +} + +static void add_guid(efi_guid_t **guid_param, char *guid) +{ + unsigned char uuid_buf[16]; + + *guid_param = malloc(sizeof(efi_guid_t)); + if (!*guid_param) + print_and_exit(MALLOC_FAIL_STR); + + if (uuid_parse(guid, uuid_buf)) + print_and_exit("Wrong guid format\n"); + + convert_uuid_to_guid(uuid_buf); + memcpy(*guid_param, uuid_buf, sizeof(efi_guid_t)); +} + +static void add_string(char **dst, char *val) +{ + *dst = strdup(val); + if (!*dst) + print_and_exit(MALLOC_FAIL_STR); +} + +static void match_and_populate_param(char *key, char *val, + struct efi_capsule_params *param) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(capsule_params); i++) { + if (!strcmp(key, capsule_params[i])) { + switch (i) { + case 0: + add_guid(¶m->image_guid, val); + return; + case 1: + param->image_index = strtoul(val, NULL, 0); + if (param->image_index == ULONG_MAX) + print_and_exit("Enter a valid value of index bewtween 1-255"); + return; + case 2: + add_string(¶m->privkey_file, val); + return; + case 3: + add_string(¶m->cert_file, val); + return; + case 4: + add_string(¶m->input_file, val); + return; + case 5: + add_string(¶m->capsule_file, val); + return; + case 6: + param->hardware_instance = strtoul(val, NULL, 0); + if (param->hardware_instance == ULONG_MAX) + print_and_exit("Enter a valid hardware instance value"); + return; + case 7: + param->monotonic_count = strtoull(val, NULL, 0); + if (param->monotonic_count == ULLONG_MAX) + print_and_exit("Enter a valid monotonic count value"); + return; + case 8: + if (!strcmp(val, "normal")) + param->capsule = CAPSULE_NORMAL_BLOB; + else if (!strcmp(val, "accept")) + param->capsule = CAPSULE_ACCEPT; + else if (!strcmp(val, "revert")) + param->capsule = CAPSULE_REVERT; + else + print_and_exit("Invalid type of capsule"); + + return; + case 9: + param->oemflags = strtoul(val, NULL, 0); + if (param->oemflags > 0xffff) + print_and_exit("OemFlags must be between 0x0 and 0xffff\n"); + return; + case 10: + param->fmp.fw_version = strtoul(val, NULL, 0); + param->fmp.have_header = true; + return; + } + } + } + + fprintf(stderr, "Undefined param %s specified. ", key); + fprintf(stderr, "Please check the documentation for reference config file syntax\n"); + exit(EXIT_FAILURE); +} + +static int get_capsule_params(char *line, struct efi_capsule_params *params) +{ + char *key = NULL; + char *val = NULL; + unsigned char token; + + if (param_delim_checks(line, &token)) + return token; + + key = strtok(line, ":"); + if (key) + val = strtok(NULL, "\0"); + else + print_and_exit("Expect the params in a key:value pair\n"); + + match_and_populate_param(key, val, params); + + return 0; +} + +static char *skip_whitespace(char *line) +{ + char *ptr, *newline; + + ptr = malloc(strlen(line) + 1); + if (!ptr) + print_and_exit(MALLOC_FAIL_STR); + + for (newline = ptr; *line; line++) + if (!isblank(*line)) + *ptr++ = *line; + *ptr = '\0'; + return newline; +} + +static int parse_capsule_payload_params(FILE *fp, struct efi_capsule_params *params) +{ + char *line = NULL; + char *newline; + size_t n = 0; + ssize_t len; + + while ((len = getline(&line, &n, fp)) != -1) { + if (len == 1 && line[len - 1] == '\n') + continue; + + line[len - 1] = '\0'; + + newline = skip_whitespace(line); + + if (newline[0] == '#') + continue; + + if (get_capsule_params(newline, params) == PEND) + return 0; + } + + if (errno == EINVAL || errno == ENOMEM) { + fprintf(stderr, "getline() returned an error %s reading the line\n", + strerror(errno)); + exit(EXIT_FAILURE); + } else if (params_start == 1 || params_end == 0) { + fprintf(stderr, "Params should be passed within braces. "); + fprintf(stderr, "Please check the documentation for reference config file syntax\n"); + exit(EXIT_FAILURE); + } else { + return -1; + } +} + +static void params_dependency_check(struct efi_capsule_params *params) +{ + /* check necessary parameters */ + if ((params->capsule == CAPSULE_NORMAL_BLOB && + ((!params->input_file || !params->capsule_file || + !params->image_guid) || + ((params->privkey_file && !params->cert_file) || + (!params->privkey_file && params->cert_file)))) || + (params->capsule != CAPSULE_NORMAL_BLOB && + (!params->capsule_file || + (params->capsule == CAPSULE_ACCEPT && !params->image_guid) || + (params->capsule == CAPSULE_REVERT && params->image_guid)))) { + print_usage(); + exit(EXIT_FAILURE); + } +} + +static void generate_capsule(struct efi_capsule_params *params) +{ + if (params->capsule != CAPSULE_NORMAL_BLOB) { + if (create_empty_capsule(params->capsule_file, + params->image_guid, + params->capsule == + CAPSULE_ACCEPT) < 0) + print_and_exit("Creating empty capsule failed\n"); + } else if (create_fwbin(params->capsule_file, params->input_file, + params->image_guid, params->image_index, + params->hardware_instance, + ¶ms->fmp, + params->monotonic_count, + params->privkey_file, + params->cert_file, + (uint16_t)params->oemflags) < 0) { + print_and_exit("Creating firmware capsule failed\n"); + } +} + +/** + * capsule_with_cfg_file() - Generate capsule from config file + * @cfg_file: Path to the config file + * + * Parse the capsule parameters from the config file and use the + * parameters for generating one or more capsules. + * + * Return: None + * + */ +void capsule_with_cfg_file(const char *cfg_file) +{ + FILE *fp; + struct efi_capsule_params params = { 0 }; + + fp = fopen(cfg_file, "r"); + if (!fp) { + fprintf(stderr, "Unable to open the capsule config file %s\n", + cfg_file); + exit(EXIT_FAILURE); + } + + params_start = 0; + params_end = 1; + + while (parse_capsule_payload_params(fp, ¶ms) != -1) { + params_dependency_check(¶ms); + generate_capsule(¶ms); + + memset(¶ms, 0, sizeof(struct efi_capsule_params)); + } +}

Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for
generating the above have to be setup before invoking the build. Set this up in the CI configuration docker file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: * New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile.
Note: Earlier, this setup was being done in the azure and gitlab yaml files. Now that this has been moved to the Dockerfile, this will require generating a new container image and referencing that image in the yaml files for the CI to work when these patches get applied.
tools/docker/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 3d2b64a355..294a0b0a53 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ rm -rf /tmp/qemu-linaro
+# Set up capsule files for UEFI capsule update testing +RUN mkdir -p /tmp/capsules && \ + cd /tmp/capsules/ && \ + 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 && \ + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \ + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \ + cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \ + chmod -R uog+rw /tmp/capsules/ + # Build genimage (required by some targets to generate disk images) RUN wget -O - https://github.com/pengutronix/genimage/releases/download/v14/genimage-14.ta... | tar -C /tmp -xJ && \ cd /tmp/genimage-14 && \

On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for generating the above have to be setup before invoking the build. Set this up in the CI configuration docker file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile.
Note: Earlier, this setup was being done in the azure and gitlab yaml files. Now that this has been moved to the Dockerfile, this will require generating a new container image and referencing that image in the yaml files for the CI to work when these patches get applied.
tools/docker/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 3d2b64a355..294a0b0a53 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ rm -rf /tmp/qemu-linaro
+# Set up capsule files for UEFI capsule update testing +RUN mkdir -p /tmp/capsules && \
- cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
- 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \
- cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \
- chmod -R uog+rw /tmp/capsules/
# Build genimage (required by some targets to generate disk images) RUN wget -O - https://github.com/pengutronix/genimage/releases/download/v14/genimage-14.ta... | tar -C /tmp -xJ && \ cd /tmp/genimage-14 && \ -- 2.34.1
Regards, Simon

On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for generating the above have to be setup before invoking the build. Set this up in the CI configuration docker file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile.
Note: Earlier, this setup was being done in the azure and gitlab yaml files. Now that this has been moved to the Dockerfile, this will require generating a new container image and referencing that image in the yaml files for the CI to work when these patches get applied.
tools/docker/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 3d2b64a355..294a0b0a53 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ rm -rf /tmp/qemu-linaro
+# Set up capsule files for UEFI capsule update testing +RUN mkdir -p /tmp/capsules && \
- cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
- 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \
- cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \
- chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.

On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote:
On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for generating the above have to be setup before invoking the build. Set this up in the CI configuration docker file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile.
Note: Earlier, this setup was being done in the azure and gitlab yaml files. Now that this has been moved to the Dockerfile, this will require generating a new container image and referencing that image in the yaml files for the CI to work when these patches get applied.
tools/docker/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 3d2b64a355..294a0b0a53 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ rm -rf /tmp/qemu-linaro
+# Set up capsule files for UEFI capsule update testing +RUN mkdir -p /tmp/capsules && \
- cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
- 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \
- cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \
- chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
-sughosh

On Wed, Jul 26, 2023 at 03:16:38PM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote:
On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for generating the above have to be setup before invoking the build. Set this up in the CI configuration docker file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile.
Note: Earlier, this setup was being done in the azure and gitlab yaml files. Now that this has been moved to the Dockerfile, this will require generating a new container image and referencing that image in the yaml files for the CI to work when these patches get applied.
tools/docker/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 3d2b64a355..294a0b0a53 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ rm -rf /tmp/qemu-linaro
+# Set up capsule files for UEFI capsule update testing +RUN mkdir -p /tmp/capsules && \
- cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
Yes, copying the files rather than relying on them being in /tmp is better, but..
- 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \
- cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \
- chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
It takes 10 minutes or so to build grub, and we use it in multiple tests. Running openssl takes not even a second. Why are we doing this in the Dockerfile? Is this needed in more than one test? If so, does it matter if we have the same certs in each test?

On Wed, 26 Jul 2023 at 18:53, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 03:16:38PM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote:
On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for generating the above have to be setup before invoking the build. Set this up in the CI configuration docker file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile.
Note: Earlier, this setup was being done in the azure and gitlab yaml files. Now that this has been moved to the Dockerfile, this will require generating a new container image and referencing that image in the yaml files for the CI to work when these patches get applied.
tools/docker/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 3d2b64a355..294a0b0a53 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ rm -rf /tmp/qemu-linaro
+# Set up capsule files for UEFI capsule update testing +RUN mkdir -p /tmp/capsules && \
- cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
Yes, copying the files rather than relying on them being in /tmp is better, but..
- 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \
- cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \
- chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
It takes 10 minutes or so to build grub, and we use it in multiple tests. Running openssl takes not even a second. Why are we doing this in the Dockerfile? Is this needed in more than one test? If so, does it matter if we have the same certs in each test?
The reason why these files are needed is that they need to be present before we start the build, for the sandbox variants. I was creating these in the yml files in the earlier versions. Simon suggested putting them in the docker file since these commands don't have to be run on every invocation. These files are needed for the build and pytest stages of the CI.
-sughosh

Hi Tom,
On Wed, 26 Jul 2023 at 07:23, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 03:16:38PM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote:
On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for generating the above have to be setup before invoking the build. Set this up in the CI configuration docker file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile.
Note: Earlier, this setup was being done in the azure and gitlab yaml files. Now that this has been moved to the Dockerfile, this will require generating a new container image and referencing that image in the yaml files for the CI to work when these patches get applied.
tools/docker/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 3d2b64a355..294a0b0a53 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ rm -rf /tmp/qemu-linaro
+# Set up capsule files for UEFI capsule update testing +RUN mkdir -p /tmp/capsules && \
- cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
Yes, copying the files rather than relying on them being in /tmp is better, but..
- 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \
- cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \
- chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
It takes 10 minutes or so to build grub, and we use it in multiple tests. Running openssl takes not even a second. Why are we doing this in the Dockerfile? Is this needed in more than one test? If so, does it matter if we have the same certs in each test?
Yes it is actually much faster that I expected, so I suppose we can go back to having it in the test itself, e.g. in a pytest fixture.
Regards, Simon

hi Simon,
On Wed, 26 Jul 2023 at 19:41, Simon Glass sjg@chromium.org wrote:
Hi Tom,
On Wed, 26 Jul 2023 at 07:23, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 03:16:38PM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote:
On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for generating the above have to be setup before invoking the build. Set this up in the CI configuration docker file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- New patch which moves the setting up of the files needed for testing the EFI capsule update feature to the Dockerfile.
Note: Earlier, this setup was being done in the azure and gitlab yaml files. Now that this has been moved to the Dockerfile, this will require generating a new container image and referencing that image in the yaml files for the CI to work when these patches get applied.
tools/docker/Dockerfile | 12 ++++++++++++ 1 file changed, 12 insertions(+)
diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile index 3d2b64a355..294a0b0a53 100644 --- a/tools/docker/Dockerfile +++ b/tools/docker/Dockerfile @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ rm -rf /tmp/qemu-linaro
+# Set up capsule files for UEFI capsule update testing +RUN mkdir -p /tmp/capsules && \
- cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
Yes, copying the files rather than relying on them being in /tmp is better, but..
- 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \
- openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \
- cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \
- chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
It takes 10 minutes or so to build grub, and we use it in multiple tests. Running openssl takes not even a second. Why are we doing this in the Dockerfile? Is this needed in more than one test? If so, does it matter if we have the same certs in each test?
Yes it is actually much faster that I expected, so I suppose we can go back to having it in the test itself, e.g. in a pytest fixture.
If not part of the docker image, these commands will still have to run as part of the azure and gitlab yml files. They are needed before the build is invoked, as they serve as input files needed to generate the capsules as part of the build. The pytest fixtures would be run a) only for the pytest stages and b) after the build has completed.
-sughosh

Hi Sughosh,
On Wed, 26 Jul 2023 at 08:41, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 19:41, Simon Glass sjg@chromium.org wrote:
Hi Tom,
On Wed, 26 Jul 2023 at 07:23, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 03:16:38PM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote:
On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote: > > Support has being added through earlier commits to build capsules > and embed the public key needed for capsule authentication as part of > u-boot build. > > From the testing point-of-view, this means the input files needed for > generating the above have to be setup before invoking the build. Set > this up in the CI configuration docker file for testing the capsule > update feature. > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > --- > Changes since V4: > * New patch which moves the setting up of the files needed for testing > the EFI capsule update feature to the Dockerfile. > > Note: Earlier, this setup was being done in the azure and gitlab yaml > files. Now that this has been moved to the Dockerfile, this will > require generating a new container image and referencing that image in > the yaml files for the CI to work when these patches get applied. > > tools/docker/Dockerfile | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > > diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile > index 3d2b64a355..294a0b0a53 100644 > --- a/tools/docker/Dockerfile > +++ b/tools/docker/Dockerfile > @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ > cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ > rm -rf /tmp/qemu-linaro > > +# Set up capsule files for UEFI capsule update testing > +RUN mkdir -p /tmp/capsules && \ > + cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
Yes, copying the files rather than relying on them being in /tmp is better, but..
> + 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
> + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \ > + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \ > + cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \ > + chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
It takes 10 minutes or so to build grub, and we use it in multiple tests. Running openssl takes not even a second. Why are we doing this in the Dockerfile? Is this needed in more than one test? If so, does it matter if we have the same certs in each test?
Yes it is actually much faster that I expected, so I suppose we can go back to having it in the test itself, e.g. in a pytest fixture.
If not part of the docker image, these commands will still have to run as part of the azure and gitlab yml files. They are needed before the build is invoked, as they serve as input files needed to generate the capsules as part of the build. The pytest fixtures would be run a) only for the pytest stages and b) after the build has completed.
OK, so let's just create the files before they are needed?
One thought I had that might accelerate this long-running series, is just to do the binman part first (with tests), then add it into the build and CI once that is merged?
Regards, Simon

On Wed, Jul 26, 2023 at 08:11:44PM +0530, Sughosh Ganu wrote:
hi Simon,
On Wed, 26 Jul 2023 at 19:41, Simon Glass sjg@chromium.org wrote:
Hi Tom,
On Wed, 26 Jul 2023 at 07:23, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 03:16:38PM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote:
On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote: > > Support has being added through earlier commits to build capsules > and embed the public key needed for capsule authentication as part of > u-boot build. > > From the testing point-of-view, this means the input files needed for > generating the above have to be setup before invoking the build. Set > this up in the CI configuration docker file for testing the capsule > update feature. > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > --- > Changes since V4: > * New patch which moves the setting up of the files needed for testing > the EFI capsule update feature to the Dockerfile. > > Note: Earlier, this setup was being done in the azure and gitlab yaml > files. Now that this has been moved to the Dockerfile, this will > require generating a new container image and referencing that image in > the yaml files for the CI to work when these patches get applied. > > tools/docker/Dockerfile | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > > diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile > index 3d2b64a355..294a0b0a53 100644 > --- a/tools/docker/Dockerfile > +++ b/tools/docker/Dockerfile > @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ > cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ > rm -rf /tmp/qemu-linaro > > +# Set up capsule files for UEFI capsule update testing > +RUN mkdir -p /tmp/capsules && \ > + cd /tmp/capsules/ && \
You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
Yes, copying the files rather than relying on them being in /tmp is better, but..
> + 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 && \
We don't want these files, just the certs, since they are the things that take a long time:
> + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \ > + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \ > + cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \ > + chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
It takes 10 minutes or so to build grub, and we use it in multiple tests. Running openssl takes not even a second. Why are we doing this in the Dockerfile? Is this needed in more than one test? If so, does it matter if we have the same certs in each test?
Yes it is actually much faster that I expected, so I suppose we can go back to having it in the test itself, e.g. in a pytest fixture.
If not part of the docker image, these commands will still have to run as part of the azure and gitlab yml files. They are needed before the build is invoked, as they serve as input files needed to generate the capsules as part of the build. The pytest fixtures would be run a) only for the pytest stages and b) after the build has completed.
So lets just make use of the artifacts feature, generate these once per CI run and pass them to the jobs that need them? The documentation should reflect that you need to make the certs for production, and for testing purposes see the following sections / stanzas in the GitLab and Azure CI files. Then the pytest part doesn't need to handle the case of running this on your own, since if you are, you need to have read the docs and followed instructions.

On Wed, 26 Jul 2023 at 22:09, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 08:11:44PM +0530, Sughosh Ganu wrote:
hi Simon,
On Wed, 26 Jul 2023 at 19:41, Simon Glass sjg@chromium.org wrote:
Hi Tom,
On Wed, 26 Jul 2023 at 07:23, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 03:16:38PM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote:
On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote: > On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote: > > > > Support has being added through earlier commits to build capsules > > and embed the public key needed for capsule authentication as part of > > u-boot build. > > > > From the testing point-of-view, this means the input files needed for > > generating the above have to be setup before invoking the build. Set > > this up in the CI configuration docker file for testing the capsule > > update feature. > > > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > > --- > > Changes since V4: > > * New patch which moves the setting up of the files needed for testing > > the EFI capsule update feature to the Dockerfile. > > > > Note: Earlier, this setup was being done in the azure and gitlab yaml > > files. Now that this has been moved to the Dockerfile, this will > > require generating a new container image and referencing that image in > > the yaml files for the CI to work when these patches get applied. > > > > tools/docker/Dockerfile | 12 ++++++++++++ > > 1 file changed, 12 insertions(+) > > > > diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile > > index 3d2b64a355..294a0b0a53 100644 > > --- a/tools/docker/Dockerfile > > +++ b/tools/docker/Dockerfile > > @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ > > cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ > > rm -rf /tmp/qemu-linaro > > > > +# Set up capsule files for UEFI capsule update testing > > +RUN mkdir -p /tmp/capsules && \ > > + cd /tmp/capsules/ && \ > > You can just use ${UBOOT_TRAVIS_BUILD_DIR} here
That's not present in Dockerfiles, only at runtime within jobs (because we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
Yes, copying the files rather than relying on them being in /tmp is better, but..
> > + 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 && \ > > We don't want these files, just the certs, since they are the things > that take a long time: > > > + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \ > > + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \ > > + cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \ > > + chmod -R uog+rw /tmp/capsules/
How long does it even take to make these certs? I'm not sure it's great to make these and stage them in /tmp and expect them to be around at test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
It takes 10 minutes or so to build grub, and we use it in multiple tests. Running openssl takes not even a second. Why are we doing this in the Dockerfile? Is this needed in more than one test? If so, does it matter if we have the same certs in each test?
Yes it is actually much faster that I expected, so I suppose we can go back to having it in the test itself, e.g. in a pytest fixture.
If not part of the docker image, these commands will still have to run as part of the azure and gitlab yml files. They are needed before the build is invoked, as they serve as input files needed to generate the capsules as part of the build. The pytest fixtures would be run a) only for the pytest stages and b) after the build has completed.
So lets just make use of the artifacts feature, generate these once per CI run and pass them to the jobs that need them? The documentation should reflect that you need to make the certs for production, and for testing purposes see the following sections / stanzas in the GitLab and Azure CI files. Then the pytest part doesn't need to handle the case of running this on your own, since if you are, you need to have read the docs and followed instructions.
So if I understand you right, what you are suggesting is that we add the generation of the files and certs using the artifacts feature for the CI runs. And also dropping patch 9 of this series [1].
-sughosh
[1] - https://lists.denx.de/pipermail/u-boot/2023-July/524498.html

On Thu, Jul 27, 2023 at 01:30:04AM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 22:09, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 08:11:44PM +0530, Sughosh Ganu wrote:
hi Simon,
On Wed, 26 Jul 2023 at 19:41, Simon Glass sjg@chromium.org wrote:
Hi Tom,
On Wed, 26 Jul 2023 at 07:23, Tom Rini trini@konsulko.com wrote:
On Wed, Jul 26, 2023 at 03:16:38PM +0530, Sughosh Ganu wrote:
On Wed, 26 Jul 2023 at 04:26, Tom Rini trini@konsulko.com wrote: > > On Tue, Jul 25, 2023 at 04:52:38PM -0600, Simon Glass wrote: > > On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote: > > > > > > Support has being added through earlier commits to build capsules > > > and embed the public key needed for capsule authentication as part of > > > u-boot build. > > > > > > From the testing point-of-view, this means the input files needed for > > > generating the above have to be setup before invoking the build. Set > > > this up in the CI configuration docker file for testing the capsule > > > update feature. > > > > > > Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org > > > --- > > > Changes since V4: > > > * New patch which moves the setting up of the files needed for testing > > > the EFI capsule update feature to the Dockerfile. > > > > > > Note: Earlier, this setup was being done in the azure and gitlab yaml > > > files. Now that this has been moved to the Dockerfile, this will > > > require generating a new container image and referencing that image in > > > the yaml files for the CI to work when these patches get applied. > > > > > > tools/docker/Dockerfile | 12 ++++++++++++ > > > 1 file changed, 12 insertions(+) > > > > > > diff --git a/tools/docker/Dockerfile b/tools/docker/Dockerfile > > > index 3d2b64a355..294a0b0a53 100644 > > > --- a/tools/docker/Dockerfile > > > +++ b/tools/docker/Dockerfile > > > @@ -206,6 +206,18 @@ RUN mkdir -p /opt/nokia && \ > > > cp /tmp/qemu-linaro/arm-softmmu/qemu-system-arm /opt/nokia && \ > > > rm -rf /tmp/qemu-linaro > > > > > > +# Set up capsule files for UEFI capsule update testing > > > +RUN mkdir -p /tmp/capsules && \ > > > + cd /tmp/capsules/ && \ > > > > You can just use ${UBOOT_TRAVIS_BUILD_DIR} here > > That's not present in Dockerfiles, only at runtime within jobs (because > we set it).
I can copy the files into UBOOT_TRAVIS_BUILD_DIR as part of the job, similar to what is being done for the grub*.efi files.
Yes, copying the files rather than relying on them being in /tmp is better, but..
> > > + 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 && \ > > > > We don't want these files, just the certs, since they are the things > > that take a long time: > > > > > + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER.key -out SIGNER.crt -nodes -days 365 && \ > > > + openssl req -x509 -sha256 -newkey rsa:2048 -subj /CN=TEST_SIGNER/ -keyout SIGNER2.key -out SIGNER2.crt -nodes -days 365 && \ > > > + cert-to-efi-sig-list SIGNER.crt SIGNER.esl && \ > > > + chmod -R uog+rw /tmp/capsules/ > > How long does it even take to make these certs? I'm not sure it's great > to make these and stage them in /tmp and expect them to be around at > test time.
Should I mimic what is being done for the various grub.efi files? I believe that these are in the /opt/grub/ directory of the docker image, and get copied to the build dir at runtime.
It takes 10 minutes or so to build grub, and we use it in multiple tests. Running openssl takes not even a second. Why are we doing this in the Dockerfile? Is this needed in more than one test? If so, does it matter if we have the same certs in each test?
Yes it is actually much faster that I expected, so I suppose we can go back to having it in the test itself, e.g. in a pytest fixture.
If not part of the docker image, these commands will still have to run as part of the azure and gitlab yml files. They are needed before the build is invoked, as they serve as input files needed to generate the capsules as part of the build. The pytest fixtures would be run a) only for the pytest stages and b) after the build has completed.
So lets just make use of the artifacts feature, generate these once per CI run and pass them to the jobs that need them? The documentation should reflect that you need to make the certs for production, and for testing purposes see the following sections / stanzas in the GitLab and Azure CI files. Then the pytest part doesn't need to handle the case of running this on your own, since if you are, you need to have read the docs and followed instructions.
So if I understand you right, what you are suggesting is that we add the generation of the files and certs using the artifacts feature for the CI runs. And also dropping patch 9 of this series [1].
Yes, we should be able to drop that patch in favor of a combination of documentation and generating and passing it around as needed in CI.

Add support in binman for generating capsules. The capsule parameters can be specified either through a config file or through the capsule binman entry. Also add test cases in binman for capsule generation, and enable this testing on the sandbox_spl variant.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: * Rebase on top of current HEAD. * Remove blank lines after function comments. * Fix a couple of typos. * Use single quotes for strings. * Put the GUIDs in variables with relevant names. * Declare certain values in local variables instead of member values. * Add comments for explaning the payload offsets in the capsule file. * Drop the test case for generating the capsule from the config file. * Define payload data for the capsule tests. * Add logic to find input and output files in capsule generation in the indir and outdir directories when absolute path is not passed.
configs/sandbox_spl_defconfig | 1 + tools/binman/btool/mkeficapsule.py | 153 ++++++++++++++++++ tools/binman/entries.rst | 42 +++++ tools/binman/etype/capsule.py | 132 +++++++++++++++ tools/binman/ftest.py | 115 +++++++++++++ tools/binman/test/307_capsule.dts | 19 +++ tools/binman/test/308_capsule_signed.dts | 21 +++ tools/binman/test/309_capsule_version.dts | 20 +++ tools/binman/test/310_capsule_missing_key.dts | 20 +++ .../binman/test/311_capsule_missing_index.dts | 18 +++ .../binman/test/312_capsule_missing_guid.dts | 17 ++ .../test/313_capsule_missing_payload.dts | 18 +++ tools/binman/test/314_capsule_missing.dts | 18 +++ tools/binman/test/files/capsule_cfg.txt | 6 + 14 files changed, 600 insertions(+) create mode 100644 tools/binman/btool/mkeficapsule.py create mode 100644 tools/binman/etype/capsule.py create mode 100644 tools/binman/test/307_capsule.dts create mode 100644 tools/binman/test/308_capsule_signed.dts create mode 100644 tools/binman/test/309_capsule_version.dts create mode 100644 tools/binman/test/310_capsule_missing_key.dts create mode 100644 tools/binman/test/311_capsule_missing_index.dts create mode 100644 tools/binman/test/312_capsule_missing_guid.dts create mode 100644 tools/binman/test/313_capsule_missing_payload.dts create mode 100644 tools/binman/test/314_capsule_missing.dts create mode 100644 tools/binman/test/files/capsule_cfg.txt
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig index 8d50162b27..65223475ab 100644 --- a/configs/sandbox_spl_defconfig +++ b/configs/sandbox_spl_defconfig @@ -249,3 +249,4 @@ CONFIG_UNIT_TEST=y CONFIG_SPL_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y +CONFIG_TOOLS_MKEFICAPSULE=y diff --git a/tools/binman/btool/mkeficapsule.py b/tools/binman/btool/mkeficapsule.py new file mode 100644 index 0000000000..bfd6552b9a --- /dev/null +++ b/tools/binman/btool/mkeficapsule.py @@ -0,0 +1,153 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright 2023 Linaro Limited +# +"""Bintool implementation for mkeficapsule tool + +mkeficapsule is a tool used for generating EFI capsules. + +The following are the command-line options to be provided +to the tool +Usage: mkeficapsule [options] <image blob> <output file> +Options: + -g, --guid <guid string> guid for image blob type + -i, --index <index> update image index + -I, --instance <instance> update hardware instance + -v, --fw-version <version> firmware version + -p, --private-key <privkey file> private key file + -c, --certificate <cert file> signer's certificate file + -m, --monotonic-count <count> monotonic count + -d, --dump_sig dump signature (*.p7) + -A, --fw-accept firmware accept capsule, requires GUID, no image blob + -R, --fw-revert firmware revert capsule, takes no GUID, no image blob + -o, --capoemflag Capsule OEM Flag, an integer between 0x0000 and 0xffff + -f, --cfg-file <config file> config file with capsule parameters + -h, --help print a help message +""" + +from binman import bintool + +class Bintoolmkeficapsule(bintool.Bintool): + """Handles the 'mkeficapsule' tool + + This bintool is used for generating the EFI capsules. The + capsule generation parameters can either be specified through + command-line, or through a config file. + """ + def __init__(self, name): + super().__init__(name, 'mkeficapsule tool for generating capsules') + + def capsule_cfg_file(self, cfg_file): + """Generate a capsule reading parameters from config file + + Args: + cfg_file (str): Path to the config file + + Returns: + str: Tool output + """ + args = [ + f'--cfg-file={cfg_file}' + ] + return self.run_cmd(*args) + + def cmdline_capsule(self, image_index, image_guid, hardware_instance, + payload, output_fname, version=0): + """Generate a capsule through commandline provided parameters + + Args: + image_index (int): Unique number for identifying payload image + image_guid (str): GUID used for identifying the image + hardware_instance (int): Optional unique hardware instance of + a device in the system. 0 if not being used + payload (str): Path to the input payload image + output_fname (str): Path to the output capsule file + version (int): Image version (Optional) + + Returns: + str: Tool output + """ + if version: + args = [ + f'--index={image_index}', + f'--fw-version={version}', + f'--guid={image_guid}', + f'--instance={hardware_instance}', + payload, + output_fname + ] + else: + args = [ + f'--index={image_index}', + f'--guid={image_guid}', + f'--instance={hardware_instance}', + payload, + output_fname + ] + + return self.run_cmd(*args) + + def cmdline_auth_capsule(self, image_index, image_guid, hardware_instance, + monotonic_count, priv_key, pub_key, + payload, output_fname, version=0): + """Generate a signed capsule through commandline provided parameters + + Args: + image_index (int): Unique number for identifying payload image + image_guid (str): GUID used for identifying the image + hardware_instance (int): Optional unique hardware instance of + a device in the system. 0 if not being used + monotonic_count (int): Count used when signing an image + priv_key (str): Path to the private key + pub_key(str): Path to the public key + payload (str): Path to the input payload image + output_fname (str): Path to the output capsule file + version (int): Image version (Optional) + + Returns: + str: Tool output + """ + if version: + args = [ + f'--index={image_index}', + f'--guid={image_guid}', + f'--instance={hardware_instance}', + f'--monotonic-count={monotonic_count}', + f'--private-key={priv_key}', + f'--certificate={pub_key}', + f'--fw-version={version}', + payload, + output_fname + ] + else: + args = [ + f'--index={image_index}', + f'--guid={image_guid}', + f'--instance={hardware_instance}', + f'--monotonic-count={monotonic_count}', + f'--private-key={priv_key}', + f'--certificate={pub_key}', + payload, + output_fname + ] + + return self.run_cmd(*args) + + def fetch(self, method): + """Fetch handler for mkeficapsule + + This builds the tool from source + + Returns: + tuple: + str: Filename of fetched file to copy to a suitable directory + str: Name of temp directory to remove, or None + """ + if method != bintool.FETCH_BUILD: + return None + + cmd = ['tools-only_defconfig', 'tools'] + result = self.build_from_git( + 'https://source.denx.de/u-boot/u-boot.git', + cmd, + 'tools/mkeficapsule') + return result diff --git a/tools/binman/entries.rst b/tools/binman/entries.rst index f2376932be..d0efe95374 100644 --- a/tools/binman/entries.rst +++ b/tools/binman/entries.rst @@ -283,6 +283,48 @@ entry; similarly for SPL.
+.. _etype_capsule: + +Entry: capsule: Entry for generating EFI Capsule files +------------------------------------------------------ + +This is an entry for generating EFI capsules. + +The parameters needed for generation of the capsules can either be +provided separately, or through a config file. + +Properties / Entry arguments: + - cfg-file: Config file for providing capsule + parameters. These are parameters needed for generating the + capsules. The parameters can be listed by running the + './tools/mkeficapsule -h' command. + - image-index: Unique number for identifying corresponding + payload image. Number between 1 and descriptor count, i.e. + the total number of firmware images that can be updated. + - image-type-id: Image GUID which will be used for identifying the + updatable image on the board. + - hardware-instance: Optional number for identifying unique + hardware instance of a device in the system. Default value of 0 + for images where value is not to be used. + - fw-version: Optional value of image version that can be put on + the capsule through the Firmware Management Protocol(FMP) header. + - monotonic-count: Count used when signing an image. + - private-key: Path to PEM formatted .key private key file. + - pub-key-cert: Path to PEM formatted .crt public key certificate + file. + - filename: Path to the input(payload) file. File can be any + format, a binary or an elf, platform specific. + - capsule: Path to the output capsule file. A capsule is a + continuous set of data as defined by the EFI specification. Refer + to the specification for more details. + +For more details on the description of the capsule format, and the capsule +update functionality, refer Section 8.5 and Chapter 23 in the UEFI +specification. +https://uefi.org/sites/default/files/resources/UEFI_Spec_2_10_Aug29.pdf + + + .. _etype_cbfs:
Entry: cbfs: Coreboot Filesystem (CBFS) diff --git a/tools/binman/etype/capsule.py b/tools/binman/etype/capsule.py new file mode 100644 index 0000000000..53fb668c00 --- /dev/null +++ b/tools/binman/etype/capsule.py @@ -0,0 +1,132 @@ +# SPDX-License-Identifier: GPL-2.0+ +# Copyright (c) 2023 Linaro Limited +# +# Entry-type module for producing a capsule +# + +import os + +from binman.entry import Entry +from dtoc import fdt_util +from u_boot_pylib import tools + +class Entry_capsule(Entry): + """Entry for generating EFI capsules + + This is an entry for generating EFI capsules. + + The parameters needed for generation of the capsules can + either be provided separately, or through a config file. + + Properties / Entry arguments: + - cfg-file: Config file for providing capsule + parameters. These are parameters needed for generating the + capsules. The parameters can be listed by running the + './tools/mkeficapsule -h' command. + - image-index: Unique number for identifying corresponding + payload image. Number between 1 and descriptor count, i.e. + the total number of firmware images that can be updated. + - image-type-id: Image GUID which will be used for identifying the + updatable image on the board. + - hardware-instance: Optional number for identifying unique + hardware instance of a device in the system. Default value of 0 + for images where value is not to be used. + - fw-version: Optional value of image version that can be put on + the capsule through the Firmware Management Protocol(FMP) header. + - monotonic-count: Count used when signing an image. + - private-key: Path to PEM formatted .key private key file. + - pub-key-cert: Path to PEM formatted .crt public key certificate + file. + - filename: Path to the input(payload) file. File can be any + format, a binary or an elf, platform specific. + - capsule: Path to the output capsule file. A capsule is a + continuous set of data as defined by the EFI specification. Refer + to the specification for more details. + + For more details on the description of the capsule format, and the capsule + update functionality, refer Section 8.5 and Chapter 23 in the UEFI + specification. + https://uefi.org/sites/default/files/resources/UEFI_Spec_2_10_Aug29.pdf + """ + def __init__(self, section, etype, node): + super().__init__(section, etype, node) + self.image_index = 0 + self.image_guid = '' + self.hardware_instance = 0 + self.monotonic_count = 0 + self.fw_version = 0 + self.private_key = '' + self.pub_key_cert = '' + self.auth = 0 + self.payload = '' + self.capsule_fname = '' + + def ReadNode(self): + super().ReadNode() + + self.cfg_file = fdt_util.GetString(self._node, 'cfg-file') + if self.cfg_file: + if not os.path.isabs(self.cfg_file): + self.cfg_file = tools.get_input_filename(self.cfg_file) + else: + self.image_index = fdt_util.GetInt(self._node, 'image-index') + if not self.image_index: + self.Raise('mkeficapsule must be provided an Image Index') + + self.image_guid = fdt_util.GetString(self._node, 'image-type-id') + if not self.image_guid: + self.Raise('mkeficapsule must be provided an Image GUID') + + self.fw_version = fdt_util.GetInt(self._node, 'fw-version') + self.hardware_instance = fdt_util.GetInt(self._node, 'hardware-instance') + self.monotonic_count = fdt_util.GetInt(self._node, 'monotonic-count') + + self.private_key = fdt_util.GetString(self._node, 'private-key') + self.pub_key_cert = fdt_util.GetString(self._node, 'pub-key-cert') + + if ((self.private_key and not self.pub_key_cert) or (self.pub_key_cert and not self.private_key)): + self.Raise('Both private key and public key certificate need to be provided') + elif not (self.private_key and self.pub_key_cert): + self.auth = 0 + else: + self.auth = 1 + + self.payload = fdt_util.GetString(self._node, 'filename') + if not self.payload: + self.Raise('mkeficapsule must be provided an input filename(payload)') + if not os.path.isabs(self.payload): + self.payload = tools.get_input_filename(self.payload) + + self.capsule_fname = fdt_util.GetString(self._node, 'capsule') + if not self.capsule_fname: + self.Raise('Specify the output capsule file') + if not os.path.isabs(self.capsule_fname): + self.capsule_fname = tools.get_output_filename(self.capsule_fname) + + def _GenCapsule(self): + if self.cfg_file: + return self.mkeficapsule.capsule_cfg_file(self.cfg_file) + elif self.auth: + return self.mkeficapsule.cmdline_auth_capsule(self.image_index, + self.image_guid, + self.hardware_instance, + self.monotonic_count, + self.private_key, + self.pub_key_cert, + self.payload, + self.capsule_fname, + self.fw_version) + else: + return self.mkeficapsule.cmdline_capsule(self.image_index, + self.image_guid, + self.hardware_instance, + self.payload, + self.capsule_fname, + self.fw_version) + + def ObtainContents(self): + self.SetContents(tools.to_bytes(self._GenCapsule())) + return True + + def AddBintools(self, btools): + self.mkeficapsule = self.AddBintool(btools, 'mkeficapsule') diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 1cfa349d38..13059d93d5 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -48,6 +48,7 @@ U_BOOT_VPL_DATA = b'vpl76543210fedcbazywxyz_' BLOB_DATA = b'89' ME_DATA = b'0abcd' VGA_DATA = b'vga' +EFI_DATA = b'efi' U_BOOT_DTB_DATA = b'udtb' U_BOOT_SPL_DTB_DATA = b'spldtb' U_BOOT_TPL_DTB_DATA = b'tpldtb' @@ -119,6 +120,11 @@ COMP_BINTOOLS = ['bzip2', 'gzip', 'lz4', 'lzma_alone', 'lzop', 'xz', 'zstd']
TEE_ADDR = 0x5678
+# Firmware Management Protocol(FMP) GUID +FW_MGMT_GUID = 'edd5cb6d2de8444cbda17194199ad92a' +# Image GUID specified in the DTS +CAPSULE_IMAGE_GUID = '52cfd7092007104791d108469b7fe9c8' + class TestFunctional(unittest.TestCase): """Functional tests for binman
@@ -7087,5 +7093,114 @@ fdt fdtmap Extract the devicetree blob from the fdtmap self.assertEqual(fdt_util.GetString(key_node, "key-name-hint"), "key")
+ def _CheckCapsule(self, signed_capsule=False, version_check=False): + fmp_signature = "4d535331" # 'M', 'S', 'S', '1' + fmp_size = "10" + fmp_fw_version = "02" + + self.capsule_data = tools.read_file(self.capsule_fname) + + # Firmware Management Protocol(FMP) GUID - offset(0 - 32) + self.assertEqual(FW_MGMT_GUID, self.capsule_data.hex()[:32]) + # Image GUID - offset(96 - 128) + self.assertEqual(CAPSULE_IMAGE_GUID, self.capsule_data.hex()[96:128]) + + if version_check: + # FMP header signature - offset(184 - 192) + self.assertEqual(fmp_signature, self.capsule_data.hex()[184:192]) + # FMP header size - offset(192 - 194) + self.assertEqual(fmp_size, self.capsule_data.hex()[192:194]) + # firmware version - offset(200 - 202) + self.assertEqual(fmp_fw_version, self.capsule_data.hex()[200:202]) + + if signed_capsule: + # payload offset signed capsule(4770 - 4776) + self.assertEqual(self.payload_data.hex(), self.capsule_data.hex()[4770:4776]) + elif version_check: + # payload offset for non-signed capsule with version header(216 - 222) + self.assertEqual(self.payload_data.hex(), self.capsule_data.hex()[216:222]) + else: + # payload offset for non-signed capsule with no version header(184 - 190) + self.assertEqual(self.payload_data.hex(), self.capsule_data.hex()[184:190]) + + def testCapsuleGen(self): + """Test generation of EFI capsule""" + self.payload_data = EFI_DATA + + TestFunctional._MakeInputFile('payload.txt', self.payload_data) + + self._DoReadFile('307_capsule.dts') + + self.capsule_fname = tools.get_output_filename('test.capsule') + self.assertTrue(os.path.exists(self.capsule_fname)) + + self._CheckCapsule() + + def testSignedCapsuleGen(self): + """Test generation of EFI capsule""" + self.payload_data = EFI_DATA + + TestFunctional._MakeInputFile('payload.txt', self.payload_data) + + self._DoReadFile('308_capsule_signed.dts') + + self.capsule_fname = tools.get_output_filename('test.capsule') + self.assertTrue(os.path.exists(self.capsule_fname)) + + self._CheckCapsule(signed_capsule=True) + + def testCapsuleGenVersionSupport(self): + """Test generation of EFI capsule with version support""" + self.payload_data = EFI_DATA + + TestFunctional._MakeInputFile('payload.txt', self.payload_data) + + self._DoReadFile('309_capsule_version.dts') + + self.capsule_fname = tools.get_output_filename('test.capsule') + self.assertTrue(os.path.exists(self.capsule_fname)) + + self._CheckCapsule(version_check=True) + + def testCapsuleGenKeyMissing(self): + """Test that binman errors out on missing key""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('310_capsule_missing_key.dts') + + self.assertIn("Both private key and public key certificate need to be provided", + str(e.exception)) + + def testCapsuleGenIndexMissing(self): + """Test that binman errors out on missing image index""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('311_capsule_missing_index.dts') + + self.assertIn("mkeficapsule must be provided an Image Index", + str(e.exception)) + + def testCapsuleGenGuidMissing(self): + """Test that binman errors out on missing image GUID""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('312_capsule_missing_guid.dts') + + self.assertIn("mkeficapsule must be provided an Image GUID", + str(e.exception)) + + def testCapsuleGenPayloadMissing(self): + """Test that binman errors out on missing input(payload)image""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('313_capsule_missing_payload.dts') + + self.assertIn("mkeficapsule must be provided an input filename(payload)", + str(e.exception)) + + def testCapsuleGenCapsuleFileMissing(self): + """Test that binman errors out on missing output capsule file""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('314_capsule_missing.dts') + + self.assertIn("Specify the output capsule file", + str(e.exception)) + if __name__ == "__main__": unittest.main() diff --git a/tools/binman/test/307_capsule.dts b/tools/binman/test/307_capsule.dts new file mode 100644 index 0000000000..afc2478698 --- /dev/null +++ b/tools/binman/test/307_capsule.dts @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + capsule { + image-index = <0x1>; + /* Image GUID for testing capsule update */ + image-type-id = "09D7CF52-0720-4710-91D1-08469B7FE9C8"; + hardware-instance = <0x0>; + filename = "payload.txt"; + capsule = "test.capsule"; + }; + }; +}; diff --git a/tools/binman/test/308_capsule_signed.dts b/tools/binman/test/308_capsule_signed.dts new file mode 100644 index 0000000000..2de0f198f4 --- /dev/null +++ b/tools/binman/test/308_capsule_signed.dts @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + capsule { + image-index = <0x1>; + /* Image GUID for testing capsule update */ + image-type-id = "09D7CF52-0720-4710-91D1-08469B7FE9C8"; + hardware-instance = <0x0>; + private-key = "tools/binman/test/key.key"; + pub-key-cert = "tools/binman/test/key.pem"; + filename = "payload.txt"; + capsule = "test.capsule"; + }; + }; +}; diff --git a/tools/binman/test/309_capsule_version.dts b/tools/binman/test/309_capsule_version.dts new file mode 100644 index 0000000000..d449d22e6a --- /dev/null +++ b/tools/binman/test/309_capsule_version.dts @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + capsule { + image-index = <0x1>; + fw-version = <0x2>; + /* Image GUID for testing capsule update */ + image-type-id = "09D7CF52-0720-4710-91D1-08469B7FE9C8"; + hardware-instance = <0x0>; + filename = "payload.txt"; + capsule = "test.capsule"; + }; + }; +}; diff --git a/tools/binman/test/310_capsule_missing_key.dts b/tools/binman/test/310_capsule_missing_key.dts new file mode 100644 index 0000000000..69e800df91 --- /dev/null +++ b/tools/binman/test/310_capsule_missing_key.dts @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + capsule { + image-index = <0x1>; + /* Image GUID for testing capsule update */ + image-type-id = "09D7CF52-0720-4710-91D1-08469B7FE9C8"; + hardware-instance = <0x0>; + private-key = "tools/binman/test/key.key"; + filename = "payload.txt"; + capsule = "test.capsule"; + }; + }; +}; diff --git a/tools/binman/test/311_capsule_missing_index.dts b/tools/binman/test/311_capsule_missing_index.dts new file mode 100644 index 0000000000..a84cee7905 --- /dev/null +++ b/tools/binman/test/311_capsule_missing_index.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + capsule { + /* Image GUID for testing capsule update */ + image-type-id = "09D7CF52-0720-4710-91D1-08469B7FE9C8"; + hardware-instance = <0x0>; + filename = "payload.txt"; + capsule = "test.capsule"; + }; + }; +}; diff --git a/tools/binman/test/312_capsule_missing_guid.dts b/tools/binman/test/312_capsule_missing_guid.dts new file mode 100644 index 0000000000..b81aa3ecd2 --- /dev/null +++ b/tools/binman/test/312_capsule_missing_guid.dts @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + capsule { + image-index = <0x1>; + hardware-instance = <0x0>; + filename = "payload.txt"; + capsule = "test.capsule"; + }; + }; +}; diff --git a/tools/binman/test/313_capsule_missing_payload.dts b/tools/binman/test/313_capsule_missing_payload.dts new file mode 100644 index 0000000000..6dd0a77702 --- /dev/null +++ b/tools/binman/test/313_capsule_missing_payload.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + capsule { + image-index = <0x1>; + /* Image GUID for testing capsule update */ + image-type-id = "09D7CF52-0720-4710-91D1-08469B7FE9C8"; + hardware-instance = <0x0>; + capsule = "test.capsule"; + }; + }; +}; diff --git a/tools/binman/test/314_capsule_missing.dts b/tools/binman/test/314_capsule_missing.dts new file mode 100644 index 0000000000..df12f23e6c --- /dev/null +++ b/tools/binman/test/314_capsule_missing.dts @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + capsule { + image-index = <0x1>; + /* Image GUID for testing capsule update */ + image-type-id = "09D7CF52-0720-4710-91D1-08469B7FE9C8"; + hardware-instance = <0x0>; + filename = "payload.txt"; + }; + }; +}; diff --git a/tools/binman/test/files/capsule_cfg.txt b/tools/binman/test/files/capsule_cfg.txt new file mode 100644 index 0000000000..bf44a431b9 --- /dev/null +++ b/tools/binman/test/files/capsule_cfg.txt @@ -0,0 +1,6 @@ +{ + image-index: 1 + image-guid: 09D7CF52-0720-4710-91D1-08469B7FE9C8 + payload: /tmp/capsules/payload.txt + capsule: /tmp/capsules/test.capsule +}

Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Add support in binman for generating capsules. The capsule parameters can be specified either through a config file or through the capsule binman entry. Also add test cases in binman for capsule generation, and enable this testing on the sandbox_spl variant.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Rebase on top of current HEAD.
- Remove blank lines after function comments.
- Fix a couple of typos.
- Use single quotes for strings.
- Put the GUIDs in variables with relevant names.
- Declare certain values in local variables instead of member values.
- Add comments for explaning the payload offsets in the capsule file.
- Drop the test case for generating the capsule from the config file.
- Define payload data for the capsule tests.
- Add logic to find input and output files in capsule generation in the indir and outdir directories when absolute path is not passed.
configs/sandbox_spl_defconfig | 1 + tools/binman/btool/mkeficapsule.py | 153 ++++++++++++++++++ tools/binman/entries.rst | 42 +++++ tools/binman/etype/capsule.py | 132 +++++++++++++++ tools/binman/ftest.py | 115 +++++++++++++ tools/binman/test/307_capsule.dts | 19 +++ tools/binman/test/308_capsule_signed.dts | 21 +++ tools/binman/test/309_capsule_version.dts | 20 +++ tools/binman/test/310_capsule_missing_key.dts | 20 +++ .../binman/test/311_capsule_missing_index.dts | 18 +++ .../binman/test/312_capsule_missing_guid.dts | 17 ++ .../test/313_capsule_missing_payload.dts | 18 +++ tools/binman/test/314_capsule_missing.dts | 18 +++ tools/binman/test/files/capsule_cfg.txt | 6 + 14 files changed, 600 insertions(+) create mode 100644 tools/binman/btool/mkeficapsule.py create mode 100644 tools/binman/etype/capsule.py create mode 100644 tools/binman/test/307_capsule.dts create mode 100644 tools/binman/test/308_capsule_signed.dts create mode 100644 tools/binman/test/309_capsule_version.dts create mode 100644 tools/binman/test/310_capsule_missing_key.dts create mode 100644 tools/binman/test/311_capsule_missing_index.dts create mode 100644 tools/binman/test/312_capsule_missing_guid.dts create mode 100644 tools/binman/test/313_capsule_missing_payload.dts create mode 100644 tools/binman/test/314_capsule_missing.dts create mode 100644 tools/binman/test/files/capsule_cfg.txt
I made all my comments on the previous rev of this patch. Sorry for the delay.
Regards, Simon

The UEFI capsule can now be generate by specifying the capsule parameters through a config file. Additionally, the capsules can be generated as part of u-boot build, through binman. Highlight these changes in the documentation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: None
doc/develop/uefi/uefi.rst | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index b2854b52a6..29955d943e 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -318,6 +318,79 @@ Run the following command --guid <image GUID> \ <capsule_file_name>
+Alternatively, the capsules can be generated through a config +file. When generating the capsules through a config file, the Kconfig +symbol CONFIG_EFI_CAPSULE_CFG_FILE is to be used for specifying the +path to the config file. + +The config file describes the parameters that are used for generating +one or more capsules. The parameters for a given capsule file are +specified within curly braces, in the form of "key:value" pairs. All +the parameters that are currently supported by the mkeficapsule tool +can be specified through the config file. + +The following are some example payload parameters specified through +the config file. + +.. code-block:: none + + { + image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660 + hardware-instance: 0 + monotonic-count: 1 + payload: u-boot.bin + image-index: 1 + fw-version: 2 + private-key: /path/to/priv/key + pub-key-cert: /path/to/pub/key + capsule: u-boot.capsule + } + { + image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e + hardware-instance: 0 + payload: u-boot.itb + image-index: 2 + fw-version: 7 + oemflags: 0x8000 + capsule: fit.capsule + } + { + capsule-type: accept + image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e + capsule: accept.capsule + } + { + capsule-type: revert + capsule: revert.capsule + } + +The following are the keys that specify the capsule parameters + +..code-block:: none + + image-guid: Image GUID + image-index: Image index value + fw-version: Image version + private-key: Path to the private key file used for capsule signing + pub-key-cert: Path to the public key crt file used for capsule signing + payload: Path to the capsule payload file + capsule: Path to the output capsule file that is generated + hardware-instance: Hardware Instance value + monotonic-count: Monotonic count value + capsule-type: Specifies capsule type. normal(default), accept or revert + oemflags: 16bit Oemflags value to be used(populated in capsule header) + +When generating capsules through a config file, the command would look +like + +.. code-block:: console + + $ mkeficapsule --cfg-file </path/to/the/config/file> + + +Capsule with firmware version +***************************** + The UEFI specification does not define the firmware versioning mechanism. EDK II reference implementation inserts the FMP Payload Header right before the payload. It coutains the fw_version and lowest supported version, @@ -345,6 +418,17 @@ add --fw-version option in mkeficapsule tool. If the --fw-version option is not set, FMP Payload Header is not inserted and fw_version is set as 0.
+ +Capsule Generation through binman +********************************* + +Support has also been added to generate capsules during u-boot build +through binman. This requires the platform's DTB to be populated with +the capsule entry nodes for binman. The capsules then can be generated +by specifying the capsule parameters either through a config file, or +by specifying them as properties in the capsule entry node. + + Performing the update *********************

On 25.07.23 10:57, Sughosh Ganu wrote:
The UEFI capsule can now be generate by specifying the capsule parameters through a config file. Additionally, the capsules can be generated as part of u-boot build, through binman. Highlight these changes in the documentation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4: None
doc/develop/uefi/uefi.rst | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index b2854b52a6..29955d943e 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -318,6 +318,79 @@ Run the following command --guid <image GUID> \ <capsule_file_name>
+Alternatively, the capsules can be generated through a config +file. When generating the capsules through a config file, the Kconfig +symbol CONFIG_EFI_CAPSULE_CFG_FILE is to be used for specifying the +path to the config file.
+The config file describes the parameters that are used for generating +one or more capsules. The parameters for a given capsule file are +specified within curly braces, in the form of "key:value" pairs. All +the parameters that are currently supported by the mkeficapsule tool +can be specified through the config file.
+The following are some example payload parameters specified through +the config file.
+.. code-block:: none
- {
image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660
hardware-instance: 0
monotonic-count: 1
payload: u-boot.bin
image-index: 1
fw-version: 2
private-key: /path/to/priv/key
pub-key-cert: /path/to/pub/key
capsule: u-boot.capsule
- }
- {
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
hardware-instance: 0
payload: u-boot.itb
image-index: 2
fw-version: 7
oemflags: 0x8000
capsule: fit.capsule
- }
- {
capsule-type: accept
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
capsule: accept.capsule
- }
- {
capsule-type: revert
capsule: revert.capsule
- }
This seems to be neither YAML nor JSON. Can't we use a standardized format? YAML is easily parsed in C with libfyaml (see https://www.wpsoftware.net/andrew/pages/libyaml.html).
Best regards
Heinrich
+The following are the keys that specify the capsule parameters
+..code-block:: none
- image-guid: Image GUID
- image-index: Image index value
- fw-version: Image version
- private-key: Path to the private key file used for capsule signing
- pub-key-cert: Path to the public key crt file used for capsule signing
- payload: Path to the capsule payload file
- capsule: Path to the output capsule file that is generated
- hardware-instance: Hardware Instance value
- monotonic-count: Monotonic count value
- capsule-type: Specifies capsule type. normal(default), accept or revert
- oemflags: 16bit Oemflags value to be used(populated in capsule header)
+When generating capsules through a config file, the command would look +like
+.. code-block:: console
- $ mkeficapsule --cfg-file </path/to/the/config/file>
+Capsule with firmware version +*****************************
- The UEFI specification does not define the firmware versioning mechanism. EDK II reference implementation inserts the FMP Payload Header right before the payload. It coutains the fw_version and lowest supported version,
@@ -345,6 +418,17 @@ add --fw-version option in mkeficapsule tool. If the --fw-version option is not set, FMP Payload Header is not inserted and fw_version is set as 0.
+Capsule Generation through binman +*********************************
+Support has also been added to generate capsules during u-boot build +through binman. This requires the platform's DTB to be populated with +the capsule entry nodes for binman. The capsules then can be generated +by specifying the capsule parameters either through a config file, or +by specifying them as properties in the capsule entry node.
- Performing the update

Hi,
On Tue, 25 Jul 2023 at 10:18, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 25.07.23 10:57, Sughosh Ganu wrote:
The UEFI capsule can now be generate by specifying the capsule parameters through a config file. Additionally, the capsules can be generated as part of u-boot build, through binman. Highlight these changes in the documentation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4: None
doc/develop/uefi/uefi.rst | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index b2854b52a6..29955d943e 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -318,6 +318,79 @@ Run the following command --guid <image GUID> \ <capsule_file_name>
+Alternatively, the capsules can be generated through a config +file. When generating the capsules through a config file, the Kconfig +symbol CONFIG_EFI_CAPSULE_CFG_FILE is to be used for specifying the +path to the config file.
+The config file describes the parameters that are used for generating +one or more capsules. The parameters for a given capsule file are +specified within curly braces, in the form of "key:value" pairs. All +the parameters that are currently supported by the mkeficapsule tool +can be specified through the config file.
+The following are some example payload parameters specified through +the config file.
+.. code-block:: none
{
image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660
hardware-instance: 0
monotonic-count: 1
payload: u-boot.bin
image-index: 1
fw-version: 2
private-key: /path/to/priv/key
pub-key-cert: /path/to/pub/key
capsule: u-boot.capsule
}
{
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
hardware-instance: 0
payload: u-boot.itb
image-index: 2
fw-version: 7
oemflags: 0x8000
capsule: fit.capsule
}
{
capsule-type: accept
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
capsule: accept.capsule
}
{
capsule-type: revert
capsule: revert.capsule
}
This seems to be neither YAML nor JSON. Can't we use a standardized format? YAML is easily parsed in C with libfyaml (see https://www.wpsoftware.net/andrew/pages/libyaml.html).
Can we please get this series landed without the config file at first? If it useful we can add it later, but it is a complexity that is not necessary for an initial series.
Regards, Simon

hi Simon,
On Wed, 26 Jul 2023 at 04:24, Simon Glass sjg@chromium.org wrote:
Hi,
On Tue, 25 Jul 2023 at 10:18, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 25.07.23 10:57, Sughosh Ganu wrote:
The UEFI capsule can now be generate by specifying the capsule parameters through a config file. Additionally, the capsules can be generated as part of u-boot build, through binman. Highlight these changes in the documentation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4: None
doc/develop/uefi/uefi.rst | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index b2854b52a6..29955d943e 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -318,6 +318,79 @@ Run the following command --guid <image GUID> \ <capsule_file_name>
+Alternatively, the capsules can be generated through a config +file. When generating the capsules through a config file, the Kconfig +symbol CONFIG_EFI_CAPSULE_CFG_FILE is to be used for specifying the +path to the config file.
+The config file describes the parameters that are used for generating +one or more capsules. The parameters for a given capsule file are +specified within curly braces, in the form of "key:value" pairs. All +the parameters that are currently supported by the mkeficapsule tool +can be specified through the config file.
+The following are some example payload parameters specified through +the config file.
+.. code-block:: none
{
image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660
hardware-instance: 0
monotonic-count: 1
payload: u-boot.bin
image-index: 1
fw-version: 2
private-key: /path/to/priv/key
pub-key-cert: /path/to/pub/key
capsule: u-boot.capsule
}
{
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
hardware-instance: 0
payload: u-boot.itb
image-index: 2
fw-version: 7
oemflags: 0x8000
capsule: fit.capsule
}
{
capsule-type: accept
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
capsule: accept.capsule
}
{
capsule-type: revert
capsule: revert.capsule
}
This seems to be neither YAML nor JSON. Can't we use a standardized format? YAML is easily parsed in C with libfyaml (see https://www.wpsoftware.net/andrew/pages/libyaml.html).
Can we please get this series landed without the config file at first? If it useful we can add it later, but it is a complexity that is not necessary for an initial series.
We do need support for generation of capsules through the config file. There is another patchset [1] which will be leveraging generation of capsules through the config file. I believe AMD(Xilinx) too is looking for support of such functionality, whereby the capsule gets generated after reading the parameters from the config file. Not being able to generate capsules through the config file as part of the build would be a half baked support.
In my earlier reply [2] to your concern about using relative paths for capsule generation, I had mentioned that if we cannot extend binman tests to use absolute paths, we can drop testing this scenario in the binman tests suite since this feature is actually getting tested as part of the larger EFI capsule update feature testing. Would that not be okay with you? Else we have the option of using absolute paths for the indir and outdir, instead of the runtime generated directories, only for this feature test of course.
-sughosh
[1] - https://lists.denx.de/pipermail/u-boot/2023-June/520407.html [2] - https://lists.denx.de/pipermail/u-boot/2023-July/523779.html

Hi Sughosh,
On Wed, 26 Jul 2023 at 03:17, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 04:24, Simon Glass sjg@chromium.org wrote:
Hi,
On Tue, 25 Jul 2023 at 10:18, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 25.07.23 10:57, Sughosh Ganu wrote:
The UEFI capsule can now be generate by specifying the capsule parameters through a config file. Additionally, the capsules can be generated as part of u-boot build, through binman. Highlight these changes in the documentation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4: None
doc/develop/uefi/uefi.rst | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index b2854b52a6..29955d943e 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -318,6 +318,79 @@ Run the following command --guid <image GUID> \ <capsule_file_name>
+Alternatively, the capsules can be generated through a config +file. When generating the capsules through a config file, the Kconfig +symbol CONFIG_EFI_CAPSULE_CFG_FILE is to be used for specifying the +path to the config file.
+The config file describes the parameters that are used for generating +one or more capsules. The parameters for a given capsule file are +specified within curly braces, in the form of "key:value" pairs. All +the parameters that are currently supported by the mkeficapsule tool +can be specified through the config file.
+The following are some example payload parameters specified through +the config file.
+.. code-block:: none
{
image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660
hardware-instance: 0
monotonic-count: 1
payload: u-boot.bin
image-index: 1
fw-version: 2
private-key: /path/to/priv/key
pub-key-cert: /path/to/pub/key
capsule: u-boot.capsule
}
{
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
hardware-instance: 0
payload: u-boot.itb
image-index: 2
fw-version: 7
oemflags: 0x8000
capsule: fit.capsule
}
{
capsule-type: accept
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
capsule: accept.capsule
}
{
capsule-type: revert
capsule: revert.capsule
}
This seems to be neither YAML nor JSON. Can't we use a standardized format? YAML is easily parsed in C with libfyaml (see https://www.wpsoftware.net/andrew/pages/libyaml.html).
Can we please get this series landed without the config file at first? If it useful we can add it later, but it is a complexity that is not necessary for an initial series.
We do need support for generation of capsules through the config file. There is another patchset [1] which will be leveraging generation of capsules through the config file. I believe AMD(Xilinx) too is looking for support of such functionality, whereby the capsule gets generated after reading the parameters from the config file. Not being able to generate capsules through the config file as part of the build would be a half baked support.
Well let's drop it for now. It is creating a parallel description format when we are trying to have just one (binman).
In my earlier reply [2] to your concern about using relative paths for capsule generation, I had mentioned that if we cannot extend binman tests to use absolute paths, we can drop testing this scenario in the binman tests suite since this feature is actually getting tested as part of the larger EFI capsule update feature testing. Would that not be okay with you? Else we have the option of using absolute paths for the indir and outdir, instead of the runtime generated directories, only for this feature test of course.
No, let's drop the config file for now. It is making everything too confusing.
Regards, Simon
-sughosh
[1] - https://lists.denx.de/pipermail/u-boot/2023-June/520407.html [2] - https://lists.denx.de/pipermail/u-boot/2023-July/523779.html

hi Heinrich,
On Tue, 25 Jul 2023 at 21:42, Heinrich Schuchardt xypron.glpk@gmx.de wrote:
On 25.07.23 10:57, Sughosh Ganu wrote:
The UEFI capsule can now be generate by specifying the capsule parameters through a config file. Additionally, the capsules can be generated as part of u-boot build, through binman. Highlight these changes in the documentation.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4: None
doc/develop/uefi/uefi.rst | 84 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/doc/develop/uefi/uefi.rst b/doc/develop/uefi/uefi.rst index b2854b52a6..29955d943e 100644 --- a/doc/develop/uefi/uefi.rst +++ b/doc/develop/uefi/uefi.rst @@ -318,6 +318,79 @@ Run the following command --guid <image GUID> \ <capsule_file_name>
+Alternatively, the capsules can be generated through a config +file. When generating the capsules through a config file, the Kconfig +symbol CONFIG_EFI_CAPSULE_CFG_FILE is to be used for specifying the +path to the config file.
+The config file describes the parameters that are used for generating +one or more capsules. The parameters for a given capsule file are +specified within curly braces, in the form of "key:value" pairs. All +the parameters that are currently supported by the mkeficapsule tool +can be specified through the config file.
+The following are some example payload parameters specified through +the config file.
+.. code-block:: none
{
image-guid: 02f4d760-cfd5-43bd-8e2d-a42acb33c660
hardware-instance: 0
monotonic-count: 1
payload: u-boot.bin
image-index: 1
fw-version: 2
private-key: /path/to/priv/key
pub-key-cert: /path/to/pub/key
capsule: u-boot.capsule
}
{
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
hardware-instance: 0
payload: u-boot.itb
image-index: 2
fw-version: 7
oemflags: 0x8000
capsule: fit.capsule
}
{
capsule-type: accept
image-guid: 4ce292da-1dd8-428d-a1c2-77743ef8b96e
capsule: accept.capsule
}
{
capsule-type: revert
capsule: revert.capsule
}
This seems to be neither YAML nor JSON. Can't we use a standardized format? YAML is easily parsed in C with libfyaml (see https://www.wpsoftware.net/andrew/pages/libyaml.html).
I used this key:value format since I wanted to keep this as close to the one used in EDK2 as possible. EDK2 does use json files, but the format is very similar to what I have introduced here. I have attached a file for your reference.
-sughosh
Best regards
Heinrich
+The following are the keys that specify the capsule parameters
+..code-block:: none
- image-guid: Image GUID
- image-index: Image index value
- fw-version: Image version
- private-key: Path to the private key file used for capsule signing
- pub-key-cert: Path to the public key crt file used for capsule signing
- payload: Path to the capsule payload file
- capsule: Path to the output capsule file that is generated
- hardware-instance: Hardware Instance value
- monotonic-count: Monotonic count value
- capsule-type: Specifies capsule type. normal(default), accept or revert
- oemflags: 16bit Oemflags value to be used(populated in capsule header)
+When generating capsules through a config file, the command would look +like
+.. code-block:: console
- $ mkeficapsule --cfg-file </path/to/the/config/file>
+Capsule with firmware version +*****************************
- The UEFI specification does not define the firmware versioning mechanism. EDK II reference implementation inserts the FMP Payload Header right before the payload. It coutains the fw_version and lowest supported version,
@@ -345,6 +418,17 @@ add --fw-version option in mkeficapsule tool. If the --fw-version option is not set, FMP Payload Header is not inserted and fw_version is set as 0.
+Capsule Generation through binman +*********************************
+Support has also been added to generate capsules during u-boot build +through binman. This requires the platform's DTB to be populated with +the capsule entry nodes for binman. The capsules then can be generated +by specifying the capsule parameters either through a config file, or +by specifying them as properties in the capsule entry node.
- Performing the update

Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for
the above have to be setup before invoking the build. Set this up in the pytest configuration file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org Reviewed-by: Simon Glass sjg@chromium.org --- Changes since V4: None
test/py/conftest.py | 84 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/test/py/conftest.py b/test/py/conftest.py index fc9dd3a83f..1092cb713b 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -80,6 +80,86 @@ def pytest_addoption(parser): help='Run sandbox under gdbserver. The argument is the channel '+ 'over which gdbserver should communicate, e.g. localhost:1234')
+def setup_capsule_build(source_dir, build_dir, board_type, log): + """Setup the platform's build for testing capsule updates + + This generates the payload/input files needed for testing the + capsule update functionality, along with the keys for signing + the capsules. An EFI Signature List(ESL) file, which houses the + public key for capsule authentication is generated as + well. + + The ESL file is subsequently embedded into the platform's + dtb during the u-boot build, to be used for capsule + authentication. + + Two sets of keys are generated, namely SIGNER and SIGNER2. + The SIGNER2 key pair is used as a malicious key for testing the + the capsule authentication functionality. + + All the generated files are placed under the /tmp/capsules/ + directory. + + Args: + soruce_dir (str): Directory containing source code + build_dir (str): Directory to build in + board_type (str): board_type parameter (e.g. 'sandbox') + log (Logfile): Log file to use + + Returns: + Nothing. + """ + def run_command(name, cmd, source_dir): + with log.section(name): + if isinstance(cmd, str): + cmd = cmd.split() + runner = log.get_runner(name, None) + runner.run(cmd, cwd=source_dir) + runner.close() + log.status_pass('OK') + + def gen_capsule_payloads(capsule_dir): + fname = f'{capsule_dir}u-boot.bin.old' + with open(fname, 'w') as fd: + fd.write('u-boot:Old') + + fname = f'{capsule_dir}u-boot.bin.new' + with open(fname, 'w') as fd: + fd.write('u-boot:New') + + fname = f'{capsule_dir}u-boot.env.old' + with open(fname, 'w') as fd: + fd.write('u-boot-env:Old') + + fname = f'{capsule_dir}u-boot.env.new' + with open(fname, 'w') as fd: + fd.write('u-boot-env:New') + + capsule_sig_dir = '/tmp/capsules/' + sig_name = 'SIGNER' + mkdir_p(capsule_sig_dir) + name = 'openssl' + cmd = ( 'openssl req -x509 -sha256 -newkey rsa:2048 ' + '-subj /CN=TEST_SIGNER/ -keyout ' + f'{capsule_sig_dir}{sig_name}.key ' + f'-out {capsule_sig_dir}{sig_name}.crt -nodes -days 365' ) + run_command(name, cmd, source_dir) + + name = 'cert-to-efi-sig-list' + cmd = ( f'cert-to-efi-sig-list {capsule_sig_dir}{sig_name}.crt ' + f'{capsule_sig_dir}{sig_name}.esl' ) + run_command(name, cmd, source_dir) + + sig_name = 'SIGNER2' + name = 'openssl' + cmd = ( 'openssl req -x509 -sha256 -newkey rsa:2048 ' + '-subj /CN=TEST_SIGNER/ -keyout ' + f'{capsule_sig_dir}{sig_name}.key ' + f'-out {capsule_sig_dir}{sig_name}.crt -nodes -days 365' ) + run_command(name, cmd, source_dir) + + gen_capsule_payloads(capsule_sig_dir) + def run_build(config, source_dir, build_dir, board_type, log): """run_build: Build U-Boot
@@ -90,6 +170,10 @@ def run_build(config, source_dir, build_dir, board_type, log): board_type (str): board_type parameter (e.g. 'sandbox') log (Logfile): Log file to use """ + capsule_boards = ( 'sandbox', 'sandbox64', 'sandbox_flattree' ) + if board_type in capsule_boards: + setup_capsule_build(source_dir, build_dir, board_type, log) + if config.getoption('buildman'): if build_dir != source_dir: dest_args = ['-o', build_dir, '-w']

Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for the above have to be setup before invoking the build. Set this up in the pytest configuration file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
Changes since V4: None
test/py/conftest.py | 84 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/test/py/conftest.py b/test/py/conftest.py index fc9dd3a83f..1092cb713b 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -80,6 +80,86 @@ def pytest_addoption(parser): help='Run sandbox under gdbserver. The argument is the channel '+ 'over which gdbserver should communicate, e.g. localhost:1234')
+def setup_capsule_build(source_dir, build_dir, board_type, log):
- """Setup the platform's build for testing capsule updates
- This generates the payload/input files needed for testing the
- capsule update functionality, along with the keys for signing
- the capsules. An EFI Signature List(ESL) file, which houses the
- public key for capsule authentication is generated as
- well.
- The ESL file is subsequently embedded into the platform's
- dtb during the u-boot build, to be used for capsule
- authentication.
- Two sets of keys are generated, namely SIGNER and SIGNER2.
- The SIGNER2 key pair is used as a malicious key for testing the
- the capsule authentication functionality.
- All the generated files are placed under the /tmp/capsules/
- directory.
- Args:
soruce_dir (str): Directory containing source code
build_dir (str): Directory to build in
board_type (str): board_type parameter (e.g. 'sandbox')
log (Logfile): Log file to use
- Returns:
Nothing.
- """
- def run_command(name, cmd, source_dir):
with log.section(name):
if isinstance(cmd, str):
cmd = cmd.split()
runner = log.get_runner(name, None)
runner.run(cmd, cwd=source_dir)
runner.close()
log.status_pass('OK')
- def gen_capsule_payloads(capsule_dir):
fname = f'{capsule_dir}u-boot.bin.old'
with open(fname, 'w') as fd:
fd.write('u-boot:Old')
fname = f'{capsule_dir}u-boot.bin.new'
with open(fname, 'w') as fd:
fd.write('u-boot:New')
fname = f'{capsule_dir}u-boot.env.old'
with open(fname, 'w') as fd:
fd.write('u-boot-env:Old')
fname = f'{capsule_dir}u-boot.env.new'
with open(fname, 'w') as fd:
fd.write('u-boot-env:New')
- capsule_sig_dir = '/tmp/capsules/'
- sig_name = 'SIGNER'
- mkdir_p(capsule_sig_dir)
- name = 'openssl'
- cmd = ( 'openssl req -x509 -sha256 -newkey rsa:2048 '
'-subj /CN=TEST_SIGNER/ -keyout '
f'{capsule_sig_dir}{sig_name}.key '
f'-out {capsule_sig_dir}{sig_name}.crt -nodes -days 365' )
- run_command(name, cmd, source_dir)
Can you drop this now that the docker file does it?
- name = 'cert-to-efi-sig-list'
- cmd = ( f'cert-to-efi-sig-list {capsule_sig_dir}{sig_name}.crt '
f'{capsule_sig_dir}{sig_name}.esl' )
- run_command(name, cmd, source_dir)
- sig_name = 'SIGNER2'
- name = 'openssl'
- cmd = ( 'openssl req -x509 -sha256 -newkey rsa:2048 '
'-subj /CN=TEST_SIGNER/ -keyout '
f'{capsule_sig_dir}{sig_name}.key '
f'-out {capsule_sig_dir}{sig_name}.crt -nodes -days 365' )
- run_command(name, cmd, source_dir)
- gen_capsule_payloads(capsule_sig_dir)
def run_build(config, source_dir, build_dir, board_type, log): """run_build: Build U-Boot
@@ -90,6 +170,10 @@ def run_build(config, source_dir, build_dir, board_type, log): board_type (str): board_type parameter (e.g. 'sandbox') log (Logfile): Log file to use """
- capsule_boards = ( 'sandbox', 'sandbox64', 'sandbox_flattree' )
- if board_type in capsule_boards:
setup_capsule_build(source_dir, build_dir, board_type, log)
- if config.getoption('buildman'): if build_dir != source_dir: dest_args = ['-o', build_dir, '-w']
-- 2.34.1
Regards, Simon

hi Simon,
On Wed, 26 Jul 2023 at 04:23, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for the above have to be setup before invoking the build. Set this up in the pytest configuration file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
Changes since V4: None
test/py/conftest.py | 84 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/test/py/conftest.py b/test/py/conftest.py index fc9dd3a83f..1092cb713b 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -80,6 +80,86 @@ def pytest_addoption(parser): help='Run sandbox under gdbserver. The argument is the channel '+ 'over which gdbserver should communicate, e.g. localhost:1234')
+def setup_capsule_build(source_dir, build_dir, board_type, log):
- """Setup the platform's build for testing capsule updates
- This generates the payload/input files needed for testing the
- capsule update functionality, along with the keys for signing
- the capsules. An EFI Signature List(ESL) file, which houses the
- public key for capsule authentication is generated as
- well.
- The ESL file is subsequently embedded into the platform's
- dtb during the u-boot build, to be used for capsule
- authentication.
- Two sets of keys are generated, namely SIGNER and SIGNER2.
- The SIGNER2 key pair is used as a malicious key for testing the
- the capsule authentication functionality.
- All the generated files are placed under the /tmp/capsules/
- directory.
- Args:
soruce_dir (str): Directory containing source code
build_dir (str): Directory to build in
board_type (str): board_type parameter (e.g. 'sandbox')
log (Logfile): Log file to use
- Returns:
Nothing.
- """
- def run_command(name, cmd, source_dir):
with log.section(name):
if isinstance(cmd, str):
cmd = cmd.split()
runner = log.get_runner(name, None)
runner.run(cmd, cwd=source_dir)
runner.close()
log.status_pass('OK')
- def gen_capsule_payloads(capsule_dir):
fname = f'{capsule_dir}u-boot.bin.old'
with open(fname, 'w') as fd:
fd.write('u-boot:Old')
fname = f'{capsule_dir}u-boot.bin.new'
with open(fname, 'w') as fd:
fd.write('u-boot:New')
fname = f'{capsule_dir}u-boot.env.old'
with open(fname, 'w') as fd:
fd.write('u-boot-env:Old')
fname = f'{capsule_dir}u-boot.env.new'
with open(fname, 'w') as fd:
fd.write('u-boot-env:New')
- capsule_sig_dir = '/tmp/capsules/'
- sig_name = 'SIGNER'
- mkdir_p(capsule_sig_dir)
- name = 'openssl'
- cmd = ( 'openssl req -x509 -sha256 -newkey rsa:2048 '
'-subj /CN=TEST_SIGNER/ -keyout '
f'{capsule_sig_dir}{sig_name}.key '
f'-out {capsule_sig_dir}{sig_name}.crt -nodes -days 365' )
- run_command(name, cmd, source_dir)
Can you drop this now that the docker file does it?
This handles the scenario of running the pytest on the host machine. We can run the tests on our host machine as well, and the capsule tests need to be supported even for that test scenario. The docker file will only handle the CI environment.
-sughosh
- name = 'cert-to-efi-sig-list'
- cmd = ( f'cert-to-efi-sig-list {capsule_sig_dir}{sig_name}.crt '
f'{capsule_sig_dir}{sig_name}.esl' )
- run_command(name, cmd, source_dir)
- sig_name = 'SIGNER2'
- name = 'openssl'
- cmd = ( 'openssl req -x509 -sha256 -newkey rsa:2048 '
'-subj /CN=TEST_SIGNER/ -keyout '
f'{capsule_sig_dir}{sig_name}.key '
f'-out {capsule_sig_dir}{sig_name}.crt -nodes -days 365' )
- run_command(name, cmd, source_dir)
- gen_capsule_payloads(capsule_sig_dir)
def run_build(config, source_dir, build_dir, board_type, log): """run_build: Build U-Boot
@@ -90,6 +170,10 @@ def run_build(config, source_dir, build_dir, board_type, log): board_type (str): board_type parameter (e.g. 'sandbox') log (Logfile): Log file to use """
- capsule_boards = ( 'sandbox', 'sandbox64', 'sandbox_flattree' )
- if board_type in capsule_boards:
setup_capsule_build(source_dir, build_dir, board_type, log)
- if config.getoption('buildman'): if build_dir != source_dir: dest_args = ['-o', build_dir, '-w']
-- 2.34.1
Regards, Simon

Hi Sughosh,
On Wed, 26 Jul 2023 at 03:00, Sughosh Ganu sughosh.ganu@linaro.org wrote:
hi Simon,
On Wed, 26 Jul 2023 at 04:23, Simon Glass sjg@chromium.org wrote:
Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has being added through earlier commits to build capsules and embed the public key needed for capsule authentication as part of u-boot build.
From the testing point-of-view, this means the input files needed for the above have to be setup before invoking the build. Set this up in the pytest configuration file for testing the capsule update feature.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org Reviewed-by: Simon Glass sjg@chromium.org
Changes since V4: None
test/py/conftest.py | 84 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+)
diff --git a/test/py/conftest.py b/test/py/conftest.py index fc9dd3a83f..1092cb713b 100644 --- a/test/py/conftest.py +++ b/test/py/conftest.py @@ -80,6 +80,86 @@ def pytest_addoption(parser): help='Run sandbox under gdbserver. The argument is the channel '+ 'over which gdbserver should communicate, e.g. localhost:1234')
+def setup_capsule_build(source_dir, build_dir, board_type, log):
- """Setup the platform's build for testing capsule updates
- This generates the payload/input files needed for testing the
- capsule update functionality, along with the keys for signing
- the capsules. An EFI Signature List(ESL) file, which houses the
- public key for capsule authentication is generated as
- well.
- The ESL file is subsequently embedded into the platform's
- dtb during the u-boot build, to be used for capsule
- authentication.
- Two sets of keys are generated, namely SIGNER and SIGNER2.
- The SIGNER2 key pair is used as a malicious key for testing the
- the capsule authentication functionality.
- All the generated files are placed under the /tmp/capsules/
- directory.
- Args:
soruce_dir (str): Directory containing source code
build_dir (str): Directory to build in
board_type (str): board_type parameter (e.g. 'sandbox')
log (Logfile): Log file to use
- Returns:
Nothing.
- """
- def run_command(name, cmd, source_dir):
with log.section(name):
if isinstance(cmd, str):
cmd = cmd.split()
runner = log.get_runner(name, None)
runner.run(cmd, cwd=source_dir)
runner.close()
log.status_pass('OK')
- def gen_capsule_payloads(capsule_dir):
fname = f'{capsule_dir}u-boot.bin.old'
with open(fname, 'w') as fd:
fd.write('u-boot:Old')
fname = f'{capsule_dir}u-boot.bin.new'
with open(fname, 'w') as fd:
fd.write('u-boot:New')
fname = f'{capsule_dir}u-boot.env.old'
with open(fname, 'w') as fd:
fd.write('u-boot-env:Old')
fname = f'{capsule_dir}u-boot.env.new'
with open(fname, 'w') as fd:
fd.write('u-boot-env:New')
- capsule_sig_dir = '/tmp/capsules/'
- sig_name = 'SIGNER'
- mkdir_p(capsule_sig_dir)
- name = 'openssl'
- cmd = ( 'openssl req -x509 -sha256 -newkey rsa:2048 '
'-subj /CN=TEST_SIGNER/ -keyout '
f'{capsule_sig_dir}{sig_name}.key '
f'-out {capsule_sig_dir}{sig_name}.crt -nodes -days 365' )
- run_command(name, cmd, source_dir)
Can you drop this now that the docker file does it?
This handles the scenario of running the pytest on the host machine. We can run the tests on our host machine as well, and the capsule tests need to be supported even for that test scenario. The docker file will only handle the CI environment.
OK I see.
Regards, Simon

The embedding of the public key EFI Signature List(ESL) file into the platform's DTB is now done at the time of u-boot build. Remove this logic from the capsule update test' configuration.
Include the public key for the sandbox and sandbox_flattree variant as part of the build.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: None
configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 1 + test/py/tests/test_efi_capsule/conftest.py | 37 ++++---------------- test/py/tests/test_efi_capsule/signature.dts | 10 ------ 4 files changed, 9 insertions(+), 40 deletions(-) delete mode 100644 test/py/tests/test_efi_capsule/signature.dts
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 19cc6701e6..53e342b3fa 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -342,6 +342,7 @@ CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y CONFIG_EFI_CAPSULE_ON_DISK=y CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y CONFIG_EFI_CAPSULE_AUTHENTICATE=y +CONFIG_EFI_CAPSULE_ESL_FILE="/tmp/capsules/SIGNER.esl" CONFIG_EFI_SECURE_BOOT=y CONFIG_TEST_FDTDEC=y CONFIG_UNIT_TEST=y diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig index 8aa295686d..06b1408b90 100644 --- a/configs/sandbox_flattree_defconfig +++ b/configs/sandbox_flattree_defconfig @@ -227,6 +227,7 @@ CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y CONFIG_EFI_CAPSULE_ON_DISK=y CONFIG_EFI_CAPSULE_FIRMWARE_FIT=y CONFIG_EFI_CAPSULE_AUTHENTICATE=y +CONFIG_EFI_CAPSULE_ESL_FILE="/tmp/capsules/SIGNER.esl" CONFIG_UNIT_TEST=y CONFIG_UT_TIME=y CONFIG_UT_DM=y diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py index 054be1ee97..99b502902e 100644 --- a/test/py/tests/test_efi_capsule/conftest.py +++ b/test/py/tests/test_efi_capsule/conftest.py @@ -25,48 +25,25 @@ def efi_capsule_data(request, u_boot_config): image_path = u_boot_config.persistent_data_dir + '/test_efi_capsule.img'
try: + capsules_path_dir = '/tmp/capsules/' # Create a target device check_call('dd if=/dev/zero of=./spi.bin bs=1MiB count=16', shell=True)
check_call('rm -rf %s' % mnt_point, shell=True) 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) + check_call('cp %s/* %s ' % (capsules_path_dir, data_dir), shell=True)
# Update dtb to add the version information check_call('cd %s; ' 'cp %s/test/py/tests/test_efi_capsule/version.dts .' % (data_dir, u_boot_config.source_dir), shell=True) + + capsule_auth_enabled = u_boot_config.buildconfig.get( + 'config_efi_capsule_authenticate') if capsule_auth_enabled: + check_call('cp %s/arch/sandbox/dts/test.dtb %s/test_sig.dtb' % + (u_boot_config.build_dir, data_dir), shell=True) check_call('cd %s; ' 'dtc -@ -I dts -O dtb -o version.dtbo version.dts; ' 'fdtoverlay -i test_sig.dtb ' diff --git a/test/py/tests/test_efi_capsule/signature.dts b/test/py/tests/test_efi_capsule/signature.dts deleted file mode 100644 index 078cfc76c9..0000000000 --- a/test/py/tests/test_efi_capsule/signature.dts +++ /dev/null @@ -1,10 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ - -/dts-v1/; -/plugin/; - -&{/} { - signature { - capsule-key = /incbin/("SIGNER.esl"); - }; -};

On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The embedding of the public key EFI Signature List(ESL) file into the platform's DTB is now done at the time of u-boot build. Remove this logic from the capsule update test' configuration.
Include the public key for the sandbox and sandbox_flattree variant as part of the build.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4: None
configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 1 + test/py/tests/test_efi_capsule/conftest.py | 37 ++++---------------- test/py/tests/test_efi_capsule/signature.dts | 10 ------ 4 files changed, 9 insertions(+), 40 deletions(-) delete mode 100644 test/py/tests/test_efi_capsule/signature.dts
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 19cc6701e6..53e342b3fa 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -342,6 +342,7 @@ CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y CONFIG_EFI_CAPSULE_ON_DISK=y CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y CONFIG_EFI_CAPSULE_AUTHENTICATE=y +CONFIG_EFI_CAPSULE_ESL_FILE="/tmp/capsules/SIGNER.esl"
No, we cannot use hard-coded pathnames, still.
Please grep for /tmp/capsules throughout your series.
You should be able to drop the path if you put the file in the right dir in the test. It runs in the working directory, I believe.
[..]
Regards, Simon

hi Simon,
On Wed, 26 Jul 2023 at 04:24, Simon Glass sjg@chromium.org wrote:
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The embedding of the public key EFI Signature List(ESL) file into the platform's DTB is now done at the time of u-boot build. Remove this logic from the capsule update test' configuration.
Include the public key for the sandbox and sandbox_flattree variant as part of the build.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4: None
configs/sandbox_defconfig | 1 + configs/sandbox_flattree_defconfig | 1 + test/py/tests/test_efi_capsule/conftest.py | 37 ++++---------------- test/py/tests/test_efi_capsule/signature.dts | 10 ------ 4 files changed, 9 insertions(+), 40 deletions(-) delete mode 100644 test/py/tests/test_efi_capsule/signature.dts
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 19cc6701e6..53e342b3fa 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -342,6 +342,7 @@ CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y CONFIG_EFI_CAPSULE_ON_DISK=y CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y CONFIG_EFI_CAPSULE_AUTHENTICATE=y +CONFIG_EFI_CAPSULE_ESL_FILE="/tmp/capsules/SIGNER.esl"
No, we cannot use hard-coded pathnames, still.
Please grep for /tmp/capsules throughout your series.
You should be able to drop the path if you put the file in the right dir in the test. It runs in the working directory, I believe.
Okay, let me check this out.
-sughosh

Support has been added to the mkeficapsule tool to generate capsules by parsing the capsule parameters through a config file. Add a config file for generating capsules. These capsules will be used for testing the capsule update feature on sandbox platform.
Enable generation of capsules through the config file on the sandbox variant.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: * Use a relative path for CONFIG_EFI_CAPSULE_CFG_FILE. * Remove logic to copy capsule config file to /tmp/capsules/ directory, as the capsule entry can handle relative paths. * Add a comment in the capsule config file for the image GUIDs being used. * Use lower case for image GUIDs.
configs/sandbox_defconfig | 2 + .../test_efi_capsule/sandbox_capsule_cfg.txt | 175 ++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 test/py/tests/test_efi_capsule/sandbox_capsule_cfg.txt
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 53e342b3fa..49ca6f5f61 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -343,6 +343,8 @@ CONFIG_EFI_CAPSULE_ON_DISK=y CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y CONFIG_EFI_CAPSULE_AUTHENTICATE=y CONFIG_EFI_CAPSULE_ESL_FILE="/tmp/capsules/SIGNER.esl" +CONFIG_EFI_CAPSULE_CFG_FILE="test/py/tests/test_efi_capsule/sandbox_capsule_cfg.txt" +CONFIG_EFI_USE_CAPSULE_CFG_FILE=y CONFIG_EFI_SECURE_BOOT=y CONFIG_TEST_FDTDEC=y CONFIG_UNIT_TEST=y diff --git a/test/py/tests/test_efi_capsule/sandbox_capsule_cfg.txt b/test/py/tests/test_efi_capsule/sandbox_capsule_cfg.txt new file mode 100644 index 0000000000..bfce3bbb5f --- /dev/null +++ b/test/py/tests/test_efi_capsule/sandbox_capsule_cfg.txt @@ -0,0 +1,175 @@ +# This is a config file used for generating EFI capsules for the +# sandbox platform. The image GUIDs used in this file are as +# follows +# +# 09d7cf52-0720-4710-91d1-08469b7fe9c8 - u-boot image GUID +# +# 5a7021f5-fef2-48b4-aaba-832e777418c0 - u-boot env image GUID +# +# 3673b45d-6a7c-46f3-9e60-adabb03f7937 - FIT image GUID +# +# 058b7d83-50d5-4c47-a195-60d86ad341c4 - Incorrect GUID for the platform +# + +{ + image-index: 1 + image-guid: 09d7cf52-0720-4710-91d1-08469b7fe9c8 + payload: /tmp/capsules/u-boot.bin.new + capsule: /tmp/capsules/Test01 +} +{ + image-index: 2 + image-guid: 5a7021f5-fef2-48b4-aaba-832e777418c0 + payload: /tmp/capsules/u-boot.env.new + capsule: /tmp/capsules/Test02 +} +{ + image-index: 1 + image-guid: 058b7d83-50d5-4c47-a195-60d86ad341c4 + payload: /tmp/capsules/u-boot.bin.new + capsule: /tmp/capsules/Test03 + +} +{ + image-index: 1 + image-guid: 3673b45d-6a7c-46f3-9e60-adabb03f7937 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test04 + +} +{ + image-index: 1 + image-guid: 058b7d83-50d5-4c47-a195-60d86ad341c4 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test05 + +} +{ + image-index: 1 + image-guid: 058b7d83-50d5-4c47-a195-60d86ad341c4 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test05 +} +{ + image-index: 1 + monotonic-count: 1 + private-key: /tmp/capsules/SIGNER.key + pub-key-cert: /tmp/capsules/SIGNER.crt + image-guid: 09d7cf52-0720-4710-91d1-08469b7fe9c8 + payload: /tmp/capsules/u-boot.bin.new + capsule: /tmp/capsules/Test11 +} +{ + image-index: 1 + monotonic-count: 1 + private-key: /tmp/capsules/SIGNER2.key + pub-key-cert: /tmp/capsules/SIGNER2.crt + image-guid: 09d7cf52-0720-4710-91d1-08469b7fe9c8 + payload: /tmp/capsules/u-boot.bin.new + capsule: /tmp/capsules/Test12 +} +{ + image-index: 1 + monotonic-count: 1 + private-key: /tmp/capsules/SIGNER.key + pub-key-cert: /tmp/capsules/SIGNER.crt + image-guid: 3673b45d-6a7c-46f3-9e60-adabb03f7937 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test13 +} +{ + image-index: 1 + monotonic-count: 1 + private-key: /tmp/capsules/SIGNER2.key + pub-key-cert: /tmp/capsules/SIGNER2.crt + image-guid: 3673b45d-6a7c-46f3-9e60-adabb03f7937 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test14 +} +{ + image-index: 1 + fw-version: 5 + image-guid: 09d7cf52-0720-4710-91d1-08469b7fe9c8 + payload: /tmp/capsules/u-boot.bin.new + capsule: /tmp/capsules/Test101 +} +{ + image-index: 2 + fw-version: 10 + image-guid: 5a7021f5-fef2-48b4-aaba-832e777418c0 + payload: /tmp/capsules/u-boot.env.new + capsule: /tmp/capsules/Test102 +} +{ + image-index: 1 + fw-version: 2 + image-guid: 09d7cf52-0720-4710-91d1-08469b7fe9c8 + payload: /tmp/capsules/u-boot.bin.new + capsule: /tmp/capsules/Test103 + +} +{ + image-index: 1 + fw-version: 5 + image-guid: 3673b45d-6a7c-46f3-9e60-adabb03f7937 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test104 +} +{ + image-index: 1 + fw-version: 2 + image-guid: 3673b45d-6a7c-46f3-9e60-adabb03f7937 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test105 + +} +{ + image-index: 1 + monotonic-count: 1 + fw-version: 5 + private-key: /tmp/capsules/SIGNER.key + pub-key-cert: /tmp/capsules/SIGNER.crt + image-guid: 09d7cf52-0720-4710-91d1-08469b7fe9c8 + payload: /tmp/capsules/u-boot.bin.new + capsule: /tmp/capsules/Test111 +} +{ + image-index: 2 + monotonic-count: 1 + fw-version: 10 + private-key: /tmp/capsules/SIGNER.key + pub-key-cert: /tmp/capsules/SIGNER.crt + image-guid: 5a7021f5-fef2-48b4-aaba-832e777418c0 + payload: /tmp/capsules/u-boot.env.new + capsule: /tmp/capsules/Test112 +} +{ + image-index: 1 + monotonic-count: 1 + fw-version: 2 + private-key: /tmp/capsules/SIGNER.key + pub-key-cert: /tmp/capsules/SIGNER.crt + image-guid: 09d7cf52-0720-4710-91d1-08469b7fe9c8 + payload: /tmp/capsules/u-boot.bin.new + capsule: /tmp/capsules/Test113 +} +{ + image-index: 1 + fw-version: 5 + monotonic-count: 1 + private-key: /tmp/capsules/SIGNER.key + pub-key-cert: /tmp/capsules/SIGNER.crt + image-guid: 3673b45d-6a7c-46f3-9e60-adabb03f7937 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test114 +} +{ + image-index: 1 + fw-version: 2 + monotonic-count: 1 + private-key: /tmp/capsules/SIGNER.key + pub-key-cert: /tmp/capsules/SIGNER.crt + image-guid: 3673b45d-6a7c-46f3-9e60-adabb03f7937 + payload: /tmp/capsules/uboot_bin_env.itb + capsule: /tmp/capsules/Test115 +}

Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
Support has been added to the mkeficapsule tool to generate capsules by parsing the capsule parameters through a config file. Add a config file for generating capsules. These capsules will be used for testing the capsule update feature on sandbox platform.
Enable generation of capsules through the config file on the sandbox variant.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Use a relative path for CONFIG_EFI_CAPSULE_CFG_FILE.
- Remove logic to copy capsule config file to /tmp/capsules/ directory, as the capsule entry can handle relative paths.
- Add a comment in the capsule config file for the image GUIDs being used.
- Use lower case for image GUIDs.
configs/sandbox_defconfig | 2 + .../test_efi_capsule/sandbox_capsule_cfg.txt | 175 ++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 test/py/tests/test_efi_capsule/sandbox_capsule_cfg.txt
Please just drop the config file, at least for now. It is a whole other can of worms and we have enough of those already,
Regards, Simon

The EFI capsule files can now be generated as part of u-boot build. This is done through binman. Add capsule entry nodes in the u-boot.dtsi for the sandbox architecture for generating the capsules. Remove the corresponding generation of capsules from the capsule update conftest file.
The capsules are generated through the config file for the sandbox variant, and through explicit parameters for the sandbox_flattree variant.
Also generate the FIT image used for testing the capsule update feature on the sandbox_flattree variant through binman. Remove the now superfluous its file which was used for generating this FIT image.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org --- Changes since V4: * Define macros for the image GUIDs being used for generating the capsules. * Use lower case for image GUIDs.
arch/sandbox/dts/u-boot.dtsi | 271 ++++++++++++++++++ test/py/tests/test_efi_capsule/conftest.py | 127 -------- .../tests/test_efi_capsule/uboot_bin_env.its | 36 --- 3 files changed, 271 insertions(+), 163 deletions(-) delete mode 100644 test/py/tests/test_efi_capsule/uboot_bin_env.its
diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi index 60bd004937..7606db3764 100644 --- a/arch/sandbox/dts/u-boot.dtsi +++ b/arch/sandbox/dts/u-boot.dtsi @@ -7,11 +7,282 @@ */
#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT + +#define SANDBOX_UBOOT_IMAGE_GUID "09d7cf52-0720-4710-91d1-08469b7fe9c8" +#define SANDBOX_UBOOT_ENV_IMAGE_GUID "5a7021f5-fef2-48b4-aaba-832e777418c0" +#define SANDBOX_FIT_IMAGE_GUID "3673b45d-6a7c-46f3-9e60-adabb03f7937" +#define SANDBOX_INCORRECT_GUID "058b7d83-50d5-4c47-a195-60d86ad341c4" + / { #ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE signature { capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE); }; #endif + + binman: binman { + multiple-images; + }; +}; + +&binman { + itb { + filename = "/tmp/capsules/uboot_bin_env.itb"; + + fit { + description = "Automatic U-Boot environment update"; + #address-cells = <2>; + + images { + u-boot-bin { + description = "U-Boot binary on SPI Flash"; + compression = "none"; + type = "firmware"; + arch = "sandbox"; + load = <0>; + blob { + filename = "/tmp/capsules/u-boot.bin.new"; + }; + + hash-1 { + algo = "sha1"; + }; + }; + u-boot-env { + description = "U-Boot environment on SPI Flash"; + compression = "none"; + type = "firmware"; + arch = "sandbox"; + load = <0>; + blob { + filename = "/tmp/capsules/u-boot.env.new"; + }; + + hash-1 { + algo = "sha1"; + }; + }; + }; + }; + }; + +#ifdef CONFIG_EFI_USE_CAPSULE_CFG_FILE + capsule1 { + capsule { + cfg-file = CONFIG_EFI_CAPSULE_CFG_FILE; + }; + }; +#else + capsule2 { + capsule { + image-index = <0x1>; + image-type-id = SANDBOX_UBOOT_IMAGE_GUID; + filename = "/tmp/capsules/u-boot.bin.new"; + capsule = "/tmp/capsules/Test01"; + }; + }; + + capsule3 { + capsule { + image-index = <0x2>; + image-type-id = SANDBOX_UBOOT_ENV_IMAGE_GUID; + filename = "/tmp/capsules/u-boot.env.new"; + capsule = "/tmp/capsules/Test02"; + }; + }; + + capsule4 { + capsule { + image-index = <0x1>; + image-type-id = SANDBOX_INCORRECT_GUID; + filename = "/tmp/capsules/u-boot.bin.new"; + capsule = "/tmp/capsules/Test03"; + }; + }; + + capsule5 { + capsule { + image-index = <0x1>; + image-type-id = SANDBOX_FIT_IMAGE_GUID; + filename = "/tmp/capsules/uboot_bin_env.itb"; + capsule = "/tmp/capsules/Test04"; + }; + }; + + capsule6 { + capsule { + image-index = <0x1>; + image-type-id = SANDBOX_INCORRECT_GUID; + filename = "/tmp/capsules/uboot_bin_env.itb"; + capsule = "/tmp/capsules/Test05"; + }; + }; + + capsule7 { + capsule { + image-index = <0x1>; + fw-version = <0x5>; + image-type-id = SANDBOX_UBOOT_IMAGE_GUID; + filename = "/tmp/capsules/u-boot.bin.new"; + capsule = "/tmp/capsules/Test101"; + }; + }; + + capsule8 { + capsule { + image-index = <0x2>; + fw-version = <0xa>; + image-type-id = SANDBOX_UBOOT_ENV_IMAGE_GUID; + filename = "/tmp/capsules/u-boot.env.new"; + capsule = "/tmp/capsules/Test102"; + }; + }; + + capsule9 { + capsule { + image-index = <0x1>; + fw-version = <0x2>; + image-type-id = SANDBOX_UBOOT_IMAGE_GUID; + filename = "/tmp/capsules/u-boot.bin.new"; + capsule = "/tmp/capsules/Test103"; + }; + }; + + capsule10 { + capsule { + image-index = <0x1>; + fw-version = <0x5>; + image-type-id = SANDBOX_FIT_IMAGE_GUID; + filename = "/tmp/capsules/uboot_bin_env.itb"; + capsule = "/tmp/capsules/Test104"; + }; + }; + + capsule11 { + capsule { + image-index = <0x1>; + fw-version = <0x2>; + image-type-id = SANDBOX_FIT_IMAGE_GUID; + filename = "/tmp/capsules/uboot_bin_env.itb"; + capsule = "/tmp/capsules/Test105"; + }; + }; + +#ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE + capsule12 { + capsule { + image-index = <0x1>; + image-type-id = SANDBOX_UBOOT_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER.key"; + pub-key-cert = "/tmp/capsules/SIGNER.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/u-boot.bin.new"; + capsule = "/tmp/capsules/Test11"; + }; + }; + + capsule13 { + capsule { + image-index = <0x1>; + image-type-id = SANDBOX_UBOOT_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER2.key"; + pub-key-cert = "/tmp/capsules/SIGNER2.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/u-boot.bin.new"; + capsule = "/tmp/capsules/Test12"; + }; + }; + + capsule14 { + capsule { + image-index = <0x1>; + image-type-id = SANDBOX_FIT_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER.key"; + pub-key-cert = "/tmp/capsules/SIGNER.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/uboot_bin_env.itb"; + capsule = "/tmp/capsules/Test13"; + }; + }; + + capsule15 { + capsule { + image-index = <0x1>; + image-type-id = SANDBOX_FIT_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER2.key"; + pub-key-cert = "/tmp/capsules/SIGNER2.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/uboot_bin_env.itb"; + capsule = "/tmp/capsules/Test14"; + }; + }; + + capsule16 { + capsule { + image-index = <0x1>; + fw-version = <0x5>; + image-type-id = SANDBOX_UBOOT_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER.key"; + pub-key-cert = "/tmp/capsules/SIGNER.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/u-boot.bin.new"; + capsule = "/tmp/capsules/Test111"; + }; + }; + + capsule17 { + capsule { + image-index = <0x2>; + fw-version = <0xa>; + image-type-id = SANDBOX_UBOOT_ENV_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER.key"; + pub-key-cert = "/tmp/capsules/SIGNER.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/u-boot.env.new"; + capsule = "/tmp/capsules/Test112"; + }; + }; + + capsule18 { + capsule { + image-index = <0x1>; + fw-version = <0x2>; + image-type-id = SANDBOX_UBOOT_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER.key"; + pub-key-cert = "/tmp/capsules/SIGNER.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/u-boot.bin.new"; + capsule = "/tmp/capsules/Test113"; + }; + }; + + capsule19 { + capsule { + image-index = <0x1>; + fw-version = <0x5>; + image-type-id = SANDBOX_FIT_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER.key"; + pub-key-cert = "/tmp/capsules/SIGNER.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/uboot_bin_env.itb"; + capsule = "/tmp/capsules/Test114"; + }; + }; + + capsule20 { + capsule { + image-index = <0x1>; + fw-version = <0x2>; + image-type-id = SANDBOX_FIT_IMAGE_GUID; + private-key = "/tmp/capsules/SIGNER.key"; + pub-key-cert = "/tmp/capsules/SIGNER.crt"; + monotonic-count = <0x1>; + filename = "/tmp/capsules/uboot_bin_env.itb"; + capsule = "/tmp/capsules/Test115"; + }; + }; + +#endif /* CONFIG_EFI_CAPSULE_AUTHENTICATE */ +#endif /* CONFIG_EFI_USE_CAPSULE_CFG_FILE */ }; #endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT */ diff --git a/test/py/tests/test_efi_capsule/conftest.py b/test/py/tests/test_efi_capsule/conftest.py index 99b502902e..ca44249a38 100644 --- a/test/py/tests/test_efi_capsule/conftest.py +++ b/test/py/tests/test_efi_capsule/conftest.py @@ -56,133 +56,6 @@ def efi_capsule_data(request, u_boot_config): '-o test_ver.dtb version.dtbo' % (data_dir, u_boot_config.build_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, - shell=True) - check_call('sed -e "s?BINFILE1?u-boot.bin.new?" -e "s?BINFILE2?u-boot.env.new?" %s/test/py/tests/test_efi_capsule/uboot_bin_env.its > %s/uboot_bin_env.its' % - (u_boot_config.source_dir, data_dir), - shell=True) - 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 --index 1 --guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot.bin.new Test01' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 2 --guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot.env.new Test02' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 058B7D83-50D5-4C47-A195-60D86AD341C4 u-boot.bin.new Test03' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 uboot_bin_env.itb Test04' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 1 --guid 058B7D83-50D5-4C47-A195-60D86AD341C4 uboot_bin_env.itb Test05' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 1 --fw-version 5 ' - '--guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot.bin.new Test101' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 2 --fw-version 10 ' - '--guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 u-boot.env.new Test102' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 1 --fw-version 2 ' - '--guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 u-boot.bin.new Test103' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 1 --fw-version 5 ' - '--guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 uboot_bin_env.itb Test104' % - (data_dir, u_boot_config.build_dir), - shell=True) - check_call('cd %s; %s/tools/mkeficapsule --index 1 --fw-version 2 ' - '--guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 uboot_bin_env.itb Test105' % - (data_dir, u_boot_config.build_dir), - shell=True) - - if capsule_auth_enabled: - # raw firmware signed with proper key - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' - '--private-key SIGNER.key --certificate SIGNER.crt ' - '--guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 ' - 'u-boot.bin.new Test11' - % (data_dir, u_boot_config.build_dir), - shell=True) - # raw firmware signed with *mal* key - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' - '--private-key SIGNER2.key ' - '--certificate SIGNER2.crt ' - '--guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 ' - 'u-boot.bin.new Test12' - % (data_dir, u_boot_config.build_dir), - shell=True) - # FIT firmware signed with proper key - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' - '--private-key SIGNER.key --certificate SIGNER.crt ' - '--guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 ' - 'uboot_bin_env.itb Test13' - % (data_dir, u_boot_config.build_dir), - shell=True) - # FIT firmware signed with *mal* key - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' - '--private-key SIGNER2.key ' - '--certificate SIGNER2.crt ' - '--guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 ' - 'uboot_bin_env.itb Test14' - % (data_dir, u_boot_config.build_dir), - shell=True) - # raw firmware signed with proper key with version information - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' - '--fw-version 5 ' - '--private-key SIGNER.key --certificate SIGNER.crt ' - '--guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 ' - 'u-boot.bin.new Test111' - % (data_dir, u_boot_config.build_dir), - shell=True) - # raw firmware signed with proper key with version information - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 2 --monotonic-count 1 ' - '--fw-version 10 ' - '--private-key SIGNER.key --certificate SIGNER.crt ' - '--guid 5A7021F5-FEF2-48B4-AABA-832E777418C0 ' - 'u-boot.env.new Test112' - % (data_dir, u_boot_config.build_dir), - shell=True) - # raw firmware signed with proper key with lower version information - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' - '--fw-version 2 ' - '--private-key SIGNER.key --certificate SIGNER.crt ' - '--guid 09D7CF52-0720-4710-91D1-08469B7FE9C8 ' - 'u-boot.bin.new Test113' - % (data_dir, u_boot_config.build_dir), - shell=True) - # FIT firmware signed with proper key with version information - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' - '--fw-version 5 ' - '--private-key SIGNER.key --certificate SIGNER.crt ' - '--guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 ' - 'uboot_bin_env.itb Test114' - % (data_dir, u_boot_config.build_dir), - shell=True) - # FIT firmware signed with proper key with lower version information - check_call('cd %s; ' - '%s/tools/mkeficapsule --index 1 --monotonic-count 1 ' - '--fw-version 2 ' - '--private-key SIGNER.key --certificate SIGNER.crt ' - '--guid 3673B45D-6A7C-46F3-9E60-ADABB03F7937 ' - 'uboot_bin_env.itb Test115' - % (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' % (mnt_point, image_path), shell=True) diff --git a/test/py/tests/test_efi_capsule/uboot_bin_env.its b/test/py/tests/test_efi_capsule/uboot_bin_env.its deleted file mode 100644 index fc65907481..0000000000 --- a/test/py/tests/test_efi_capsule/uboot_bin_env.its +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Automatic software update for U-Boot - * Make sure the flashing addresses ('load' prop) is correct for your board! - */ - -/dts-v1/; - -/ { - description = "Automatic U-Boot environment update"; - #address-cells = <2>; - - images { - u-boot-bin { - description = "U-Boot binary on SPI Flash"; - data = /incbin/("BINFILE1"); - compression = "none"; - type = "firmware"; - arch = "sandbox"; - load = <0>; - hash-1 { - algo = "sha1"; - }; - }; - u-boot-env { - description = "U-Boot environment on SPI Flash"; - data = /incbin/("BINFILE2"); - compression = "none"; - type = "firmware"; - arch = "sandbox"; - load = <0>; - hash-1 { - algo = "sha1"; - }; - }; - }; -};

Hi Sughosh,
On Tue, 25 Jul 2023 at 02:58, Sughosh Ganu sughosh.ganu@linaro.org wrote:
The EFI capsule files can now be generated as part of u-boot build. This is done through binman. Add capsule entry nodes in the u-boot.dtsi for the sandbox architecture for generating the capsules. Remove the corresponding generation of capsules from the capsule update conftest file.
The capsules are generated through the config file for the sandbox variant, and through explicit parameters for the sandbox_flattree variant.
Also generate the FIT image used for testing the capsule update feature on the sandbox_flattree variant through binman. Remove the now superfluous its file which was used for generating this FIT image.
Signed-off-by: Sughosh Ganu sughosh.ganu@linaro.org
Changes since V4:
- Define macros for the image GUIDs being used for generating the capsules.
- Use lower case for image GUIDs.
arch/sandbox/dts/u-boot.dtsi | 271 ++++++++++++++++++ test/py/tests/test_efi_capsule/conftest.py | 127 -------- .../tests/test_efi_capsule/uboot_bin_env.its | 36 --- 3 files changed, 271 insertions(+), 163 deletions(-) delete mode 100644 test/py/tests/test_efi_capsule/uboot_bin_env.its
diff --git a/arch/sandbox/dts/u-boot.dtsi b/arch/sandbox/dts/u-boot.dtsi index 60bd004937..7606db3764 100644 --- a/arch/sandbox/dts/u-boot.dtsi +++ b/arch/sandbox/dts/u-boot.dtsi @@ -7,11 +7,282 @@ */
#ifdef CONFIG_EFI_HAVE_CAPSULE_SUPPORT
+#define SANDBOX_UBOOT_IMAGE_GUID "09d7cf52-0720-4710-91d1-08469b7fe9c8" +#define SANDBOX_UBOOT_ENV_IMAGE_GUID "5a7021f5-fef2-48b4-aaba-832e777418c0" +#define SANDBOX_FIT_IMAGE_GUID "3673b45d-6a7c-46f3-9e60-adabb03f7937" +#define SANDBOX_INCORRECT_GUID "058b7d83-50d5-4c47-a195-60d86ad341c4"
That looks better
/ { #ifdef CONFIG_EFI_CAPSULE_AUTHENTICATE signature { capsule-key = /incbin/(CONFIG_EFI_CAPSULE_ESL_FILE); }; #endif
binman: binman {
multiple-images;
};
+};
+&binman {
itb {
filename = "/tmp/capsules/uboot_bin_env.itb";
fit {
description = "Automatic U-Boot environment update";
#address-cells = <2>;
images {
u-boot-bin {
description = "U-Boot binary on SPI Flash";
compression = "none";
type = "firmware";
arch = "sandbox";
load = <0>;
blob {
filename = "/tmp/capsules/u-boot.bin.new";
};
hash-1 {
algo = "sha1";
};
};
u-boot-env {
description = "U-Boot environment on SPI Flash";
compression = "none";
type = "firmware";
arch = "sandbox";
load = <0>;
blob {
filename = "/tmp/capsules/u-boot.env.new";
};
hash-1 {
algo = "sha1";
};
};
};
};
};
+#ifdef CONFIG_EFI_USE_CAPSULE_CFG_FILE
capsule1 {
capsule {
cfg-file = CONFIG_EFI_CAPSULE_CFG_FILE;
};
};
+#else
capsule2 {
capsule {
image-index = <0x1>;
image-type-id = SANDBOX_UBOOT_IMAGE_GUID;
filename = "/tmp/capsules/u-boot.bin.new";
capsule = "/tmp/capsules/Test01";
You can do:
capsule-2 { type = "efi-capsule"; }
and avoid the double nesting.
As per my other contents, you can't refer to filenames here...just put the things you want in the capsule as subnodes of the capsule node. [..]
Regards, Simon
participants (5)
-
Heinrich Schuchardt
-
Ilias Apalodimas
-
Simon Glass
-
Sughosh Ganu
-
Tom Rini