diff mbox series

[3/4] tools: add fdtsig command

Message ID 20210512045753.62288-4-takahiro.akashi@linaro.org
State New
Headers show
Series efi_loader: capsule: improve capsule authentication support | expand

Commit Message

AKASHI Takahiro May 12, 2021, 4:57 a.m. UTC
This command allows us to add a certificate (or public key) to dtb blob:
{
	signature {
		capsule-key = "...";
	};
}

The value is actually a signature list in terms of UEFI specificaion,
and used in verifying UEFI capsules.

The code was originally developed by Sughosh and derived from
mkeficapsule.c.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

---
 Makefile       |   2 +-
 tools/Makefile |   2 +
 tools/fdtsig.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 277 insertions(+), 1 deletion(-)
 create mode 100644 tools/fdtsig.c

-- 
2.31.0

Comments

Heinrich Schuchardt May 13, 2021, 5:23 a.m. UTC | #1
On 5/12/21 6:57 AM, AKASHI Takahiro wrote:
> This command allows us to add a certificate (or public key) to dtb blob:

> {

> 	signature {

> 		capsule-key = "...";

> 	};

> }

>

> The value is actually a signature list in terms of UEFI specificaion,

> and used in verifying UEFI capsules.

>

> The code was originally developed by Sughosh and derived from

> mkeficapsule.c.


I have no clue how you want to use this command. Please, provide a
description of the workflow using this command.

In your comments for patch 2 you wrote that the -K and -D option can be
replaced by tools provided by the device-tree compiler package. Why do
they reappear here?

Please, add a man-page (/doc/fdtsig.1).


>

> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

> ---

>   Makefile       |   2 +-

>   tools/Makefile |   2 +

>   tools/fdtsig.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++

>   3 files changed, 277 insertions(+), 1 deletion(-)

>   create mode 100644 tools/fdtsig.c

>

> diff --git a/Makefile b/Makefile

> index 9806464357e0..8b40987234a0 100644

> --- a/Makefile

> +++ b/Makefile

> @@ -1016,7 +1016,7 @@ quiet_cmd_lzma = LZMA    $@

>   cmd_lzma = lzma -c -z -k -9 $< > $@

>

>   quiet_cmd_fdtsig = FDTSIG  $@

> -cmd_fdtsig = $(srctree)/tools/fdtsig.sh $(CONFIG_EFI_PKEY_FILE) $@

> +cmd_fdtsig = $(objtree)/tools/fdtsig -K $(CONFIG_EFI_PKEY_FILE) -D $@

>

>   cfg: u-boot.cfg

>

> diff --git a/tools/Makefile b/tools/Makefile

> index 71a52719620c..e6fd1dbade19 100644

> --- a/tools/Makefile

> +++ b/tools/Makefile

> @@ -234,6 +234,8 @@ HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include

>   ifneq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),)

>   HOSTLDLIBS_mkeficapsule += \

>   	$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")

> +	fdtsig-objs	:= fdtsig.o $(LIBFDT_OBJS)

> +	hostprogs-y += fdtsig

>   endif

>   hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule

>

> diff --git a/tools/fdtsig.c b/tools/fdtsig.c

> new file mode 100644

> index 000000000000..daa1e63c3b33

> --- /dev/null

> +++ b/tools/fdtsig.c

> @@ -0,0 +1,274 @@

> +// SPDX-License-Identifier: GPL-2.0

> +/*

> + * Copyright 2021 Linaro Limited

> + * The code in this file was extracted from mkeficapsule.c


That information is better described by the git log.

Please, explain here what this tool is used for.

Best regards

Heinrich

> + */

> +

> +#include <errno.h>

> +#include <fcntl.h>

> +#include <getopt.h>

> +#include <malloc.h>

> +#include <stdbool.h>

> +#include <stdio.h>

> +#include <unistd.h>

> +

> +#include <sys/mman.h>

> +#include <sys/stat.h>

> +

> +#include <linux/libfdt.h>

> +

> +#define SIGNATURE_NODENAME	"signature"

> +#define OVERLAY_NODENAME	"__overlay__"

> +

> +static const char *tool_name = "fdtsig";

> +

> +static const char *opts_short = "D:K:Oh";

> +

> +static struct option options[] = {

> +	{"dtb", required_argument, NULL, 'D'},

> +	{"public key", required_argument, NULL, 'K'},

> +	{"overlay", no_argument, NULL, 'O'},

> +	{"help", no_argument, NULL, 'h'},

> +	{NULL, 0, NULL, 0},

> +};

> +

> +static void print_usage(void)

> +{

> +	printf("Usage: %s [options]\n"

> +	       "Options:\n"

> +

> +	       "\t-K, --public-key <key file> public key esl file\n"

> +	       "\t-D, --dtb <dtb file>        dtb file\n"

> +	       "\t-O, --overlay               the dtb file is an overlay\n"

> +	       "\t-h, --help                  print a help message\n",

> +	       tool_name);

> +}

> +

> +static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size,

> +				bool overlay)

> +{

> +	int parent;

> +	int ov_node;

> +	int frag_node;

> +	int ret = 0;

> +

> +	if (overlay) {

> +		/*

> +		 * The signature would be stored in the

> +		 * first fragment node of the overlay

> +		 */

> +		frag_node = fdt_first_subnode(dptr, 0);

> +		if (frag_node == -FDT_ERR_NOTFOUND) {

> +			fprintf(stderr,

> +				"Couldn't find the fragment node: %s\n",

> +				fdt_strerror(frag_node));

> +			goto done;

> +		}

> +

> +		ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME);

> +		if (ov_node == -FDT_ERR_NOTFOUND) {

> +			fprintf(stderr,

> +				"Couldn't find the __overlay__ node: %s\n",

> +				fdt_strerror(ov_node));

> +			goto done;

> +		}

> +	} else {

> +		ov_node = 0;

> +	}

> +

> +	parent = fdt_subnode_offset(dptr, ov_node, SIGNATURE_NODENAME);

> +	if (parent == -FDT_ERR_NOTFOUND) {

> +		parent = fdt_add_subnode(dptr, ov_node, SIGNATURE_NODENAME);

> +		if (parent < 0) {

> +			ret = parent;

> +			if (ret != -FDT_ERR_NOSPACE) {

> +				fprintf(stderr,

> +					"Couldn't create signature node: %s\n",

> +					fdt_strerror(parent));

> +			}

> +		}

> +	}

> +	if (ret)

> +		goto done;

> +

> +	/* Write the key to the FDT node */

> +	ret = fdt_setprop(dptr, parent, "capsule-key",

> +			  sptr, key_size);

> +

> +done:

> +	if (ret)

> +		ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;

> +

> +	return ret;

> +}

> +

> +static int add_public_key(const char *pkey_file, const char *dtb_file,

> +			  bool overlay)

> +{

> +	int ret;

> +	int srcfd = -1;

> +	int destfd = -1;

> +	void *sptr = NULL;

> +	void *dptr = NULL;

> +	off_t src_size;

> +	struct stat pub_key;

> +	struct stat dtb;

> +

> +	/* Find out the size of the public key */

> +	srcfd = open(pkey_file, O_RDONLY);

> +	if (srcfd == -1) {

> +		fprintf(stderr, "%s: Can't open %s: %s\n",

> +			__func__, pkey_file, strerror(errno));

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	ret = fstat(srcfd, &pub_key);

> +	if (ret == -1) {

> +		fprintf(stderr, "%s: Can't stat %s: %s\n",

> +			__func__, pkey_file, strerror(errno));

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	src_size = pub_key.st_size;

> +

> +	/* mmap the public key esl file */

> +	sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0);

> +	if (sptr == MAP_FAILED) {

> +		fprintf(stderr, "%s: Failed to mmap %s:%s\n",

> +			__func__, pkey_file, strerror(errno));

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	/* Open the dest FDT */

> +	destfd = open(dtb_file, O_RDWR);

> +	if (destfd == -1) {

> +		fprintf(stderr, "%s: Can't open %s: %s\n",

> +			__func__, dtb_file, strerror(errno));

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	ret = fstat(destfd, &dtb);

> +	if (ret == -1) {

> +		fprintf(stderr, "%s: Can't stat %s: %s\n",

> +			__func__, dtb_file, strerror(errno));

> +		goto err;

> +	}

> +

> +	dtb.st_size += src_size + 0x30;

> +	if (ftruncate(destfd, dtb.st_size)) {

> +		fprintf(stderr, "%s: Can't expand %s: %s\n",

> +			__func__, dtb_file, strerror(errno));

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	errno = 0;

> +	/* mmap the dtb file */

> +	dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,

> +		    destfd, 0);

> +	if (dptr == MAP_FAILED) {

> +		fprintf(stderr, "%s: Failed to mmap %s:%s\n",

> +			__func__, dtb_file, strerror(errno));

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	if (fdt_check_header(dptr)) {

> +		fprintf(stderr, "%s: Invalid FDT header\n", __func__);

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	ret = fdt_open_into(dptr, dptr, dtb.st_size);

> +	if (ret) {

> +		fprintf(stderr, "%s: Cannot expand FDT: %s\n",

> +			__func__, fdt_strerror(ret));

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	/* Copy the esl file to the expanded FDT */

> +	ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);

> +	if (ret < 0) {

> +		fprintf(stderr, "%s: Unable to add public key to the FDT\n",

> +			__func__);

> +		ret = -1;

> +		goto err;

> +	}

> +

> +	ret = 0;

> +

> +err:

> +	if (sptr)

> +		munmap(sptr, src_size);

> +

> +	if (dptr)

> +		munmap(dptr, dtb.st_size);

> +

> +	if (srcfd != -1)

> +		close(srcfd);

> +

> +	if (destfd != -1)

> +		close(destfd);

> +

> +	return ret;

> +}

> +

> +int main(int argc, char **argv)

> +{

> +	char *pkey_file;

> +	char *dtb_file;

> +	bool overlay;

> +	int c, idx, ret;

> +

> +	pkey_file = NULL;

> +	dtb_file = NULL;

> +	overlay = false;

> +

> +	for (;;) {

> +		c = getopt_long(argc, argv, opts_short, options, &idx);

> +		if (c == -1)

> +			break;

> +

> +		switch (c) {

> +		case 'K':

> +			if (pkey_file) {

> +				printf("Public Key already specified\n");

> +				return -1;

> +			}

> +			pkey_file = optarg;

> +			break;

> +		case 'D':

> +			if (dtb_file) {

> +				printf("DTB file already specified\n");

> +				return -1;

> +			}

> +			dtb_file = optarg;

> +			break;

> +		case 'O':

> +			overlay = true;

> +			break;

> +		case 'h':

> +			print_usage();

> +			return 0;

> +		}

> +	}

> +

> +	/* check necessary parameters */

> +	if (!pkey_file || !dtb_file) {

> +		print_usage();

> +		exit(EXIT_FAILURE);

> +	}

> +

> +	ret = add_public_key(pkey_file, dtb_file, overlay);

> +	if (ret == -1) {

> +		printf("Adding public key to the dtb failed\n");

> +		exit(EXIT_FAILURE);

> +	}

> +

> +	exit(EXIT_SUCCESS);

> +}

>
AKASHI Takahiro May 13, 2021, 7:03 a.m. UTC | #2
On Thu, May 13, 2021 at 07:23:43AM +0200, Heinrich Schuchardt wrote:
> On 5/12/21 6:57 AM, AKASHI Takahiro wrote:

> > This command allows us to add a certificate (or public key) to dtb blob:

> > {

> > 	signature {

> > 		capsule-key = "...";

> > 	};

> > }

> > 

> > The value is actually a signature list in terms of UEFI specificaion,

> > and used in verifying UEFI capsules.

> > 

> > The code was originally developed by Sughosh and derived from

> > mkeficapsule.c.

> 

> I have no clue how you want to use this command. Please, provide a

> description of the workflow using this command.


Please read my patch carefully, in particular, Makefile.
In this patch, fdtsig.sh, which is introduced in Patch#2, is
replaced with fdtsig (C version).

I think that the workflow is trivial.

> In your comments for patch 2 you wrote that the -K and -D option can be

> replaced by tools provided by the device-tree compiler package. Why do

> they reappear here?


?
As I said, I don't intend to ask you to merge this patch.

In the cover letter,
! NOTE:
! I temporarily include Patch#3 in order to show that it is not worth
! implementing in C as we can do the same thing with a very small
! shell script.

Patch #1, #2 and #4 are just fine.

-Takahiro Akashi


> Please, add a man-page (/doc/fdtsig.1).

> 

> 

> > 

> > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>

> > ---

> >   Makefile       |   2 +-

> >   tools/Makefile |   2 +

> >   tools/fdtsig.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++

> >   3 files changed, 277 insertions(+), 1 deletion(-)

> >   create mode 100644 tools/fdtsig.c

> > 

> > diff --git a/Makefile b/Makefile

> > index 9806464357e0..8b40987234a0 100644

> > --- a/Makefile

> > +++ b/Makefile

> > @@ -1016,7 +1016,7 @@ quiet_cmd_lzma = LZMA    $@

> >   cmd_lzma = lzma -c -z -k -9 $< > $@

> > 

> >   quiet_cmd_fdtsig = FDTSIG  $@

> > -cmd_fdtsig = $(srctree)/tools/fdtsig.sh $(CONFIG_EFI_PKEY_FILE) $@

> > +cmd_fdtsig = $(objtree)/tools/fdtsig -K $(CONFIG_EFI_PKEY_FILE) -D $@

> > 

> >   cfg: u-boot.cfg

> > 

> > diff --git a/tools/Makefile b/tools/Makefile

> > index 71a52719620c..e6fd1dbade19 100644

> > --- a/tools/Makefile

> > +++ b/tools/Makefile

> > @@ -234,6 +234,8 @@ HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include

> >   ifneq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),)

> >   HOSTLDLIBS_mkeficapsule += \

> >   	$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")

> > +	fdtsig-objs	:= fdtsig.o $(LIBFDT_OBJS)

> > +	hostprogs-y += fdtsig

> >   endif

> >   hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule

> > 

> > diff --git a/tools/fdtsig.c b/tools/fdtsig.c

> > new file mode 100644

> > index 000000000000..daa1e63c3b33

> > --- /dev/null

> > +++ b/tools/fdtsig.c

> > @@ -0,0 +1,274 @@

> > +// SPDX-License-Identifier: GPL-2.0

> > +/*

> > + * Copyright 2021 Linaro Limited

> > + * The code in this file was extracted from mkeficapsule.c

> 

> That information is better described by the git log.

> 

> Please, explain here what this tool is used for.

> 

> Best regards

> 

> Heinrich

> 

> > + */

> > +

> > +#include <errno.h>

> > +#include <fcntl.h>

> > +#include <getopt.h>

> > +#include <malloc.h>

> > +#include <stdbool.h>

> > +#include <stdio.h>

> > +#include <unistd.h>

> > +

> > +#include <sys/mman.h>

> > +#include <sys/stat.h>

> > +

> > +#include <linux/libfdt.h>

> > +

> > +#define SIGNATURE_NODENAME	"signature"

> > +#define OVERLAY_NODENAME	"__overlay__"

> > +

> > +static const char *tool_name = "fdtsig";

> > +

> > +static const char *opts_short = "D:K:Oh";

> > +

> > +static struct option options[] = {

> > +	{"dtb", required_argument, NULL, 'D'},

> > +	{"public key", required_argument, NULL, 'K'},

> > +	{"overlay", no_argument, NULL, 'O'},

> > +	{"help", no_argument, NULL, 'h'},

> > +	{NULL, 0, NULL, 0},

> > +};

> > +

> > +static void print_usage(void)

> > +{

> > +	printf("Usage: %s [options]\n"

> > +	       "Options:\n"

> > +

> > +	       "\t-K, --public-key <key file> public key esl file\n"

> > +	       "\t-D, --dtb <dtb file>        dtb file\n"

> > +	       "\t-O, --overlay               the dtb file is an overlay\n"

> > +	       "\t-h, --help                  print a help message\n",

> > +	       tool_name);

> > +}

> > +

> > +static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size,

> > +				bool overlay)

> > +{

> > +	int parent;

> > +	int ov_node;

> > +	int frag_node;

> > +	int ret = 0;

> > +

> > +	if (overlay) {

> > +		/*

> > +		 * The signature would be stored in the

> > +		 * first fragment node of the overlay

> > +		 */

> > +		frag_node = fdt_first_subnode(dptr, 0);

> > +		if (frag_node == -FDT_ERR_NOTFOUND) {

> > +			fprintf(stderr,

> > +				"Couldn't find the fragment node: %s\n",

> > +				fdt_strerror(frag_node));

> > +			goto done;

> > +		}

> > +

> > +		ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME);

> > +		if (ov_node == -FDT_ERR_NOTFOUND) {

> > +			fprintf(stderr,

> > +				"Couldn't find the __overlay__ node: %s\n",

> > +				fdt_strerror(ov_node));

> > +			goto done;

> > +		}

> > +	} else {

> > +		ov_node = 0;

> > +	}

> > +

> > +	parent = fdt_subnode_offset(dptr, ov_node, SIGNATURE_NODENAME);

> > +	if (parent == -FDT_ERR_NOTFOUND) {

> > +		parent = fdt_add_subnode(dptr, ov_node, SIGNATURE_NODENAME);

> > +		if (parent < 0) {

> > +			ret = parent;

> > +			if (ret != -FDT_ERR_NOSPACE) {

> > +				fprintf(stderr,

> > +					"Couldn't create signature node: %s\n",

> > +					fdt_strerror(parent));

> > +			}

> > +		}

> > +	}

> > +	if (ret)

> > +		goto done;

> > +

> > +	/* Write the key to the FDT node */

> > +	ret = fdt_setprop(dptr, parent, "capsule-key",

> > +			  sptr, key_size);

> > +

> > +done:

> > +	if (ret)

> > +		ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;

> > +

> > +	return ret;

> > +}

> > +

> > +static int add_public_key(const char *pkey_file, const char *dtb_file,

> > +			  bool overlay)

> > +{

> > +	int ret;

> > +	int srcfd = -1;

> > +	int destfd = -1;

> > +	void *sptr = NULL;

> > +	void *dptr = NULL;

> > +	off_t src_size;

> > +	struct stat pub_key;

> > +	struct stat dtb;

> > +

> > +	/* Find out the size of the public key */

> > +	srcfd = open(pkey_file, O_RDONLY);

> > +	if (srcfd == -1) {

> > +		fprintf(stderr, "%s: Can't open %s: %s\n",

> > +			__func__, pkey_file, strerror(errno));

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	ret = fstat(srcfd, &pub_key);

> > +	if (ret == -1) {

> > +		fprintf(stderr, "%s: Can't stat %s: %s\n",

> > +			__func__, pkey_file, strerror(errno));

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	src_size = pub_key.st_size;

> > +

> > +	/* mmap the public key esl file */

> > +	sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0);

> > +	if (sptr == MAP_FAILED) {

> > +		fprintf(stderr, "%s: Failed to mmap %s:%s\n",

> > +			__func__, pkey_file, strerror(errno));

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	/* Open the dest FDT */

> > +	destfd = open(dtb_file, O_RDWR);

> > +	if (destfd == -1) {

> > +		fprintf(stderr, "%s: Can't open %s: %s\n",

> > +			__func__, dtb_file, strerror(errno));

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	ret = fstat(destfd, &dtb);

> > +	if (ret == -1) {

> > +		fprintf(stderr, "%s: Can't stat %s: %s\n",

> > +			__func__, dtb_file, strerror(errno));

> > +		goto err;

> > +	}

> > +

> > +	dtb.st_size += src_size + 0x30;

> > +	if (ftruncate(destfd, dtb.st_size)) {

> > +		fprintf(stderr, "%s: Can't expand %s: %s\n",

> > +			__func__, dtb_file, strerror(errno));

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	errno = 0;

> > +	/* mmap the dtb file */

> > +	dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,

> > +		    destfd, 0);

> > +	if (dptr == MAP_FAILED) {

> > +		fprintf(stderr, "%s: Failed to mmap %s:%s\n",

> > +			__func__, dtb_file, strerror(errno));

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	if (fdt_check_header(dptr)) {

> > +		fprintf(stderr, "%s: Invalid FDT header\n", __func__);

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	ret = fdt_open_into(dptr, dptr, dtb.st_size);

> > +	if (ret) {

> > +		fprintf(stderr, "%s: Cannot expand FDT: %s\n",

> > +			__func__, fdt_strerror(ret));

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	/* Copy the esl file to the expanded FDT */

> > +	ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);

> > +	if (ret < 0) {

> > +		fprintf(stderr, "%s: Unable to add public key to the FDT\n",

> > +			__func__);

> > +		ret = -1;

> > +		goto err;

> > +	}

> > +

> > +	ret = 0;

> > +

> > +err:

> > +	if (sptr)

> > +		munmap(sptr, src_size);

> > +

> > +	if (dptr)

> > +		munmap(dptr, dtb.st_size);

> > +

> > +	if (srcfd != -1)

> > +		close(srcfd);

> > +

> > +	if (destfd != -1)

> > +		close(destfd);

> > +

> > +	return ret;

> > +}

> > +

> > +int main(int argc, char **argv)

> > +{

> > +	char *pkey_file;

> > +	char *dtb_file;

> > +	bool overlay;

> > +	int c, idx, ret;

> > +

> > +	pkey_file = NULL;

> > +	dtb_file = NULL;

> > +	overlay = false;

> > +

> > +	for (;;) {

> > +		c = getopt_long(argc, argv, opts_short, options, &idx);

> > +		if (c == -1)

> > +			break;

> > +

> > +		switch (c) {

> > +		case 'K':

> > +			if (pkey_file) {

> > +				printf("Public Key already specified\n");

> > +				return -1;

> > +			}

> > +			pkey_file = optarg;

> > +			break;

> > +		case 'D':

> > +			if (dtb_file) {

> > +				printf("DTB file already specified\n");

> > +				return -1;

> > +			}

> > +			dtb_file = optarg;

> > +			break;

> > +		case 'O':

> > +			overlay = true;

> > +			break;

> > +		case 'h':

> > +			print_usage();

> > +			return 0;

> > +		}

> > +	}

> > +

> > +	/* check necessary parameters */

> > +	if (!pkey_file || !dtb_file) {

> > +		print_usage();

> > +		exit(EXIT_FAILURE);

> > +	}

> > +

> > +	ret = add_public_key(pkey_file, dtb_file, overlay);

> > +	if (ret == -1) {

> > +		printf("Adding public key to the dtb failed\n");

> > +		exit(EXIT_FAILURE);

> > +	}

> > +

> > +	exit(EXIT_SUCCESS);

> > +}

> > 

>
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index 9806464357e0..8b40987234a0 100644
--- a/Makefile
+++ b/Makefile
@@ -1016,7 +1016,7 @@  quiet_cmd_lzma = LZMA    $@
 cmd_lzma = lzma -c -z -k -9 $< > $@
 
 quiet_cmd_fdtsig = FDTSIG  $@
-cmd_fdtsig = $(srctree)/tools/fdtsig.sh $(CONFIG_EFI_PKEY_FILE) $@
+cmd_fdtsig = $(objtree)/tools/fdtsig -K $(CONFIG_EFI_PKEY_FILE) -D $@
 
 cfg: u-boot.cfg
 
diff --git a/tools/Makefile b/tools/Makefile
index 71a52719620c..e6fd1dbade19 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -234,6 +234,8 @@  HOSTCFLAGS_asn1_compiler.o = -idirafter $(srctree)/include
 ifneq ($(CONFIG_EFI_CAPSULE_AUTHENTICATE),)
 HOSTLDLIBS_mkeficapsule += \
 	$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
+	fdtsig-objs	:= fdtsig.o $(LIBFDT_OBJS)
+	hostprogs-y += fdtsig
 endif
 hostprogs-$(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) += mkeficapsule
 
diff --git a/tools/fdtsig.c b/tools/fdtsig.c
new file mode 100644
index 000000000000..daa1e63c3b33
--- /dev/null
+++ b/tools/fdtsig.c
@@ -0,0 +1,274 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2021 Linaro Limited
+ * The code in this file was extracted from mkeficapsule.c
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <linux/libfdt.h>
+
+#define SIGNATURE_NODENAME	"signature"
+#define OVERLAY_NODENAME	"__overlay__"
+
+static const char *tool_name = "fdtsig";
+
+static const char *opts_short = "D:K:Oh";
+
+static struct option options[] = {
+	{"dtb", required_argument, NULL, 'D'},
+	{"public key", required_argument, NULL, 'K'},
+	{"overlay", no_argument, NULL, 'O'},
+	{"help", no_argument, NULL, 'h'},
+	{NULL, 0, NULL, 0},
+};
+
+static void print_usage(void)
+{
+	printf("Usage: %s [options]\n"
+	       "Options:\n"
+
+	       "\t-K, --public-key <key file> public key esl file\n"
+	       "\t-D, --dtb <dtb file>        dtb file\n"
+	       "\t-O, --overlay               the dtb file is an overlay\n"
+	       "\t-h, --help                  print a help message\n",
+	       tool_name);
+}
+
+static int fdt_add_pub_key_data(void *sptr, void *dptr, size_t key_size,
+				bool overlay)
+{
+	int parent;
+	int ov_node;
+	int frag_node;
+	int ret = 0;
+
+	if (overlay) {
+		/*
+		 * The signature would be stored in the
+		 * first fragment node of the overlay
+		 */
+		frag_node = fdt_first_subnode(dptr, 0);
+		if (frag_node == -FDT_ERR_NOTFOUND) {
+			fprintf(stderr,
+				"Couldn't find the fragment node: %s\n",
+				fdt_strerror(frag_node));
+			goto done;
+		}
+
+		ov_node = fdt_subnode_offset(dptr, frag_node, OVERLAY_NODENAME);
+		if (ov_node == -FDT_ERR_NOTFOUND) {
+			fprintf(stderr,
+				"Couldn't find the __overlay__ node: %s\n",
+				fdt_strerror(ov_node));
+			goto done;
+		}
+	} else {
+		ov_node = 0;
+	}
+
+	parent = fdt_subnode_offset(dptr, ov_node, SIGNATURE_NODENAME);
+	if (parent == -FDT_ERR_NOTFOUND) {
+		parent = fdt_add_subnode(dptr, ov_node, SIGNATURE_NODENAME);
+		if (parent < 0) {
+			ret = parent;
+			if (ret != -FDT_ERR_NOSPACE) {
+				fprintf(stderr,
+					"Couldn't create signature node: %s\n",
+					fdt_strerror(parent));
+			}
+		}
+	}
+	if (ret)
+		goto done;
+
+	/* Write the key to the FDT node */
+	ret = fdt_setprop(dptr, parent, "capsule-key",
+			  sptr, key_size);
+
+done:
+	if (ret)
+		ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
+
+	return ret;
+}
+
+static int add_public_key(const char *pkey_file, const char *dtb_file,
+			  bool overlay)
+{
+	int ret;
+	int srcfd = -1;
+	int destfd = -1;
+	void *sptr = NULL;
+	void *dptr = NULL;
+	off_t src_size;
+	struct stat pub_key;
+	struct stat dtb;
+
+	/* Find out the size of the public key */
+	srcfd = open(pkey_file, O_RDONLY);
+	if (srcfd == -1) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			__func__, pkey_file, strerror(errno));
+		ret = -1;
+		goto err;
+	}
+
+	ret = fstat(srcfd, &pub_key);
+	if (ret == -1) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			__func__, pkey_file, strerror(errno));
+		ret = -1;
+		goto err;
+	}
+
+	src_size = pub_key.st_size;
+
+	/* mmap the public key esl file */
+	sptr = mmap(0, src_size, PROT_READ, MAP_SHARED, srcfd, 0);
+	if (sptr == MAP_FAILED) {
+		fprintf(stderr, "%s: Failed to mmap %s:%s\n",
+			__func__, pkey_file, strerror(errno));
+		ret = -1;
+		goto err;
+	}
+
+	/* Open the dest FDT */
+	destfd = open(dtb_file, O_RDWR);
+	if (destfd == -1) {
+		fprintf(stderr, "%s: Can't open %s: %s\n",
+			__func__, dtb_file, strerror(errno));
+		ret = -1;
+		goto err;
+	}
+
+	ret = fstat(destfd, &dtb);
+	if (ret == -1) {
+		fprintf(stderr, "%s: Can't stat %s: %s\n",
+			__func__, dtb_file, strerror(errno));
+		goto err;
+	}
+
+	dtb.st_size += src_size + 0x30;
+	if (ftruncate(destfd, dtb.st_size)) {
+		fprintf(stderr, "%s: Can't expand %s: %s\n",
+			__func__, dtb_file, strerror(errno));
+		ret = -1;
+		goto err;
+	}
+
+	errno = 0;
+	/* mmap the dtb file */
+	dptr = mmap(0, dtb.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
+		    destfd, 0);
+	if (dptr == MAP_FAILED) {
+		fprintf(stderr, "%s: Failed to mmap %s:%s\n",
+			__func__, dtb_file, strerror(errno));
+		ret = -1;
+		goto err;
+	}
+
+	if (fdt_check_header(dptr)) {
+		fprintf(stderr, "%s: Invalid FDT header\n", __func__);
+		ret = -1;
+		goto err;
+	}
+
+	ret = fdt_open_into(dptr, dptr, dtb.st_size);
+	if (ret) {
+		fprintf(stderr, "%s: Cannot expand FDT: %s\n",
+			__func__, fdt_strerror(ret));
+		ret = -1;
+		goto err;
+	}
+
+	/* Copy the esl file to the expanded FDT */
+	ret = fdt_add_pub_key_data(sptr, dptr, src_size, overlay);
+	if (ret < 0) {
+		fprintf(stderr, "%s: Unable to add public key to the FDT\n",
+			__func__);
+		ret = -1;
+		goto err;
+	}
+
+	ret = 0;
+
+err:
+	if (sptr)
+		munmap(sptr, src_size);
+
+	if (dptr)
+		munmap(dptr, dtb.st_size);
+
+	if (srcfd != -1)
+		close(srcfd);
+
+	if (destfd != -1)
+		close(destfd);
+
+	return ret;
+}
+
+int main(int argc, char **argv)
+{
+	char *pkey_file;
+	char *dtb_file;
+	bool overlay;
+	int c, idx, ret;
+
+	pkey_file = NULL;
+	dtb_file = NULL;
+	overlay = false;
+
+	for (;;) {
+		c = getopt_long(argc, argv, opts_short, options, &idx);
+		if (c == -1)
+			break;
+
+		switch (c) {
+		case 'K':
+			if (pkey_file) {
+				printf("Public Key already specified\n");
+				return -1;
+			}
+			pkey_file = optarg;
+			break;
+		case 'D':
+			if (dtb_file) {
+				printf("DTB file already specified\n");
+				return -1;
+			}
+			dtb_file = optarg;
+			break;
+		case 'O':
+			overlay = true;
+			break;
+		case 'h':
+			print_usage();
+			return 0;
+		}
+	}
+
+	/* check necessary parameters */
+	if (!pkey_file || !dtb_file) {
+		print_usage();
+		exit(EXIT_FAILURE);
+	}
+
+	ret = add_public_key(pkey_file, dtb_file, overlay);
+	if (ret == -1) {
+		printf("Adding public key to the dtb failed\n");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}