I'm trying to use ECDSA (prime256v1) for signature verification in U-Boot (git tag "v2025.10"). I used the sample configuration from Verified Boot on the Beaglebone Black as a template. When using RSA-2048 to sign the FIT in u-boot, everything works as expected; booting with RSA signed image boots fine, but ECDSA signed image fails to boot as expected.
I copied the working RSA FIT its file and renamed it to "ec256fit.its"; I then modified the algo and key-name-hint fields for ECDSA:
/dts-v1/;
/ {
description = "Simple image with single Linux kernel and FDT blob";
#address-cells = <1>;
images {
kernel {
description = "Linux kernel";
data = /incbin/("./zImage");
type = "kernel";
arch = "arm";
os = "linux";
compression = "none";
load = <0x60100000>;
entry = <0x60100000>;
hash-1 {
algo = "sha256";
};
};
fdt-1 {
description = "Flattened Device Tree blob";
data = /incbin/("./vexpress-v2p-ca9.dtb");
type = "flat_dt";
arch = "arm";
compression = "none";
hash-1 {
algo = "sha256";
};
};
};
configurations {
default = "conf-1";
conf-1 {
description = "Boot Linux kernel with FDT blob";
kernel = "kernel";
fdt = "fdt-1";
signature-1 {
algo = "sha256,ecdsa256";
key-name-hint = "ec256";
sign-images = "fdt", "kernel";
};
};
};
};
I generated ECDSA keys using openssl:
openssl ecparam -name prime256v1 -genkey -out $KEY_DIR/ec256.key
openssl req -batch -new -x509 -key $KEY_DIR/ec256.key -out $KEY_DIR/ec256.crt
I then signed the image:
$UBOOT_DIR/tools/mkimage -f $IMAGE_DIR/fit/ec256fit.its -K $IMAGE_DIR/fit/vexpress-v2p-ca9-pub-ec256.dtb -k $KEY_DIR -r $IMAGE_DIR/fit/ec256signed.fit
Can not get key file '/home/james/Projects/system/images/keys/ec256.pem'
Failed to sign 'signature-1' signature node in 'conf-1' conf node
mkimage complained about not finding ec256.pem, so I created a symlink to ec256.key and ran mkimage again; this time no warnings or errors.
$ $UBOOT_DIR/tools/mkimage -f $IMAGE_DIR/fit/ec256fit.its -K $IMAGE_DIR/fit/vexpress-v2p-ca9-pub-ec256.dtb -k $KEY_DIR -r $IMAGE_DIR/fit/ec256signed.fit
FIT description: Simple image with single Linux kernel and FDT blob
Created: Thu Nov 20 12:35:56 2025
Image 0 (kernel)
Description: Linux kernel
Created: Thu Nov 20 12:35:56 2025
Type: Kernel Image
Compression: uncompressed
Data Size: 5818864 Bytes = 5682.48 KiB = 5.55 MiB
Architecture: ARM
OS: Linux
Load Address: 0x60100000
Entry Point: 0x60100000
Hash algo: sha256
Hash value: 112939b1e0884ac2e09ca11e6d5f9bf541b2cf3f7dd3a0e4259d5696caa7ebc0
Image 1 (fdt-1)
Description: Flattened Device Tree blob
Created: Thu Nov 20 12:35:56 2025
Type: Flat Device Tree
Compression: uncompressed
Data Size: 13728 Bytes = 13.41 KiB = 0.01 MiB
Architecture: ARM
Hash algo: sha256
Hash value: cc8806f7514eaf6e313bc0ac0f7758361a8ebd6ddb2ecb926047952eb252c762
Default Configuration: 'conf-1'
Configuration 0 (conf-1)
Description: Boot Linux kernel with FDT blob
Kernel: kernel
FDT: fdt-1
Sign algo: sha256,ecdsa256:ec256
Sign value: 533a1b08715c7d63e15e56d6195ea26144f7a08403793445b26524ff6db2d79942a52f75e0c82110d59846ef235278ccc3aa012ff3af1e825a365047d5782cad
Timestamp: Thu Nov 20 12:35:56 2025
Signature written to '/home/james/Projects/system/images/fit/ec256signed.fit', node '/configurations/conf-1/signature-1'
Public key written to '/home/james/Projects/system/images/fit/vexpress-v2p-ca9-pub-ec256.dtb', node '/signature/ec256'
It stated that the signature has been written to "ec256signed.fit" in node "/configurations/conf-1/signature-1" and the public key to "vexpress-v2p-ca9-pub-ec256.dtb". I verified that the public key was indeed in the dtb file by decompiling it into dts file:
...
signature {
ec256 {
required = "conf";
algo = "sha256,ecdsa256";
ecdsa,y-point = <0x3cf7b533 0x15e22ecd 0xa183a2d5 0x59504031 0x42ba7cbb 0xfd30b358 0x7d1820fb 0xee2587b>;
ecdsa,x-point = <0x86e2a451 0x12d94ee2 0x20c481c3 0x13fcfab3 0x3694b8e0 0x52d8a2aa 0xf2de6cd1 0x18377409>;
ecdsa,curve = "prime256v1";
key-name-hint = "ec256";
};
};
...
I verified the signed image:
$UBOOT_DIR/tools/fit_check_sign -f $IMAGE_DIR/fit/ec256signed.fit -k $IMAGE_DIR/fit/vexpress-v2p-ca9-pub-ec256.dtb
Loading ECDSA key: curve=prime256v1, bits=256
Successfully loaded ECDSA key from FDT node 172
Verifying Hash Integrity for node 'conf-1'... sha256,ecdsa256:ec256+
Verified OK, loading images
## Loading kernel (any) from FIT Image at 7163ca400000 ...
Using 'conf-1' configuration
Verifying Hash Integrity ...
Loading ECDSA key: curve=prime256v1, bits=256
Successfully loaded ECDSA key from FDT node 172
sha256,ecdsa256:ec256+
OK
Trying 'kernel' kernel subimage
Description: Linux kernel
Created: Thu Nov 20 12:35:56 2025
Type: Kernel Image
Compression: uncompressed
Data Size: 5818864 Bytes = 5682.48 KiB = 5.55 MiB
Architecture: ARM
OS: Linux
Load Address: 0x60100000
Entry Point: 0x60100000
Hash algo: sha256
Hash value: 112939b1e0884ac2e09ca11e6d5f9bf541b2cf3f7dd3a0e4259d5696caa7ebc0
Verifying Hash Integrity ...
sha256+
OK
Decrypting Data ...
OK
Loading Kernel Image to 0
## Loading fdt (any) from FIT Image at 7163ca400000 ...
Using 'conf-1' configuration
Verifying Hash Integrity ...
Loading ECDSA key: curve=prime256v1, bits=256
Successfully loaded ECDSA key from FDT node 172
sha256,ecdsa256:ec256+
OK
Trying 'fdt-1' fdt subimage
Description: Flattened Device Tree blob
Created: Thu Nov 20 12:35:56 2025
Type: Flat Device Tree
Compression: uncompressed
Data Size: 13728 Bytes = 13.41 KiB = 0.01 MiB
Architecture: ARM
Hash algo: sha256
Hash value: cc8806f7514eaf6e313bc0ac0f7758361a8ebd6ddb2ecb926047952eb252c762
Verifying Hash Integrity ...
sha256+
OK
Decrypting Data ...
OK
Loading Flat Device Tree to 0
## Loading ramdisk (any) from FIT Image at 7163ca400000 ...
Using 'conf-1' configuration
Verifying Hash Integrity ...
Loading ECDSA key: curve=prime256v1, bits=256
Successfully loaded ECDSA key from FDT node 172
sha256,ecdsa256:ec256+
OK
Could not find subimage node type 'ramdisk'
Signature check OK
No error was reported, so I rebuilt the U-Boot using the checked dtb:
make clean && make O=b/vexpress_ca9x4 EXT_DTB=${IMAGE_DIR}/fit/vexpress-v2p-ca9-pub-ec256.dtb
The U-Boot .config file is as follows:
CONFIG_ECDSA=y
CONFIG_ECDSA_VERIFY=y
CONFIG_RSA=y
CONFIG_RSA_VERIFY=y
CONFIG_SHA256=y
CONFIG_FIT_VERBOSE=y
CONFIG_OF_LIBFDT=y
CONFIG_FIT=y
CONFIG_FIT_ENABLE_SHA256_SUPPORT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_OF_CONTROL=y
When I tried to load the signed image, I get the following error:
> load mmc 0:1 ${loadaddr} ec256signed.fit
5834321 bytes read in 2109 ms (2.6 MiB/s)
=> iminfo ${loadaddr}
## Checking Image at 61000000 ...
FIT image found
FIT description: Simple image with single Linux kernel and FDT blob
Image 0 (kernel)
Description: Linux kernel
Type: Kernel Image
Compression: uncompressed
Data Start: 0x610000e0
Data Size: 5818864 Bytes = 5.5 MiB
Architecture: ARM
OS: Linux
Load Address: 0x60100000
Entry Point: 0x60100000
Hash algo: sha256
Hash value: 112939b1e0884ac2e09ca11e6d5f9bf541b2cf3f7dd3a0e4259d5696caa7ebc0
Image 1 (fdt-1)
Description: Flattened Device Tree blob
Type: Flat Device Tree
Compression: uncompressed
Data Start: 0x6158cbd0
Data Size: 13728 Bytes = 13.4 KiB
Architecture: ARM
Hash algo: sha256
Hash value: cc8806f7514eaf6e313bc0ac0f7758361a8ebd6ddb2ecb926047952eb252c762
Default Configuration: 'conf-1'
Configuration 0 (conf-1)
Description: Boot Linux kernel with FDT blob
Kernel: kernel
FDT: fdt-1
Sign algo: sha256,ecdsa256:ec256
Sign value: 533a1b08715c7d63e15e56d6195ea26144f7a08403793445b26524ff6db2d79942a52f75e0c82110d59846ef235278ccc3aa012ff3af1e825a365047d5782cad
## Checking hash(es) for FIT Image at 61000000 ...
Hash(es) for Image 0 (kernel): sha256+
Hash(es) for Image 1 (fdt-1): sha256+
=> bootm ${loadaddr}
## Loading kernel (any) from FIT Image at 61000000 ...
Using 'conf-1' configuration
Verifying Hash Integrity ... sha256,ecdsa256:ec256- error!
Verification failed for '<NULL>' hash node in 'conf-1' config node
Failed to verify required signature 'ec256'
Bad Data Hash
ERROR -2: can't get kernel image!
I can no longer boot using the RSA signed image; this implies that the public key and signatures have been updated in the U-Boot as well. The iminfo command shows the signature value that matches the signature from fit_check_sign command. Seems like the fit image file contains the signature, but U-Boot is unable to verify it because the public key wasn't extracted from the dtb file when I rebuilt U-Boot.