This documents shows how to secure and encrypt boot loader image for i.MX6 processor. Secure boot is necessary to be sure that CPU is allowed to run genuine and authentic images. Encrypted image secures your intellectual property from theft. Both methods secure/encryption can be extended to cover whole software on board.
Boot loader image encryption is easy to do with CST tools and HAB feature build in Freescale processor. Encrypted image preparation is consist of three parts:
- Encrypt u-boot.imx plain image by CST utility;
- Wrap DEK to get DEK blob by specific board;
- Append DEK blob key to the u-boot image.
In this document as reference board we used SABRESD iMX6q. But it's easily to adjust it for any other board based on i.MX6 CPU with HAB4.1 feature.
Encrypted u-boot image consist of: IVT, DCD, u-boot.bin, CSF, dek_blob.bin. In our example finished u-boot_encrypted.imx image looks like:
Address in file
| Data |
|---|
| 0x000000 | IVT |
| 0x000020 | DCD + pad to address 0xC00 |
| 0x000C00 | u-boot.bin + pad to address* 0x7BC000 |
| 0x07DBB8 | CSF bin data + pad to address** 0x07DBB8 + Wrapped DEK (dek_blob.bin)** |
* (IVT + DCD + u-boot.bin) has to be padded to align 0x1000.
** (CSF bin data + padding + dek_blob.bin) has to have size 0x2000
Step-by-step instruction:
- Clone u-boot git repository.
$ mkdir ~/imx6encryption
$ cd ~/imx6encryption
$ git clone git://git.denx.de/u-boot.git
$ cd u-boot
$ git checkout v2016.03 -b tmp
- To enable secure features in u-boot modify the following files:
- Add function usec2ticks to the end of file timer.c.
$ nano arch/arm/imx-common/timer.c
unsigned long usec2ticks(unsigned long usec)
{
ulong ticks;
if (usec < 1000)
ticks = ((usec * (get_tbclk()/1000)) + 500) / 1000;
else
ticks = ((usec / 10) * (get_tbclk() / 100000));
return ticks;
}
Press Ctrl+X and Y and Enter to save changes.
- In file mx6q_4x_mt41j128.cfg add string CSF 0x2000 after string BOOT_FROM sd
$ nano board/freescale/mx6sabresd/mx6q_4x_mt41j128.cfg
Press Ctrl+X and Y and Enter to save changes.
Add defines in file mx6sabresd.h before string #define CONFIG_MACH_TYPE 3980.
$ nano include/configs/mx6sabresd.h
#define CONFIG_SECURE_BOOT
#define CONFIG_SYS_FSL_SEC_COMPAT 4 /* HAB version */
#define CONFIG_FSL_CAAM
#define CONFIG_CMD_DEKBLOB
#define CONFIG_SYS_FSL_SEC_LE
#define CONFIG_FAT_WRITE
Press Ctrl+X and Y and Enter to save changes.
- Delete the following strings:
gpimage.0 \
gpimage-common.o \
omapimage.o \
in Makefile.
$ nano tools/Makefile
Press Ctrl+X and Y and Enter to save changes
- Download Linaro GCC compiler.
$ cd ~/imx6encryption
$ wget -c https://releases.linaro.org/components/toolchain/binaries/5.3-2016.02/arm-linux-gnueabihf/gcc-linaro...
$ tar xf gcc-linaro-5.3-2016.02-x86_64_arm-linux-gnueabihf.tar.xz
$ export CC=`pwd`/gcc-linaro-5.3-2016.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
Check compiler version.
$ ${CC}gcc --version
Output:
arm-linux-gnueabihf-gcc (Linaro GCC 5.3-2016.02) 5.3.1 20160113
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- Build u-boot image with mx6qsabresd_defconfig.
$ cd u-boot
$ make ARCH=arm CROSS_COMPILE=${CC} distclean
$ make ARCH=arm CROSS_COMPILE=${CC} mx6qsabresd_defconfig
$ make ARCH=arm CROSS_COMPILE=${CC}
- Using mkimage utility build and get information of u-boot.imx image.
$ ./tools/mkimage -T imximage -n board/freescale/mx6sabresd/mx6q_4x_mt41j128.cfg.cfgtmp -e 0x17800000 -d u-boot.bin u-boot.imx
Output:
Image Type: Freescale IMX Boot Image
Image Ver: 2 (i.MX53/6/7 compatible)
Data Size: 516096 Bytes = 504.00 kB = 0.49 MB
Load Address: 177ff420
Entry Point: 17800000
HAB Blocks: 177ff400 00000000 0007bc00
- Register an account on NXP website to have access to download NXP Code Signing Tool for the High Assurance Boot library. Copy downloaded archive into “imx6encryption” folder.
$ cd ~/imx6encryption
$ tar xf cst-2.3.1.tar.gz
$ cd cst-2.3.1
$ chmod u+x linux64/* keys/*
- Compile back end sources of CST utility
$ sudo apt-get install libssl-dev
$ cd ~/imx6encryption/cst-2.3.1/code/back_end/src
$ gcc -o cst -I ../hdr -L ../../../linux64/lib *.c -lfrontend -lcrypto
$ mv cst ../../../linux64
- Generate keys and certificates which will be used to sign boot loader image.
$ cd ~/imx6encryption/cst-2.3.1/keys
- Generate SRK table.
$ cd ~/imx6encryption/cst-2.3.1/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_2048_65537_v3_ca_crt.pem,./SRK2_sha256_2048_65537_v3_ca_crt.pem,./SRK3_sha256_2048_65537_v3_ca_crt.pem,./SRK4_sha256_2048_65537_v3_ca_crt.pem -f 1
CST utility requires CSF script. This file describes certificates, keys and the data ranges used in sign and encryption functions. Create u-boot.csf file.
$ cd ~/imx6encryption/cst-2.3.1/linux64
$ nano u-boot.csf
And put the following text:
[Header]
Version = 4.1
Hash Algorithm = SHA256
Engine Configuration = 0
Certificate Format = X509
Signature Format = CMS
Engine = CAAM
[Install SRK]
File = "../crts/SRK_1_2_3_4_table.bin"
# Index of the key location in the SRK table to be installed
Source index = 0
[Install CSFK]
# Key used to authenticate the CSF data
File = "../crts/CSF1_1_sha256_2048_65537_v3_usr_crt.pem"
[Authenticate CSF]
[Unlock]
Engine = CAAM
Features = RNG
[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_2048_65537_v3_usr_crt.pem"
[Authenticate Data]
# Key slot index used to authenticate the image data
Verification Index = 2
# Address Offset Length Data File Path
Blocks = 0x177ff400 0x00000000 0x00000C10 "./u-boot.imx"
#Encrypt the boot image and create a DEK
[Install Secret Key]
Verification Index = 0
Target Index = 0
Key = "./dek.bin"
Key Length = 128
Blob Address = 0x1787CFB8
#Provide DEK blob location to decrypt
[Decrypt Data]
Verification Index = 0
Mac Bytes = 16
Blocks = 0x17800010 0x00000C10 0x0007AFF0 "./u-boot.imx"
Press Ctrl+X and Y and Enter to save changes.
- Execute CST utility to encrypt image. Note that after execution u-boot.imx file will be encrypted.
$ cp ~/imx6encryption/u-boot/u-boot.imx .
$ ./cst --o u-boot_csf.bin < u-boot.csf
$ objcopy -I binary -O binary --pad-to=0x1FB8 --gap-fill=0x00 u-boot_csf.bin u-boot_csf.bin
- Prepare SD card partition table. Check SD card name in system ($dmesg | tail), for example used /dev/sdb.
$ echo -e "o""\n""n""\n""p""\n""1""\n""2048""\n""+256M""\n""w" | sudo fdisk /dev/sdb
$ sudo mkfs.vfat /dev/sdb1
$ cd ~/imx6encryption/u-boot
$ sudo dd if=u-boot.imx of=/dev/sdb bs=512 seek=2
$ sync
- Wrap DEK to get DEK blob from i.MX6 CPU. Mount partition 1 and copy dek.bin file to the 1st FAT partition on SD card.
$ cd ~/imx6encryption/cst-2.3.1/linux64
$ mkdir /tmp/partition0
$ sudo mount /dev/sdb1 /tmp/partition0
$ sudo cp dek.bin /tmp/partition0
$ sudo umount /tmp/partition0
- Insert SD card into the board. And press any key to enter into u-boot prompt. Firstly load dek.bin to the RAM memory. Use dek_blob command to wrap dek.bin. Write file from RAM memory to SD card.
=> fatload mmc 1:1 0x10800000 dek.bin
=> dek_blob 0x10800000 0x10801000 128
=> fatwrite mmc 1:1 0x10801000 dek_blob.bin 0x48
- Append DEK blob key to the u-boot image. Mount SD card partition 1 and copy dek_blob.bin file to the linux64 folder.
$ mkdir -p /tmp/partition0
$ sudo mount /dev/sdb1 /tmp/partition0
$ cd /tmp/partition0
$ cp dek_blob.bin ~/imx6encryption/cst-2.3.1/linux64/
$ cd ~/imx6encryption/cst-2.3.1/linux64/
$ sudo umount /tmp/partition0
$ cat u-boot_csf.bin >> u-boot.imx
$ cat dek_blob.bin >> u-boot.imx
- Install encrypted u-boot.imx into SD card.
$ sudo dd if=u-boot.imx of=/dev/sdb bs=512 seek=2
$ sync
- Insert SD card into the board. Press any key to enter into u-boot prompt. And check if hab_status command executes without HAB Event errors.
=> hab_status
- Attention, OTP fuses can be programmed once, double check everything before burning. If everything is fine, burn required fuses SRK_HASH, SEC_CONFIG as described in AN4581.
As a result we have encrypted boot image which can be loaded and executed by only current board. Because dek_blob.bin is unique per i.MX6 CPU.
Vitaliy Vasinovich
April 2016