[PATCH 13/16] tools: Add a new tool to sign FDT blobs

Simon Glass sjg at chromium.org
Fri Nov 12 20:28:14 CET 2021


This works similarly to FIT signing except that it signs the entire FDT
(with a few exclusions), rather than just FIT configurations or images.

Also it is a stand-alone tool rather than being part of mkimage.

The signature is added to the FDT so it can be checked later, to ensure
that no modifications were made to the FDT.

The /chosen node is excluded, since U-Boot may want to update it.

Signed-off-by: Simon Glass <sjg at chromium.org>
---

 include/image.h   |  29 ++++
 tools/Makefile    |   8 +-
 tools/fdt-host.c  | 333 ++++++++++++++++++++++++++++++++++++++++++++++
 tools/fdt_host.h  |  19 +++
 tools/fdt_sign.c  | 210 +++++++++++++++++++++++++++++
 tools/imagetool.h |   1 +
 6 files changed, 598 insertions(+), 2 deletions(-)
 create mode 100644 tools/fdt-host.c
 create mode 100644 tools/fdt_sign.c

diff --git a/include/image.h b/include/image.h
index 733fa016694..b2767883636 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1154,6 +1154,35 @@ int fit_check_ramdisk(const void *fit, int os_noffset,
 int calculate_hash(const void *data, int data_len, const char *algo,
 			uint8_t *value, int *value_len);
 
+/**
+ * fdt_add_verif_data() - add verification data to an FDT blob
+ *
+ * @keydir:	Directory containing keys
+ * @keyfile:	Filename containing .key file
+ * @kwydest:	FDT blob to write public key information to (NULL if none)
+ * @fit:	Pointer to the FIT format image header
+ * @key_name:	Name of key used to sign (used for node name and .crt file)
+ * @comment:	Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ * @engine_id:	Engine to use for signing
+ * @cmdname:	Command name used when reporting errors
+ * @summary:	Returns information about what data was written
+ *
+ * Adds hash values for all component images in the FIT blob.
+ * Hashes are calculated for all component images which have hash subnodes
+ * with algorithm property set to one of the supported hash algorithms.
+ *
+ * Also add signatures if signature nodes are present.
+ *
+ * returns
+ *     0, on success
+ *     libfdt error code, on failure
+ */
+int fdt_add_verif_data(const char *keydir, const char *keyfile, void *keydest,
+		       void *blob, const char *key_name, const char *comment,
+		       bool require_keys, const char *engine_id,
+		       const char *cmdname, struct image_summary *summary);
+
 /*
  * At present we only support signing on the host, and verification on the
  * device
diff --git a/tools/Makefile b/tools/Makefile
index 1763f44cac4..07eca631cb0 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -72,12 +72,14 @@ hostprogs-y += mkenvimage
 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) += fit_info fit_check_sign \
+	fdt_sign
 
 hostprogs-$(CONFIG_CMD_BOOTEFI_SELFTEST) += file2include
 
 FIT_OBJS-y := fit_common.o fit_image.o image-host.o boot/image-fit.o
-FIT_SIG_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := image-sig-host.o boot/image-fit-sig.o
+FIT_SIG_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := image-sig-host.o \
+	boot/image-fit-sig.o fdt-host.o
 FIT_CIPHER_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := boot/image-cipher.o
 
 # The following files are synced with upstream DTC.
@@ -154,6 +156,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_sign-objs   := $(dumpimage-mkimage-objs) fdt_sign.o
 file2include-objs := file2include.o
 
 ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),)
@@ -191,6 +194,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_sign := $(HOSTLDLIBS_mkimage)
 
 hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
 hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
diff --git a/tools/fdt-host.c b/tools/fdt-host.c
new file mode 100644
index 00000000000..8aa0e099f2f
--- /dev/null
+++ b/tools/fdt-host.c
@@ -0,0 +1,333 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2021 Google, LLC
+ * Written by Simon Glass <sjg at chromium.org>
+ */
+
+#include "mkimage.h"
+#include <fdt_region.h>
+#include <image.h>
+#include <version.h>
+
+/**
+ * fdt_setup_sig() - Setup the signing info ready for use
+ *
+ * @info: Info to set up
+ * @keydir: Directory holding private keys
+ * @keyfile: Filename of private or public key (NULL to find it in @keydir)
+ * @keyname: Name to use for key node if added
+ * @blob: FDT blob to sign
+ * @algo_name: Algorithm name to use for signing, e.g. "sha256,rsa2048"
+ * @padding_name: Padding method to use for signing, NULL if none
+ * @require_keys: Mark signing keys as 'required' (else they are optional)
+ * @engine_id: Engine to use for signin, NULL for default
+ * @return 0 if OK, -ENOMEM if out of memory, -ENOSYS if unsupported algorithm
+ */
+static int fdt_setup_sig(struct image_sign_info *info, const char *keydir,
+			 const char *keyfile, const char *keyname, void *blob,
+			 const char *algo_name, const char *padding_name,
+			 const char *require_keys, const char *engine_id)
+{
+	memset(info, '\0', sizeof(*info));
+	info->keydir = keydir;
+	info->keyfile = keyfile;
+	info->keyname = keyname;
+	info->fit = blob;
+	info->name = strdup(algo_name);
+	if (!info->name) {
+		printf("Out of memory for algo_name\n");
+		return -ENOMEM;
+	}
+	info->checksum = image_get_checksum_algo(algo_name);
+	info->crypto = image_get_crypto_algo(algo_name);
+	info->padding = image_get_padding_algo(padding_name);
+	info->require_keys = require_keys;
+	info->engine_id = engine_id;
+	if (!info->checksum || !info->crypto) {
+		printf("Unsupported signature algorithm (%s)\n", algo_name);
+		return -ENOSYS;
+	}
+
+	return 0;
+}
+
+/**
+ * h_exclude_nodes() - Handles excluding certain nodes from the FDT
+ *
+ * This is called by fdt_next_region() when it wants to find out if a node or
+ * property should be included in the hash.
+ *
+ * This function simply omits the /chosen node as well as /signature and any
+ * subnodes.
+ *
+ * @return 0 if the node should be excluded, -1 for everything else (meaning it
+ *	has no opinion)
+ */
+static int h_exclude_nodes(void *priv, const void *fdt, int offset, int type,
+			   const char *data, int size)
+{
+	if (type == FDT_IS_NODE) {
+		/* Ignore the chosen node as well as /signature and subnodes */
+		if (!strcmp("/chosen", data) ||
+		    !strncmp("/signature", data, 10))
+			return 0;
+	}
+
+	return -1;
+}
+
+/**
+ * run_find_regions() - Use the fdt region calculation to get a list of regions
+ *
+ * This finds the regions of the FDT that need to be hashed so that it can be
+ * protected against modification by a signature
+ *
+ * @fdt: FDT blob to check
+ * @include_func: Function to call to determine whether to include an element of
+ * the devicetree
+ * @priv: Private data, set to NULL for now
+ * @region: Region list to fill in
+ * @max_regions: Max size of region list, e.g. 100
+ * @path: Place to keep the path to each node (used by this function)
+ * @path_len: Max size of @path, 200 bytes is recommended
+ * @return 0 if OK, -FDT_ERR_... on error
+ */
+static int run_find_regions(const void *fdt,
+			    int (*include_func)(void *priv, const void *fdt,
+						int offset, int type,
+						const char *data, int size),
+			    void *priv, struct fdt_region *region,
+			    int max_regions, char *path, int path_len,
+			    int flags)
+{
+	struct fdt_region_state state;
+	int count;
+	int ret;
+
+	count = 0;
+	ret = fdt_first_region(fdt, include_func, NULL, &region[count++], path,
+			       path_len, flags, &state);
+	while (ret == 0) {
+		ret = fdt_next_region(fdt, include_func, NULL,
+				      count < max_regions ? &region[count] :
+				      NULL, path, path_len, flags, &state);
+		if (!ret)
+			count++;
+	}
+	if (ret && ret != -FDT_ERR_NOTFOUND)
+		return ret;
+
+	return count;
+}
+
+int fdt_get_regions(const void *blob, int strtab_len,
+		    struct image_region **regionp, int *region_countp)
+{
+	struct image_region *region;
+	struct fdt_region fdt_regions[100];
+	char path[200];
+	int count;
+
+	/* Get a list of regions to hash */
+	count = run_find_regions(blob, h_exclude_nodes, NULL, fdt_regions,
+				 ARRAY_SIZE(fdt_regions), path, sizeof(path),
+				 FDT_REG_SUPERNODES | FDT_REG_ADD_MEM_RSVMAP |
+				 FDT_REG_ADD_STRING_TAB);
+	if (count < 0) {
+		fprintf(stderr, "Failed to hash device tree\n");
+		return -EIO;
+	}
+	if (count == 0) {
+		fprintf(stderr, "No data to hash for device tree");
+		return -EINVAL;
+	}
+
+	/* Limit the string table to what was hashed */
+	if (strtab_len != -1) {
+		if (strtab_len < 0 ||
+		    strtab_len > fdt_regions[count - 1].size) {
+			fprintf(stderr, "Invalid string-table offset\n");
+			return -EINVAL;
+		}
+		fdt_regions[count - 1].size = strtab_len;
+	}
+
+	/* Build our list of data blocks */
+	region = fit_region_make_list(blob, fdt_regions, count, NULL);
+	if (!region) {
+		fprintf(stderr, "Out of memory making region list'\n");
+		return -ENOMEM;
+	}
+#ifdef DEBUG
+	int i;
+
+	printf("Regions:\n");
+	for (i = 0; i < count; i++) {
+		printf("region %d: %x %x %x\n", i, fdt_regions[i].offset,
+		       fdt_regions[i].size,
+		       fdt_regions[i].offset + fdt_regions[i].size);
+	}
+#endif
+	*region_countp = count;
+	*regionp = region;
+
+	return 0;
+}
+
+/**
+ * fdt_write_sig() - write the signature to an FDT
+ *
+ * This writes the signature and signer data to the FDT
+ *
+ * @blob: pointer to the FDT header
+ * @noffset: hash node offset
+ * @value: signature value to be set
+ * @value_len: signature value length
+ * @comment: Text comment to write (NULL for none)
+ *
+ * returns
+ *     offset of node where things were added, on success
+ *     -FDT_ERR_..., on failure
+ */
+static int fdt_write_sig(void *blob, uint8_t *value, int value_len,
+			 const char *algo_name, const char *sig_name,
+			 const char *comment, const char *cmdname)
+{
+	uint32_t strdata[2];
+	int string_size;
+	int sigs_node, noffset;
+	int ret;
+
+	/*
+	 * Get the current string size, before we update the FIT and add
+	 * more
+	 */
+	string_size = fdt_size_dt_strings(blob);
+
+	sigs_node = fdt_subnode_offset(blob, 0, FIT_SIG_NODENAME);
+	if (sigs_node == -FDT_ERR_NOTFOUND)
+		sigs_node = fdt_add_subnode(blob, 0, FIT_SIG_NODENAME);
+	if (sigs_node < 0)
+		return sigs_node;
+
+	/* Create a node for this signature */
+	noffset = fdt_subnode_offset(blob, sigs_node, sig_name);
+	if (noffset == -FDT_ERR_NOTFOUND)
+		noffset = fdt_add_subnode(blob, sigs_node, sig_name);
+	if (noffset < 0)
+		return noffset;
+
+	ret = fdt_setprop(blob, noffset, FIT_VALUE_PROP, value, value_len);
+	if (!ret) {
+		ret = fdt_setprop_string(blob, noffset, FIT_ALGO_PROP,
+					 algo_name);
+	}
+	if (!ret) {
+		ret = fdt_setprop_string(blob, noffset, "signer-name",
+					 "fdt_sign");
+	}
+	if (!ret) {
+		ret = fdt_setprop_string(blob, noffset, "signer-version",
+					 PLAIN_VERSION);
+	}
+	if (comment && !ret)
+		ret = fdt_setprop_string(blob, noffset, "comment", comment);
+	if (!ret) {
+		time_t timestamp = imagetool_get_source_date(cmdname,
+							     time(NULL));
+		uint32_t t = cpu_to_uimage(timestamp);
+
+		ret = fdt_setprop(blob, noffset, FIT_TIMESTAMP_PROP, &t,
+				  sizeof(uint32_t));
+	}
+
+	/* This is a legacy offset, it is unused, and must remain 0. */
+	strdata[0] = 0;
+	strdata[1] = cpu_to_fdt32(string_size);
+	if (!ret) {
+		ret = fdt_setprop(blob, noffset, "hashed-strings",
+				  strdata, sizeof(strdata));
+	}
+	if (ret)
+		return ret;
+
+	return noffset;
+}
+
+static int fdt_process_sig(const char *keydir, const char *keyfile,
+			   void *keydest, void *blob, const char *keyname,
+			   const char *comment, int require_keys,
+			   const char *engine_id, const char *cmdname,
+			   struct image_summary *summary)
+{
+	struct image_sign_info info;
+	struct image_region *region;
+	int region_count;
+	uint8_t *value;
+	uint value_len;
+	int ret;
+
+	ret = fdt_get_regions(blob, -1, &region, &region_count);
+	if (ret)
+		return ret;
+	ret = fdt_setup_sig(&info, keydir, keyfile, keyname, blob,
+			    "sha256,rsa2048", NULL, require_keys ? "fdt" : NULL,
+			    engine_id);
+	if (ret)
+		return ret;
+
+	ret = info.crypto->sign(&info, region, region_count, &value,
+				&value_len);
+	free(region);
+	if (ret) {
+		fprintf(stderr, "Failed to sign FDT\n");
+
+		/* We allow keys to be missing */
+		if (ret == -ENOENT)
+			return 0;
+		return -1;
+	}
+
+	ret = fdt_write_sig(blob, value, value_len, info.name, keyname, comment,
+			    cmdname);
+	if (ret < 0) {
+		if (ret == -FDT_ERR_NOSPACE)
+			return -ENOSPC;
+		printf("Can't write signature: %s\n", fdt_strerror(ret));
+		return -1;
+	}
+	summary->sig_offset = ret;
+	fdt_get_path(blob, ret, summary->sig_path,
+		     sizeof(summary->sig_path));
+	free(value);
+
+	/* Write the public key into the supplied FDT file */
+	if (keydest) {
+		ret = info.crypto->add_verify_data(&info, keydest);
+		if (ret < 0) {
+			if (ret != -ENOSPC)
+				fprintf(stderr, "Failed to add verification data (err=%d)\n",
+					ret);
+			return ret;
+		}
+		summary->keydest_offset = ret;
+		fdt_get_path(keydest, ret, summary->keydest_path,
+			     sizeof(summary->keydest_path));
+	}
+
+	return 0;
+}
+
+/* This function exists just to mirror fit_image_add_verification_data() */
+int fdt_add_verif_data(const char *keydir, const char *keyfile, void *keydest,
+		       void *blob, const char *keyname, const char *comment,
+		       bool require_keys, const char *engine_id,
+		       const char *cmdname, struct image_summary *summary)
+{
+	int ret;
+
+	ret = fdt_process_sig(keydir, keyfile, keydest, blob, keyname, comment,
+			      require_keys, engine_id, cmdname, summary);
+
+	return ret;
+}
diff --git a/tools/fdt_host.h b/tools/fdt_host.h
index bc42306c9e5..877f098676b 100644
--- a/tools/fdt_host.h
+++ b/tools/fdt_host.h
@@ -10,6 +10,8 @@
 #include "../include/linux/libfdt.h"
 #include "../include/fdt_support.h"
 
+struct image_region;
+
 /**
  * fdt_remove_unused_strings() - Remove any unused strings from an FDT
  *
@@ -38,4 +40,21 @@ int fdt_remove_unused_strings(const void *old, void *new);
 int fit_check_sign(const void *fit, const void *key,
 		   const char *fit_uname_config);
 
+/**
+ * fdt_get_regions() - Get the regions to sign
+ *
+ * This calculates a list of node to hash for this particular configuration,
+ * then finds which regions of the devicetree they correspond to.
+ *
+ * @blob:	Pointer to the FDT blob to sign
+ * @strtab_len:	Length in bytes of the string table to sign, -1 to sign it all
+ * @regionp: Returns list of regions that need to be hashed (allocated; must be
+ *	freed by the caller)
+ * @region_count: Returns number of regions
+ * @return 0 if OK, -ENOMEM if out of memory, -EIO if the regions to hash could
+ * not be found, -EINVAL if no registers were found to hash
+ */
+int fdt_get_regions(const void *blob, int strtab_len,
+		    struct image_region **regionp, int *region_countp);
+
 #endif /* __FDT_HOST_H__ */
diff --git a/tools/fdt_sign.c b/tools/fdt_sign.c
new file mode 100644
index 00000000000..b3a7fb4f8bf
--- /dev/null
+++ b/tools/fdt_sign.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sign an FDT file
+ *
+ * Copyright 2021 Google LLC
+ * Written by Simon Glass <sjg at chromium.org>
+ */
+
+#include "mkimage.h"
+#include "fit_common.h"
+#include <image.h>
+
+void usage(char *cmdname)
+{
+	fprintf(stderr,
+		"Usage: %s -f dtb_file -G file.key -k dir [-K pub.dtb] [-o out_file]\n"
+		"          -f ==> set dtb file which should be signed\n"
+		"          -G ==> set signing key to use\n"
+		"          -k ==> set directory containing private keys\n"
+		"          -K ==> set DTB file to receive signing key\n"
+		"          -o ==> if not provided, dtb file is updated\n"
+		"          -S ==> name to use for signaure (defaults to -G)\n"
+		"          -r ==> mark keys as required to be verified\n"
+		"          -q ==> quiet mode\n",
+		cmdname);
+	exit(EXIT_FAILURE);
+}
+
+/**
+ * sign_fdt() - Sign an FDT
+ *
+ * @params: Image parameters
+ * @destfile: Filename of FDT being signed (only used for messages)
+ * @size_inc: Amount to expand the FDT blob by, before adding signing data
+ * @blob: FDT blob to sign
+ * @size: Size of blob in bytes
+ * @return 0 if OK, -ve on error
+ */
+static int sign_fdt(struct image_tool_params *params, const char *destfile,
+		    size_t size_inc, char *blob, int size)
+{
+	struct image_summary summary;
+	void *dest_blob = NULL;
+	struct stat dest_sbuf;
+	char def_name[80];
+	int destfd = 0;
+	int ret;
+
+	/*
+	 * If we don't have a signature name, try to make one from the keyfile.
+	 * '/path/to/dir/name.key' becomes 'name'
+	 */
+	if (!params->keyname) {
+		const char *p = strrchr(params->keyfile, '/');
+		char *q;
+
+		if (p)
+			p++;
+		else
+			p = params->keyfile;
+		strncpy(def_name, p, sizeof(def_name));
+		def_name[sizeof(def_name) - 1] = '\0';
+		q = strstr(def_name, ".key");
+		if (q && q[strlen(q)] == '\0')
+			*q = '\0';
+		params->keyname = def_name;
+	}
+
+	if (params->keydest) {
+		destfd = mmap_fdt(params->cmdname, params->keydest, size_inc,
+				  &dest_blob, &dest_sbuf, false,
+				  false);
+		if (destfd < 0) {
+			ret = -EIO;
+			fprintf(stderr, "Cannot open keydest file '%s'\n",
+				params->keydest);
+		}
+	}
+
+	ret = fdt_add_verif_data(params->keydir, params->keyfile, dest_blob,
+				 blob, params->keyname, params->comment,
+				 params->require_keys, params->engine_id,
+				 params->cmdname, &summary);
+	if (!ret && !params->quiet)
+		summary_show(&summary, destfile, params->keydest);
+
+	if (params->keydest) {
+		(void)munmap(dest_blob, dest_sbuf.st_size);
+		close(destfd);
+	}
+	if (ret < 0) {
+		if (ret != -ENOSPC)
+			fprintf(stderr, "Failed to add signature\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+/**
+ * do_fdt_sign() - Sign an FDT, expanding if needed
+ *
+ * If a separate output file is specified, the FDT blob is copied to that first.
+ *
+ * If there is not space in the FDT to add the signature, it is expanded
+ * slightly and the operation is retried.
+ *
+ * @params: Image parameters
+ * @cmdname: Name of tool (e.g. argv[0]), to use in error messages
+ * @fdtfile: Filename of FDT blob to sign
+ * @return 0 if OK, -ve on error
+ */
+static int do_fdt_sign(struct image_tool_params *params, const char *cmdname,
+		       const char *fdtfile)
+{
+	const char *destfile;
+	struct stat fsbuf;
+	int ffd, size_inc;
+	void *blob;
+	int ret;
+
+	destfile = params->outfile ? params->outfile : fdtfile;
+	for (size_inc = 0; size_inc < 64 * 1024;) {
+		if (params->outfile) {
+			if (copyfile(fdtfile, params->outfile) < 0) {
+				printf("Can't copy %s to %s\n", fdtfile,
+				       params->outfile);
+				return -EIO;
+			}
+		}
+		ffd = mmap_fdt(cmdname, destfile, size_inc, &blob, &fsbuf,
+			       params->outfile, false);
+		if (ffd < 0)
+			return -1;
+
+		ret = sign_fdt(params, destfile, 0, blob, fsbuf.st_size);
+		(void)munmap((void *)blob, fsbuf.st_size);
+		close(ffd);
+
+		if (ret >= 0 || ret != -ENOSPC)
+			break;
+		size_inc += 512;
+		debug("Not enough space in FDT '%s', trying size_inc=%#x\n",
+		      destfile, size_inc);
+	}
+
+	if (ret < 0) {
+		fprintf(stderr, "Failed to sign '%s' (error %d)\n",
+			destfile, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	struct image_tool_params params;
+	char *fdtfile = NULL;
+	char cmdname[256];
+	int ret;
+	int c;
+
+	memset(&params, '\0', sizeof(params));
+	strncpy(cmdname, *argv, sizeof(cmdname) - 1);
+	cmdname[sizeof(cmdname) - 1] = '\0';
+	while ((c = getopt(argc, argv, "f:G:k:K:o:qrS:")) != -1)
+		switch (c) {
+		case 'f':
+			fdtfile = optarg;
+			break;
+		case 'G':
+			params.keyfile = optarg;
+			break;
+		case 'k':
+			params.keydir = optarg;
+			break;
+		case 'K':
+			params.keydest = optarg;
+			break;
+		case 'o':
+			params.outfile = optarg;
+			break;
+		case 'q':
+			params.quiet = true;
+			break;
+		case 'r':
+			params.require_keys = true;
+			break;
+		case 'S':
+			params.keyname = optarg;
+			break;
+		default:
+			usage(cmdname);
+			break;
+	}
+
+	if (!fdtfile) {
+		fprintf(stderr, "%s: Missing fdt file\n", *argv);
+		usage(*argv);
+	}
+	if (!params.keyfile) {
+		fprintf(stderr, "%s: Missing key file\n", *argv);
+		usage(*argv);
+	}
+
+	ret = do_fdt_sign(&params, cmdname, fdtfile);
+
+	exit(ret);
+}
diff --git a/tools/imagetool.h b/tools/imagetool.h
index c0579c8c93c..4f9626fd1e0 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -70,6 +70,7 @@ struct image_tool_params {
 	const char *keydir;	/* Directory holding private keys */
 	const char *keydest;	/* Destination .dtb for public key */
 	const char *keyfile;	/* Filename of private or public key */
+	const char *keyname;	/* Name to use for key node if added */
 	const char *comment;	/* Comment to add to signature node */
 	int require_keys;	/* 1 to mark signing keys as 'required' */
 	int file_size;		/* Total size of output file */
-- 
2.34.0.rc1.387.gb447b232ab-goog



More information about the U-Boot mailing list