summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2021-04-15 17:10:25 -0400
committerTom Rini <trini@konsulko.com>2021-04-15 17:10:25 -0400
commita6232e065dd9e349bf5908c928734c6b5b018112 (patch)
tree49a54d23fc32194ce266f06cb8fae3eff4574339
parent45b3cf88da24206a6cb847efe837fddc120af3e8 (diff)
parentfbc777429fa35312a9ea5f106692172d3153e659 (diff)
downloadu-boot-WIP/15Apr2021.tar.gz
Merge branch '2021-04-14-assorted-vboot-improvements'WIP/15Apr2021
- Add ECDSA support to FIT images - Improve FIT image loadables (incl fpga) support - Further FIT improvements with SPL
-rw-r--r--arch/arm/cpu/armv8/fsl-layerscape/spl.c9
-rw-r--r--arch/arm/mach-rockchip/spl.c10
-rw-r--r--common/Kconfig.boot10
-rw-r--r--common/common_fit.c5
-rw-r--r--common/image-fit-sig.c2
-rw-r--r--common/image-fit.c4
-rw-r--r--common/image-sig.c13
-rw-r--r--common/spl/spl.c40
-rw-r--r--common/spl/spl_fit.c113
-rw-r--r--doc/uImage.FIT/multi-with-fpga.its3
-rw-r--r--doc/uImage.FIT/signature.txt20
-rw-r--r--doc/uImage.FIT/source_file_format.txt1
-rw-r--r--include/image.h21
-rw-r--r--include/u-boot/ecdsa.h94
-rw-r--r--include/u-boot/fdt-libcrypto.h27
-rw-r--r--include/u-boot/hash-checksum.h (renamed from include/u-boot/rsa-checksum.h)0
-rw-r--r--lib/Makefile1
-rw-r--r--lib/crypto/pkcs7_verify.c2
-rw-r--r--lib/crypto/x509_public_key.c2
-rw-r--r--lib/ecdsa/ecdsa-libcrypto.c318
-rw-r--r--lib/fdt-libcrypto.c72
-rw-r--r--lib/hash-checksum.c (renamed from lib/rsa/rsa-checksum.c)3
-rw-r--r--lib/rsa/Makefile2
-rw-r--r--lib/rsa/rsa-sign.c258
-rw-r--r--test/py/requirements.txt1
-rw-r--r--test/py/tests/test_fit_ecdsa.py111
-rw-r--r--tools/Makefile11
-rw-r--r--tools/fit_image.c3
-rw-r--r--tools/image-host.c58
-rw-r--r--tools/imagetool.h1
-rw-r--r--tools/mkimage.c6
31 files changed, 955 insertions, 266 deletions
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/spl.c b/arch/arm/cpu/armv8/fsl-layerscape/spl.c
index 01dd6a30e8..5b43a2a231 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/spl.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/spl.c
@@ -150,13 +150,4 @@ int spl_start_uboot(void)
return 1;
}
#endif /* CONFIG_SPL_OS_BOOT */
-#ifdef CONFIG_SPL_LOAD_FIT
-__weak int board_fit_config_name_match(const char *name)
-{
- /* Just empty function now - can't decide what to choose */
- debug("%s: %s\n", __func__, name);
-
- return 0;
-}
-#endif
#endif /* CONFIG_SPL_BUILD */
diff --git a/arch/arm/mach-rockchip/spl.c b/arch/arm/mach-rockchip/spl.c
index 4b5c22dc13..02c40fb37e 100644
--- a/arch/arm/mach-rockchip/spl.c
+++ b/arch/arm/mach-rockchip/spl.c
@@ -151,13 +151,3 @@ void board_init_f(ulong dummy)
#endif
preloader_console_init();
}
-
-#ifdef CONFIG_SPL_LOAD_FIT
-int __weak board_fit_config_name_match(const char *name)
-{
- /* Just empty function now - can't decide what to choose */
- debug("%s: %s\n", __func__, name);
-
- return 0;
-}
-#endif
diff --git a/common/Kconfig.boot b/common/Kconfig.boot
index 9c335f4f8c..5a18d62d78 100644
--- a/common/Kconfig.boot
+++ b/common/Kconfig.boot
@@ -202,6 +202,16 @@ config SPL_LOAD_FIT
particular it can handle selecting from multiple device tree
and passing the correct one to U-Boot.
+ This path has the following limitations:
+
+ 1. "loadables" images, other than FTDs, which do not have a "load"
+ property will not be loaded. This limitation also applies to FPGA
+ images with the correct "compatible" string.
+ 2. For FPGA images, only the "compatible" = "u-boot,fpga-legacy"
+ loading method is supported.
+ 3. FDTs are only loaded for images with an "os" property of "u-boot".
+ "linux" images are also supported with Falcon boot mode.
+
config SPL_LOAD_FIT_ADDRESS
hex "load address of fit image"
depends on SPL_LOAD_FIT
diff --git a/common/common_fit.c b/common/common_fit.c
index 219674d467..cde2dc45e9 100644
--- a/common/common_fit.c
+++ b/common/common_fit.c
@@ -22,6 +22,11 @@ ulong fdt_getprop_u32(const void *fdt, int node, const char *prop)
return fdt32_to_cpu(*cell);
}
+__weak int board_fit_config_name_match(const char *name)
+{
+ return -EINVAL;
+}
+
/*
* Iterate over all /configurations subnodes and call a platform specific
* function to find the matching configuration.
diff --git a/common/image-fit-sig.c b/common/image-fit-sig.c
index 34ebb8edfe..55ddf1879e 100644
--- a/common/image-fit-sig.c
+++ b/common/image-fit-sig.c
@@ -16,7 +16,7 @@ DECLARE_GLOBAL_DATA_PTR;
#include <fdt_region.h>
#include <image.h>
#include <u-boot/rsa.h>
-#include <u-boot/rsa-checksum.h>
+#include <u-boot/hash-checksum.h>
#define IMAGE_MAX_HASHED_NODES 100
diff --git a/common/image-fit.c b/common/image-fit.c
index b972042f43..e614643fe3 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -1959,6 +1959,8 @@ static const char *fit_get_image_type_property(int type)
return FIT_FDT_PROP;
case IH_TYPE_KERNEL:
return FIT_KERNEL_PROP;
+ case IH_TYPE_FIRMWARE:
+ return FIT_FIRMWARE_PROP;
case IH_TYPE_RAMDISK:
return FIT_RAMDISK_PROP;
case IH_TYPE_X86_SETUP:
@@ -2091,6 +2093,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_CHECK_ALL);
type_ok = fit_image_check_type(fit, noffset, image_type) ||
fit_image_check_type(fit, noffset, IH_TYPE_FIRMWARE) ||
+ fit_image_check_type(fit, noffset, IH_TYPE_TEE) ||
(image_type == IH_TYPE_KERNEL &&
fit_image_check_type(fit, noffset, IH_TYPE_KERNEL_NOLOAD));
@@ -2098,6 +2101,7 @@ int fit_image_load(bootm_headers_t *images, ulong addr,
image_type == IH_TYPE_FPGA ||
fit_image_check_os(fit, noffset, IH_OS_LINUX) ||
fit_image_check_os(fit, noffset, IH_OS_U_BOOT) ||
+ fit_image_check_os(fit, noffset, IH_OS_TEE) ||
fit_image_check_os(fit, noffset, IH_OS_OPENRTOS) ||
fit_image_check_os(fit, noffset, IH_OS_EFI) ||
fit_image_check_os(fit, noffset, IH_OS_VXWORKS);
diff --git a/common/image-sig.c b/common/image-sig.c
index 4abd3c080f..0f8e592aba 100644
--- a/common/image-sig.c
+++ b/common/image-sig.c
@@ -16,8 +16,9 @@
DECLARE_GLOBAL_DATA_PTR;
#endif /* !USE_HOSTCC*/
#include <image.h>
+#include <u-boot/ecdsa.h>
#include <u-boot/rsa.h>
-#include <u-boot/rsa-checksum.h>
+#include <u-boot/hash-checksum.h>
#define IMAGE_MAX_HASHED_NODES 100
@@ -83,8 +84,14 @@ struct crypto_algo crypto_algos[] = {
.sign = rsa_sign,
.add_verify_data = rsa_add_verify_data,
.verify = rsa_verify,
- }
-
+ },
+ {
+ .name = "ecdsa256",
+ .key_len = ECDSA256_BYTES,
+ .sign = ecdsa_sign,
+ .add_verify_data = ecdsa_add_verify_data,
+ .verify = ecdsa_verify,
+ },
};
struct padding_algo padding_algos[] = {
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 556a91ab53..8c4cd933cf 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -202,7 +202,7 @@ static int spl_load_fit_image(struct spl_image_info *spl_image,
{
bootm_headers_t images;
const char *fit_uname_config = NULL;
- const char *fit_uname_fdt = FIT_FDT_PROP;
+ uintptr_t fdt_hack;
const char *uname;
ulong fw_data = 0, dt_data = 0, img_data = 0;
ulong fw_len = 0, dt_len = 0, img_len = 0;
@@ -215,15 +215,33 @@ static int spl_load_fit_image(struct spl_image_info *spl_image,
ret = fit_image_load(&images, (ulong)header,
NULL, &fit_uname_config,
IH_ARCH_DEFAULT, IH_TYPE_STANDALONE, -1,
- FIT_LOAD_REQUIRED, &fw_data, &fw_len);
+ FIT_LOAD_OPTIONAL, &fw_data, &fw_len);
+ if (ret >= 0) {
+ printf("DEPRECATED: 'standalone = ' property.");
+ printf("Please use either 'firmware =' or 'kernel ='\n");
+ } else {
+ ret = fit_image_load(&images, (ulong)header, NULL,
+ &fit_uname_config, IH_ARCH_DEFAULT,
+ IH_TYPE_FIRMWARE, -1, FIT_LOAD_OPTIONAL,
+ &fw_data, &fw_len);
+ }
+
+ if (ret < 0) {
+ ret = fit_image_load(&images, (ulong)header, NULL,
+ &fit_uname_config, IH_ARCH_DEFAULT,
+ IH_TYPE_KERNEL, -1, FIT_LOAD_OPTIONAL,
+ &fw_data, &fw_len);
+ }
+
if (ret < 0)
return ret;
spl_image->size = fw_len;
spl_image->entry_point = fw_data;
spl_image->load_addr = fw_data;
- spl_image->os = IH_OS_U_BOOT;
- spl_image->name = "U-Boot";
+ if (fit_image_get_os(header, ret, &spl_image->os))
+ spl_image->os = IH_OS_INVALID;
+ spl_image->name = genimg_get_os_name(spl_image->os);
debug(SPL_TPL_PROMPT "payload image: %32s load addr: 0x%lx size: %d\n",
spl_image->name, spl_image->load_addr, spl_image->size);
@@ -231,13 +249,21 @@ static int spl_load_fit_image(struct spl_image_info *spl_image,
#ifdef CONFIG_SPL_FIT_SIGNATURE
images.verify = 1;
#endif
- ret = fit_image_load(&images, (ulong)header,
- &fit_uname_fdt, &fit_uname_config,
+ ret = fit_image_load(&images, (ulong)header, NULL, &fit_uname_config,
IH_ARCH_DEFAULT, IH_TYPE_FLATDT, -1,
FIT_LOAD_OPTIONAL, &dt_data, &dt_len);
- if (ret >= 0)
+ if (ret >= 0) {
spl_image->fdt_addr = (void *)dt_data;
+ if (spl_image->os == IH_OS_U_BOOT) {
+ /* HACK: U-boot expects FDT at a specific address */
+ fdt_hack = spl_image->load_addr + spl_image->size;
+ fdt_hack = (fdt_hack + 3) & ~3;
+ debug("Relocating FDT to %p\n", spl_image->fdt_addr);
+ memcpy((void *)fdt_hack, spl_image->fdt_addr, dt_len);
+ }
+ }
+
conf_noffset = fit_conf_get_node((const void *)header,
fit_uname_config);
if (conf_noffset <= 0)
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 49508fc518..4288f571fc 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -224,7 +224,7 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size,
* @image_info: will be filled with information about the loaded image
* If the FIT node does not contain a "load" (address) property,
* the image gets loaded to the address pointed to by the
- * load_addr member in this struct.
+ * load_addr member in this struct, if load_addr is not 0
*
* Return: 0 on success or a negative error number.
*/
@@ -259,8 +259,14 @@ static int spl_load_fit_image(struct spl_load_info *info, ulong sector,
debug("%s ", genimg_get_comp_name(image_comp));
}
- if (fit_image_get_load(fit, node, &load_addr))
+ if (fit_image_get_load(fit, node, &load_addr)) {
+ if (!image_info->load_addr) {
+ printf("Can't load %s: No load address and no buffer\n",
+ fit_get_name(fit, node, NULL));
+ return -ENOBUFS;
+ }
load_addr = image_info->load_addr;
+ }
if (!fit_image_get_data_position(fit, node, &offset)) {
external_data = true;
@@ -474,6 +480,20 @@ static int spl_fit_record_loadable(const struct spl_fit_info *ctx, int index,
return ret;
}
+static int spl_fit_image_is_fpga(const void *fit, int node)
+{
+ const char *type;
+
+ if (!IS_ENABLED(CONFIG_SPL_FPGA))
+ return 0;
+
+ type = fdt_getprop(fit, node, FIT_TYPE_PROP, NULL);
+ if (!type)
+ return 0;
+
+ return !strcmp(type, "fpga");
+}
+
static int spl_fit_image_get_os(const void *fit, int noffset, uint8_t *os)
{
if (!CONFIG_IS_ENABLED(FIT_IMAGE_TINY) || CONFIG_IS_ENABLED(OS_BOOT))
@@ -523,6 +543,64 @@ __weak bool spl_load_simple_fit_skip_processing(void)
return false;
}
+static void warn_deprecated(const char *msg)
+{
+ printf("DEPRECATED: %s\n", msg);
+ printf("\tSee doc/uImage.FIT/source_file_format.txt\n");
+}
+
+static int spl_fit_upload_fpga(struct spl_fit_info *ctx, int node,
+ struct spl_image_info *fpga_image)
+{
+ const char *compatible;
+ int ret;
+
+ debug("FPGA bitstream at: %x, size: %x\n",
+ (u32)fpga_image->load_addr, fpga_image->size);
+
+ compatible = fdt_getprop(ctx->fit, node, "compatible", NULL);
+ if (!compatible)
+ warn_deprecated("'fpga' image without 'compatible' property");
+ else if (strcmp(compatible, "u-boot,fpga-legacy"))
+ printf("Ignoring compatible = %s property\n", compatible);
+
+ ret = fpga_load(0, (void *)fpga_image->load_addr, fpga_image->size,
+ BIT_FULL);
+ if (ret) {
+ printf("%s: Cannot load the image to the FPGA\n", __func__);
+ return ret;
+ }
+
+ puts("FPGA image loaded from FIT\n");
+
+ return 0;
+}
+
+static int spl_fit_load_fpga(struct spl_fit_info *ctx,
+ struct spl_load_info *info, ulong sector)
+{
+ int node, ret;
+
+ struct spl_image_info fpga_image = {
+ .load_addr = 0,
+ };
+
+ node = spl_fit_get_image_node(ctx, "fpga", 0);
+ if (node < 0)
+ return node;
+
+ warn_deprecated("'fpga' property in config node. Use 'loadables'");
+
+ /* Load the image and set up the fpga_image structure */
+ ret = spl_load_fit_image(info, sector, ctx, node, &fpga_image);
+ if (ret) {
+ printf("%s: Cannot load the FPGA: %i\n", __func__, ret);
+ return ret;
+ }
+
+ return spl_fit_upload_fpga(ctx, node, &fpga_image);
+}
+
static int spl_simple_fit_read(struct spl_fit_info *ctx,
struct spl_load_info *info, ulong sector,
const void *fit_header)
@@ -606,31 +684,8 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
if (ret < 0)
return ret;
-#ifdef CONFIG_SPL_FPGA
- node = spl_fit_get_image_node(&ctx, "fpga", 0);
- if (node >= 0) {
- /* Load the image and set up the spl_image structure */
- ret = spl_load_fit_image(info, sector, &ctx, node, spl_image);
- if (ret) {
- printf("%s: Cannot load the FPGA: %i\n", __func__, ret);
- return ret;
- }
-
- debug("FPGA bitstream at: %x, size: %x\n",
- (u32)spl_image->load_addr, spl_image->size);
-
- ret = fpga_load(0, (const void *)spl_image->load_addr,
- spl_image->size, BIT_FULL);
- if (ret) {
- printf("%s: Cannot load the image to the FPGA\n",
- __func__);
- return ret;
- }
-
- puts("FPGA image loaded from FIT\n");
- node = -1;
- }
-#endif
+ if (IS_ENABLED(CONFIG_SPL_FPGA))
+ spl_fit_load_fpga(&ctx, info, sector);
/*
* Find the U-Boot image using the following search order:
@@ -700,6 +755,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
if (firmware_node == node)
continue;
+ image_info.load_addr = 0;
ret = spl_load_fit_image(info, sector, &ctx, node, &image_info);
if (ret < 0) {
printf("%s: can't load image loadables index %d (ret = %d)\n",
@@ -707,6 +763,9 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
return ret;
}
+ if (spl_fit_image_is_fpga(ctx.fit, node))
+ spl_fit_upload_fpga(&ctx, node, &image_info);
+
if (!spl_fit_image_get_os(ctx.fit, node, &os_type))
debug("Loadable is %s\n", genimg_get_os_name(os_type));
diff --git a/doc/uImage.FIT/multi-with-fpga.its b/doc/uImage.FIT/multi-with-fpga.its
index 47ee5760c4..021cbc7cf4 100644
--- a/doc/uImage.FIT/multi-with-fpga.its
+++ b/doc/uImage.FIT/multi-with-fpga.its
@@ -29,6 +29,7 @@
arch = "arm";
compression = "none";
load = <0x30000000>;
+ compatible = "u-boot,fpga-legacy"
hash-1 {
algo = "md5";
};
@@ -61,7 +62,7 @@
description = "Linux with fpga";
kernel = "linux_kernel";
fdt = "fdt-1";
- fpga = "fpga";
+ loadables = "fpga";
};
};
};
diff --git a/doc/uImage.FIT/signature.txt b/doc/uImage.FIT/signature.txt
index a3455889ed..d9a9121190 100644
--- a/doc/uImage.FIT/signature.txt
+++ b/doc/uImage.FIT/signature.txt
@@ -142,7 +142,7 @@ public key in U-Boot's control FDT (using CONFIG_OF_CONTROL).
Public keys should be stored as sub-nodes in a /signature node. Required
properties are:
-- algo: Algorithm name (e.g. "sha1,rsa2048")
+- algo: Algorithm name (e.g. "sha1,rsa2048" or "sha256,ecdsa256")
Optional properties are:
@@ -167,6 +167,11 @@ For RSA the following are mandatory:
- rsa,r-squared: (2^num-bits)^2 as a big-endian multi-word integer
- rsa,n0-inverse: -1 / modulus[0] mod 2^32
+For ECDSA the following are mandatory:
+- ecdsa,curve: Name of ECDSA curve (e.g. "prime256v1")
+- ecdsa,x-point: Public key X coordinate as a big-endian multi-word integer
+- ecdsa,y-point: Public key Y coordinate as a big-endian multi-word integer
+
These parameters can be added to a binary device tree using parameter -K of the
mkimage command::
@@ -467,6 +472,19 @@ Test Verified Boot Run: signed config with bad hash: OK
Test passed
+Software signing: keydir vs keyfile
+-----------------------------------
+
+In the simplest case, signing is done by giving mkimage the 'keyfile'. This is
+the path to a file containing the signing key.
+
+The alternative is to pass the 'keydir' argument. In this case the filename of
+the key is derived from the 'keydir' and the "key-name-hint" property in the
+FIT. In this case the "key-name-hint" property is mandatory, and the key must
+exist in "<keydir>/<key-name-hint>.<ext>" Here the extension "ext" is
+specific to the signing algorithm.
+
+
Hardware Signing with PKCS#11 or with HSM
-----------------------------------------
diff --git a/doc/uImage.FIT/source_file_format.txt b/doc/uImage.FIT/source_file_format.txt
index 00ed3ebe93..f93ac6d1c7 100644
--- a/doc/uImage.FIT/source_file_format.txt
+++ b/doc/uImage.FIT/source_file_format.txt
@@ -184,6 +184,7 @@ the '/images' node should have the following layout:
Mandatory for types: "firmware", and "kernel".
- compatible : compatible method for loading image.
Mandatory for types: "fpga", and images that do not specify a load address.
+ To use the generic fpga loading routine, use "u-boot,fpga-legacy".
Optional nodes:
- hash-1 : Each hash sub-node represents separate hash or checksum
diff --git a/include/image.h b/include/image.h
index aeb0d37ac0..3ff3c035a7 100644
--- a/include/image.h
+++ b/include/image.h
@@ -1136,9 +1136,10 @@ int fit_cipher_data(const char *keydir, void *keydest, void *fit,
* 0, on success
* libfdt error code, on failure
*/
-int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
- const char *comment, int require_keys,
- const char *engine_id, const char *cmdname);
+int fit_add_verification_data(const char *keydir, const char *keyfile,
+ void *keydest, void *fit, const char *comment,
+ int require_keys, const char *engine_id,
+ const char *cmdname);
int fit_image_verify_with_data(const void *fit, int image_noffset,
const void *data, size_t size);
@@ -1224,16 +1225,19 @@ int calculate_hash(const void *data, int data_len, const char *algo,
# if defined(CONFIG_FIT_SIGNATURE)
# define IMAGE_ENABLE_SIGN 1
# define IMAGE_ENABLE_VERIFY 1
+# define IMAGE_ENABLE_VERIFY_ECDSA 1
# define FIT_IMAGE_ENABLE_VERIFY 1
# include <openssl/evp.h>
# else
# define IMAGE_ENABLE_SIGN 0
# define IMAGE_ENABLE_VERIFY 0
+# define IMAGE_ENABLE_VERIFY_ECDSA 0
# define FIT_IMAGE_ENABLE_VERIFY 0
# endif
#else
# define IMAGE_ENABLE_SIGN 0
# define IMAGE_ENABLE_VERIFY CONFIG_IS_ENABLED(RSA_VERIFY)
+# define IMAGE_ENABLE_VERIFY_ECDSA 0
# define FIT_IMAGE_ENABLE_VERIFY CONFIG_IS_ENABLED(FIT_SIGNATURE)
#endif
@@ -1253,10 +1257,17 @@ void image_set_host_blob(void *host_blob);
#endif
#endif /* IMAGE_ENABLE_FIT */
-/* Information passed to the signing routines */
+/*
+ * Information passed to the signing routines
+ *
+ * Either 'keydir', 'keyname', or 'keyfile' can be NULL. However, either
+ * 'keyfile', or both 'keydir' and 'keyname' should have valid values. If
+ * neither are valid, some operations might fail with EINVAL.
+ */
struct image_sign_info {
const char *keydir; /* Directory conaining keys */
const char *keyname; /* Name of key to use */
+ const char *keyfile; /* Filename of private or public key */
void *fit; /* Pointer to FIT blob */
int node_offset; /* Offset of signature node */
const char *name; /* Algorithm name */
@@ -1283,7 +1294,7 @@ struct image_region {
};
#if IMAGE_ENABLE_VERIFY
-# include <u-boot/rsa-checksum.h>
+# include <u-boot/hash-checksum.h>
#endif
struct checksum_algo {
const char *name;
diff --git a/include/u-boot/ecdsa.h b/include/u-boot/ecdsa.h
new file mode 100644
index 0000000000..979690d966
--- /dev/null
+++ b/include/u-boot/ecdsa.h
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2020, Alexandru Gagniuc <mr.nuke.me@gmail.com>.
+ */
+
+#ifndef _ECDSA_H
+#define _ECDSA_H
+
+#include <errno.h>
+#include <image.h>
+#include <linux/kconfig.h>
+
+/**
+ * crypto_algo API impementation for ECDSA;
+ * @see "struct crypto_algo"
+ * @{
+ */
+#if IMAGE_ENABLE_SIGN
+/**
+ * sign() - calculate and return signature for given input data
+ *
+ * @info: Specifies key and FIT information
+ * @data: Pointer to the input data
+ * @data_len: Data length
+ * @sigp: Set to an allocated buffer holding the signature
+ * @sig_len: Set to length of the calculated hash
+ *
+ * This computes input data signature according to selected algorithm.
+ * Resulting signature value is placed in an allocated buffer, the
+ * pointer is returned as *sigp. The length of the calculated
+ * signature is returned via the sig_len pointer argument. The caller
+ * should free *sigp.
+ *
+ * @return: 0, on success, -ve on error
+ */
+int ecdsa_sign(struct image_sign_info *info, const struct image_region region[],
+ int region_count, uint8_t **sigp, uint *sig_len);
+
+/**
+ * add_verify_data() - Add verification information to FDT
+ *
+ * Add public key information to the FDT node, suitable for
+ * verification at run-time. The information added depends on the
+ * algorithm being used. I just copypasted this from rsa.h.
+ *
+ * @info: Specifies key and FIT information
+ * @keydest: Destination FDT blob for public key data
+ * @return: 0, on success, -ENOSPC if the keydest FDT blob ran out of space,
+ * other -ve value on error
+ */
+int ecdsa_add_verify_data(struct image_sign_info *info, void *keydest);
+#else
+static inline
+int ecdsa_sign(struct image_sign_info *info, const struct image_region region[],
+ int region_count, uint8_t **sigp, uint *sig_len)
+{
+ return -ENXIO;
+}
+
+static inline
+int ecdsa_add_verify_data(struct image_sign_info *info, void *keydest)
+{
+ return -ENXIO;
+}
+#endif
+
+#if IMAGE_ENABLE_VERIFY_ECDSA
+/**
+ * verify() - Verify a signature against some data
+ *
+ * @info: Specifies key and FIT information
+ * @data: Pointer to the input data
+ * @data_len: Data length
+ * @sig: Signature
+ * @sig_len: Number of bytes in signature
+ * @return 0 if verified, -ve on error
+ */
+int ecdsa_verify(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t *sig, uint sig_len);
+#else
+static inline
+int ecdsa_verify(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t *sig, uint sig_len)
+{
+ return -ENXIO;
+}
+#endif
+/** @} */
+
+#define ECDSA256_BYTES (256 / 8)
+
+#endif
diff --git a/include/u-boot/fdt-libcrypto.h b/include/u-boot/fdt-libcrypto.h
new file mode 100644
index 0000000000..5142f37039
--- /dev/null
+++ b/include/u-boot/fdt-libcrypto.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (c) 2020, Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Copyright (c) 2013, Google Inc.
+ */
+
+#ifndef _FDT_LIBCRYPTO_H
+#define _FDT_LIBCRYPTO_H
+
+#include <openssl/bn.h>
+
+/**
+ * fdt_add_bignum() - Write a libcrypto BIGNUM as an FDT property
+ *
+ * Convert a libcrypto BIGNUM * into a big endian array of integers.
+ *
+ * @blob: FDT blob to modify
+ * @noffset: Offset of the FDT node
+ * @prop_name: What to call the property in the FDT
+ * @num: pointer to a libcrypto big number
+ * @num_bits: How big is 'num' in bits?
+ * @return 0 if all good all working, -ve on horror
+ */
+int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
+ BIGNUM *num, int num_bits);
+
+#endif /* _FDT_LIBCRYPTO_H */
diff --git a/include/u-boot/rsa-checksum.h b/include/u-boot/hash-checksum.h
index 54e6a73744..54e6a73744 100644
--- a/include/u-boot/rsa-checksum.h
+++ b/include/u-boot/hash-checksum.h
diff --git a/lib/Makefile b/lib/Makefile
index c42d4e1233..6825671955 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -61,6 +61,7 @@ endif
obj-$(CONFIG_$(SPL_)ACPIGEN) += acpi/
obj-$(CONFIG_$(SPL_)MD5) += md5.o
obj-$(CONFIG_$(SPL_)RSA) += rsa/
+obj-$(CONFIG_FIT_SIGNATURE) += hash-checksum.o
obj-$(CONFIG_SHA1) += sha1.o
obj-$(CONFIG_SHA256) += sha256.o
obj-$(CONFIG_SHA512_ALGO) += sha512.o
diff --git a/lib/crypto/pkcs7_verify.c b/lib/crypto/pkcs7_verify.c
index 58683ef614..82c5c745d4 100644
--- a/lib/crypto/pkcs7_verify.c
+++ b/lib/crypto/pkcs7_verify.c
@@ -15,7 +15,7 @@
#include <linux/bitops.h>
#include <linux/compat.h>
#include <linux/asn1.h>
-#include <u-boot/rsa-checksum.h>
+#include <u-boot/hash-checksum.h>
#include <crypto/public_key.h>
#include <crypto/pkcs7_parser.h>
#else
diff --git a/lib/crypto/x509_public_key.c b/lib/crypto/x509_public_key.c
index 91810a8640..d557ab27ae 100644
--- a/lib/crypto/x509_public_key.c
+++ b/lib/crypto/x509_public_key.c
@@ -19,7 +19,7 @@
#include <linux/kernel.h>
#ifdef __UBOOT__
#include <crypto/x509_parser.h>
-#include <u-boot/rsa-checksum.h>
+#include <u-boot/hash-checksum.h>
#else
#include <linux/slab.h>
#include <keys/asymmetric-subtype.h>
diff --git a/lib/ecdsa/ecdsa-libcrypto.c b/lib/ecdsa/ecdsa-libcrypto.c
new file mode 100644
index 0000000000..1757a14562
--- /dev/null
+++ b/lib/ecdsa/ecdsa-libcrypto.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * ECDSA image signing implementation using libcrypto backend
+ *
+ * The signature is a binary representation of the (R, S) points, padded to the
+ * key size. The signature will be (2 * key_size_bits) / 8 bytes.
+ *
+ * Deviations from behavior of RSA equivalent:
+ * - Verification uses private key. This is not technically required, but a
+ * limitation on how clumsy the openssl API is to use.
+ * - Handling of keys and key paths:
+ * - The '-K' key directory option must contain path to the key file,
+ * instead of the key directory.
+ * - No assumptions are made about the file extension of the key
+ * - The 'key-name-hint' property is only used for naming devicetree nodes,
+ * but is not used for looking up keys on the filesystem.
+ *
+ * Copyright (c) 2020,2021, Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ */
+
+#include <u-boot/ecdsa.h>
+#include <u-boot/fdt-libcrypto.h>
+#include <openssl/ssl.h>
+#include <openssl/ec.h>
+#include <openssl/bn.h>
+
+/* Image signing context for openssl-libcrypto */
+struct signer {
+ EVP_PKEY *evp_key; /* Pointer to EVP_PKEY object */
+ EC_KEY *ecdsa_key; /* Pointer to EC_KEY object */
+ void *hash; /* Pointer to hash used for verification */
+ void *signature; /* Pointer to output signature. Do not free()!*/
+};
+
+static int alloc_ctx(struct signer *ctx, const struct image_sign_info *info)
+{
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (!OPENSSL_init_ssl(0, NULL)) {
+ fprintf(stderr, "Failure to init SSL library\n");
+ return -1;
+ }
+
+ ctx->hash = malloc(info->checksum->checksum_len);
+ ctx->signature = malloc(info->crypto->key_len * 2);
+
+ if (!ctx->hash || !ctx->signature)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void free_ctx(struct signer *ctx)
+{
+ if (ctx->ecdsa_key)
+ EC_KEY_free(ctx->ecdsa_key);
+
+ if (ctx->evp_key)
+ EVP_PKEY_free(ctx->evp_key);
+
+ if (ctx->hash)
+ free(ctx->hash);
+}
+
+/*
+ * Convert an ECDSA signature to raw format
+ *
+ * openssl DER-encodes 'binary' signatures. We want the signature in a raw
+ * (R, S) point pair. So we have to dance a bit.
+ */
+static void ecdsa_sig_encode_raw(void *buf, const ECDSA_SIG *sig, size_t order)
+{
+ int point_bytes = order;
+ const BIGNUM *r, *s;
+ uintptr_t s_buf;
+
+ ECDSA_SIG_get0(sig, &r, &s);
+ s_buf = (uintptr_t)buf + point_bytes;
+ BN_bn2binpad(r, buf, point_bytes);
+ BN_bn2binpad(s, (void *)s_buf, point_bytes);
+}
+
+/* Get a signature from a raw encoding */
+static ECDSA_SIG *ecdsa_sig_from_raw(void *buf, size_t order)
+{
+ int point_bytes = order;
+ uintptr_t s_buf;
+ ECDSA_SIG *sig;
+ BIGNUM *r, *s;
+
+ sig = ECDSA_SIG_new();
+ if (!sig)
+ return NULL;
+
+ s_buf = (uintptr_t)buf + point_bytes;
+ r = BN_bin2bn(buf, point_bytes, NULL);
+ s = BN_bin2bn((void *)s_buf, point_bytes, NULL);
+ ECDSA_SIG_set0(sig, r, s);
+
+ return sig;
+}
+
+/* ECDSA key size in bytes */
+static size_t ecdsa_key_size_bytes(const EC_KEY *key)
+{
+ const EC_GROUP *group;
+
+ group = EC_KEY_get0_group(key);
+ return EC_GROUP_order_bits(group) / 8;
+}
+
+static int read_key(struct signer *ctx, const char *key_name)
+{
+ FILE *f = fopen(key_name, "r");
+
+ if (!f) {
+ fprintf(stderr, "Can not get key file '%s'\n", key_name);
+ return -ENOENT;
+ }
+
+ ctx->evp_key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
+ fclose(f);
+ if (!ctx->evp_key) {
+ fprintf(stderr, "Can not read key from '%s'\n", key_name);
+ return -EIO;
+ }
+
+ if (EVP_PKEY_id(ctx->evp_key) != EVP_PKEY_EC) {
+ fprintf(stderr, "'%s' is not an ECDSA key\n", key_name);
+ return -EINVAL;
+ }
+
+ ctx->ecdsa_key = EVP_PKEY_get1_EC_KEY(ctx->evp_key);
+ if (!ctx->ecdsa_key)
+ fprintf(stderr, "Can not extract ECDSA key\n");
+
+ return (ctx->ecdsa_key) ? 0 : -EINVAL;
+}
+
+/* Prepare a 'signer' context that's ready to sign and verify. */
+static int prepare_ctx(struct signer *ctx, const struct image_sign_info *info)
+{
+ int key_len_bytes, ret;
+ char kname[1024];
+
+ memset(ctx, 0, sizeof(*ctx));
+
+ if (info->keyfile) {
+ snprintf(kname, sizeof(kname), "%s", info->keyfile);
+ } else if (info->keydir && info->keyname) {
+ snprintf(kname, sizeof(kname), "%s/%s.pem", info->keydir,
+ info->keyname);
+ } else {
+ fprintf(stderr, "keyfile, keyname, or key-name-hint missing\n");
+ return -EINVAL;
+ }
+
+ ret = alloc_ctx(ctx, info);
+ if (ret)
+ return ret;
+
+ ret = read_key(ctx, kname);
+ if (ret)
+ return ret;
+
+ key_len_bytes = ecdsa_key_size_bytes(ctx->ecdsa_key);
+ if (key_len_bytes != info->crypto->key_len) {
+ fprintf(stderr, "Expected a %u-bit key, got %u-bit key\n",
+ info->crypto->key_len * 8, key_len_bytes * 8);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int do_sign(struct signer *ctx, struct image_sign_info *info,
+ const struct image_region region[], int region_count)
+{
+ const struct checksum_algo *algo = info->checksum;
+ ECDSA_SIG *sig;
+
+ algo->calculate(algo->name, region, region_count, ctx->hash);
+ sig = ECDSA_do_sign(ctx->hash, algo->checksum_len, ctx->ecdsa_key);
+
+ ecdsa_sig_encode_raw(ctx->signature, sig, info->crypto->key_len);
+
+ return 0;
+}
+
+static int ecdsa_check_signature(struct signer *ctx, struct image_sign_info *info)
+{
+ ECDSA_SIG *sig;
+ int okay;
+
+ sig = ecdsa_sig_from_raw(ctx->signature, info->crypto->key_len);
+ if (!sig)
+ return -ENOMEM;
+
+ okay = ECDSA_do_verify(ctx->hash, info->checksum->checksum_len,
+ sig, ctx->ecdsa_key);
+ if (!okay)
+ fprintf(stderr, "WARNING: Signature is fake news!\n");
+
+ ECDSA_SIG_free(sig);
+ return !okay;
+}
+
+static int do_verify(struct signer *ctx, struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t *raw_sig, uint sig_len)
+{
+ const struct checksum_algo *algo = info->checksum;
+
+ if (sig_len != info->crypto->key_len * 2) {
+ fprintf(stderr, "Signature has wrong length\n");
+ return -EINVAL;
+ }
+
+ memcpy(ctx->signature, raw_sig, sig_len);
+ algo->calculate(algo->name, region, region_count, ctx->hash);
+
+ return ecdsa_check_signature(ctx, info);
+}
+
+int ecdsa_sign(struct image_sign_info *info, const struct image_region region[],
+ int region_count, uint8_t **sigp, uint *sig_len)
+{
+ struct signer ctx;
+ int ret;
+
+ ret = prepare_ctx(&ctx, info);
+ if (ret >= 0) {
+ do_sign(&ctx, info, region, region_count);
+ *sigp = ctx.signature;
+ *sig_len = info->crypto->key_len * 2;
+
+ ret = ecdsa_check_signature(&ctx, info);
+ }
+
+ free_ctx(&ctx);
+ return ret;
+}
+
+int ecdsa_verify(struct image_sign_info *info,
+ const struct image_region region[], int region_count,
+ uint8_t *sig, uint sig_len)
+{
+ struct signer ctx;
+ int ret;
+
+ ret = prepare_ctx(&ctx, info);
+ if (ret >= 0)
+ ret = do_verify(&ctx, info, region, region_count, sig, sig_len);
+
+ free_ctx(&ctx);
+ return ret;
+}
+
+static int do_add(struct signer *ctx, void *fdt, const char *key_node_name)
+{
+ int signature_node, key_node, ret, key_bits;
+ const char *curve_name;
+ const EC_GROUP *group;
+ const EC_POINT *point;
+ BIGNUM *x, *y;
+
+ signature_node = fdt_subnode_offset(fdt, 0, FIT_SIG_NODENAME);
+ if (signature_node < 0) {
+ fprintf(stderr, "Could not find 'signature node: %s\n",
+ fdt_strerror(signature_node));
+ return signature_node;
+ }
+
+ key_node = fdt_add_subnode(fdt, signature_node, key_node_name);
+ if (key_node < 0) {
+ fprintf(stderr, "Could not create '%s' node: %s\n",
+ key_node_name, fdt_strerror(key_node));
+ return key_node;
+ }
+
+ group = EC_KEY_get0_group(ctx->ecdsa_key);
+ key_bits = EC_GROUP_order_bits(group);
+ curve_name = OBJ_nid2sn(EC_GROUP_get_curve_name(group));
+ /* Let 'x' and 'y' memory leak by not BN_free()'ing them. */
+ x = BN_new();
+ y = BN_new();
+ point = EC_KEY_get0_public_key(ctx->ecdsa_key);
+ EC_POINT_get_affine_coordinates(group, point, x, y, NULL);
+
+ ret = fdt_setprop_string(fdt, key_node, "ecdsa,curve", curve_name);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_add_bignum(fdt, key_node, "ecdsa,x-point", x, key_bits);
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_add_bignum(fdt, key_node, "ecdsa,y-point", y, key_bits);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+int ecdsa_add_verify_data(struct image_sign_info *info, void *fdt)
+{
+ const char *fdt_key_name;
+ struct signer ctx;
+ int ret;
+
+ fdt_key_name = info->keyname ? info->keyname : "default-key";
+ ret = prepare_ctx(&ctx, info);
+ if (ret >= 0)
+ do_add(&ctx, fdt, fdt_key_name);
+
+ free_ctx(&ctx);
+ return ret;
+}
diff --git a/lib/fdt-libcrypto.c b/lib/fdt-libcrypto.c
new file mode 100644
index 0000000000..ecb0344c8f
--- /dev/null
+++ b/lib/fdt-libcrypto.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2020, Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Copyright (c) 2013, Google Inc.
+ */
+
+#include <libfdt.h>
+#include <u-boot/fdt-libcrypto.h>
+
+int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
+ BIGNUM *num, int num_bits)
+{
+ int nwords = num_bits / 32;
+ int size;
+ uint32_t *buf, *ptr;
+ BIGNUM *tmp, *big2, *big32, *big2_32;
+ BN_CTX *ctx;
+ int ret;
+
+ tmp = BN_new();
+ big2 = BN_new();
+ big32 = BN_new();
+ big2_32 = BN_new();
+
+ /*
+ * Note: This code assumes that all of the above succeed, or all fail.
+ * In practice memory allocations generally do not fail (unless the
+ * process is killed), so it does not seem worth handling each of these
+ * as a separate case. Technicaly this could leak memory on failure,
+ * but a) it won't happen in practice, and b) it doesn't matter as we
+ * will immediately exit with a failure code.
+ */
+ if (!tmp || !big2 || !big32 || !big2_32) {
+ fprintf(stderr, "Out of memory (bignum)\n");
+ return -ENOMEM;
+ }
+ ctx = BN_CTX_new();
+ if (!ctx) {
+ fprintf(stderr, "Out of memory (bignum context)\n");
+ return -ENOMEM;
+ }
+ BN_set_word(big2, 2L);
+ BN_set_word(big32, 32L);
+ BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */
+
+ size = nwords * sizeof(uint32_t);
+ buf = malloc(size);
+ if (!buf) {
+ fprintf(stderr, "Out of memory (%d bytes)\n", size);
+ return -ENOMEM;
+ }
+
+ /* Write out modulus as big endian array of integers */
+ for (ptr = buf + nwords - 1; ptr >= buf; ptr--) {
+ BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */
+ *ptr = cpu_to_fdt32(BN_get_word(tmp));
+ BN_rshift(num, num, 32); /* N = N/B */
+ }
+
+ /*
+ * We try signing with successively increasing size values, so this
+ * might fail several times
+ */
+ ret = fdt_setprop(blob, noffset, prop_name, buf, size);
+ free(buf);
+ BN_free(tmp);
+ BN_free(big2);
+ BN_free(big32);
+ BN_free(big2_32);
+
+ return ret ? -FDT_ERR_NOSPACE : 0;
+}
diff --git a/lib/rsa/rsa-checksum.c b/lib/hash-checksum.c
index e60debb7df..d732ecc38f 100644
--- a/lib/rsa/rsa-checksum.c
+++ b/lib/hash-checksum.c
@@ -13,7 +13,8 @@
#else
#include "fdt_host.h"
#endif
-#include <u-boot/rsa.h>
+#include <hash.h>
+#include <image.h>
int hash_calculate(const char *name,
const struct image_region region[],
diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile
index 8b75d41f04..c9ac72c1e2 100644
--- a/lib/rsa/Makefile
+++ b/lib/rsa/Makefile
@@ -5,6 +5,6 @@
# (C) Copyright 2000-2007
# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
-obj-$(CONFIG_$(SPL_TPL_)RSA_VERIFY) += rsa-verify.o rsa-checksum.o
+obj-$(CONFIG_$(SPL_TPL_)RSA_VERIFY) += rsa-verify.o
obj-$(CONFIG_$(SPL_TPL_)RSA_VERIFY_WITH_PKEY) += rsa-keyprop.o
obj-$(CONFIG_RSA_SOFTWARE_EXP) += rsa-mod-exp.o
diff --git a/lib/rsa/rsa-sign.c b/lib/rsa/rsa-sign.c
index 1f0d81bd7a..5a1583b8f7 100644
--- a/lib/rsa/rsa-sign.c
+++ b/lib/rsa/rsa-sign.c
@@ -9,7 +9,9 @@
#include <string.h>
#include <image.h>
#include <time.h>
+#include <u-boot/fdt-libcrypto.h>
#include <openssl/bn.h>
+#include <openssl/ec.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
@@ -51,19 +53,21 @@ static int rsa_err(const char *msg)
*
* @keydir: Directory containins the key
* @name Name of key file (will have a .crt extension)
- * @rsap Returns RSA object, or NULL on failure
- * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ * @evpp Returns EVP_PKEY object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
-static int rsa_pem_get_pub_key(const char *keydir, const char *name, RSA **rsap)
+static int rsa_pem_get_pub_key(const char *keydir, const char *name, EVP_PKEY **evpp)
{
char path[1024];
- EVP_PKEY *key;
+ EVP_PKEY *key = NULL;
X509 *cert;
- RSA *rsa;
FILE *f;
int ret;
- *rsap = NULL;
+ if (!evpp)
+ return -EINVAL;
+
+ *evpp = NULL;
snprintf(path, sizeof(path), "%s/%s.crt", keydir, name);
f = fopen(path, "r");
if (!f) {
@@ -88,22 +92,12 @@ static int rsa_pem_get_pub_key(const char *keydir, const char *name, RSA **rsap)
goto err_pubkey;
}
- /* Convert to a RSA_style key. */
- rsa = EVP_PKEY_get1_RSA(key);
- if (!rsa) {
- rsa_err("Couldn't convert to a RSA style key");
- ret = -EINVAL;
- goto err_rsa;
- }
fclose(f);
- EVP_PKEY_free(key);
+ *evpp = key;
X509_free(cert);
- *rsap = rsa;
return 0;
-err_rsa:
- EVP_PKEY_free(key);
err_pubkey:
X509_free(cert);
err_cert:
@@ -117,19 +111,20 @@ err_cert:
* @keydir: Key prefix
* @name Name of key
* @engine Engine to use
- * @rsap Returns RSA object, or NULL on failure
- * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ * @evpp Returns EVP_PKEY object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_engine_get_pub_key(const char *keydir, const char *name,
- ENGINE *engine, RSA **rsap)
+ ENGINE *engine, EVP_PKEY **evpp)
{
const char *engine_id;
char key_id[1024];
- EVP_PKEY *key;
- RSA *rsa;
- int ret;
+ EVP_PKEY *key = NULL;
+
+ if (!evpp)
+ return -EINVAL;
- *rsap = NULL;
+ *evpp = NULL;
engine_id = ENGINE_get_id(engine);
@@ -165,22 +160,9 @@ static int rsa_engine_get_pub_key(const char *keydir, const char *name,
if (!key)
return rsa_err("Failure loading public key from engine");
- /* Convert to a RSA_style key. */
- rsa = EVP_PKEY_get1_RSA(key);
- if (!rsa) {
- rsa_err("Couldn't convert to a RSA style key");
- ret = -EINVAL;
- goto err_rsa;
- }
-
- EVP_PKEY_free(key);
- *rsap = rsa;
+ *evpp = key;
return 0;
-
-err_rsa:
- EVP_PKEY_free(key);
- return ret;
}
/**
@@ -189,15 +171,15 @@ err_rsa:
* @keydir: Directory containing the key (PEM file) or key prefix (engine)
* @name Name of key file (will have a .crt extension)
* @engine Engine to use
- * @rsap Returns RSA object, or NULL on failure
- * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ * @evpp Returns EVP_PKEY object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_get_pub_key(const char *keydir, const char *name,
- ENGINE *engine, RSA **rsap)
+ ENGINE *engine, EVP_PKEY **evpp)
{
if (engine)
- return rsa_engine_get_pub_key(keydir, name, engine, rsap);
- return rsa_pem_get_pub_key(keydir, name, rsap);
+ return rsa_engine_get_pub_key(keydir, name, engine, evpp);
+ return rsa_pem_get_pub_key(keydir, name, evpp);
}
/**
@@ -205,18 +187,26 @@ static int rsa_get_pub_key(const char *keydir, const char *name,
*
* @keydir: Directory containing the key
* @name Name of key file (will have a .key extension)
- * @rsap Returns RSA object, or NULL on failure
- * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ * @evpp Returns EVP_PKEY object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_pem_get_priv_key(const char *keydir, const char *name,
- RSA **rsap)
+ const char *keyfile, EVP_PKEY **evpp)
{
- char path[1024];
- RSA *rsa;
- FILE *f;
+ char path[1024] = {0};
+ FILE *f = NULL;
+
+ if (!evpp)
+ return -EINVAL;
+
+ *evpp = NULL;
+ if (keydir && name)
+ snprintf(path, sizeof(path), "%s/%s.key", keydir, name);
+ else if (keyfile)
+ snprintf(path, sizeof(path), "%s", keyfile);
+ else
+ return -EINVAL;
- *rsap = NULL;
- snprintf(path, sizeof(path), "%s/%s.key", keydir, name);
f = fopen(path, "r");
if (!f) {
fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n",
@@ -224,14 +214,12 @@ static int rsa_pem_get_priv_key(const char *keydir, const char *name,
return -ENOENT;
}
- rsa = PEM_read_RSAPrivateKey(f, 0, NULL, path);
- if (!rsa) {
+ if (!PEM_read_PrivateKey(f, evpp, NULL, path)) {
rsa_err("Failure reading private key");
fclose(f);
return -EPROTO;
}
fclose(f);
- *rsap = rsa;
return 0;
}
@@ -242,23 +230,27 @@ static int rsa_pem_get_priv_key(const char *keydir, const char *name,
* @keydir: Key prefix
* @name Name of key
* @engine Engine to use
- * @rsap Returns RSA object, or NULL on failure
- * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ * @evpp Returns EVP_PKEY object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_engine_get_priv_key(const char *keydir, const char *name,
- ENGINE *engine, RSA **rsap)
+ const char *keyfile,
+ ENGINE *engine, EVP_PKEY **evpp)
{
const char *engine_id;
char key_id[1024];
- EVP_PKEY *key;
- RSA *rsa;
- int ret;
+ EVP_PKEY *key = NULL;
- *rsap = NULL;
+ if (!evpp)
+ return -EINVAL;
engine_id = ENGINE_get_id(engine);
if (engine_id && !strcmp(engine_id, "pkcs11")) {
+ if (!keydir && !name) {
+ fprintf(stderr, "Please use 'keydir' with PKCS11\n");
+ return -EINVAL;
+ }
if (keydir)
if (strstr(keydir, "object="))
snprintf(key_id, sizeof(key_id),
@@ -273,14 +265,19 @@ static int rsa_engine_get_priv_key(const char *keydir, const char *name,
"pkcs11:object=%s;type=private",
name);
} else if (engine_id) {
- if (keydir)
+ if (keydir && name)
snprintf(key_id, sizeof(key_id),
"%s%s",
keydir, name);
- else
+ else if (keydir)
snprintf(key_id, sizeof(key_id),
"%s",
name);
+ else if (keyfile)
+ snprintf(key_id, sizeof(key_id), "%s", keyfile);
+ else
+ return -EINVAL;
+
} else {
fprintf(stderr, "Engine not supported\n");
return -ENOTSUP;
@@ -290,22 +287,9 @@ static int rsa_engine_get_priv_key(const char *keydir, const char *name,
if (!key)
return rsa_err("Failure loading private key from engine");
- /* Convert to a RSA_style key. */
- rsa = EVP_PKEY_get1_RSA(key);
- if (!rsa) {
- rsa_err("Couldn't convert to a RSA style key");
- ret = -EINVAL;
- goto err_rsa;
- }
-
- EVP_PKEY_free(key);
- *rsap = rsa;
+ *evpp = key;
return 0;
-
-err_rsa:
- EVP_PKEY_free(key);
- return ret;
}
/**
@@ -314,15 +298,16 @@ err_rsa:
* @keydir: Directory containing the key (PEM file) or key prefix (engine)
* @name Name of key
* @engine Engine to use for signing
- * @rsap Returns RSA object, or NULL on failure
- * @return 0 if ok, -ve on error (in which case *rsap will be set to NULL)
+ * @evpp Returns EVP_PKEY object, or NULL on failure
+ * @return 0 if ok, -ve on error (in which case *evpp will be set to NULL)
*/
static int rsa_get_priv_key(const char *keydir, const char *name,
- ENGINE *engine, RSA **rsap)
+ const char *keyfile, ENGINE *engine, EVP_PKEY **evpp)
{
if (engine)
- return rsa_engine_get_priv_key(keydir, name, engine, rsap);
- return rsa_pem_get_priv_key(keydir, name, rsap);
+ return rsa_engine_get_priv_key(keydir, name, keyfile, engine,
+ evpp);
+ return rsa_pem_get_priv_key(keydir, name, keyfile, evpp);
}
static int rsa_init(void)
@@ -416,12 +401,11 @@ static void rsa_engine_remove(ENGINE *e)
}
}
-static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
+static int rsa_sign_with_key(EVP_PKEY *pkey, struct padding_algo *padding_algo,
struct checksum_algo *checksum_algo,
const struct image_region region[], int region_count,
uint8_t **sigp, uint *sig_size)
{
- EVP_PKEY *key;
EVP_PKEY_CTX *ckey;
EVP_MD_CTX *context;
int ret = 0;
@@ -429,16 +413,7 @@ static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
uint8_t *sig;
int i;
- key = EVP_PKEY_new();
- if (!key)
- return rsa_err("EVP_PKEY object creation failed");
-
- if (!EVP_PKEY_set1_RSA(key, rsa)) {
- ret = rsa_err("EVP key setup failed");
- goto err_set;
- }
-
- size = EVP_PKEY_size(key);
+ size = EVP_PKEY_size(pkey);
sig = malloc(size);
if (!sig) {
fprintf(stderr, "Out of memory for signature (%zu bytes)\n",
@@ -454,7 +429,7 @@ static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
}
EVP_MD_CTX_init(context);
- ckey = EVP_PKEY_CTX_new(key, NULL);
+ ckey = EVP_PKEY_CTX_new(pkey, NULL);
if (!ckey) {
ret = rsa_err("EVP key context creation failed");
goto err_create;
@@ -462,7 +437,7 @@ static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
if (EVP_DigestSignInit(context, &ckey,
checksum_algo->calculate_sign(),
- NULL, key) <= 0) {
+ NULL, pkey) <= 0) {
ret = rsa_err("Signer setup failed");
goto err_sign;
}
@@ -497,7 +472,6 @@ static int rsa_sign_with_key(RSA *rsa, struct padding_algo *padding_algo,
EVP_MD_CTX_reset(context);
#endif
EVP_MD_CTX_destroy(context);
- EVP_PKEY_free(key);
debug("Got signature: %d bytes, expected %zu\n", *sig_size, size);
*sigp = sig;
@@ -510,8 +484,6 @@ err_sign:
err_create:
free(sig);
err_alloc:
-err_set:
- EVP_PKEY_free(key);
return ret;
}
@@ -519,7 +491,7 @@ int rsa_sign(struct image_sign_info *info,
const struct image_region region[], int region_count,
uint8_t **sigp, uint *sig_len)
{
- RSA *rsa;
+ EVP_PKEY *pkey = NULL;
ENGINE *e = NULL;
int ret;
@@ -533,15 +505,16 @@ int rsa_sign(struct image_sign_info *info,
goto err_engine;
}
- ret = rsa_get_priv_key(info->keydir, info->keyname, e, &rsa);
+ ret = rsa_get_priv_key(info->keydir, info->keyname, info->keyfile,
+ e, &pkey);
if (ret)
goto err_priv;
- ret = rsa_sign_with_key(rsa, info->padding, info->checksum, region,
+ ret = rsa_sign_with_key(pkey, info->padding, info->checksum, region,
region_count, sigp, sig_len);
if (ret)
goto err_sign;
- RSA_free(rsa);
+ EVP_PKEY_free(pkey);
if (info->engine_id)
rsa_engine_remove(e);
rsa_remove();
@@ -549,7 +522,7 @@ int rsa_sign(struct image_sign_info *info,
return ret;
err_sign:
- RSA_free(rsa);
+ EVP_PKEY_free(pkey);
err_priv:
if (info->engine_id)
rsa_engine_remove(e);
@@ -680,70 +653,6 @@ int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp,
return ret;
}
-static int fdt_add_bignum(void *blob, int noffset, const char *prop_name,
- BIGNUM *num, int num_bits)
-{
- int nwords = num_bits / 32;
- int size;
- uint32_t *buf, *ptr;
- BIGNUM *tmp, *big2, *big32, *big2_32;
- BN_CTX *ctx;
- int ret;
-
- tmp = BN_new();
- big2 = BN_new();
- big32 = BN_new();
- big2_32 = BN_new();
-
- /*
- * Note: This code assumes that all of the above succeed, or all fail.
- * In practice memory allocations generally do not fail (unless the
- * process is killed), so it does not seem worth handling each of these
- * as a separate case. Technicaly this could leak memory on failure,
- * but a) it won't happen in practice, and b) it doesn't matter as we
- * will immediately exit with a failure code.
- */
- if (!tmp || !big2 || !big32 || !big2_32) {
- fprintf(stderr, "Out of memory (bignum)\n");
- return -ENOMEM;
- }
- ctx = BN_CTX_new();
- if (!ctx) {
- fprintf(stderr, "Out of memory (bignum context)\n");
- return -ENOMEM;
- }
- BN_set_word(big2, 2L);
- BN_set_word(big32, 32L);
- BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */
-
- size = nwords * sizeof(uint32_t);
- buf = malloc(size);
- if (!buf) {
- fprintf(stderr, "Out of memory (%d bytes)\n", size);
- return -ENOMEM;
- }
-
- /* Write out modulus as big endian array of integers */
- for (ptr = buf + nwords - 1; ptr >= buf; ptr--) {
- BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */
- *ptr = cpu_to_fdt32(BN_get_word(tmp));
- BN_rshift(num, num, 32); /* N = N/B */
- }
-
- /*
- * We try signing with successively increasing size values, so this
- * might fail several times
- */
- ret = fdt_setprop(blob, noffset, prop_name, buf, size);
- free(buf);
- BN_free(tmp);
- BN_free(big2);
- BN_free(big32);
- BN_free(big2_32);
-
- return ret ? -FDT_ERR_NOSPACE : 0;
-}
-
int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
{
BIGNUM *modulus, *r_squared;
@@ -754,6 +663,7 @@ int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
int ret;
int bits;
RSA *rsa;
+ EVP_PKEY *pkey = NULL;
ENGINE *e = NULL;
debug("%s: Getting verification data\n", __func__);
@@ -762,9 +672,15 @@ int rsa_add_verify_data(struct image_sign_info *info, void *keydest)
if (ret)
return ret;
}
- ret = rsa_get_pub_key(info->keydir, info->keyname, e, &rsa);
+ ret = rsa_get_pub_key(info->keydir, info->keyname, e, &pkey);
if (ret)
goto err_get_pub_key;
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
+ rsa = EVP_PKEY_get1_RSA(pkey);
+#else
+ rsa = EVP_PKEY_get0_RSA(pkey);
+#endif
ret = rsa_get_params(rsa, &exponent, &n0_inv, &modulus, &r_squared);
if (ret)
goto err_get_params;
@@ -834,7 +750,11 @@ done:
if (ret)
ret = ret == -FDT_ERR_NOSPACE ? -ENOSPC : -EIO;
err_get_params:
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || \
+ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x02070000fL)
RSA_free(rsa);
+#endif
+ EVP_PKEY_free(pkey);
err_get_pub_key:
if (info->engine_id)
rsa_engine_remove(e);
diff --git a/test/py/requirements.txt b/test/py/requirements.txt
index 89ca259b21..9c346b4b41 100644
--- a/test/py/requirements.txt
+++ b/test/py/requirements.txt
@@ -10,6 +10,7 @@ packaging==19.2
pbr==5.4.3
pluggy==0.13.0
py==1.8.0
+pycryptodomex==3.9.8
pyelftools==0.27
pygit2==0.28.2
pyparsing==2.4.2
diff --git a/test/py/tests/test_fit_ecdsa.py b/test/py/tests/test_fit_ecdsa.py
new file mode 100644
index 0000000000..87b6081222
--- /dev/null
+++ b/test/py/tests/test_fit_ecdsa.py
@@ -0,0 +1,111 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (c) 2020,2021 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+
+"""
+Test ECDSA signing of FIT images
+
+This test uses mkimage to sign an existing FIT image with an ECDSA key. The
+signature is then extracted, and verified against pyCryptodome.
+This test doesn't run the sandbox. It only checks the host tool 'mkimage'
+"""
+
+import pytest
+import u_boot_utils as util
+from Cryptodome.Hash import SHA256
+from Cryptodome.PublicKey import ECC
+from Cryptodome.Signature import DSS
+
+class SignableFitImage(object):
+ """ Helper to manipulate a FIT image on disk """
+ def __init__(self, cons, file_name):
+ self.fit = file_name
+ self.cons = cons
+ self.signable_nodes = set()
+
+ def __fdt_list(self, path):
+ return util.run_and_log(self.cons, f'fdtget -l {self.fit} {path}')
+
+ def __fdt_set(self, node, **prop_value):
+ for prop, value in prop_value.items():
+ util.run_and_log(self.cons, f'fdtput -ts {self.fit} {node} {prop} {value}')
+
+ def __fdt_get_binary(self, node, prop):
+ numbers = util.run_and_log(self.cons, f'fdtget -tbi {self.fit} {node} {prop}')
+
+ bignum = bytearray()
+ for little_num in numbers.split():
+ bignum.append(int(little_num))
+
+ return bignum
+
+ def find_signable_image_nodes(self):
+ for node in self.__fdt_list('/images').split():
+ image = f'/images/{node}'
+ if 'signature' in self.__fdt_list(image):
+ self.signable_nodes.add(image)
+
+ return self.signable_nodes
+
+ def change_signature_algo_to_ecdsa(self):
+ for image in self.signable_nodes:
+ self.__fdt_set(f'{image}/signature', algo='sha256,ecdsa256')
+
+ def sign(self, mkimage, key_file):
+ util.run_and_log(self.cons, [mkimage, '-F', self.fit, f'-G{key_file}'])
+
+ def check_signatures(self, key):
+ for image in self.signable_nodes:
+ raw_sig = self.__fdt_get_binary(f'{image}/signature', 'value')
+ raw_bin = self.__fdt_get_binary(image, 'data')
+
+ sha = SHA256.new(raw_bin)
+ verifier = DSS.new(key, 'fips-186-3')
+ verifier.verify(sha, bytes(raw_sig))
+
+
+@pytest.mark.buildconfigspec('fit_signature')
+@pytest.mark.requiredtool('dtc')
+@pytest.mark.requiredtool('fdtget')
+@pytest.mark.requiredtool('fdtput')
+def test_fit_ecdsa(u_boot_console):
+ """ Test that signatures generated by mkimage are legible. """
+ def generate_ecdsa_key():
+ return ECC.generate(curve='prime256v1')
+
+ def assemble_fit_image(dest_fit, its, destdir):
+ dtc_args = f'-I dts -O dtb -i {destdir}'
+ util.run_and_log(cons, [mkimage, '-D', dtc_args, '-f', its, dest_fit])
+
+ def dtc(dts):
+ dtb = dts.replace('.dts', '.dtb')
+ util.run_and_log(cons, f'dtc {datadir}/{dts} -O dtb -o {tempdir}/{dtb}')
+
+ cons = u_boot_console
+ mkimage = cons.config.build_dir + '/tools/mkimage'
+ datadir = cons.config.source_dir + '/test/py/tests/vboot/'
+ tempdir = cons.config.result_dir
+ key_file = f'{tempdir}/ecdsa-test-key.pem'
+ fit_file = f'{tempdir}/test.fit'
+ dtc('sandbox-kernel.dts')
+
+ key = generate_ecdsa_key()
+
+ # Create a fake kernel image -- zeroes will do just fine
+ with open(f'{tempdir}/test-kernel.bin', 'w') as fd:
+ fd.write(500 * chr(0))
+
+ # invocations of mkimage expect to read the key from disk
+ with open(key_file, 'w') as f:
+ f.write(key.export_key(format='PEM'))
+
+ assemble_fit_image(fit_file, f'{datadir}/sign-images-sha256.its', tempdir)
+
+ fit = SignableFitImage(cons, fit_file)
+ nodes = fit.find_signable_image_nodes()
+ if len(nodes) == 0:
+ raise ValueError('FIT image has no "/image" nodes with "signature"')
+
+ fit.change_signature_algo_to_ecdsa()
+ fit.sign(mkimage, key_file)
+ fit.check_signatures(key)
diff --git a/tools/Makefile b/tools/Makefile
index 62de7e6fe0..d020c55d66 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -67,12 +67,18 @@ LIBFDT_OBJS := $(addprefix libfdt/, fdt.o fdt_ro.o fdt_wip.o fdt_sw.o fdt_rw.o \
fdt_strerror.o fdt_empty_tree.o fdt_addresses.o fdt_overlay.o)
RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \
- rsa-sign.o rsa-verify.o rsa-checksum.o \
+ rsa-sign.o rsa-verify.o \
rsa-mod-exp.o)
+ECDSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/ecdsa/, ecdsa-libcrypto.o)
+
AES_OBJS-$(CONFIG_FIT_CIPHER) := $(addprefix lib/aes/, \
aes-encrypt.o aes-decrypt.o)
+# Cryptographic helpers that depend on openssl/libcrypto
+LIBCRYPTO_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/, \
+ fdt-libcrypto.o)
+
ROCKCHIP_OBS = lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
# common objs for dumpimage and mkimage
@@ -106,6 +112,7 @@ dumpimage-mkimage-objs := aisimage.o \
socfpgaimage.o \
sunxi_egon.o \
lib/crc16.o \
+ lib/hash-checksum.o \
lib/sha1.o \
lib/sha256.o \
lib/sha512.o \
@@ -114,10 +121,12 @@ dumpimage-mkimage-objs := aisimage.o \
zynqimage.o \
zynqmpimage.o \
zynqmpbif.o \
+ $(LIBCRYPTO_OBJS-y) \
$(LIBFDT_OBJS) \
gpimage.o \
gpimage-common.o \
mtk_image.o \
+ $(ECDSA_OBJS-y) \
$(RSA_OBJS-y) \
$(AES_OBJS-y)
diff --git a/tools/fit_image.c b/tools/fit_image.c
index d440d143c6..ae30f80783 100644
--- a/tools/fit_image.c
+++ b/tools/fit_image.c
@@ -68,7 +68,8 @@ static int fit_add_file_data(struct image_tool_params *params, size_t size_inc,
}
if (!ret) {
- ret = fit_add_verification_data(params->keydir, dest_blob, ptr,
+ ret = fit_add_verification_data(params->keydir,
+ params->keyfile, dest_blob, ptr,
params->comment,
params->require_keys,
params->engine_id,
diff --git a/tools/image-host.c b/tools/image-host.c
index 33a224129a..270d36fe45 100644
--- a/tools/image-host.c
+++ b/tools/image-host.c
@@ -153,8 +153,9 @@ static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
}
static int fit_image_setup_sig(struct image_sign_info *info,
- const char *keydir, void *fit, const char *image_name,
- int noffset, const char *require_keys, const char *engine_id)
+ const char *keydir, const char *keyfile, void *fit,
+ const char *image_name, int noffset, const char *require_keys,
+ const char *engine_id)
{
const char *node_name;
char *algo_name;
@@ -171,6 +172,7 @@ static int fit_image_setup_sig(struct image_sign_info *info,
memset(info, '\0', sizeof(*info));
info->keydir = keydir;
+ info->keyfile = keyfile;
info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
info->fit = fit;
info->node_offset = noffset;
@@ -207,8 +209,8 @@ static int fit_image_setup_sig(struct image_sign_info *info,
* @engine_id: Engine to use for signing
* @return 0 if ok, -1 on error
*/
-static int fit_image_process_sig(const char *keydir, void *keydest,
- void *fit, const char *image_name,
+static int fit_image_process_sig(const char *keydir, const char *keyfile,
+ void *keydest, void *fit, const char *image_name,
int noffset, const void *data, size_t size,
const char *comment, int require_keys, const char *engine_id,
const char *cmdname)
@@ -220,8 +222,9 @@ static int fit_image_process_sig(const char *keydir, void *keydest,
uint value_len;
int ret;
- if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset,
- require_keys ? "image" : NULL, engine_id))
+ if (fit_image_setup_sig(&info, keydir, keyfile, fit, image_name,
+ noffset, require_keys ? "image" : NULL,
+ engine_id))
return -1;
node_name = fit_get_name(fit, noffset, NULL);
@@ -598,9 +601,10 @@ int fit_image_cipher_data(const char *keydir, void *keydest,
* @engine_id: Engine to use for signing
* @return: 0 on success, <0 on failure
*/
-int fit_image_add_verification_data(const char *keydir, void *keydest,
- void *fit, int image_noffset, const char *comment,
- int require_keys, const char *engine_id, const char *cmdname)
+int fit_image_add_verification_data(const char *keydir, const char *keyfile,
+ void *keydest, void *fit, int image_noffset,
+ const char *comment, int require_keys, const char *engine_id,
+ const char *cmdname)
{
const char *image_name;
const void *data;
@@ -632,10 +636,10 @@ int fit_image_add_verification_data(const char *keydir, void *keydest,
strlen(FIT_HASH_NODENAME))) {
ret = fit_image_process_hash(fit, image_name, noffset,
data, size);
- } else if (IMAGE_ENABLE_SIGN && keydir &&
+ } else if (IMAGE_ENABLE_SIGN && (keydir || keyfile) &&
!strncmp(node_name, FIT_SIG_NODENAME,
strlen(FIT_SIG_NODENAME))) {
- ret = fit_image_process_sig(keydir, keydest,
+ ret = fit_image_process_sig(keydir, keyfile, keydest,
fit, image_name, noffset, data, size,
comment, require_keys, engine_id, cmdname);
}
@@ -918,10 +922,10 @@ static int fit_config_get_data(void *fit, int conf_noffset, int noffset,
return 0;
}
-static int fit_config_process_sig(const char *keydir, void *keydest,
- void *fit, const char *conf_name, int conf_noffset,
- int noffset, const char *comment, int require_keys,
- const char *engine_id, const char *cmdname)
+static int fit_config_process_sig(const char *keydir, const char *keyfile,
+ void *keydest, void *fit, const char *conf_name,
+ int conf_noffset, int noffset, const char *comment,
+ int require_keys, const char *engine_id, const char *cmdname)
{
struct image_sign_info info;
const char *node_name;
@@ -938,7 +942,7 @@ static int fit_config_process_sig(const char *keydir, void *keydest,
&region_count, &region_prop, &region_proplen))
return -1;
- if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset,
+ if (fit_image_setup_sig(&info, keydir, keyfile, fit, conf_name, noffset,
require_keys ? "conf" : NULL, engine_id))
return -1;
@@ -983,9 +987,10 @@ static int fit_config_process_sig(const char *keydir, void *keydest,
return 0;
}
-static int fit_config_add_verification_data(const char *keydir, void *keydest,
- void *fit, int conf_noffset, const char *comment,
- int require_keys, const char *engine_id, const char *cmdname)
+static int fit_config_add_verification_data(const char *keydir,
+ const char *keyfile, void *keydest, void *fit, int conf_noffset,
+ const char *comment, int require_keys, const char *engine_id,
+ const char *cmdname)
{
const char *conf_name;
int noffset;
@@ -1002,7 +1007,7 @@ static int fit_config_add_verification_data(const char *keydir, void *keydest,
node_name = fit_get_name(fit, noffset, NULL);
if (!strncmp(node_name, FIT_SIG_NODENAME,
strlen(FIT_SIG_NODENAME))) {
- ret = fit_config_process_sig(keydir, keydest,
+ ret = fit_config_process_sig(keydir, keyfile, keydest,
fit, conf_name, conf_noffset, noffset, comment,
require_keys, engine_id, cmdname);
}
@@ -1048,9 +1053,10 @@ int fit_cipher_data(const char *keydir, void *keydest, void *fit,
return 0;
}
-int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
- const char *comment, int require_keys,
- const char *engine_id, const char *cmdname)
+int fit_add_verification_data(const char *keydir, const char *keyfile,
+ void *keydest, void *fit, const char *comment,
+ int require_keys, const char *engine_id,
+ const char *cmdname)
{
int images_noffset, confs_noffset;
int noffset;
@@ -1072,7 +1078,7 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
* Direct child node of the images parent node,
* i.e. component image node.
*/
- ret = fit_image_add_verification_data(keydir, keydest,
+ ret = fit_image_add_verification_data(keydir, keyfile, keydest,
fit, noffset, comment, require_keys, engine_id,
cmdname);
if (ret)
@@ -1080,7 +1086,7 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
}
/* If there are no keys, we can't sign configurations */
- if (!IMAGE_ENABLE_SIGN || !keydir)
+ if (!IMAGE_ENABLE_SIGN || !(keydir || keyfile))
return 0;
/* Find configurations parent node offset */
@@ -1095,7 +1101,7 @@ int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
for (noffset = fdt_first_subnode(fit, confs_noffset);
noffset >= 0;
noffset = fdt_next_subnode(fit, noffset)) {
- ret = fit_config_add_verification_data(keydir, keydest,
+ ret = fit_config_add_verification_data(keydir, keyfile, keydest,
fit, noffset, comment,
require_keys,
engine_id, cmdname);
diff --git a/tools/imagetool.h b/tools/imagetool.h
index 2801ea9e9f..e229a34ffc 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -67,6 +67,7 @@ struct image_tool_params {
const char *outfile; /* Output filename */
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 *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 */
diff --git a/tools/mkimage.c b/tools/mkimage.c
index 68d5206cb4..cc7b242faf 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -108,6 +108,7 @@ static void usage(const char *msg)
"Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-p addr] [-r] [-N engine]\n"
" -k => set directory containing private keys\n"
" -K => write public keys to this .dtb file\n"
+ " -G => use this signing key (in lieu of -k)\n"
" -c => add comment in signature node\n"
" -F => re-sign existing FIT image\n"
" -p => place external data at a static position\n"
@@ -151,7 +152,7 @@ static void process_args(int argc, char **argv)
int opt;
while ((opt = getopt(argc, argv,
- "a:A:b:B:c:C:d:D:e:Ef:Fk:i:K:ln:N:p:O:rR:qstT:vVx")) != -1) {
+ "a:A:b:B:c:C:d:D:e:Ef:FG:k:i:K:ln:N:p:O:rR:qstT:vVx")) != -1) {
switch (opt) {
case 'a':
params.addr = strtoull(optarg, &ptr, 16);
@@ -226,6 +227,9 @@ static void process_args(int argc, char **argv)
params.type = IH_TYPE_FLATDT;
params.fflag = 1;
break;
+ case 'G':
+ params.keyfile = optarg;
+ break;
case 'i':
params.fit_ramdisk = optarg;
break;