diff options
Diffstat (limited to 'doc/uImage.FIT/beaglebone_vboot.txt')
| -rw-r--r-- | doc/uImage.FIT/beaglebone_vboot.txt | 607 |
1 files changed, 0 insertions, 607 deletions
diff --git a/doc/uImage.FIT/beaglebone_vboot.txt b/doc/uImage.FIT/beaglebone_vboot.txt deleted file mode 100644 index ebd2068ed38..00000000000 --- a/doc/uImage.FIT/beaglebone_vboot.txt +++ /dev/null @@ -1,607 +0,0 @@ -Verified Boot on the Beaglebone Black -===================================== - -Introduction ------------- - -Before reading this, please read verified-boot.txt and signature.txt. These -instructions are for mainline U-Boot from v2014.07 onwards. - -There is quite a bit of documentation in this directory describing how -verified boot works in U-Boot. There is also a test which runs through the -entire process of signing an image and running U-Boot (sandbox) to check it. -However, it might be useful to also have an example on a real board. - -Beaglebone Black is a fairly common board so seems to be a reasonable choice -for an example of how to enable verified boot using U-Boot. - -First a note that may to help avoid confusion. U-Boot and Linux both use -device tree. They may use the same device tree source, but it is seldom useful -for them to use the exact same binary from the same place. More typically, -U-Boot has its device tree packaged wtih it, and the kernel's device tree is -packaged with the kernel. In particular this is important with verified boot, -since U-Boot's device tree must be immutable. If it can be changed then the -public keys can be changed and verified boot is useless. An attacker can -simply generate a new key and put his public key into U-Boot so that -everything verifies. On the other hand the kernel's device tree typically -changes when the kernel changes, so it is useful to package an updated device -tree with the kernel binary. U-Boot supports the latter with its flexible FIT -format (Flat Image Tree). - - -Overview --------- - -The steps are roughly as follows: - -1. Build U-Boot for the board, with the verified boot options enabled. - -2. Obtain a suitable Linux kernel - -3. Create a Image Tree Source file (ITS) file describing how you want the -kernel to be packaged, compressed and signed. - -4. Create a key pair - -5. Sign the kernel - -6. Put the public key into U-Boot's image - -7. Put U-Boot and the kernel onto the board - -8. Try it - - -Step 1: Build U-Boot --------------------- - -a. Set up the environment variable to point to your toolchain. You will need -this for U-Boot and also for the kernel if you build it. For example if you -installed a Linaro version manually it might be something like: - - export CROSS_COMPILE=/opt/linaro/gcc-linaro-arm-linux-gnueabihf-4.8-2013.08_linux/bin/arm-linux-gnueabihf- - -or if you just installed gcc-arm-linux-gnueabi then it might be - - export CROSS_COMPILE=arm-linux-gnueabi- - -b. Configure and build U-Boot with verified boot enabled: - - export UBOOT=/path/to/u-boot - cd $UBOOT - # You can add -j10 if you have 10 CPUs to make it faster - make O=b/am335x_boneblack_vboot am335x_boneblack_vboot_config all - export UOUT=$UBOOT/b/am335x_boneblack_vboot - -c. You will now have a U-Boot image: - - file b/am335x_boneblack_vboot/u-boot-dtb.img -b/am335x_boneblack_vboot/u-boot-dtb.img: u-boot legacy uImage, U-Boot 2014.07-rc2-00065-g2f69f8, Firmware/ARM, Firmware Image (Not compressed), 395375 bytes, Sat May 31 16:19:04 2014, Load Address: 0x80800000, Entry Point: 0x00000000, Header CRC: 0x0ABD6ACA, Data CRC: 0x36DEF7E4 - - -Step 2: Build Linux --------------------- - -a. Find the kernel image ('Image') and device tree (.dtb) file you plan to -use. In our case it is am335x-boneblack.dtb and it is built with the kernel. -At the time of writing an SD Boot image can be obtained from here: - - http://www.elinux.org/Beagleboard:Updating_The_Software#Image_For_Booting_From_microSD - -You can write this to an SD card and then mount it to extract the kernel and -device tree files. - -You can also build a kernel. Instructions for this are are here: - - http://elinux.org/Building_BBB_Kernel - -or you can use your favourite search engine. Following these instructions -produces a kernel Image and device tree files. For the record the steps were: - - export KERNEL=/path/to/kernel - cd $KERNEL - git clone git://github.com/beagleboard/kernel.git . - git checkout v3.14 - ./patch.sh - cp configs/beaglebone kernel/arch/arm/configs/beaglebone_defconfig - cd kernel - make beaglebone_defconfig - make uImage dtbs # -j10 if you have 10 CPUs - export OKERNEL=$KERNEL/kernel/arch/arm/boot - -c. You now have the 'Image' and 'am335x-boneblack.dtb' files needed to boot. - - -Step 3: Create the ITS ----------------------- - -Set up a directory for your work. - - export WORK=/path/to/dir - cd $WORK - -Put this into a file in that directory called sign.its: - -/dts-v1/; - -/ { - description = "Beaglebone black"; - #address-cells = <1>; - - images { - kernel { - data = /incbin/("Image.lzo"); - type = "kernel"; - arch = "arm"; - os = "linux"; - compression = "lzo"; - load = <0x80008000>; - entry = <0x80008000>; - hash-1 { - algo = "sha1"; - }; - }; - fdt-1 { - description = "beaglebone-black"; - data = /incbin/("am335x-boneblack.dtb"); - type = "flat_dt"; - arch = "arm"; - compression = "none"; - hash-1 { - algo = "sha1"; - }; - }; - }; - configurations { - default = "conf-1"; - conf-1 { - kernel = "kernel"; - fdt = "fdt-1"; - signature-1 { - algo = "sha1,rsa2048"; - key-name-hint = "dev"; - sign-images = "fdt", "kernel"; - }; - }; - }; -}; - - -The explanation for this is all in the documentation you have already read. -But briefly it packages a kernel and device tree, and provides a single -configuration to be signed with a key named 'dev'. The kernel is compressed -with LZO to make it smaller. - - -Step 4: Create a key pair -------------------------- - -See signature.txt for details on this step. - - cd $WORK - mkdir keys - openssl genrsa -F4 -out keys/dev.key 2048 - openssl req -batch -new -x509 -key keys/dev.key -out keys/dev.crt - -Note: keys/dev.key contains your private key and is very secret. If anyone -gets access to that file they can sign kernels with it. Keep it secure. - - -Step 5: Sign the kernel ------------------------ - -We need to use mkimage (which was built when you built U-Boot) to package the -Linux kernel into a FIT (Flat Image Tree, a flexible file format that U-Boot -can load) using the ITS file you just created. - -At the same time we must put the public key into U-Boot device tree, with the -'required' property, which tells U-Boot that this key must be verified for the -image to be valid. You will make this key available to U-Boot for booting in -step 6. - - ln -s $OKERNEL/dts/am335x-boneblack.dtb - ln -s $OKERNEL/Image - ln -s $UOUT/u-boot-dtb.img - cp $UOUT/arch/arm/dts/am335x-boneblack.dtb am335x-boneblack-pubkey.dtb - lzop Image - $UOUT/tools/mkimage -f sign.its -K am335x-boneblack-pubkey.dtb -k keys -r image.fit - -You should see something like this: - -FIT description: Beaglebone black -Created: Sun Jun 1 12:50:30 2014 - Image 0 (kernel) - Description: unavailable - Created: Sun Jun 1 12:50:30 2014 - Type: Kernel Image - Compression: lzo compressed - Data Size: 7790938 Bytes = 7608.34 kB = 7.43 MB - Architecture: ARM - OS: Linux - Load Address: 0x80008000 - Entry Point: 0x80008000 - Hash algo: sha1 - Hash value: c94364646427e10f423837e559898ef02c97b988 - Image 1 (fdt-1) - Description: beaglebone-black - Created: Sun Jun 1 12:50:30 2014 - Type: Flat Device Tree - Compression: uncompressed - Data Size: 31547 Bytes = 30.81 kB = 0.03 MB - Architecture: ARM - Hash algo: sha1 - Hash value: cb09202f889d824f23b8e4404b781be5ad38a68d - Default Configuration: 'conf-1' - Configuration 0 (conf-1) - Description: unavailable - Kernel: kernel - FDT: fdt-1 - - -Now am335x-boneblack-pubkey.dtb contains the public key and image.fit contains -the signed kernel. Jump to step 6 if you like, or continue reading to increase -your understanding. - -You can also run fit_check_sign to check it: - - $UOUT/tools/fit_check_sign -f image.fit -k am335x-boneblack-pubkey.dtb - -which results in: - -Verifying Hash Integrity ... sha1,rsa2048:dev+ -## Loading kernel from FIT Image at 7fc6ee469000 ... - Using 'conf-1' configuration - Verifying Hash Integrity ... -sha1,rsa2048:dev+ -OK - - Trying 'kernel' kernel subimage - Description: unavailable - Created: Sun Jun 1 12:50:30 2014 - Type: Kernel Image - Compression: lzo compressed - Data Size: 7790938 Bytes = 7608.34 kB = 7.43 MB - Architecture: ARM - OS: Linux - Load Address: 0x80008000 - Entry Point: 0x80008000 - Hash algo: sha1 - Hash value: c94364646427e10f423837e559898ef02c97b988 - Verifying Hash Integrity ... -sha1+ -OK - -Unimplemented compression type 4 -## Loading fdt from FIT Image at 7fc6ee469000 ... - Using 'conf-1' configuration - Trying 'fdt-1' fdt subimage - Description: beaglebone-black - Created: Sun Jun 1 12:50:30 2014 - Type: Flat Device Tree - Compression: uncompressed - Data Size: 31547 Bytes = 30.81 kB = 0.03 MB - Architecture: ARM - Hash algo: sha1 - Hash value: cb09202f889d824f23b8e4404b781be5ad38a68d - Verifying Hash Integrity ... -sha1+ -OK - - Loading Flat Device Tree ... OK - -## Loading ramdisk from FIT Image at 7fc6ee469000 ... - Using 'conf-1' configuration -Could not find subimage node - -Signature check OK - - -At the top, you see "sha1,rsa2048:dev+". This means that it checked an RSA key -of size 2048 bits using SHA1 as the hash algorithm. The key name checked was -'dev' and the '+' means that it verified. If it showed '-' that would be bad. - -Once the configuration is verified it is then possible to rely on the hashes -in each image referenced by that configuration. So fit_check_sign goes on to -load each of the images. We have a kernel and an FDT but no ramkdisk. In each -case fit_check_sign checks the hash and prints sha1+ meaning that the SHA1 -hash verified. This means that none of the images has been tampered with. - -There is a test in test/vboot which uses U-Boot's sandbox build to verify that -the above flow works. - -But it is fun to do this by hand, so you can load image.fit into a hex editor -like ghex, and change a byte in the kernel: - - $UOUT/tools/fit_info -f image.fit -n /images/kernel -p data -NAME: kernel -LEN: 7790938 -OFF: 168 - -This tells us that the kernel starts at byte offset 168 (decimal) in image.fit -and extends for about 7MB. Try changing a byte at 0x2000 (say) and run -fit_check_sign again. You should see something like: - -Verifying Hash Integrity ... sha1,rsa2048:dev+ -## Loading kernel from FIT Image at 7f5a39571000 ... - Using 'conf-1' configuration - Verifying Hash Integrity ... -sha1,rsa2048:dev+ -OK - - Trying 'kernel' kernel subimage - Description: unavailable - Created: Sun Jun 1 13:09:21 2014 - Type: Kernel Image - Compression: lzo compressed - Data Size: 7790938 Bytes = 7608.34 kB = 7.43 MB - Architecture: ARM - OS: Linux - Load Address: 0x80008000 - Entry Point: 0x80008000 - Hash algo: sha1 - Hash value: c94364646427e10f423837e559898ef02c97b988 - Verifying Hash Integrity ... -sha1 error -Bad hash value for 'hash-1' hash node in 'kernel' image node -Bad Data Hash - -## Loading fdt from FIT Image at 7f5a39571000 ... - Using 'conf-1' configuration - Trying 'fdt-1' fdt subimage - Description: beaglebone-black - Created: Sun Jun 1 13:09:21 2014 - Type: Flat Device Tree - Compression: uncompressed - Data Size: 31547 Bytes = 30.81 kB = 0.03 MB - Architecture: ARM - Hash algo: sha1 - Hash value: cb09202f889d824f23b8e4404b781be5ad38a68d - Verifying Hash Integrity ... -sha1+ -OK - - Loading Flat Device Tree ... OK - -## Loading ramdisk from FIT Image at 7f5a39571000 ... - Using 'conf-1' configuration -Could not find subimage node - -Signature check Bad (error 1) - - -It has detected the change in the kernel. - -You can also be sneaky and try to switch images, using the libfdt utilities -that come with dtc (package name is device-tree-compiler but you will need a -recent version like 1.4: - - dtc -v -Version: DTC 1.4.0 - -First we can check which nodes are actually hashed by the configuration: - - fdtget -l image.fit / -images -configurations - - fdtget -l image.fit /configurations -conf-1 -fdtget -l image.fit /configurations/conf-1 -signature-1 - - fdtget -p image.fit /configurations/conf-1/signature-1 -hashed-strings -hashed-nodes -timestamp -signer-version -signer-name -value -algo -key-name-hint -sign-images - - fdtget image.fit /configurations/conf-1/signature-1 hashed-nodes -/ /configurations/conf-1 /images/fdt-1 /images/fdt-1/hash /images/kernel /images/kernel/hash-1 - -This gives us a bit of a look into the signature that mkimage added. Note you -can also use fdtdump to list the entire device tree. - -Say we want to change the kernel that this configuration uses -(/images/kernel). We could just put a new kernel in the image, but we will -need to change the hash to match. Let's simulate that by changing a byte of -the hash: - - fdtget -tx image.fit /images/kernel/hash-1 value -c9436464 6427e10f 423837e5 59898ef0 2c97b988 - fdtput -tx image.fit /images/kernel/hash-1 value c9436464 6427e10f 423837e5 59898ef0 2c97b981 - -Now check it again: - - $UOUT/tools/fit_check_sign -f image.fit -k am335x-boneblack-pubkey.dtb -Verifying Hash Integrity ... sha1,rsa2048:devrsa_verify_with_keynode: RSA failed to verify: -13 -rsa_verify_with_keynode: RSA failed to verify: -13 -- -Failed to verify required signature 'key-dev' -Signature check Bad (error 1) - -This time we don't even get as far as checking the images, since the -configuration signature doesn't match. We can't change any hashes without the -signature check noticing. The configuration is essentially locked. U-Boot has -a public key for which it requires a match, and will not permit the use of any -configuration that does not match that public key. The only way the -configuration will match is if it was signed by the matching private key. - -It would also be possible to add a new signature node that does match your new -configuration. But that won't work since you are not allowed to change the -configuration in any way. Try it with a fresh (valid) image if you like by -running the mkimage link again. Then: - - fdtput -p image.fit /configurations/conf-1/signature-1 value fred - $UOUT/tools/fit_check_sign -f image.fit -k am335x-boneblack-pubkey.dtb -Verifying Hash Integrity ... - -sha1,rsa2048:devrsa_verify_with_keynode: RSA failed to verify: -13 -rsa_verify_with_keynode: RSA failed to verify: -13 -- -Failed to verify required signature 'key-dev' -Signature check Bad (error 1) - - -Of course it would be possible to add an entirely new configuration and boot -with that, but it still needs to be signed, so it won't help. - - -6. Put the public key into U-Boot's image ------------------------------------------ - -Having confirmed that the signature is doing its job, let's try it out in -U-Boot on the board. U-Boot needs access to the public key corresponding to -the private key that you signed with so that it can verify any kernels that -you sign. - - cd $UBOOT - make O=b/am335x_boneblack_vboot EXT_DTB=${WORK}/am335x-boneblack-pubkey.dtb - -Here we are overriding the normal device tree file with our one, which -contains the public key. - -Now you have a special U-Boot image with the public key. It can verify can -kernel that you sign with the private key as in step 5. - -If you like you can take a look at the public key information that mkimage -added to U-Boot's device tree: - - fdtget -p am335x-boneblack-pubkey.dtb /signature/key-dev -required -algo -rsa,r-squared -rsa,modulus -rsa,n0-inverse -rsa,num-bits -key-name-hint - -This has information about the key and some pre-processed values which U-Boot -can use to verify against it. These values are obtained from the public key -certificate by mkimage, but require quite a bit of code to generate. To save -code space in U-Boot, the information is extracted and written in raw form for -U-Boot to easily use. The same mechanism is used in Google's Chrome OS. - -Notice the 'required' property. This marks the key as required - U-Boot will -not boot any image that does not verify against this key. - - -7. Put U-Boot and the kernel onto the board -------------------------------------------- - -The method here varies depending on how you are booting. For this example we -are booting from an micro-SD card with two partitions, one for U-Boot and one -for Linux. Put it into your machine and write U-Boot and the kernel to it. -Here the card is /dev/sde: - - cd $WORK - export UDEV=/dev/sde1 # Change thes two lines to the correct device - export KDEV=/dev/sde2 - sudo mount $UDEV /mnt/tmp && sudo cp $UOUT/u-boot-dtb.img /mnt/tmp/u-boot.img && sleep 1 && sudo umount $UDEV - sudo mount $KDEV /mnt/tmp && sudo cp $WORK/image.fit /mnt/tmp/boot/image.fit && sleep 1 && sudo umount $KDEV - - -8. Try it ---------- - -Boot the board using the commands below: - - setenv bootargs console=ttyO0,115200n8 quiet root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait - ext2load mmc 0:2 82000000 /boot/image.fit - bootm 82000000 - -You should then see something like this: - -U-Boot# setenv bootargs console=ttyO0,115200n8 quiet root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait -U-Boot# ext2load mmc 0:2 82000000 /boot/image.fit -7824930 bytes read in 589 ms (12.7 MiB/s) -U-Boot# bootm 82000000 -## Loading kernel from FIT Image at 82000000 ... - Using 'conf-1' configuration - Verifying Hash Integrity ... sha1,rsa2048:dev+ OK - Trying 'kernel' kernel subimage - Description: unavailable - Created: 2014-06-01 19:32:54 UTC - Type: Kernel Image - Compression: lzo compressed - Data Start: 0x820000a8 - Data Size: 7790938 Bytes = 7.4 MiB - Architecture: ARM - OS: Linux - Load Address: 0x80008000 - Entry Point: 0x80008000 - Hash algo: sha1 - Hash value: c94364646427e10f423837e559898ef02c97b988 - Verifying Hash Integrity ... sha1+ OK -## Loading fdt from FIT Image at 82000000 ... - Using 'conf-1' configuration - Trying 'fdt-1' fdt subimage - Description: beaglebone-black - Created: 2014-06-01 19:32:54 UTC - Type: Flat Device Tree - Compression: uncompressed - Data Start: 0x8276e2ec - Data Size: 31547 Bytes = 30.8 KiB - Architecture: ARM - Hash algo: sha1 - Hash value: cb09202f889d824f23b8e4404b781be5ad38a68d - Verifying Hash Integrity ... sha1+ OK - Booting using the fdt blob at 0x8276e2ec - Uncompressing Kernel Image ... OK - Loading Device Tree to 8fff5000, end 8ffffb3a ... OK - -Starting kernel ... - -[ 0.582377] omap_init_mbox: hwmod doesn't have valid attrs -[ 2.589651] musb-hdrc musb-hdrc.0.auto: Failed to request rx1. -[ 2.595830] musb-hdrc musb-hdrc.0.auto: musb_init_controller failed with status -517 -[ 2.606470] musb-hdrc musb-hdrc.1.auto: Failed to request rx1. -[ 2.612723] musb-hdrc musb-hdrc.1.auto: musb_init_controller failed with status -517 -[ 2.940808] drivers/rtc/hctosys.c: unable to open rtc device (rtc0) -[ 7.248889] libphy: PHY 4a101000.mdio:01 not found -[ 7.253995] net eth0: phy 4a101000.mdio:01 not found on slave 1 -systemd-fsck[83]: Angstrom: clean, 50607/218160 files, 306348/872448 blocks - -.---O---. -| | .-. o o -| | |-----.-----.-----.| | .----..-----.-----. -| | | __ | ---'| '--.| .-'| | | -| | | | | |--- || --'| | | ' | | | | -'---'---'--'--'--. |-----''----''--' '-----'-'-'-' - -' | - '---' - -The Angstrom Distribution beaglebone ttyO0 - -Angstrom v2012.12 - Kernel 3.14.1+ - -beaglebone login: - -At this point your kernel has been verified and you can be sure that it is one -that you signed. As an exercise, try changing image.fit as in step 5 and see -what happens. - - -Further Improvements --------------------- - -Several of the steps here can be easily automated. In particular it would be -capital if signing and packaging a kernel were easy, perhaps a simple make -target in the kernel. - -Some mention of how to use multiple .dtb files in a FIT might be useful. - -U-Boot's verified boot mechanism has not had a robust and independent security -review. Such a review should look at the implementation and its resistance to -attacks. - -Perhaps the verified boot feature could could be integrated into the Amstrom -distribution. - - -Simon Glass -2-June-14 |
