preload_check_sign is added so that it can be used to authenticate images
signed with the pre-load signature supported by binman and U-Boot.
It could also be used to test the signature in binman tests signing
images with the pre-load.

Signed-off-by: Paul HENRYS <paul.henrys_...@softathome.com>
---
Changes for v2:
- Replace the call to EVP_PKEY_get_bits() by EVP_PKEY_size() supported by older
  openssl versions. It's also make more sense to use EVP_PKEY_size() than
  calculating the size.
  This fixes the tools build on MacOS using OpenSSL 1.1.

 tools/.gitignore           |   1 +
 tools/Kconfig              |   5 ++
 tools/Makefile             |   5 ++
 tools/preload_check_sign.c | 160 +++++++++++++++++++++++++++++++++++++
 4 files changed, 171 insertions(+)
 create mode 100644 tools/preload_check_sign.c

diff --git a/tools/.gitignore b/tools/.gitignore
index 0108c567309..6a5c613f772 100644
--- a/tools/.gitignore
+++ b/tools/.gitignore
@@ -29,6 +29,7 @@
 /mxsboot
 /ncb
 /prelink-riscv
+/preload_check_sign
 /printinitialenv
 /proftool
 /relocate-rela
diff --git a/tools/Kconfig b/tools/Kconfig
index 01ff0fcf748..8e272ee99a8 100644
--- a/tools/Kconfig
+++ b/tools/Kconfig
@@ -9,6 +9,11 @@ config MKIMAGE_DTC_PATH
          some cases the system dtc may not support all required features
          and the path to a different version should be given here.
 
+config TOOLS_IMAGE_PRE_LOAD
+       def_bool y
+       help
+         Enable pre-load signature support in the tools builds.
+
 config TOOLS_CRC16
        def_bool y
        help
diff --git a/tools/Makefile b/tools/Makefile
index 237fa900a24..e5f5eea47c7 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -66,6 +66,7 @@ mkenvimage-objs := mkenvimage.o os_support.o 
generated/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_TOOLS_LIBCRYPTO) += preload_check_sign
 
 ifneq ($(CONFIG_CMD_BOOTEFI_SELFTEST)$(CONFIG_FWU_MDATA_GPT_BLK),)
 hostprogs-y += file2include
@@ -89,6 +90,8 @@ ECDSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix 
generated/lib/ecdsa/, ecdsa-
 AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix generated/lib/aes/, \
                                        aes-encrypt.o aes-decrypt.o)
 
+PRELOAD_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := generated/boot/image-pre-load.o
+
 # Cryptographic helpers and image types that depend on openssl/libcrypto
 LIBCRYPTO_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := \
                        generated/lib/fdt-libcrypto.o \
@@ -158,6 +161,7 @@ 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
+preload_check_sign-objs := $(dumpimage-mkimage-objs) $(PRELOAD_OBJS-y) 
preload_check_sign.o
 
 ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_TOOLS_LIBCRYPTO),)
 # Add CFG_MXS into host CFLAGS, so we can check whether or not register
@@ -195,6 +199,7 @@ HOSTLDLIBS_dumpimage := $(HOSTLDLIBS_mkimage)
 HOSTLDLIBS_fit_info := $(HOSTLDLIBS_mkimage)
 HOSTLDLIBS_fit_check_sign := $(HOSTLDLIBS_mkimage)
 HOSTLDLIBS_fdt_add_pubkey := $(HOSTLDLIBS_mkimage)
+HOSTLDLIBS_preload_check_sign := $(HOSTLDLIBS_mkimage)
 
 hostprogs-$(CONFIG_EXYNOS5250) += mkexynosspl
 hostprogs-$(CONFIG_EXYNOS5420) += mkexynosspl
diff --git a/tools/preload_check_sign.c b/tools/preload_check_sign.c
new file mode 100644
index 00000000000..ebead459273
--- /dev/null
+++ b/tools/preload_check_sign.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Check a file including a preload header including a signature
+ *
+ * Copyright (c) 2025 Paul HENRYS <paul.henrys_...@softathome.com>
+ *
+ * Binman makes it possible to generate a preload header signing part or the
+ * complete file. The tool preload_check_sign allows to verify and authenticate
+ * a file starting with a preload header.
+ */
+#include <stdio.h>
+#include <unistd.h>
+#include <openssl/pem.h>
+#include <openssl/evp.h>
+#include <openssl/err.h>
+#include <image.h>
+
+extern void image_pre_load_sig_set_info(struct image_sig_info *info);
+extern int image_pre_load_sig(ulong addr);
+
+static void usage(char *cmdname)
+{
+       fprintf(stderr, "Usage: %s -f file -k PEM key file\n"
+                       "          -f ==> set file which should be checked\n"
+                       "          -k ==> PEM key file\n"
+                       "          -a ==> algo (default: sha256,rsa2048)\n"
+                       "          -p ==> padding (default: pkcs-1.5)\n"
+                       "          -h ==> help\n",
+               cmdname);
+       exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+       int ret = 0;
+       char cmdname[256];
+       char *file = NULL;
+       char *keyfile = NULL;
+       int c;
+       FILE *fp = NULL;
+       FILE *fp_key = NULL;
+       size_t bytes;
+       long filesize;
+       void *buffer = NULL;
+       EVP_PKEY *pkey = NULL;
+       char *algo = "sha256,rsa2048";
+       char *padding = "pkcs-1.5";
+       struct image_sig_info info = {0};
+
+       strncpy(cmdname, *argv, sizeof(cmdname) - 1);
+       cmdname[sizeof(cmdname) - 1] = '\0';
+       while ((c = getopt(argc, argv, "f:k:a:p:h")) != -1)
+               switch (c) {
+               case 'f':
+                       file = optarg;
+                       break;
+               case 'k':
+                       keyfile = optarg;
+                       break;
+               case 'a':
+                       algo = optarg;
+                       break;
+               case 'p':
+                       padding = optarg;
+                       break;
+               default:
+                       usage(cmdname);
+                       break;
+       }
+
+       if (!file) {
+               fprintf(stderr, "%s: Missing file\n", *argv);
+               usage(*argv);
+       }
+
+       if (!keyfile) {
+               fprintf(stderr, "%s: Missing key file\n", *argv);
+               usage(*argv);
+       }
+
+       fp = fopen(file, "r");
+       if (!fp) {
+               fprintf(stderr, "Error opening file: %s\n", file);
+               ret = EXIT_FAILURE;
+               goto out;
+       }
+
+       fseek(fp, 0, SEEK_END);
+       filesize = ftell(fp);
+       rewind(fp);
+
+       buffer = malloc(filesize);
+       if (!buffer) {
+               fprintf(stderr, "Memory allocation failed");
+               ret = EXIT_FAILURE;
+               goto out;
+       }
+
+       bytes = fread(buffer, 1, filesize, fp);
+       if (bytes != filesize) {
+               fprintf(stderr, "Error reading file\n");
+               ret = EXIT_FAILURE;
+               goto out;
+       }
+
+       fp_key = fopen(keyfile, "r");
+       if (!fp_key) {
+               fprintf(stderr, "Error opening file: %s\n", keyfile);
+               ret = EXIT_FAILURE;
+               goto out;
+       }
+
+       /* Attempt to read the private key */
+       pkey = PEM_read_PrivateKey(fp_key, NULL, NULL, NULL);
+       if (!pkey) {
+               /* If private key reading fails, try reading as a public key */
+               fseek(fp_key, 0, SEEK_SET);
+               pkey = PEM_read_PUBKEY(fp_key, NULL, NULL, NULL);
+       }
+       if (!pkey) {
+               fprintf(stderr, "Unable to retrieve the public key: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               ret = EXIT_FAILURE;
+               goto out;
+       }
+
+       info.algo_name = algo;
+       info.padding_name = padding;
+       info.key = (uint8_t *)pkey;
+       info.mandatory = 1;
+       info.sig_size = EVP_PKEY_size(pkey);
+       if (info.sig_size < 0) {
+               fprintf(stderr, "Fail to retrieve the signature size: %s\n",
+                       ERR_error_string(ERR_get_error(), NULL));
+               ret = EXIT_FAILURE;
+               goto out;
+       }
+
+       /* Compute signature information */
+       info.sig_info.name     = info.algo_name;
+       info.sig_info.padding  = image_get_padding_algo(info.padding_name);
+       info.sig_info.checksum = image_get_checksum_algo(info.sig_info.name);
+       info.sig_info.crypto   = image_get_crypto_algo(info.sig_info.name);
+       info.sig_info.key      = info.key;
+       info.sig_info.keylen   = info.key_len;
+
+       /* Check the signature */
+       image_pre_load_sig_set_info(&info);
+       ret = image_pre_load_sig((ulong)buffer);
+out:
+       if (fp)
+               fclose(fp);
+       if (fp_key)
+               fclose(fp_key);
+       if (info.key)
+               EVP_PKEY_free(pkey);
+       free(buffer);
+
+       exit(ret);
+}
-- 
2.43.0

Reply via email to