This post intends to provide all the information you need to understand and use the HAB on your Boundary Devices’ platform.
The goal is also to provide an update on our older blog post on the subject as it required an old U-Boot version. Since then, HAB support has been added to mainline U-Boot and encryption is now possible on top of binary signature.
For simplicity and clarity, this guide and examples have been made on i.MX6Q Nitrogen6x so it applies to most our i.MX6 platforms.
However, for i.MX6SX Nit6_SoloX and i.MX7D Nitrogen7 some changes must be made because the fuse map and the RAM start address are different. Please contact us for instructions on those two platforms.
Vulnerability Errata: It has been disclosed by NXP that as of today (July 2017), all our i.MX-based platforms are vulnerable:
The Boot ROM on certain affected devices has been subsequently updated to prevent these vulnerabilities.
Please contact your NXP Support/ Sales representative for further information on mitigations or ordering revised silicon.
Prerequisites
- Code Signing Tools (CST)
- Account required on NXP website
- https://www.nxp.com/webapp/sps/download/license.jsp?colCode=IMX_CST_TOOL
- Provides valuable documentation
- U-Boot source code
- See latest branch from U-Boot repo
- https://github.com/boundarydevices/u-boot-imx6/tree/boundary-v2016.03
- Boundary Devices’ platform
- Any of the platforms from our store
- Patience & focus
- If you miss a step, this can brick your platform for good
- You’ve been WARNED!
HAB architecture
Before getting started, let’s explain a few acronyms related to this subject
- CSF: Command Sequence File
- CST: Code-Signing Tool
- DCD: Device Configuration Data
- DEK: Data Encryption Key
- HAB: High Assurance Boot
- IVT: Image Vector Table
- SRK: Super Root Key
The HAB library is a sub-component of the boot ROM on i.MX processors. It is responsible for verifying the digital signatures included as part of the product software and ensures that, when the processor is configured as a secure device, no unauthenticated code is allowed to run.
On processors supporting the feature, encrypted boot may also be used to provide image cloning protection and, depending on the use case, image confidentiality. The HAB library can not only be used to authenticate the first stage of the boot chain, but the other components of the boot chain as well such as the Linux kernel.
In short, enabling HAB/secure boot on your platform prevents hackers to alter the boot process, making sure only the software you have previously signed/approved can be ran. The ROM and HAB cannot be changed so they can be considered as trusted software components.
First, i.MX Boot ROM reads the eFuses to determine the security configuration of the SoC and the type of the boot device.
The ROM then loads the bootloader image to DDR memory. The image contains both the bootloader itself and digital signature data and public key certificate data which are collectively called CSF data. This latter is generated off-line using the HAB CST which is introduced in the next section.
Once the bootloader is loaded, execution is then passed to the HAB library which will verify the signatures of the bootloader stage. If signature verification fails, execution is not allowed to leave the ROM for securely configured SoCs, also called “closed” devices.
So as long as a device is not “closed”, the ROM will execute the code loaded in RAM. However, with an “open” device, you will be able to see HAB events which will tell you if the image would pass the authentication process. This last statement is very important since this is what will allow us to make sure the security is working before “closing” the device.
In order to understand the signed image generation, it is best to have a look at the final U-Boot image layout.
In case you want to use the encryption capability, then the image would look like the following.
Note that all the addresses in the previous diagrams are dependent on U-Boot size and therefore do not necessarily match your setup, it is more for an example.
How to enable/use it?
The below procedure will describe an example on how it has been done on one Nitrogen6x, make sure to modify the serial/password/keys values by your own!
1- Creation of the keys
First you need to unpack the Code Siging Tools package from NXP:
1 2 | ~$ tar xzf cst-2.3.2. tar .gz ~$ cd cst-2.3.2 /keys |
Then a couple of files need to be created, the first one being name ‘serial’ with an 8-digit content. OpenSSL uses the contents of this file for the certificate serial numbers.
1 2 | ~ /cst-2 .3.2 /keys $ vi serial 42424242 |
Create a file called ‘key_pass.txt’ that contains your pass phrase that will protect the HAB code signing private keys.
The format of this file is the pass phase repeated on the first and second lines of the file.
1 2 3 | ~ /cst-2 .3.2 /keys $ vi key_pass.txt Boundary123! Boundary123! |
You can now create the signature keys.
1 2 3 4 5 6 7 8 9 | ~ /cst-2 .3.2 /keys $ . /hab4_pki_tree .sh ... Do you want to use an existing CA key (y /n )?: n Do you want to use Elliptic Curve Cryptography (y /n )?: n Enter key length in bits for PKI tree: 4096 Enter PKI tree duration (years): 10 How many Super Root Keys should be generated? 4 Do you want the SRK certificates to have the CA flag set ? (y /n )?: y ... |
Create the fuse table and binary to be flashed later.
1 2 3 4 5 6 | ~ /cst-2 .3.2 /keys $ cd .. /crts/ ~ /cst-2 .3.2 /crts $ .. /linux64/srktool -h 4 -t SRK_1_2_3_4_table.bin -e SRK_1_2_3_4_fuse.bin -d sha256 -c \ . /SRK1_sha256_4096_65537_v3_ca_crt .pem,. /SRK2_sha256_4096_65537_v3_ca_crt .pem,. /SRK3_sha256_4096_65537_v3_ca_crt .pem,. /SRK4_sha256_4096_65537_v3_ca_crt .pem -f 1 ~ /cst-2 .3.2 /crts $ hexdump -C SRK_1_2_3_4_fuse.bin 00000000 c2 64 a0 72 56 49 82 69 59 60 96 63 15 20 84 04 |.d.rVI.iY`.c. ..| 00000010 0e 88 6a 41 3b 45 33 f5 28 6c 30 23 6e 36 2c 8e |..jA;E3.(l0 #n6,.| |
2- Flashing the keys
The fuse table generated in the previous section is what needs to be flashed to the device. However, the hexdump command above doesn’t show the values in their correct endianness, instead the command below will be more useful.
1 2 3 4 5 6 7 8 9 | ~ /cst-2 .3.2 /crts $ hexdump -e '/4 "0x"' -e '/4 "%X""\n"' < SRK_1_2_3_4_fuse.bin 0x72A064C2 0x69824956 0x63966059 0x4842015 0x416A880E 0xF533453B 0x23306C28 0x8E2C366E |
The above command gives you what needs to be flashed in the proper order.
The commands below are made for i.MX6QDL, not i.MX7D or i.MX6SX. Make sure to use your own values here, otherwise your board will never be able to authenticate the boot image.
1 2 3 4 5 6 7 8 | => fuse prog -y 3 0 0x72A064C2 => fuse prog -y 3 1 0x69824956 => fuse prog -y 3 2 0x63966059 => fuse prog -y 3 3 0x4842015 => fuse prog -y 3 4 0x416A880E => fuse prog -y 3 5 0xF533453B => fuse prog -y 3 6 0x23306C28 => fuse prog -y 3 7 0x8E2C366E |
If you flashed the above by mistake, without reading the note above, know that we share the set of keys used for this blog post:
As a customer pointed out, for i.MX6 CPU with the TO1.0 revision (pre-production), you also need to flash some random MasterKey (OTPMK):
1 2 3 | => fuse prog -y 2 0 0xdeadbeef ... => fuse prog -y 2 7 0xdadadada |
3- Build U-Boot with security features
Build U-Boot with the CONFIG_SECURE_BOOT configuration enabled. Here is an example for Nitrogen6q/BD-SL-iMX6:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ~$ git clone https: //github .com /boundarydevices/u-boot-imx6 \ -b boundary-v2016.03 ~$ cd u-boot-imx6 ~ /u-boot-imx6 $ export ARCH=arm ~ /u-boot-imx6 $ export CROSS_COMPILE=arm-linux-gnueabihf- ~ /u-boot-imx6 $ make nitrogen6q_defconfig ~ /u-boot-imx6 $ make menuconfig < select 'ARM architecture' - 'Support i.MX HAB features' > ~ /u-boot-imx6 $ make V=1 ... . /tools/mkimage -n board /boundary/nitrogen6x/nitrogen6q .cfg.cfgtmp -T imximage -e 0x17800000 -d u-boot.bin u-boot.imx Image Type: Freescale IMX Boot Image Image Ver: 2 (i.MX53 /6/7 compatible) Data Size: 512000 Bytes = 500.00 kB = 0.49 MB Load Address: 177ff420 Entry Point: 17800000 HAB Blocks: 177ff400 00000000 00078c00 |
Note that the last line “HAB Blocks” is very important when creating the .csf
file later on.
4.a- Sign a U-Boot image
If you just want to sign your binary, follow this section and then go straight to section 5. Otherwise, if you want to encrypt and sign your binary, jump to next section directly.
Go to the CST tools again:
1 2 | ~$ cd ~ /cst-2 .3.2 /linux64/ ~ /cst-2 .3.2 /linux64 $ cp ~ /u-boot-imx6/u-boot .imx . |
At this point you need to create a u-boot.csf file using the “HAB Blocks” information from previous section and the template provided in the HABCST_UG.pdf documentation which is provided in the CST package.
For more convenience, we created a .csf
file that applies to Nitrogen6x using latest U-Boot.
1 2 3 4 5 | ~ /cst-2 .3.2 /linux64 $ wget -O u-boot.csf \ https: //storage .googleapis.com /boundarydevices .com /u-boot_sign .csf ... edit the size in the "Blocks = " line... ~ /cst-2 .3.2 /linux64 $ . /cst --o u-boot_csf.bin --i u-boot.csf CSF Processed successfully and signed data available in u-boot_csf.bin |
You can now generate the final binary by concatenating the u-boot.imx
image with the CSF binary:
1 | ~ /cst-2 .3.2 /linux64 $ cat u-boot.imx u-boot_csf.bin > u-boot_signed.imx |
You can copy this binary to the root of an SD card along with 6x_upgrade
. Don’t forget that the name of the binary must match the platform name (see U-Boot blog post for the explanation).
1 | ~ /cst-2 .3.2 /linux64 $ cp u-boot_signed.imx /u-boot .nitrogen6q |
You can now flash this signed version of U-Boot, see section 5.
4.b- Encrypt and sign an image
First, the CST binary provided in the NXP package doesn’t allow to use encryption, so you need to build a new binary yourself:
1 2 3 | ~$ cd ~ /cst-2 .3.2 /code/back_end/src ~ /cst-2 .3.2 /code/back_end/src $ gcc -o cst_encrypt -I .. /hdr -L ../../.. /linux64/lib *.c -lfrontend -lcrypto ~ /cst-2 .3.2 /code/back_end/src $ cp cst_encrypt ../../.. /linux64/ |
Then you can download the .csf
we’ve prepared for encryption and build both the DEK blob and the CSF binary:
1 2 3 4 5 6 7 | ~$ cd ~ /cst-2 .3.2 /linux64/ ~ /cst-2 .3.2 /linux64 $ cp ~ /u-boot-imx6/u-boot .imx . ~ /cst-2 .3.2 /linux64 $ wget -O u-boot.csf \ https: //storage .googleapis.com /boundarydevices .com /u-boot_encrypt .csf ... edit the size in the "Blocks = " line... ~ /cst-2 .3.2 /linux64 $ . /cst_encrypt --o u-boot_csf.bin --i u-boot.csf CSF Processed successfully and signed data available in u-boot_csf.bin |
At this point, make sure to modify the csf file to match your binary:
- The
[Authenticate Data]
section must cover the IVT + DCD table size and NOT the padding- As an example:
Blocks = 0x177ff400 0x0 0x344 "u-boot.imx"
- As an example:
- The
[Decrypt Data]
section must cover the U-Boot data (after IVT + DCD + padding)- As an example:
Blocks = 0x17800000 0x00000C00 0x00078000 "u-boot.imx"
- As an example:
The above will produce the following binaries:
u-boot.imx
: encrypted version of u-bootu-boot_csf.bin
: CSF binarydek.bin
: DEK key that needs to be transformed into a blob- Each CPU generates a different blob!!
In order to generate the dek blob, the dek.bin
must be provided to a U-Boot dek tool which will compute the blob using the secrete and unique key from the specific CPU it is running on. The easiest approach is to copy the dek.bin
to the root of an sdcard and issue the following:
1 2 | => load mmc 0 10800000 dek.bin => dek_blob 0x10800000 0x10801000 128 |
Write this blob to SDCard, here is the procedure to write to a EXT4 partition:
1 | => ext4write mmc 0 0x10801000 /dek_blob .bin 0x48 |
Here is the equivalent for a FAT partition:
1 | => fatwrite mmc 0 0x10801000 dek_blob.bin 0x48 |
Once you’ve retrieved the dek_blob.bin
, you can generate the final signed & encrypted image. The cst_encrypt
binary tool generated earlier will sign the binary and encrypt its content in place.
1 2 3 | ~ /cst-2 .3.2 /linux64 $ objcopy -I binary -O binary --pad-to=0x1F00 \ --gap-fill=0x00 u-boot_csf.bin u-boot_csf.bin ~ /cst-2 .3.2 /linux64 $ cat u-boot.imx u-boot_csf.bin dek_blob.bin > u-boot_encrypt.imx |
Note that the CSF region in U-Boot header is set to 0x2000 whereas we pad it to 0x1F00. The reason is that this region also includes the dek_blob.bin
, otherwise the boot ROM won’t load the dek blob to memory.
As a result we have encrypted boot image which can be loaded and executed by only current board since dek_blob.bin
is unique per board/CPU.
Finally, you can copy this binary to the root of an SD card along with 6x_upgrade
. Don’t forget that the name of the binary must match the platform name (see U-Boot blog post for the explanation).
1 | ~ /cst-2 .3.2 /linux64 $ cp u-boot_encrypt.imx /u-boot .nitrogen6q |
5- Flash and test the device
Use the our standard procedure to update U-Boot:
1 | => run upgradeu |
The device should reboot, then check the HAB status:
1 2 3 4 | => hab_status Secure boot disabled HAB Configuration: 0xf0, HAB State: 0x66 No HAB Events Found! |
The Secure boot disabled means that the device is open. But still the HAB engine will check the image and report errors (Events) if the signature/encryption isn’t right.
6- Closing the device?
Once you are *absolutely* sure you’ve understood what has been done so far and that you are sure it works, you can “close” the device. Once again, this step is IRREVERSIBLE, better make sure there is no HAB Events in open configuration.
Below is the procedure to “close” the device on i.MX6QDL, for other devices such as the i.MX6SoloX or i.MX7D the fuse map most likely differ and requires another command.
1 | => fuse prog 0 6 0x2 |
Going further
What about imx_usb_loader?
As explained in the HAB application notes, it is possible to use the Serial Download Protocol (SDP) on close devices using the MFGTools.
Thanks to Jérémie Corbier from Prove&Run, support has been added to imx_usb_loader to load a signed binary. Make sure to use the HEAD of the master branch to have the best support from the imx_usb_loader tool.
As the documentation says, using SDP requires:
- Modify the .csf file in order to check the DCD tabled loaded in OCRAM
- Otherwise considered as a HAB error
- Sign the u-boot.imx binary with the DCD address set to 0 in the IVT header
- Since the SDP protocol clears the DCD table address
For the first modification to be done, simply add the following to your current
1 2 3 | [Authenticate Data] Verification index = 2 Blocks = 0x00910000 0x2C 0x318 "u-boot.imx" |
Note that you cant’ have several sets of Blocks
under one Authenticate Data
tag. Instead you need to declare as many Authenticate Data
sections as Blocks
you want to be verified.
You might be wondering how to get the DCD length from the binary? It is actually given in the DCD Header (see TRM section 8.7.2). Here is a command to extract it from the u-boot.imx
binary (courtesy of Eric Nelson):
1 | $ dd if =u-boot.imx bs=1 skip=45 count=2 | od -t x2 -A none --endian=big |
Then you need to get a custom script that allows to sign the binary without the DCD table address in the IVT header since it is cleared during the SDP boot process.
1 2 3 4 5 6 7 8 | ~ /cst-2 .3.2 /linux64 $ wget \ https: //storage .googleapis.com /boundarydevices .com /mod_4_mfgtool .sh ~ /cst-2 .3.2 /linux64 $ cp ~ /u-boot-imx6/u-boot .imx . ~ /cst-2 .3.2 /linux64 $ . /mod_4_mfgtool .sh clear_dcd_addr u-boot.imx ~ /cst-2 .3.2 /linux64 $ . /cst --o u-boot_csf.bin --i u-boot.csf ~ /cst-2 .3.2 /linux64 $ . /mod_4_mfgtool .sh set_dcd_addr u-boot.imx ~ /cst-2 .3.2 /linux64 $ cat u-boot.imx u-boot_csf.bin > u-boot_signed.imx ~ /cst-2 .3.2 /linux64 $ /imx_usb u-boot_signed.imx |
What about authenticating the kernel?
Now that your bootloader image is properly authenticated and that your device is secured, you can sign your kernel image so U-Boot ensures to load a known version. Here is a zImage
layout example:
The first thing to do is to generate the IVT file. We are providing a script that allows you to do so:
1 2 3 4 5 | ~ /cst-2 .3.2 /linux64 $ wget \ https: //storage .googleapis.com /boundarydevices .com /genIVT ~ /cst-2 .3.2 /linux64 $ cp ~ /linux-imx6/arch/arm/boot/zImage . ~ /cst-2 .3.2 /linux64 $ hexdump -C zImage | tail -n 1 ~ /cst-2 .3.2 /linux64 $ vi genIVT |
The hexdump
command above allows to learn the zImage
size. Then you can modify the genIVT
to reflect the proper sizes, in our example, the size of the zImage
was 0x468628 so the next 4kB boundary was 0x469000 as you can see in the genIVT
.
1 2 3 4 5 6 7 8 | ~ /cst-2 .3.2 /linux64 $ . /genIVT ~ /cst-2 .3.2 /linux64 $ hexdump ivt.bin 00000000 d1 00 20 41 00 10 80 10 00 00 00 00 00 00 00 00 00000010 00 00 00 00 00 90 c6 10 20 90 c6 10 00 00 00 00 00000020 ~ /cst-2 .3.2 /linux64 $ objcopy -I binary -O binary --pad-to=0x469000 \ --gap-fill=0x00 zImage zImage-pad.bin ~ /cst-2 .3.2 /linux64 $ cat zImage-pad.bin ivt.bin > zImage-pad-ivt.bin |
Then you can download the .csf
file for the zImage in order to create the CSF blob and generate the signed image:
1 2 3 4 5 | ~ /cst-2 .3.2 /linux64 $ wget \ https: //storage .googleapis.com /boundarydevices .com /zImage .csf ... edit the size in the "Blocks = " line... ~ /cst-2 .3.2 /linux64 $ . /cst --o zImage_csf.bin --i zImage.csf ~ /cst-2 .3.2 /linux64 $ cat zImage-pad-ivt.bin zImage_csf.bin > zImage_signed |
That’s it, you can now modify your U-Boot bootcmd so it includes the HAB command that checks the kernel:
1 2 3 4 5 6 7 | => load mmc 0 10800000 zImage_signed 4630872 bytes read in 438 ms (10.1 MiB /s ) => hab_auth_img 10800000 469000 Authenticate image from DDR location 0x10800000... Secure boot enabled HAB Configuration: 0xcc, HAB State: 0x99 No HAB Events Found! |
Boot time impact
We have not run any test to know how much impact HAB has on boot time yet.
Enabling the signature definitely increases the time it takes before U-Boot is loaded. Feel free to let us know if you have made some comparison.
References
- https://www.nxp.com/webapp/Download?colCode=IMX6DQ6SDLSRM
- https://community.nxp.com/docs/DOC-105916
- https://www.nxp.com/files/32bit/doc/app_note/AN4581.pdf
- https://www.nxp.com/files/training/doc/dwf/DWF13_AMF_IND_T0291.pdf
- https://boundarydevices.com/secure-boot-on-i-mx6-nitrogen6x-boards/
- https://community.nxp.com/docs/DOC-330622
- https://community.nxp.com/docs/DOC-332147
Hi,
Thank you very much for the elaborate post about HAB.
On a Nitrogen6_MAX board, I flashed the keys and installed a signed U-Boot image.
I did NOT “close” the board.
The “hab status” command replies “No HAB Events Found”. So I assume that the installation of U-Boot went well.
As a next step, I did the following from the U-Boot command line:
– loaded a signed Linux
– tried to authenticate the Linux image:
hab_auth_img 10800000 4d5000
but the reply was
“hab fuse not enabled”
Does that indicate that I have to “close” the board before being able to authenticate Linux?
Hi Edgar,
Yes that is what it means, you need to close the device to authenticate the kernel.
Regards,
Gary
Thank You!
Hi ! I’m trying to use the Serial Download Protocol to update a signed image of u-boot on the board, and I’m failing at the last step.
I’m using imx_sub from the merge of Jérémie Corbier’s work (85ecb0d7c28c2fd652aa0918ffc6abe1306b1db5). Nothing shows on the serial console.
Any idea what might goes wrong ?
Hi,
Please use the latest version from master. There’s been a few improvements since Jeremie’s series, especially if you use a 6SX or 7D CPU.
Regards,
Gary
Hi!
Why is the entry in the IVT set to 0x10801000 when we load the image to 0x10800000?
Thank you,
Elena
Thanks for the post.
I was able to succeeded with signed boot, after the I close the device
=> fuse prog 0 6 0x2
But board is not able to boot with non-secure or signed image
The last hab_status was:
=> hab_status
Secure boot disabled
HAB Configuration: 0xf0, HAB State: 0x66
<>
Hi,
It seems your message is missing the end, was the hab_status saying “No HAB Events Found!”?
Now that the device is closed, you can only boot signed u-boot images, as explained in the blog post.
Regards,
Gary
Hi Gary,
hab_status not saying ‘No HAB Events Found!’ before it listed HAB events (unfortunately I missed the log), now I’m unable to boot with signed or un-signed image.
Hi,
Well the article warns you (in RED) not to close if there are HAB events.
Have you used the same keys as ours or have you created your own? If the latter, I can’t help you, sorry.
I suggest you use a JTAG to load U-Boot and check (and solve) your events
Regards,
Gary
Hi Gary, Thanks for this excellent post. So even-though HAB Securing is done still the device is vulnerable for JTAG right ?
Anuradha
Hi Anuradha,
I actually never tried but yes I believe so.
However there’s a fuse available to disable JTAG completely (see fuse map), we recommend burning that fuse to avoid JTAG connections.
Regards,
Gary
As for JTAG, the Segger product does not support flash access (https://wiki.segger.com/IMX_Series_Devices) for the i.MX7. Debug support works, though.
The only recovery option is the USB OTG port.
Yes, doing that in fuses is possible (Y)
Btw on the u-boot image signing, after I flashed the signed image to the NOR (image is only signed, no encryption), I tried to re-flash an unsigned image using run upgradeu standard procedure. This unsigned image is just a general build. And the re-flashing did happen, how come this is possible ? Onlything I skipped was master fuse key burning.
Thanks
In other words, what would happen if we use ‘run upgradeu’ (along with a correctly signed u-boot image – with some modifications to IOs) in a closed device that already have a signed image flashed and that do not have any HAB Events ?
Thanks
Hi,
All the bootscripts, 6x_upgrade/bootscript, are not secure, so we highly recommend not using them.
Right now it doesn’t check the script signature, nor the 6x_upgrade checks the u-boot binary being flashed.
So if your binary is properly signed, good, upgradeu will update the NOR with it. But if your binary isn’t signed, the script will flash the NOR the same way.
Regards,
Gary
Hi,
I have used the same options with hab4_pki_tree.sh and I guess it will generate different keys for each try.
Hi Gary,
I’m trying now with SPL. and here is the log.
Log:
—–
U-Boot SPL 2017.05-rc2-00057-g89e52bc (Apr 24 2017 – 15:27:18)
Trying to boot from MMC1
hab fuse not enabled
U-Boot 2017.05-rc2-00057-g89e52bc (Apr 24 2017 – 15:27:18 +0530)
CPU: Freescale i.MX6Q rev1.2 at 792MHz
CPU: Industrial temperature grade (-40C to 105C) at 41C
Reset cause: POR
Model: Engicam i.CoreM6 Quad/Dual Starter Kit
…
Does SPL support HAB authentication?, seems like it’s not showing log message as ‘hab fuse not enabled’
thanks!
Jagan.
Hi Jagan,
Please do not post full logs here, use another site like pastebin instead.
To answer one question, yes SPL can support HAB signing.
However I can see that your platform is not from Boundary Devices so we won’t be able to help you any further, please ask the manufacturer of the board instead.
Regards,
Gary
Hi, could I check a few points about what I understand HAB to support:
When you say “we have encrypted boot image which can be loaded and executed by only current board since dek_blob.bin is unique per board/CPU” is that just when u-boot is not just signed but also encrypted? i.e. if not encrypted then one image *can* be used by multiple boards?
Enabling this secure booting and closing the device not only prevents booting of unsigned u-boot images but also prevents that signed u-boot from being able to boot an unsigned kernel image?
Would it be theoretically possible to use the u-boot commands to ‘dump’ the contents of the Linux rootfs [flash] partition? Is there a way around this – e.g. build a version of u-boot which doesn’t have the necessary command(s) for this?
Similarly, could JTAG be used to grab the rootfs contents, or does the securing process disable JTAG?
(Essentially my primary concern is preventing the installed rootfs from being read)
Thanks
Hi,
Yes signed (not encrypted) images can be used by multiple boards.
No closing the device doesn’t prevent unsigned kernel loading. Closing the device only modify the BootROM behavior, this latter is only in charge of loading U-Boot. Then what U-Boot does is only up to you, it can check the kernel image but it can also discard it.
Yes you can limit U-Boot not to be able to expose the block device but you’ll always need to be able to read it at least. One option is to remove the command prompt to make sure people can’t enter commands.
Yes there’s a way to disable JTAG by burning a fuse, please ask NXP for more details about it (or read fuse map + security manual).
Regards,
Gary
Hi, for a signed kernel image, is there a way to check the hab_authentication result in u-boot and if no events to boot the image ?
Thanks
Hi,
Have you checked the return value of the function? It should give you the ability to proceed or not with the boot.
Regards,
Gary
Hi.
When encrypting an image, where do you get the signed data length from (0x344 in the example above)?
Thanks,
Yuri
Hi Yuri,
U-Boot can actually give you that info when building by adding “V=1” to your make command:
$ make V=1
…
Image Type: Freescale IMX Boot Image
Image Ver: 2 (i.MX53/6/7 compatible)
Mode: DCD
Data Size: 540672 Bytes = 528.00 KiB = 0.52 MiB
Load Address: 177ff420
Entry Point: 17800000
HAB Blocks: 177ff400 00000000 00081c00
DCD Blocks: 00910000 0000002c 00000318
Regards,
Gary
Isn’t it necessary to pad u-boot as well, similarly to zImage? U-Boot padding is mentioned in doc/README.mxc_hab and some Freescale presentation. U-Boot signing without padding worked for me, but I’m now wondering if that’s a coincidence.
Thanks.
Hi,
Those are 2 different type of padding. The kernel padding is in place in order to align the CSF bin to a known address.
For U-Boot, the padding is for the CSF section to use the whole space reserved to it as set in the DCD.
It isn’t apparently absolutely necessary, we do it for the encryption use case since the dek needs to be aligned at the end.
Regards,
Gary
When programming the fuses on a Nitrogen7 board, it went well until bank #4:
=> fuse prog -y 3 3 0x19ACB300
Programming bank 3 word 0x00000003 to 0x19acb300…
=> fuse prog -y 3 4 0x66BAF931
Programming bank 3 word 0x00000004 to 0x66baf931…
mxc_ocotp fuse_prog(): Invalid argument
ERROR
In theory, it should “just work.” The Freescale docs (https://freescale.jiveon.com/docs/DOC-332725) show programming the fuses from within Linux for the iMX7D. Is there some caveat for the Nitrogen7?
Hi,
The offset are different for i.MX7D, so you should use the same procedure as NXP provides and flash from Linux.
The article will soon be updated to show in red that fuse commands only apply to i.MX6 since i.MX7 fuse map is completely different.
Regards,
Gary
Hi,
I’m trying to use the Serial Download Protocol to update a signed image of u-boot on the board, as was enabled by Corbier’s works.
u-boot starts with:
u-boot.imx.signed:dcd,jump header
but fails with:
u-boot.imx.signed:dcd
u-boot.imx.signed:jump header
and there is this error in the imx_usb output:
j4 in err=0, last_trans=64 33 18 c0 00
We need the latter in order to load kernel images before starting u-boot.
We are working with i.mx7d,
imx_usb commit f04f225ebc1c38e81eb24745333c8622deda6b49
Any ideas?
Thanks!
Ofer
I ran into the same thing. In [Authenticate Data] you need both lines from the mkimage output for “HAB Blocks” and “DCD Blocks.” Put both of those in, and then you should be OK.
I.e.,
HAB Blocks: 877ff400 00000000 0007bc00
DCD Blocks: 00910000 0000002c 000001cc
Should be:
[Authenticate Data]
Blocks = 0x877ff400 0x00000000 0x0007bc00 “u-boot.imx”, \
0x00910000 0x0000002c 0x000001cc “u-boot.imx”,
Hi,
Yes, the imx_usb_loader section says to add the DCD block to the previous CSF file used.
Also, in my case your [Authenticate Data] section wouldn’t work so I had to have 2 of them, one for DCD the other for the binary.
Regards,
Gary
Hi,
Following your answers, we tried several options, but it didn’t solve the issue.
1.
[Authenticate Data]
Verification index = 2
Blocks = 0x877ff400 0x000 0x58c00 “U-Boot-pad.bin”,\
0x00910000 0x2c 0x1d4 “U-Boot-pad.bin”
2.
[Authenticate Data]
Verification index = 2
Blocks = 0x877ff400 0x00000000 0x00058c00 “U-Boot-pad.bin”
Blocks = 0x00910000 0x0000002c 0x000001d4 “U-Boot-pad.bin”
What are we missing here?
Regards,
Ofer
Hi,
If you read the article and my answer carefully, you’ll see you need to *add* a new “Authenticate Data” entire section for it to work.
In your example you’ve only added one “Blocks” line. So Basically you take you .csf that worked for U-Boot, and you add the section as stated in the article above. Don’t try to merge them into 1 sections.
Regards,
Gary
Hi Gary,
Yes, we also try this:
[Authenticate Data]
Verification index = 2
Blocks = 0x00910000 0x2c 0x1d4 “U-Boot-pad.bin”
[Authenticate Data]
Verification index = 2
Blocks = 0x877ff400 0x000 0x58c00 “U-Boot-pad.bin”
But we got the same results.
Regards,
Ofer
Hi Ofer,
This worked fine here. Are you sure the “Blocks” addresses and sizes are correct?
Also, was it properly signed without the DCD address and then put back for loading it?
Regards,
Gary
Hi Gary,
Yes, we think it was signed properly (without the DCD address and then put back for loading).
We also think that the “Blocks” addresses and sizes are correct.
Please note that we are able to boot the u-boot when we use one line (u-boot.imx.signed:dcd,jump header)
We are also able to boot u-boot using mfg-tool.
Regards,
Ofer
Hi Ofer,
Sorry I was following up on Brian’s comment and how those blocks should be declared.
As for loading u-boot in several stages, we have tried to do that so far, maybe you should look into how mfgtools does that.
Regards,
Gary
Huh, curious. The manual (HABCST_UG.pdf, p. 37) shows that format in the examples, and it works with CST 2.3.2.
Hi Gary,
The just “signed” image works well without any HAB events. So I want to enable SDP for a custom u-boot (but based around u-boot 2016) we compiled for a custom board. Would the DCD address in custom u-boot.csf be different to the one shown here ? This is how my csf looks like :
[Authenticate Data]
Verification index = 2
Blocks = 0x00910000 0x2C 0x318 “u-boot.imx” #I checked the last parameter, and it’s same for custom u-boot
[Authenticate Data]
Verification index = 2
Blocks = 0x177ff400 0x0 0x77c00 “u-boot.imx” #based on my HAB block info
But after flashing, now I always get hab events, take a look at this :
https://pastebin.com/cM9RfJfP
What I am missing here ?
Thanks
Okay, to further clarify : Now in the board I have a signed, proper SDP enabled u-boot image. The HAB events appear when board is in normal mode. But when downloading the same signed and SDP enabled u-boot image through imx_usb_loader, all HAB events disappear ! Why is it ?
Anuradha
Hi,
Yes, since you need a modification for a u-boot image to work in SDP, that means that the same image can NOT be used for both SDP and normal boot since the signature process isn’t the same.
Regards,
Gary
I see in your example that you select a key length of 4096 bits, whilst some other docs (including, for example, AN4581) use 2048. I just wanted to check whether there’s any cases where 4096 can’t be used e.g. for different boards?
Thanks
Hi,
All the processors using HABv4 should support 4096-bit keys. For earlier versions however it might now.
Then it’s up to you, you can use 2048-bit just as well.
Regards,
Gary
Hi Gary,
We have tried to enable secure boot and able to achieve U-boot loader verified successfully with our keys fused in open configuration and also we were seeing no HAB events. Then we tried to check the kernel image signature verification but it requires device to be closed.
But after closing the device we are unable to get the u-boot prompt, Can you please point us out a way to recover. Thanks
Cheers
Manoj
Hi Manoj,
This happened to me when using encryption, do you use encryption?
The problem in my case ended up being the area in the .csf Blocks section that wasn’t covering the whole area. Are you sure about your values?
Also, what size of key to do you use (1024, 2048 or 4096)?
For future questions, please don’t post your logs here, instead use a pastebin-like website and send the link.
Regards,
Gary
Hi
To have a high assurance boot sequence all the way to a signed linux, is it also necessary to protect “bootcmd” and “6x_bootscript” by any means? If yes, how may this be done?
Thanks, Edgar
Hi,
Yes you can signed the 6x_bootscript just like you sign the uImage.
That being said, in a secure environment, we recommend you don’t use 6x_bootscript and have you environment setup in U-Boot directly (without saving it into NOR). Because having the environment exposed in the NOR is a flaw, someone could access it and modify the env from user-space.
Regards,
Gary
Hi Gary,
We were not using encryption, we only used the signatures. The .csf values are taken from the u-boot compilation which gives the HAB blocks output with start address, offset, size (HAB Blocks: 177ff400 00000000 0007ac00). In .csf we placed same value “Blocks = 0x177ff400 0x0 0x7ac00 “u-boot.imx” .
we were using key size of 4096.
https://pastebin.com/t9pwK5ds
Hi,
Can you try adding the following to your csf file:
[Unlock]
Engine = CAAM
Features = RNG
Also, can you copy your csf file?
Regards,
Gary
Hi Gary,
File copied at https://pastebin.com/ESuRi4e1
So is there any way to recover the closed device ? Are you asking me to try with this changes on the new board ?
Cheers
Manoj
Hi Manoj,
Why do you have “Security Configuration = Open” in your .csf? I suspect this is the issue.
As for ways to recover the boards:
1- Use imx_usb_loader to boot U-Boot (see this blog post)
2- Use JTAG to load U-Boot to RAM directly
3- Use the errata in the BootROM to load an unsigned image (see blog post)
Regards,
Gary
Hi Gary,
Then the procedure to close the device is as below step by step
1. USe the csf with open and set the size (HAB blocks) correctly
2. compile the u-boot and generate the u-boot_signed.imx
3. fuse SRK keys and flash the u-boot
4. check on reset there should not be any HAB event using hab_status.
** 5) Again create u-boot_signed.imx with .CSF config closed
6) Then reflash this new u-boot_signed.imx
7) make sure no HAB event (Even though device not closed, Do we get u-boot prompt here after flashing ?)
7) close the device using the command “fuse prog 0 6 0x2”
Please let me know if the procedure is correct. Also can you please paste the link to recover here, if you have it handy. Thanks
Cheers
Manoj
Hi,
No, why using that configuration at all? You should read the blog post thoroughly and see that no where this configuration is used.
You should used the CSF as provided in the post, just update the Blocks section. Then flash this binary whether your platform is open or not.
Regards,
Gary
Possibly a non-critical error in mkimage command:
./tools/mkimage -n board/boundary/nitrogen6x/nitrogen6q.cfg.cfgtmp -T imximage -e 0x17800000 -d u-boot.bin u-boot.imx
-n means image name, so passing cfg file there seems wrong.
Hi,
This is not a command we ask to type, instead it is run by U-Boot during the binary generation.
So if you think this is a possible mistake, please send an e-mail to the U-Boot mailing list:
u-boot@lists.denx.de
Regards,
Gary
Turned out that for i.MX images “-n” parameters semantics is silently different and it’s supposed to be used for configuration file passing.
There is a security vulnerability with the encrypted configuration as given in the examples by NXP/Freescale. The encrypted image can be swapped for another encrypted image. This is literally a cut-copy-paste operation. I notified them, and they’ll have a new applications note written.
What happens is the encrypted portion of the image is not signed, and can be swapped with another image of the same size. To have an image where the signed image is encrypted, two separate signing/encrypted passes must be done with the CST, with two slightly different configurations. The images are then merged to produce the final file.
Also, NXP recommended setting the CAAM PRIBLOB bits (at 0x3090000c) to disable DEK wrapping for a final production image. This means that to upgrade the firmware, you’d have an intermediate image with a CSF that doesn’t set that bit, and then wrap the DEK blob.
I have a Bash script that produces a secure firmware image, and example CSF for it.
Hi Brian,
Can you direct me to the document that describes this NXP recommendation?
Does it give a workaround for both vulnerabilities which were published by Quarkslab?
Can you publish your script and the example?
Many thanks,
Ofer
Hi Ofer,
The recommendation for the was sent to me via tech support.
The Quarkslab vulnerability can only be changed in the ROM code. The vulnerability I found can be worked around using two CST binaries to form a third.
Start with a working CSF. First, create a CSF binary with authentication at the end, covering the entire binary:
[Install Secret Key]
Verification index = 0
Target index = 0
Key = “dek.bin”
Key Length = 128
Blob address = 0x8787BFB8
[Decrypt Data]
Verification index = 0
Mac Bytes = 16
Blocks = 0x87800000 0x00000c00 0x0007a000 “u-boot.imx”
[Authenticate Data]
Verification index = 2
Blocks = 0x877ff400 0x00000000 0x0007ac00 “u-boot.imx”
Second, move the Authenticate Data section back to its original position:
[Authenticate Data]
Verification index = 2
Blocks = 0x877ff400 0x00000000 0x0007ac00 “u-boot.imx”
[Install Secret Key]
Verification index = 0
Target index = 0
Key = “dek.bin”
Key Length = 128
Blob address = 0x8787BFB8
[Decrypt Data]
Verification index = 0
Mac Bytes = 16
Blocks = 0x87800000 0x00000c00 0x0007A000 “u-boot.imx”
The script, for a given file size, will convert these to text, chop them up, and recombine them. The CSF binary is divided into sections with 4-byte headers: type, length, version. You will have to adjust the script according to your individual binary. In my case, the binary is 4124 bytes. Thus, the files are chopped apart at specific lines. The first part of the file is the CSF in binary form. The rest of the file consists of certificates and signatures. At the end is binary data for the encryption algorithm.
The auth-at-end CSF is used as the root of the new signature file. Its signature and encryption data are removed, and the signature and encryption data from the decrypt-at-end CSF are appended.
The final signature file will have the instructions to decrypt the data, and then authenticate the entire unencrypted image. This protects against the cut-and-paste attack.
BASH script follows:
#!/bin/bash
USAGE=”Usage: $0 AuthSigName EncryptSigName FinalSigName”
: ${1?$USAGE}
: ${2?$USAGE}
: ${3?$USAGE}
rm -f “$3”
# Create the auth-at-end signature, then the decrypt-at-end signature.
# This way the last DEK.bin will be valid.
# ./cst -o CSFAUTH.bin -i CSFAUTH.txt
# ./cst -o CSFDECRYPT.bin -i csf_decrypt.txt
# Check file size is 4124 bytes, otherwise cut-copy-paste won’t work
FILESIZE=4124
SIG1SIZE=$(ls -l “$1” | awk ‘{ print $5 }’)
SIG2SIZE=$(ls -l “$2” | awk ‘{ print $5 }’)
if [[ “$SIG1SIZE” -ne “$FILESIZE” || “$SIG1SIZE” -ne “$FILESIZE” ]]
then
echo Unexpected file size for “$1” or “$2”. Adjust scripts as needed.
exit 1
fi
CSFAUTH=$(mktemp)
CSFDECRYPT=$(mktemp)
CSFSIGNATURE=$(mktemp)
CSFAESCCM=$(mktemp)
CSFFINAL=$(mktemp)
hexdump -C “$1” > “$CSFAUTH”
hexdump -C “$2” > “$CSFDECRYPT”
# Seperate the required sections
head -223 “$CSFAUTH” > “$CSFFINAL”
tail -37 “$CSFDECRYPT” | head -34 > “$CSFSIGNATURE”
tail -4 “$CSFDECRYPT” | head -3 > “$CSFAESCCM”
# Remove cruft
for i in “$CSFFINAL” “$CSFSIGNATURE” “$CSFAESCCM”
do
sed -i -e ‘s/^[0-9a-f]* //’ -e ‘s/ |.*$//’ “$i”
done
sed -i -e ‘$s/ac 00 24 41.*//’ “$CSFFINAL”
sed -i -e ‘1s/.*\(d8 02 12 41\)/\1/’ -e ‘$s/ac 00 24 41.*//’ “$CSFSIGNATURE”
sed -i -e ‘1s/.*\(ac 00 24 41\)/\1/’ “$CSFAESCCM”
# Assemble final dump file
cat “$CSFAESCCM” >> “$CSFFINAL”
cat “$CSFSIGNATURE” >> “$CSFFINAL”
xxd -revert -plain “$CSFFINAL” “$3”
rm “$CSFFINAL” “$CSFSIGNATURE” “$CSFAESCCM” “$CSFDECRYPT” “$CSFAUTH”
exit 0
Here’s the same, but in Python. It’s clearer, and it works with any signature file with encryption. (of course, you’ll have to re-indent.)
#!/usr/bin/env python3
# vim: ts=8 et sw=4 sts=4 ai
”’
Utility to merge signatures to work around unsigned encrypted section.
”’
import io
import struct
import sys
def merge(auth_sig, encrypt_sig):
”’
Merge an authenticate-last and encrypt-last CST signatures.
”’
merged = list()
merged.append(auth_sig[0]) # CSF
merged.append(auth_sig[1]) # SRK Table
merged.append(auth_sig[2]) # CSF public certificate
merged.append(auth_sig[3]) # CSF signature
merged.append(encrypt_sig[4]) # IMG public certificate
merged.append(encrypt_sig[6]) # encryption
merged.append(encrypt_sig[5]) # IMG signature
return merged
def read_signature(filename):
”’
Read a CST-generated signature file.
:param str filename: Signature file name, file generated by CST.
:rtype list: List of sections from file, with headers and padding.
”’
# pylint: disable=unused-variable
sections = list()
sig_fd = io.open(filename, ‘rb’)
hdr_buf = sig_fd.read(4)
while len(hdr_buf) == 4:
hdr_type, hdr_len, hdr_id = struct.unpack(‘>BHB’, hdr_buf)
# Padding adjustment
if hdr_len % 4 != 0:
hdr_len = ((hdr_len // 4) + 1) * 4
section_buf = sig_fd.read(hdr_len – 4)
sections.append(hdr_buf + section_buf)
hdr_buf = sig_fd.read(4)
sig_fd.close()
return sections
def main():
”’ Read, merge, write signatures ”’
auth_sig_name, encrypt_sig_name, merged_sig_name = \
sys.argv[1:]
auth_sig = read_signature(auth_sig_name)
encrypt_sig = read_signature(encrypt_sig_name)
merged_sig = merge(auth_sig, encrypt_sig)
merged_fd = io.open(merged_sig_name, ‘wb’)
for section in merged_sig:
merged_fd.write(section)
merged_fd.close()
if __name__ == “__main__”:
main()
Hi, would signing of the dtb, bootscripts be same to this procedure?
Thanks for the great tutorial. I have a question regarding the genIVT script for signing the kernel. How did you derive the IVT Header address to be 0x412000D1? Thanks!
Hi, nice document! I have a question, perhaps off-topic, it is possible to configure u-boot in order to verify if the board is trusted, such having HAB enabled or checking the presence of other signatures? Our problem is not only load a secured SW but also be sure that the secured SW run on a signed board. Thanks for help and suggestions!
Hi,
The U-Boot “hab_status” command gives you that information, it tells you whether or not the platform is closed (secured) or open (unsecure).
Regards
HI Marius,
I am using SDP protocol to boot signed custom u-boot binary on board. imx_usb_loader is updated and is on HEAD of the master branch as mentioned in https://boundarydevices.com/high-assurance-boot-hab-dummies/.
I have updated csf file with Blocks = 0x0910000 0x2c 0x2c0 “boot-loader.bin, as in hexdump of boot-loader.bin and in system.map file and can see the addresses.
I have extracted DCD pointers and size of DCD data as per the address, still not able to boot signed binary.
System is still throwing HAB event.
can you please help here?
Thanks,
Akash
Hi,
Are you absolutely sure about your ‘Blocks’ offsets and sizes? Have you kept the other part of the ‘Blocks’ section?
Please read the NXP doc that explains the HAB event meaning, this will tell you where the issue is.
Regards
Hi,
I have a few questions about HAB, assuming that we will generate an encrypted image. I have the feeling that I do not clearly identify the limits of this security functionnality.
1) Our application needs PIN code implementation, so we will need to store these codes and keep them secret. I guess that HAB is not a solution for that, do you confirm it ?
2) For a given SOM, does HAB protect against module replacement ?
3) Does HAB protect our SW (the “useful” ELF application that should run on the board) against :
– reverse engineering ?
– modification ?
– replacement ?
4) Does HAB protect against a spy SW installation ? (we must avoid audio signal acquisition by a spy SW)
For the 4 needs listed above, if HAB is not relevant, what security components would be ? (SNVS ? Any other component of TrustZone architecture ?)
Thank you for your help… 🙂
Julien
I have a slightly modified u-boot build that I would like to sign and flash on my sabrelite board.
the build finishes with:
Image Type: Freescale IMX Boot Image
Image Ver: 2 (i.MX53/6/7 compatible)
Mode: DCD
Data Size: 462848 Bytes = 452.00 KiB = 0.44 MiB
Load Address: 177ff420
Entry Point: 17800000
HAB Blocks: 177ff400 00000000 0006ec00
DCD Blocks: 00910000 0000002c 00000310
I sign the u-boot.imx using the modified .csf as shown:
[Install Key]
# Key slot index used to authenticate the key to be installed
Verification index = 0
# Key to install
Target index = 2
File = “../crts/IMG1_1_sha256_4096_65537_v3_usr_crt.pem”
[Authenticate Data]
Verification index = 2
Blocks = 0x00910000 0x2C 0x310 “u-boot.imx”
[Authenticate Data]
Verification index = 2
Blocks = 0x177ff400 0x0 0x6ec00 “u-boot.imx”
with the modified mfg script (clear DCD etc.) as shown above.
I can download the modified signed .imx using the USB tool and it boot and I show no HAB events.
I now want to flash this so I can boot on power up.
I used the following to load it from my SD card:
mmc dev
fatload mmc 0:1 0x10800000 u-boot_signed.imx
sf probe
sf erase 0 0xc0000
sf write 0x10800000 0x400 ${filesize}
device 0 offset 0x400, size 0x70858
SF: 460888 bytes @ 0x400 Written: OK
=>
It boots but I now get all kinds of HAB events.
I also tried flash loading a version of u-boot_signed.imx which is just signed without the mfg mods.
same results. boots but has HAB events.
What am I doing wrong?
Also do you have a link to the NXP document that shows how to decode the HAB events?
also you state:
“For more convenience, we created a .csf file that applies to Nitrogen6x using latest U-Boot.”
where is this? I don’t see it in the repo.
Hi,
Please read the line after that, you’ll see a ‘wget’ command that downloads the file.
Regards
This worked for me on the imx6ul but now I’m working on the imx8mq. Do these instructions still apply? Reason I ask is because on the imx8 u-boot alone cannot boot the board. To boot the board you need an imx-boot binary which includes Uboot, ATF, SPL, firmware, and DDR firmware. So, do I sign just the uboot portion or the entire imx-boot binary? Also, can I still sign the kernel the same way ?
Hi,
We haven’t tested this procedure on i.MX8M yet. I think it’d be best to ask on NXP community at this point:
https://community.nxp.com/community/imx/content
Regards