[PATCH 1/2] tools: add fdt_add_pubkey

Jan Kiszka jan.kiszka at siemens.com
Wed Nov 10 22:15:36 CET 2021


On 08.11.21 16:28, Roman Kopytin wrote:
> Having to use the -K option to mkimage to populate U-Boot's .dtb with the
> public key while signing the kernel FIT image is often a little
> awkward. In particular, when using a meta-build system such as
> bitbake/Yocto, having the tasks of the kernel and U-Boot recipes
> intertwined, modifying deployed artifacts and rebuilding U-Boot with
> an updated .dtb is quite cumbersome. Also, in some scenarios one may
> wish to build U-Boot complete with the public key(s) embedded in the
> .dtb without the corresponding private keys being present on the same
> build host.
> 
> So this adds a simple tool that allows one to disentangle the kernel
> and U-Boot builds, by simply copy-pasting just enough of the mkimage
> code to allow one to add a public key to a .dtb. When using mkimage,
> some of the information is taken from the .its used to build the
> kernel (algorithm and key name), so that of course needs to be
> supplied on the command line.
> 
> Signed-off-by: Roman Kopytin <Roman.Kopytin at kaspersky.com>
> Cc: Rasmus Villemoes <rasmus.villemoes at prevas.dk>
> ---
>  tools/.gitignore       |  1 +
>  tools/Makefile         |  3 ++
>  tools/fdt_add_pubkey.c | 97 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 101 insertions(+)
>  create mode 100755 tools/fdt_add_pubkey.c
> 
> diff --git a/tools/.gitignore b/tools/.gitignore
> index a88453f64d..f312b760e4 100644
> --- a/tools/.gitignore
> +++ b/tools/.gitignore
> @@ -6,6 +6,7 @@
>  /dumpimage
>  /easylogo/easylogo
>  /envcrc
> +/fdt_add_pubkey
>  /fdtgrep
>  /file2include
>  /fit_check_sign
> diff --git a/tools/Makefile b/tools/Makefile
> index 4a86321f64..44f25dda18 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -73,6 +73,7 @@ mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o
>  
>  hostprogs-y += dumpimage mkimage
>  hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fit_info fit_check_sign
> +hostprogs-$(CONFIG_TOOLS_LIBCRYPTO) += fdt_add_pubkey
>  
>  hostprogs-$(CONFIG_CMD_BOOTEFI_SELFTEST) += file2include
>  
> @@ -153,6 +154,7 @@ dumpimage-objs := $(dumpimage-mkimage-objs) dumpimage.o
>  mkimage-objs   := $(dumpimage-mkimage-objs) mkimage.o
>  fit_info-objs   := $(dumpimage-mkimage-objs) fit_info.o
>  fit_check_sign-objs   := $(dumpimage-mkimage-objs) fit_check_sign.o
> +fdt_add_pubkey-objs   := $(dumpimage-mkimage-objs) fdt_add_pubkey.o
>  file2include-objs := file2include.o
>  
>  ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),)
> @@ -190,6 +192,7 @@ HOSTCFLAGS_fit_image.o += -DMKIMAGE_DTC=\"$(CONFIG_MKIMAGE_DTC_PATH)\"
>  HOSTLDLIBS_dumpimage := $(HOSTLDLIBS_mkimage)
>  HOSTLDLIBS_fit_info := $(HOSTLDLIBS_mkimage)
>  HOSTLDLIBS_fit_check_sign := $(HOSTLDLIBS_mkimage)
> +HOSTLDLIBS_fdt_add_pubkey := $(HOSTLDLIBS_mkimage)
>  
>  hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
>  hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
> diff --git a/tools/fdt_add_pubkey.c b/tools/fdt_add_pubkey.c
> new file mode 100755
> index 0000000000..9306ecedd1
> --- /dev/null
> +++ b/tools/fdt_add_pubkey.c
> @@ -0,0 +1,97 @@
> +#include <image.h>
> +#include "fit_common.h"
> +
> +static const char *cmdname;
> +
> +static const char *algo_name = "sha1,rsa2048"; /* -a <algo> */
> +static const char *keydir = "."; /* -k <keydir> */
> +static const char *keyname = "key"; /* -n <keyname> */
> +static const char *require_keys; /* -r <conf|image> */
> +static const char *keydest; /* argv[n] */
> +
> +static void usage(const char *msg)
> +{
> +	fprintf(stderr, "Error: %s\n", msg);
> +	fprintf(stderr, "Usage: %s [-a <algo>] [-k <keydir>] [-n <keyname>] [-r <conf|image>] <fdt blob>\n",
> +		cmdname);
> +	exit(EXIT_FAILURE);
> +}
> +
> +static void process_args(int argc, char *argv[])
> +{
> +	int opt;
> +
> +	while((opt = getopt(argc, argv, "a:k:n:r:")) != -1) {
> +		switch (opt) {
> +		case 'k':
> +			keydir = optarg;
> +			break;
> +		case 'a':
> +			algo_name = optarg;
> +			break;
> +		case 'n':
> +			keyname = optarg;
> +			break;
> +		case 'r':
> +			require_keys = optarg;
> +			break;
> +		default:
> +			usage("Invalid option");
> +		}
> +	}
> +	/* The last parameter is expected to be the .dtb to add the public key to */
> +	if (optind < argc)
> +		keydest = argv[optind];
> +
> +	if (!keydest)
> +		usage("Missing dtb file to update");
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	struct image_sign_info info;
> +	int destfd, ret;
> +	void *dest_blob = NULL;
> +	struct stat dest_sbuf;
> +	size_t size_inc = 0;
> +
> +	cmdname = argv[0];
> +
> +	process_args(argc, argv);
> +
> +	memset(&info, 0, sizeof(info));
> +
> +	info.keydir = keydir;
> +	info.keyname = keyname;
> +	info.name = algo_name;
> +	info.require_keys = require_keys;
> +	info.crypto = image_get_crypto_algo(algo_name);
> +	if (!info.crypto) {
> +                fprintf(stderr, "Unsupported signature algorithm '%s'\n", algo_name);
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	while (1) {
> +		destfd = mmap_fdt(cmdname, keydest, size_inc, &dest_blob, &dest_sbuf, false, false);
> +		if (destfd < 0)
> +			exit(EXIT_FAILURE);
> +
> +		ret = info.crypto->add_verify_data(&info, dest_blob);
> +
> +		munmap(dest_blob, dest_sbuf.st_size);
> +		close(destfd);
> +		if (!ret || ret != -ENOSPC)
> +			break;
> +		fprintf(stderr, ".dtb too small, increasing size by 1024 bytes\n");
> +		size_inc = 1024;
> +	}
> +
> +	if (ret) {
> +		fprintf(stderr, "%s: Cannot add public key to FIT blob: %s\n",
> +			cmdname, strerror(-ret));
> +		exit(EXIT_FAILURE);
> +	}
> +
> +	exit(EXIT_SUCCESS);
> +}
> +
> 

I'm playing with this diff on top in order to support embedding into SPL 
control FDTs:

diff --git a/tools/fdt_add_pubkey.c b/tools/fdt_add_pubkey.c
index 9306ecedd1..176b6bd37d 100755
--- a/tools/fdt_add_pubkey.c
+++ b/tools/fdt_add_pubkey.c
@@ -50,10 +50,11 @@ static void process_args(int argc, char *argv[])
 int main(int argc, char *argv[])
 {
 	struct image_sign_info info;
-	int destfd, ret;
+	int signode, keynode, ret;
 	void *dest_blob = NULL;
 	struct stat dest_sbuf;
 	size_t size_inc = 0;
+	int destfd = -1;
 
 	cmdname = argv[0];
 
@@ -71,20 +72,41 @@ int main(int argc, char *argv[])
 		exit(EXIT_FAILURE);
 	}
 
-	while (1) {
+	do {
+		if (destfd >= 0) {
+			munmap(dest_blob, dest_sbuf.st_size);
+			close(destfd);
+
+			fprintf(stderr, ".dtb too small, increasing size by 1024 bytes\n");
+			size_inc = 1024;
+		}
+
 		destfd = mmap_fdt(cmdname, keydest, size_inc, &dest_blob, &dest_sbuf, false, false);
 		if (destfd < 0)
 			exit(EXIT_FAILURE);
 
 		ret = info.crypto->add_verify_data(&info, dest_blob);
-
-		munmap(dest_blob, dest_sbuf.st_size);
-		close(destfd);
-		if (!ret || ret != -ENOSPC)
+		if (ret == -ENOSPC)
+			continue;
+		else if (ret)
 			break;
-		fprintf(stderr, ".dtb too small, increasing size by 1024 bytes\n");
-		size_inc = 1024;
-	}
+
+		signode = fdt_path_offset(dest_blob, "/signature");
+		if (signode < 0) {
+			fprintf(stderr, "%s: /signature node not found?!\n",
+				cmdname);
+			exit(EXIT_FAILURE);
+		}
+
+		keynode = fdt_first_subnode(dest_blob, signode);
+		if (keynode < 0) {
+			fprintf(stderr, "%s: /signature/<key> node not found?!\n",
+				cmdname);
+			exit(EXIT_FAILURE);
+		}
+
+		ret = fdt_appendprop(dest_blob, keynode, "u-boot,dm-spl", NULL, 0);
+	} while (ret == -ENOSPC);
 
 	if (ret) {
 		fprintf(stderr, "%s: Cannot add public key to FIT blob: %s\n",
@@ -94,4 +116,3 @@ int main(int argc, char *argv[])
 
 	exit(EXIT_SUCCESS);
 }
-


This is step one. Step two is a diff - actually still rather a hack due 
to some hard-coded options - to use the tool during dtb builds:

diff --git a/common/Kconfig.boot b/common/Kconfig.boot
index d3a12be228..a9ed4d4ec4 100644
--- a/common/Kconfig.boot
+++ b/common/Kconfig.boot
@@ -279,6 +279,14 @@ config SPL_FIT_GENERATOR
 
 endif # SPL
 
+config FIT_SIGNATURE_PUB_KEYS
+	string "Public keys to use for FIT image verification"
+	depends on FIT_SIGNATURE || SPL_FIT_SIGNATURE
+	help
+	  Public keys, or certificate files to extract them from, that shall
+	  be used to verify signed FIT images. The keys will be embedded into
+	  the control device tree of U-Boot.
+
 endif # FIT
 
 config LEGACY_IMAGE_FORMAT
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 39f03398ed..65852dc1d9 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -326,9 +326,12 @@ cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \
 		-d $(depfile).dtc.tmp $(dtc-tmp) || \
 		(echo "Check $(shell pwd)/$(pre-tmp) for errors" && false) \
 		; \
+	$(foreach key,$(subst $(quote),,$(CONFIG_FIT_SIGNATURE_PUB_KEYS)), \
+		tools/fdt_add_pubkey -a sha256,rsa4096 -k $(shell dirname $(key)) \
+			-n $(subst .key,,$(shell basename $(key))) -r conf $@;) \
 	sed "s:$(pre-tmp):$(<):" $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile)
 
-$(obj)/%.dtb: $(src)/%.dts FORCE
+$(obj)/%.dtb: $(src)/%.dts tools/fdt_add_pubkey FORCE
 	$(call if_changed_dep,dtc)
 
 pre-tmp = $(subst $(comma),_,$(dot-target).pre.tmp)


This permits the workflow:

- make flash.bin (via binman)
- mkimage -r -F fit at 0x280000.fit (an embedded FIT in flash.bin)
- binman replace -i flash.bin -f fit at 0x280000.fit fit at 0x280000
(the latter on in theory, that command is broken ATM)

Jan

-- 
Siemens AG, T RDA IOT
Corporate Competence Center Embedded Linux


More information about the U-Boot mailing list