aboutsummaryrefslogtreecommitdiff
path: root/doc/usage/fit/beaglebone_vboot.rst
diff options
context:
space:
mode:
Diffstat (limited to 'doc/usage/fit/beaglebone_vboot.rst')
-rw-r--r--doc/usage/fit/beaglebone_vboot.rst612
1 files changed, 612 insertions, 0 deletions
diff --git a/doc/usage/fit/beaglebone_vboot.rst b/doc/usage/fit/beaglebone_vboot.rst
new file mode 100644
index 00000000000..0580ee10bdc
--- /dev/null
+++ b/doc/usage/fit/beaglebone_vboot.rst
@@ -0,0 +1,612 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Verified Boot on the Beaglebone Black
+=====================================
+
+Introduction
+------------
+
+Before reading this, please read :doc:`verified-boot` and :doc:`signature`.
+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 with 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:
+
+#. Build U-Boot for the board, with the verified boot options enabled.
+
+#. Obtain a suitable Linux kernel
+
+#. Create a Image Tree Source file (ITS) file describing how you want the
+ kernel to be packaged, compressed and signed.
+
+#. Create a key pair
+
+#. Sign the kernel
+
+#. Put the public key into U-Boot's image
+
+#. Put U-Boot and the kernel onto the board
+
+#. 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
+
+b. 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 :doc:`signature` 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 be integrated into the Amstrom
+distribution.
+
+
+.. sectionauthor:: Simon Glass <sjg@chromium.org>, 2-June-14