[PATCH 4/9] spl: fit: support encrypted payloads

James Hilliard james.hilliard1 at gmail.com
Thu Jul 2 03:46:54 CEST 2026


Add SPL_FIT_CIPHER and decrypt FIT image data before post-processing,
decompression or moving it to the final load address.

SPL cannot always allocate a new output buffer while loading FIT images, so
use the caller-provided decrypt-to-buffer helper. External encrypted images
are read into scratch memory first, then decrypted either in-place for
compressed payloads or into a non-overlapping buffer for direct loads.
Embedded encrypted images decrypt into the final load buffer or a scratch
buffer when decompression is still required.

Signed-off-by: James Hilliard <james.hilliard1 at gmail.com>
---
 boot/Kconfig         |  9 +++++
 boot/image-fit.c     |  2 +-
 common/spl/spl_fit.c | 92 +++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 96 insertions(+), 7 deletions(-)

diff --git a/boot/Kconfig b/boot/Kconfig
index 8e468c56176..19bbeb9ad36 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -155,6 +155,15 @@ config FIT_CIPHER
 	  Enable the feature of data ciphering/unciphering in the tool mkimage
 	  and in the u-boot support of the FIT image.
 
+config SPL_FIT_CIPHER
+	bool "Enable ciphering data in SPL FIT images"
+	depends on SPL_LOAD_FIT
+	depends on SPL_DM_AES
+	select SPL_FIT
+	help
+	  Enable unciphering of FIT image data in SPL. This allows SPL to
+	  decrypt an encrypted U-Boot proper FIT image through an AES driver.
+
 config FIT_VERITY
 	bool "dm-verity boot parameter generation from FIT metadata"
 	depends on FIT && OF_LIBFDT
diff --git a/boot/image-fit.c b/boot/image-fit.c
index dac8b35f338..1d1723bdae0 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -2290,7 +2290,7 @@ int fit_image_load(struct bootm_headers *images, ulong addr,
 	}
 
 	/* Decrypt data before uncompress/move */
-	if (IS_ENABLED(CONFIG_FIT_CIPHER) && IMAGE_ENABLE_DECRYPT) {
+	if (!tools_build() && IMAGE_ENABLE_DECRYPT) {
 		puts("   Decrypting Data ... ");
 		if (fit_image_uncipher(fit, noffset, &buf, &size)) {
 			puts("Error\n");
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index d89384449b3..57975a7638f 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -16,6 +16,7 @@
 #include <sysinfo.h>
 #include <asm/global_data.h>
 #include <asm/io.h>
+#include <limits.h>
 #include <linux/libfdt.h>
 #include <linux/printk.h>
 
@@ -193,6 +194,47 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size,
 	return ALIGN(data_size, spl_get_bl_len(info));
 }
 
+static int spl_fit_image_decrypt(const void *fit, int node, int cipher_node,
+				 void **data, size_t *size, void *dst)
+{
+	size_t dst_size;
+	int ret;
+
+	puts("   Decrypting Data ... ");
+	ret = fit_image_decrypt_data_to(fit, node, cipher_node, *data, *size,
+					dst, &dst_size);
+	if (ret) {
+		puts("Error\n");
+		return ret;
+	}
+
+	*data = dst;
+	*size = dst_size;
+
+	puts("OK\n");
+
+	return 0;
+}
+
+static bool spl_fit_ranges_overlap(ulong addr1, size_t size1,
+				   ulong addr2, size_t size2)
+{
+	ulong end1, end2;
+
+	if (!size1 || !size2)
+		return false;
+
+	end1 = addr1 + size1;
+	if (end1 < addr1)
+		end1 = ULONG_MAX;
+
+	end2 = addr2 + size2;
+	if (end2 < addr2)
+		end2 = ULONG_MAX;
+
+	return addr1 < end2 && addr2 < end1;
+}
+
 /**
  * load_simple_fit(): load the image described in a certain FIT node
  * @info:	points to information about the device to load data from
@@ -225,12 +267,15 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
 	const void *data;
 	const void *fit = ctx->fit;
 	bool external_data = false;
+	bool encrypted;
+	bool needs_decomp = false;
+	int cipher_node = -ENOENT;
+	int ret;
 
 	log_debug("starting\n");
 	if (CONFIG_IS_ENABLED(BOOTMETH_VBE) &&
 	    xpl_get_phase(info) != IH_PHASE_NONE) {
 		enum image_phase_t phase;
-		int ret;
 
 		ret = fit_image_get_phase(fit, node, &phase);
 		/* if the image is for any phase, let's use it */
@@ -256,6 +301,8 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
 	if (spl_decompression_enabled()) {
 		fit_image_get_comp(fit, node, &image_comp);
 		debug("%s ", genimg_get_comp_name(image_comp));
+		needs_decomp = image_comp == IH_COMP_GZIP ||
+			       image_comp == IH_COMP_LZMA;
 	}
 
 	if (fit_image_get_load(fit, node, &load_addr)) {
@@ -267,6 +314,10 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
 		load_addr = image_info->load_addr;
 	}
 
+	if (CONFIG_IS_ENABLED(FIT_CIPHER))
+		cipher_node = fdt_subnode_offset(fit, node, FIT_CIPHER_NODENAME);
+	encrypted = cipher_node >= 0;
+
 	if (!fit_image_get_data_position(fit, node, &offset)) {
 		external_data = true;
 	} else if (!fit_image_get_data_offset(fit, node, &offset)) {
@@ -291,11 +342,12 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
 			return 0;
 		}
 
-		if (spl_decompression_enabled() &&
-		    (image_comp == IH_COMP_GZIP || image_comp == IH_COMP_LZMA))
-			src_ptr = map_sysmem(ALIGN(CONFIG_SYS_LOAD_ADDR, ARCH_DMA_MINALIGN), len);
+		if (needs_decomp || encrypted)
+			src_ptr = map_sysmem(ALIGN(CONFIG_SYS_LOAD_ADDR,
+						   ARCH_DMA_MINALIGN), len);
 		else
-			src_ptr = map_sysmem(ALIGN(load_addr, ARCH_DMA_MINALIGN), len);
+			src_ptr = map_sysmem(ALIGN(load_addr, ARCH_DMA_MINALIGN),
+					     len);
 		length = len;
 
 		overhead = get_aligned_image_overhead(info, offset);
@@ -331,10 +383,38 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
 		puts("OK\n");
 	}
 
+	load_ptr = map_sysmem(load_addr, length);
+	if (encrypted) {
+		void *decrypt_ptr;
+
+		if (needs_decomp) {
+			if (external_data)
+				decrypt_ptr = src;
+			else
+				decrypt_ptr = map_sysmem(ALIGN(CONFIG_SYS_LOAD_ADDR,
+							       ARCH_DMA_MINALIGN),
+							 length);
+		} else if (external_data) {
+			if (spl_fit_ranges_overlap((ulong)load_ptr, length,
+						   (ulong)src, length))
+				decrypt_ptr = map_sysmem(ALIGN((ulong)src + length,
+							       ARCH_DMA_MINALIGN),
+							 length);
+			else
+				decrypt_ptr = load_ptr;
+		} else {
+			decrypt_ptr = load_ptr;
+		}
+
+		ret = spl_fit_image_decrypt(fit, node, cipher_node, &src, &length,
+					    decrypt_ptr);
+		if (ret)
+			return ret;
+	}
+
 	if (CONFIG_IS_ENABLED(FIT_IMAGE_POST_PROCESS))
 		board_fit_image_post_process(fit, node, &src, &length);
 
-	load_ptr = map_sysmem(load_addr, length);
 	if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) {
 		size = length;
 		if (gunzip(load_ptr, CONFIG_SYS_BOOTM_LEN, src, &size)) {
-- 
2.53.0



More information about the U-Boot mailing list