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.kopy...@kaspersky.com> > Cc: Rasmus Villemoes <rasmus.villem...@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 f...@0x280000.fit (an embedded FIT in flash.bin) - binman replace -i flash.bin -f f...@0x280000.fit fit@0x280000 (the latter on in theory, that command is broken ATM) Jan -- Siemens AG, T RDA IOT Corporate Competence Center Embedded Linux