
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@kaspersky.com Cc: Rasmus Villemoes rasmus.villemoes@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@0x280000.fit (an embedded FIT in flash.bin) - binman replace -i flash.bin -f fit@0x280000.fit fit@0x280000 (the latter on in theory, that command is broken ATM)
Jan