Verified Boot and FIT Image for Jetson Nano

We had been trying to get our TPM to work with SPI2 in uboot to provide security for FDE. However we have hit some roadblocks that have kept us from doing so. Our next best option is to extend the root of trust by using Verified Boot. This means we need to package our Kernel, Initrd, and FDT as a signed FIT Image.

I have started by not using signed images to just try and get the thing to boot. I am having an issue getting the FIT to boot as expected.

This is the fit-image.its file we are using:

/dts-v1/;

/ {
        description = "FIT image for Codename";
        #address-cells = <1>;

        images {
                kernel {
                        description = "Linux";
                        data = /incbin/("Image");
                        type = "kernel";
                        arch = "arm";
                        os = "linux";
                        compression = "none";
                        load = <0x84000000>;
                        entry = <0x84000000>;
                        hash-1 {
                                algo = "sha256";
                        };
                };

                initrd {
                        description = "Initrd";
                        data = /incbin/("initrd");
                        type = "ramdisk";
                        arch = "arm";
                        os = "linux";
                        compression = "none";
                        load = <0x83200000>;
                        entry = <0x83200000>;
                        hash-1 {
                                algo = "sha256";
                        };
                };

                fdt {
                        description = "DTB";
                        data = /incbin/("kernel_tegra210-p3448-0002-p3449-0000-b00.dtb");
                        type = "flat_dt";
                        arch = "arm";
                        compression = "none";
                        load = <0x83000000>;
                        entry = <0x83000000>;                        hash-1 {
                                algo = "sha256";
                        };
                };
        };

        configurations {
                default = "conf";

                conf {
                        description = "Config";
                        kernel = "kernel";
                        ramdisk = "initrd";
                        fdt = "fdt";
                };
        };
};

I used copied our Image, Initrd, and DTB to the same directory and ran:

$LINUX_FOR_TEGRA_DIR/sources/u-boot/tools/mkimage -f fit-image.its FitImage

This generates the FitImage binary that can be checked with mkimage -l:

sudo ../sources/u-boot/tools/mkimage -l FitImage 
FIT description: FIT image for Codename
Created:         Thu Nov 17 22:53:26 2022
 Image 0 (kernel)
  Description:  Linux
  Created:      Thu Nov 17 22:53:26 2022
  Type:         Kernel Image
  Compression:  uncompressed
  Data Size:    33892360 Bytes = 33098.01 KiB = 32.32 MiB
  Architecture: ARM
  OS:           Linux
  Load Address: 0x84000000
  Entry Point:  0x84000000
  Hash algo:    sha256
  Hash value:   7bc16c4173f179d71efb2d872bba5ca8cd2d30d969396f6c1911ac37b11d91d2
 Image 1 (initrd)
  Description:  Initrd
  Created:      Thu Nov 17 22:53:26 2022
  Type:         RAMDisk Image
  Compression:  uncompressed
  Data Size:    13919184 Bytes = 13592.95 KiB = 13.27 MiB
  Architecture: ARM
  OS:           Linux
  Load Address: 0x83200000
  Entry Point:  0x83200000
  Hash algo:    sha256
  Hash value:   de20057ea88c89284577bf409ecf71aa24f757971d57ced51cbad185ee5602e6
 Image 2 (fdt)
  Description:  DTB
  Created:      Thu Nov 17 22:53:26 2022
  Type:         Flat Device Tree
  Compression:  uncompressed
  Data Size:    221698 Bytes = 216.50 KiB = 0.21 MiB
  Architecture: ARM
  Load Address: 0x83000000
  Hash algo:    sha256
  Hash value:   7c6a2a9454449d7732a7c4a83dea0d0eef2007bd8d2a0d4587d31469ee2d2179
 Default Configuration: 'conf'
 Configuration 0 (conf)
  Description:  Config
  Kernel:       kernel
  Init Ramdisk: initrd
  FDT:          fdt

I added the following to the uboot config:

CONFIG_RSA=y
CONFIG_FIT=y
CONFIG_FIT_EXTERNAL_OFFSET=0x0
CONFIG_FIT_ENABLE_SHA256_SUPPORT=y
CONFIG_FIT_SIGNATURE=y
CONFIG_FIT_SIGNATURE_MAX_SIZE=0x10000000
CONFIG_USE_BOOTARGS=y
CONFIG_BOOTARGS="root=UUID=5d9904fa-9ca0-4869-b53c-4244b931e0cc rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 sdhci_tegra.en_boot_part_access=1 fsck.mode=force fsck.repair=yes rng_core.default_quality=1000"

I added the public key info to (but again, not requiring signatures yet)

/ {
    signature {
        key-dev {

I bumped the bootm size to 64MB as well.

I have CONFIG_LEGACY_IMAGE_FORMAT=y for now to support this test process.

When I flash the update uboot to LNX and add the FitImage binary blob to /boot I try and boot to it by doing the following:

ext4load mmc 0 0x95000000 /boot/FitImage
bootm 0x95000000

I then get the following:

Tegra210 (P3450-0000) # ext4load mmc 0 0x95000000 /boot/FitImage
48035172 bytes read in 1100 ms (41.6 MiB/s)
Tegra210 (P3450-0000) #
Tegra210 (P3450-0000) # bootm 0x95000000
## Loading kernel from FIT Image at 95000000 ...
   Using 'conf' configuration
   Verifying Hash Integrity ... OK
   Trying 'kernel' kernel subimage
     Description:  Linux
     Type:         Kernel Image
     Compression:  uncompressed
     Data Start:   0x950000bc
     Data Size:    33892360 Bytes = 32.3 MiB
     Architecture: ARM
     OS:           Linux
     Load Address: 0x84000000
     Entry Point:  0x84000000
     Hash algo:    sha256
     Hash value:   7bc16c4173f179d71efb2d872bba5ca8cd2d30d969396f6c1911ac37b11d91d2
   Verifying Hash Integrity ... sha256+ OK
## Loading ramdisk from FIT Image at 95000000 ...
   Using 'conf' configuration
   Verifying Hash Integrity ... OK
   Trying 'initrd' ramdisk subimage
     Description:  Initrd
     Type:         RAMDisk Image
     Compression:  uncompressed
     Data Start:   0x970529b0
     Data Size:    13919162 Bytes = 13.3 MiB
     Architecture: ARM
     OS:           Linux
     Load Address: 0x83200000
     Entry Point:  0x83200000
     Hash algo:    sha256
     Hash value:   1da6bec88f93454fb27c8255d9e0ac92898721132d09222e9bc07e6ab8612bc0
   Verifying Hash Integrity ... sha256+ OK
   Loading ramdisk from 0x970529b0 to 0x83200000
## Loading fdt from FIT Image at 95000000 ...
   Using 'conf' configuration
   Verifying Hash Integrity ... OK
   Trying 'fdt' fdt subimage
     Description:  DTB
     Type:         Flat Device Tree
     Compression:  uncompressed
     Data Start:   0x97d98e50
     Data Size:    221698 Bytes = 216.5 KiB
     Architecture: ARM
     Load Address: 0x83000000
     Hash algo:    sha256
     Hash value:   7c6a2a9454449d7732a7c4a83dea0d0eef2007bd8d2a0d4587d31469ee2d2179
   Verifying Hash Integrity ... sha256+ OK
   Loading fdt from 0x97d98e50 to 0x83000000
   Booting using the fdt blob at 0x83000000
   Loading Kernel Image
ERROR: reserving fdt memory region failed (addr=0 size=0)
ERROR: reserving fdt memory region failed (addr=0 size=0)
   Using Device Tree in place at 0000000083000000, end 0000000083039201
copying carveout for /host1x@50000000/dc@54200000...
copying carveout for /host1x@50000000/dc@54240000...
DT property /chosen/nvidia,bluetooth-mac missing in source; can't copy
DT property /chosen/nvidia,wifi-mac missing in source; can't copy
DT property /psci/nvidia,system-lp0-disable missing in source; can't copy

Starting kernel ...

It halts after “Starting kernel …” and never continues. I used the same Image, Initrd, and FDT binaries we have successfully been booting to with the normal boot process. I took the addresses from the printenv variables of uboot for where it usually loads the kernel, initrd, and the fdt.

Does someone who has done this before have a clue that could point me in the right direction to get this working?

I also tried to just build the boot args into the kernel config with CONFIG_CMDLINE. However there is no difference in the result. I still fail to get passed “Starting kernel …”

hello jjsalzano,

Uboot already has a feature called Verified Boot. There is already a tool to sign the binary In Uboot source code.
you may see-also below for reference.
[U-Boot] Need help with verified u-boot on Tegra TX2
https://blog.crysys.hu/2018/06/verified-boot-on-the-raspberry-pi/

you may see-also similar discussion thread, Kernel encryption through Secureboot - #12 by JerryChang.
thanks

Hi @JerryChang,

I believe we are talking about the same Verified Boot.
If you see in my OP, we have configured uboot to support Verified Boot, and we have built the FIT Image and it is in /boot in the APP partition. The issue is that the whole boot process haults at “Starting kernel …” after calling bootm. If we use the legacy boot the same kernel image loads without issue, it is only when we try and boot from the FIT using bootm we see this. I have tried using the upstream uboot without success as well. What we will eventually want to do is make this happen automatically with a signed FIT config node, however we are just trying to get it booting first.

@TWarren,
Tom, sorry to tag you in a random thread, but as you helped us out a lot with our uboot issue already maybe you have some more tips for us here?

@jjsalzano

I’ve never used Verified Boot in U-Boot, sorry. But my first look would be at the addresses of ramdisk, fdt, kernel, etc. With a large boot image/kernel, they can often collide (i.e. kernel image overwrites some of the fdt image), and the kernel will hang when it tries to access the fdt. So check your sizes/addresses for everything (all the xx_addr_r env vars), and leave enough padding between them so that there are no unexpected overwrites. Load each component, check it’s start bytes in RAM, then load the next, check for overwrites of previous data, etc. You’ll need to change the load addresses either at the command prompt (for interactive loading), or via the defines in the common header file for that board. Also, IIRC there’s some way to turn on super-early kernel printfs so you can debug where it’s hanging during kernel init.

HTH,

Tom

@TWarren

I had been using the same addresses for FIT that has been working with legacy boot, but I will ext4load them each individually to make sure.

We have EarlyCon enabled. But I am trying to find what needs to change to get EARLY_PRINTK built into the kernel to hopefully help us.

Thanks, Joseph

Not seeing an issue with addresses (changed some addresses around for this latest test):

fit_image_print_data()      Hash len:     32
   Verifying Hash Integrity ... sha256+ OK
   Loading fdt from 0x97d98da8 to 0x83000000
boot_get_fdt_fit() fit_uname=fdt, fit_uname_config=conf
   Booting using the fdt blob at 0x83000000
boot_get_fdt()    of_flat_tree at 0x83000000 size 0x00036202
_do_env_set() Initial value for argc=3
_do_env_set() Final value for argc=3
   Loading Kernel Image
bootm_load_os()    kernel loaded at 0x80280000, end = 0x822d2808
boot_ramdisk_high() ## initrd_high = 0x8effffff, copy_to_ram = 1
   Loading Ramdisk to 8e2b9000, end 8efff301 ... OK
boot_ramdisk_high()    ramdisk load start = 0x8e2b9000, ramdisk load end = 0x8efff301
_do_env_set() Initial value for argc=3
_do_env_set() Final value for argc=3
_do_env_set() Initial value for argc=3
_do_env_set() Final value for argc=3
boot_prep_linux() using: FDT
boot_fdt_reserve_region()    reserving fdt memory region: addr=80000000 size=20000
boot_fdt_reserve_region()    reserving fdt memory region: addr=40001000 size=3f000
boot_fdt_reserve_region()    reserving fdt memory region: addr=b0000000 size=200000
ERROR: reserving fdt memory region failed (addr=0 size=0)
ERROR: reserving fdt memory region failed (addr=0 size=0)
boot_relocate_fdt() ## device tree at 0000000083000000 ... 0000000083036201 (len=233986 [0x39202])
   Loading Device Tree to 000000008e27f000, end 000000008e2b8201 ... OK

I think the kernel isn’t getting loaded correctly at all because nothing is printed to the console even with:

  • earlycon=uart8250,mmio32,0x70006000
  • earlyprintk=uart8250-32bit,0x70006000
  • ignore_loglevel

After a lot of testing yesterday and tonight I believe I found the issue. It is small, and something I should have seen before but it took a round about way to find it.

In case anyone else is trying to figure this out:
The issue was we were specifying “arm” as the architecture. Once I changed it to “arm64” I am now able to boot with “bootm 0x95000000”.

Our next steps is to change uboot to load and call bootm automatically and then test signatures.

Thank you @JerryChang and @TWarren for taking a look.

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.