fit_check_sig not hashing everything.

I am running fit_check_sig on windows to understand in more details how it works.
What I really want, is a _precise_ description of exactly which bytes of a FIT image are fed into the hash function (and in which order) in order to calculate the hash value. I then want to reproduce that hash function in python (using the "fdt" module) in order to sign the FIT image offline. I am expecting to have to reverse engineer this description (signature.txt isn't nearly detailed enough for me), and that's fine (although if anyone wants to prove me wrong, that would be wonderful).
I have a 30MB FIT image as input, and I have added some debug to hash_calculate in rsa-checksum.c to print the amount of data being hashed. The answer is a rather scary "1106 bytes"! The good news is that I have also added debug to print out the offset within the FIT image of the regions being hashed (actually in fit_config_check_sig in image-sig.c), and used this to zero a single byte of the FIT image well away from the offsets (allegedly) being hashed - and the verification fails (yay!). So clearly I don't understand what is going on (!).
Can anyone clarify what is happening?
One slightly strange thing I notice is that fit_config_check_sig appears to be called four! times.
I am working with 2020.1, and cannot easily upgrade to the latest because the signature nodes contain @.
Debug: Verifying Hash Integrity ... In fit_config_verify MJB fit_config_verify_required_sigs In fit_config_verify_sig MJB Verifying signature for node hash@1 MJB Verifying signature for node signature@1 sha256,rsa4096:ultra-insecure Verifying 8 regions: 00 00 00 01 00 00 00 00 00 00 00 03 00 00 00 04 (offset=38 len=180) 00 00 00 03 00 00 00 07 00 00 00 30 6B 65 72 6E (offset=4cee04 len=244) hash@1 region (offset=4d5b30 len=176) 00 00 00 03 00 00 00 08 00 00 00 30 72 61 6D 64 (offset=1d4d7b4 len=184) 00 00 00 01 63 6F 6E 66 40 31 00 00 00 00 00 03 (offset=1d4d880 len=124) 00 00 00 02 00 00 00 01 73 69 67 6E 61 74 75 72 (offset=1d4d910 len=20) 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00 02 (offset=1d4dc70 len=20) 64 65 73 63 72 69 70 74 69 6F 6E 00 6E 73 68 69 (offset=1d4dc84 len=158) Total bytes hashed = 1106+ ## Loading kernel from FIT Image at 6ffffe2b0000 ... Using 'conf@1' configuration Verifying Hash Integrity ... In fit_config_verify MJB fit_config_verify_required_sigs In fit_config_verify_sig MJB Verifying signature for node hash@1 MJB Verifying signature for node signature@1 sha256,rsa4096:ultra-insecure Verifying 8 regions: 00 00 00 01 00 00 00 00 00 00 00 03 00 00 00 04 (offset=38 len=180) 00 00 00 03 00 00 00 07 00 00 00 30 6B 65 72 6E (offset=4cee04 len=244) hash@1 region (offset=4d5b30 len=176) 00 00 00 03 00 00 00 08 00 00 00 30 72 61 6D 64 (offset=1d4d7b4 len=184) 00 00 00 01 63 6F 6E 66 40 31 00 00 00 00 00 03 (offset=1d4d880 len=124) 00 00 00 02 00 00 00 01 73 69 67 6E 61 74 75 72 (offset=1d4d910 len=20) 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00 02 (offset=1d4dc70 len=20) 64 65 73 63 72 69 70 74 69 6F 6E 00 6E 73 68 69 (offset=1d4dc84 len=158) Total bytes hashed = 1106+ OK
Trying 'kernel@0' kernel subimage Description: Linux Kernel Created: Mon Apr 4 09:12:26 2022 Type: Kernel Image Compression: gzip compressed Data Size: 5041417 Bytes = 4923.26 KiB = 4.81 MiB Architecture: PowerPC OS: Linux Load Address: 0x00000000 Entry Point: 0x00000000 Hash algo: sha256 Hash value: d36fb92a4af6184ddb42619691323f8b45f84fdb77f5cc65d0d0cebd115eb6f3 Verifying Hash Integrity ... sha256+ OK
Uncompressing Kernel Image Unimplemented compression type 1 ## Loading fdt from FIT Image at 6ffffe2b0000 ... Using 'conf@1' configuration Verifying Hash Integrity ... In fit_config_verify MJB fit_config_verify_required_sigs In fit_config_verify_sig MJB Verifying signature for node hash@1 MJB Verifying signature for node signature@1 sha256,rsa4096:ultra-insecure Verifying 8 regions: 00 00 00 01 00 00 00 00 00 00 00 03 00 00 00 04 (offset=38 len=180) 00 00 00 03 00 00 00 07 00 00 00 30 6B 65 72 6E (offset=4cee04 len=244) hash@1 region (offset=4d5b30 len=176) 00 00 00 03 00 00 00 08 00 00 00 30 72 61 6D 64 (offset=1d4d7b4 len=184) 00 00 00 01 63 6F 6E 66 40 31 00 00 00 00 00 03 (offset=1d4d880 len=124) 00 00 00 02 00 00 00 01 73 69 67 6E 61 74 75 72 (offset=1d4d910 len=20) 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00 02 (offset=1d4dc70 len=20) 64 65 73 63 72 69 70 74 69 6F 6E 00 6E 73 68 69 (offset=1d4dc84 len=158) Total bytes hashed = 1106+ OK
Trying 'fdt@0' fdt subimage Description: Flattened Device Tree blob Created: Mon Apr 4 09:12:26 2022 Type: Flat Device Tree Compression: uncompressed Data Size: 27691 Bytes = 27.04 KiB = 0.03 MiB Architecture: PowerPC Hash algo: sha256 Hash value: 0a62bdfb741bc77de5a9d1104f311031f8ac33ec909943c17f2860903121a239 Verifying Hash Integrity ... sha256+ OK
Loading Flat Device Tree ## Loading ramdisk from FIT Image at 6ffffe2b0000 ... Using 'conf@1' configuration Verifying Hash Integrity ... In fit_config_verify MJB fit_config_verify_required_sigs In fit_config_verify_sig MJB Verifying signature for node hash@1 MJB Verifying signature for node signature@1 sha256,rsa4096:ultra-insecure Verifying 8 regions: 00 00 00 01 00 00 00 00 00 00 00 03 00 00 00 04 (offset=38 len=180) 00 00 00 03 00 00 00 07 00 00 00 30 6B 65 72 6E (offset=4cee04 len=244) hash@1 region (offset=4d5b30 len=176) 00 00 00 03 00 00 00 08 00 00 00 30 72 61 6D 64 (offset=1d4d7b4 len=184) 00 00 00 01 63 6F 6E 66 40 31 00 00 00 00 00 03 (offset=1d4d880 len=124) 00 00 00 02 00 00 00 01 73 69 67 6E 61 74 75 72 (offset=1d4d910 len=20) 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00 02 (offset=1d4dc70 len=20) 64 65 73 63 72 69 70 74 69 6F 6E 00 6E 73 68 69 (offset=1d4dc84 len=158) Total bytes hashed = 1106+ OK
Trying 'ramdisk@0' ramdisk subimage Description: RAMDisk Created: Mon Apr 4 09:12:26 2022 Type: RAMDisk Image Compression: uncompressed Data Size: 25656264 Bytes = 25054.95 KiB = 24.47 MiB Architecture: PowerPC OS: Linux Load Address: unavailable Entry Point: unavailable Hash algo: sha256 Hash value: e3ed2c68781d674eaadc2b6c9cf1649df479bf06e655a81bcbc3fa1a01eaecb5 Verifying Hash Integrity ... sha256+ OK
Loading RAMDisk Image Signature check OK
ITB converted to ITS (and mostly redacted) /dts-v1/; // version: 17 // last_comp_version: 16 // boot_cpuid_phys: 0x0
/ { timestamp = <0x624AA86A>; description = "Boot Image for board"; board-version = "13.2.2-101-3a98c931"; #address-cells = <0x1>; images { kernel@0 { description = "Linux Kernel"; data = [1F 8B 08 00 00 00 00 00 02 03 B4 7D 0B 58 54 47 ... ]; type = "kernel"; arch = "ppc"; os = "linux"; compression = "gzip"; load = <0x0>; entry = <0x0>; hash@1 { value = <0xD36FB92A 0x4AF6184D 0xDB426196 0x91323F8B 0x45F84FDB 0x77F5CC65 0xD0D0CEBD 0x115EB6F3>; algo = "sha256"; }; }; fdt@0 { description = "Flattened Device Tree blob"; data = [D0 0D FE ED 00 00 6C 2B 00 00 00 38 00 00 65 4C ... ]; type = "flat_dt"; arch = "ppc"; compression = "none"; hash@1 { value = <0xA62BDFB 0x741BC77D 0xE5A9D110 0x4F311031 ...>; algo = "sha256"; }; }; ramdisk@0 { description = "RAMDisk"; data = <0xFD377A58 0x5A000001 0x6922DE36 0x4C0E2D5 ... ]; type = "ramdisk"; arch = "ppc"; os = "linux"; compression = "none"; hash@1 { value = <0xE3ED2C68 0x781D674E 0xAADC2B6C 0x9CF1649D 0xF479BF06 0xE655A81B 0xCBC3FA1A 0x1EAECB5>; algo = "sha256"; }; }; }; configurations { default = "conf@1"; conf@1 { description = "Boot Linux kernel"; kernel = "kernel@0"; fdt = "fdt@0"; ramdisk = "ramdisk@0"; hash@1 { algo = "sha256"; }; signature@1 { hashed-strings = <0x0 0x9E>; hashed-nodes = "/", "/configurations/conf@1", "/images/kernel@0", "/images/kernel@0/hash@1", "/images/fdt@0", "/images/fdt@0/hash@1", "/images/ramdisk@0", "/images/ramdisk@0/hash@1"; timestamp = <0x624AA86A>; signer-version = "2020.01"; signer-name = "mkimage"; value = <0x660296EF 0xBFAC0948 0x9B43B4F8 0x3958264D 0x39ECE2A9 0xBF14C100 0xD95DD7D5 0x12525F7F 0x26399A47 0xDFA68CA8 0x80625098 0xF303AAC2 0xFE5EAA79 0x69B3264F 0x25BDB130 0x2DA1F423 0xBBD74859 0x2C7CB1A8 0x0BE7668C 0x05A112A2 0x172BA7B1 0x616EE4C2 0xE8C93859 0x05480848 0xAF5C0F8C 0xF8E0C529 0xC87ED77E 0xDADCB9AE 0x4CE2D7EA 0x54D07A8B 0xFF2715AD 0x0C177059 0x2BCCF6EF 0x93511BCA 0xDA0C16DC 0x88366F70 0x1C606BDA 0x9F6C674C 0x4E328990 0x079DC349 0x3ED2FA6E 0x8E2BFB4E 0x96FE25B9 0x4EC9C0B7 0x49D30DE7 0x98F3FABF 0xBEEC8B9B 0xE35C90DE 0x4FB4586B 0xC6952B5B 0x5539C6B9 0xAF21EA3B 0xB0F12811 0x8AF9A242 0x874658CC 0x9517C652 0xCD062B2D 0x3996FEFF 0xE8B03199 0x9333C8AC 0xEDC8F71F 0x9023AC8A 0x38D00EEB 0x0D171F03 0xDD69CCFF 0x95DEE34F 0x394221DF 0xC04EFC49 0xC3191285 0xBFFA0040 0xDFD683B7 0x53614E59 0x35365737 0x0315F22E 0x198557D7 0x1E2D2EEA 0xA444E500 0x2F54A246 0x781E3B92 0x24D5AEB8 0xEF48F5F7 0x66CAF896 0xAAAAD3E8 0xAB5B8D70 0x9D37AA44 0xB517F759 0x5F6ACA9F 0x27F3F380 0x1404A32E 0x94092308 0x1D920C89 0x4B2B3C1E 0x07BEB532 0x6A6D2BD6 0xC86E5896 0x8708BDCD 0xA70AB635 0x03568CED 0x133554DC 0x208730FC 0xEB2FF6F5 0xECA89FA1 0x8F87746F 0xEC250C3D 0xEA8A403F 0x3302323F 0xA29DA5E1 0xDF9B0198 0xB9B97C3F 0x670E286F 0xEEB58FC5 0xB5DE060B 0xCD027B2B 0x85C566E1 0x0D2ABDFF 0xC9FF7372 0x0D7CEAAB 0x9F91DF92 0x207D7E68 0x967A8C1A 0xD6FFE56B 0x79F1DB3F 0x09BD8FCE 0xD8ABB47C 0x4E26BA36 0x0377465A 0x82573591 0x280D6E89>; algo = "sha256,rsa4096"; key-name-hint = "ultra-insecure"; sign-images = "kernel", "fdt", "ramdisk"; }; }; }; };
Martin

On Thu, 7 Jul 2022 at 17:29, Martin Bonner martingreybeard@gmail.com wrote:
I have a 30MB FIT image as input, and I have added some debug to hash_calculate in rsa-checksum.c to print the amount of data being hashed. The answer is a rather scary "1106 bytes"! ...
Can anyone clarify what is happening?
Never mind. I have found fit_image_check_hash in image-fit.c (yay for gdb read watchpoints!) So the algorithm is basically "verify that the hashes of each image is correct", then calculate a hash which includes the hashes of the images (but not their data), and sign that. (I think it's overcomplicated, and complexity is the enemy of security - but it's much too late to change that.)
Martin

Hi Martin,
On Fri, 8 Jul 2022 at 01:11, Martin Bonner martingreybeard@gmail.com wrote:
On Thu, 7 Jul 2022 at 17:29, Martin Bonner martingreybeard@gmail.com wrote:
I have a 30MB FIT image as input, and I have added some debug to hash_calculate in rsa-checksum.c to print the amount of data being hashed. The answer is a rather scary "1106 bytes"! ...
Can anyone clarify what is happening?
Never mind. I have found fit_image_check_hash in image-fit.c (yay for gdb read watchpoints!) So the algorithm is basically "verify that the hashes of each image is correct", then calculate a hash which includes the hashes of the images (but not their data), and sign that. (I think it's overcomplicated, and complexity is the enemy of security - but it's much too late to change that.)
Some reasons: - it is faster to hash things only once (i.e. use the image hash we already have) - It is faster to hash smaller things (i.e. the meta data)
This of this as a tree of hashes...
Regards, Simon
participants (2)
-
Martin Bonner
-
Simon Glass