mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-27 08:33:10 +01:00 
			
		
		
		
	Add verified boot information and test
Add a description of how to implement verified boot using signed FIT images, and a simple test which verifies operation on sandbox. The test signs a FIT image and verifies it, then signs a FIT configuration and verifies it. Then it corrupts the signature to check that this is detected. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
		
							
								
								
									
										104
									
								
								doc/uImage.FIT/verified-boot.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								doc/uImage.FIT/verified-boot.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,104 @@ | ||||
| U-Boot Verified Boot | ||||
| ==================== | ||||
|  | ||||
| Introduction | ||||
| ------------ | ||||
| Verified boot here means the verification of all software loaded into a | ||||
| machine during the boot process to ensure that it is authorised and correct | ||||
| for that machine. | ||||
|  | ||||
| Verified boot extends from the moment of system reset to as far as you wish | ||||
| into the boot process. An example might be loading U-Boot from read-only | ||||
| memory, then loading a signed kernel, then using the kernel's dm-verity | ||||
| driver to mount a signed root filesystem. | ||||
|  | ||||
| A key point is that it is possible to field-upgrade the software on machines | ||||
| which use verified boot. Since the machine will only run software that has | ||||
| been correctly signed, it is safe to read software from an updatable medium. | ||||
| It is also possible to add a secondary signed firmware image, in read-write | ||||
| memory, so that firmware can easily be upgraded in a secure manner. | ||||
|  | ||||
|  | ||||
| Signing | ||||
| ------- | ||||
| Verified boot uses cryptographic algorithms to 'sign' software images. | ||||
| Images are signed using a private key known only to the signer, but can | ||||
| be verified using a public key. As its name suggests the public key can be | ||||
| made available without risk to the verification process. The private and | ||||
| public keys are mathematically related. For more information on how this | ||||
| works look up "public key cryptography" and "RSA" (a particular algorithm). | ||||
|  | ||||
| The signing and verification process looks something like this: | ||||
|  | ||||
|  | ||||
|       Signing                                      Verification | ||||
|       =======                                      ============ | ||||
|  | ||||
|  +--------------+                   * | ||||
|  | RSA key pair |                   *             +---------------+ | ||||
|  | .key  .crt   |                   *             | Public key in | | ||||
|  +--------------+       +------> public key ----->| trusted place | | ||||
|        |                |           *             +---------------+ | ||||
|        |                |           *                    | | ||||
|        v                |           *                    v | ||||
|    +---------+          |           *              +--------------+ | ||||
|    |         |----------+           *              |              | | ||||
|    | signer  |                      *              |    U-Boot    | | ||||
|    |         |----------+           *              |  signature   |--> yes/no | ||||
|    +---------+          |           *              | verification | | ||||
|       ^                 |           *              |              | | ||||
|       |                 |           *              +--------------+ | ||||
|       |                 |           *                    ^ | ||||
|  +----------+           |           *                    | | ||||
|  | Software |           +----> signed image -------------+ | ||||
|  |  image   |                       * | ||||
|  +----------+                       * | ||||
|  | ||||
|  | ||||
| The signature algorithm relies only on the public key to do its work. Using | ||||
| this key it checks the signature that it finds in the image. If it verifies | ||||
| then we know that the image is OK. | ||||
|  | ||||
| The public key from the signer allows us to verify and therefore trust | ||||
| software from updatable memory. | ||||
|  | ||||
| It is critical that the public key be secure and cannot be tampered with. | ||||
| It can be stored in read-only memory, or perhaps protected by other on-chip | ||||
| crypto provided by some modern SOCs. If the public key can ben changed, then | ||||
| the verification is worthless. | ||||
|  | ||||
|  | ||||
| Chaining Images | ||||
| --------------- | ||||
| The above method works for a signer providing images to a run-time U-Boot. | ||||
| It is also possible to extend this scheme to a second level, like this: | ||||
|  | ||||
| 1. Master private key is used by the signer to sign a first-stage image. | ||||
| 2. Master public key is placed in read-only memory. | ||||
| 2. Secondary private key is created and used to sign second-stage images. | ||||
| 3. Secondary public key is placed in first stage images | ||||
| 4. We use the master public key to verify the first-stage image. We then | ||||
| use the secondary public key in the first-stage image to verify the second- | ||||
| state image. | ||||
| 5. This chaining process can go on indefinitely. It is recommended to use a | ||||
| different key at each stage, so that a compromise in one place will not | ||||
| affect the whole change. | ||||
|  | ||||
|  | ||||
| Flattened Image Tree (FIT) | ||||
| -------------------------- | ||||
| The FIT format is alreay widely used in U-Boot. It is a flattened device | ||||
| tree (FDT) in a particular format, with images contained within. FITs | ||||
| include hashes to verify images, so it is relatively straightforward to | ||||
| add signatures as well. | ||||
|  | ||||
| The public key can be stored in U-Boot's CONFIG_OF_CONTROL device tree in | ||||
| a standard place. Then when a FIT it loaded it can be verified using that | ||||
| public key. Multiple keys and multiple signatures are supported. | ||||
|  | ||||
| See signature.txt for more information. | ||||
|  | ||||
|  | ||||
| Simon Glass | ||||
| sjg@chromium.org | ||||
| 1-1-13 | ||||
							
								
								
									
										3
									
								
								test/vboot/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								test/vboot/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| /*.dtb | ||||
| /test.fit | ||||
| /dev-keys | ||||
							
								
								
									
										7
									
								
								test/vboot/sandbox-kernel.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/vboot/sandbox-kernel.dts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| /dts-v1/; | ||||
|  | ||||
| / { | ||||
| 	model = "Sandbox Verified Boot Test"; | ||||
| 	compatible = "sandbox"; | ||||
|  | ||||
| }; | ||||
							
								
								
									
										7
									
								
								test/vboot/sandbox-u-boot.dts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								test/vboot/sandbox-u-boot.dts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| /dts-v1/; | ||||
|  | ||||
| / { | ||||
| 	model = "Sandbox Verified Boot Test"; | ||||
| 	compatible = "sandbox"; | ||||
|  | ||||
| }; | ||||
							
								
								
									
										45
									
								
								test/vboot/sign-configs.its
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								test/vboot/sign-configs.its
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| /dts-v1/; | ||||
|  | ||||
| / { | ||||
| 	description = "Chrome OS kernel image with one or more FDT blobs"; | ||||
| 	#address-cells = <1>; | ||||
|  | ||||
| 	images { | ||||
| 		kernel@1 { | ||||
| 			data = /incbin/("test-kernel.bin"); | ||||
| 			type = "kernel_noload"; | ||||
| 			arch = "sandbox"; | ||||
| 			os = "linux"; | ||||
| 			compression = "none"; | ||||
| 			load = <0x4>; | ||||
| 			entry = <0x8>; | ||||
| 			kernel-version = <1>; | ||||
| 			hash@1 { | ||||
| 				algo = "sha1"; | ||||
| 			}; | ||||
| 		}; | ||||
| 		fdt@1 { | ||||
| 			description = "snow"; | ||||
| 			data = /incbin/("sandbox-kernel.dtb"); | ||||
| 			type = "flat_dt"; | ||||
| 			arch = "sandbox"; | ||||
| 			compression = "none"; | ||||
| 			fdt-version = <1>; | ||||
| 			hash@1 { | ||||
| 				algo = "sha1"; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
| 	configurations { | ||||
| 		default = "conf@1"; | ||||
| 		conf@1 { | ||||
| 			kernel = "kernel@1"; | ||||
| 			fdt = "fdt@1"; | ||||
| 			signature@1 { | ||||
| 				algo = "sha1,rsa2048"; | ||||
| 				key-name-hint = "dev"; | ||||
| 				sign-images = "fdt", "kernel"; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										42
									
								
								test/vboot/sign-images.its
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								test/vboot/sign-images.its
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| /dts-v1/; | ||||
|  | ||||
| / { | ||||
| 	description = "Chrome OS kernel image with one or more FDT blobs"; | ||||
| 	#address-cells = <1>; | ||||
|  | ||||
| 	images { | ||||
| 		kernel@1 { | ||||
| 			data = /incbin/("test-kernel.bin"); | ||||
| 			type = "kernel_noload"; | ||||
| 			arch = "sandbox"; | ||||
| 			os = "linux"; | ||||
| 			compression = "none"; | ||||
| 			load = <0x4>; | ||||
| 			entry = <0x8>; | ||||
| 			kernel-version = <1>; | ||||
| 			signature@1 { | ||||
| 				algo = "sha1,rsa2048"; | ||||
| 				key-name-hint = "dev"; | ||||
| 			}; | ||||
| 		}; | ||||
| 		fdt@1 { | ||||
| 			description = "snow"; | ||||
| 			data = /incbin/("sandbox-kernel.dtb"); | ||||
| 			type = "flat_dt"; | ||||
| 			arch = "sandbox"; | ||||
| 			compression = "none"; | ||||
| 			fdt-version = <1>; | ||||
| 			signature@1 { | ||||
| 				algo = "sha1,rsa2048"; | ||||
| 				key-name-hint = "dev"; | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
| 	configurations { | ||||
| 		default = "conf@1"; | ||||
| 		conf@1 { | ||||
| 			kernel = "kernel@1"; | ||||
| 			fdt = "fdt@1"; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
							
								
								
									
										126
									
								
								test/vboot/vboot_test.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										126
									
								
								test/vboot/vboot_test.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| #!/bin/sh | ||||
| # | ||||
| # Copyright (c) 2013, Google Inc. | ||||
| # | ||||
| # Simple Verified Boot Test Script | ||||
| # | ||||
| # This program is free software; you can redistribute it and/or | ||||
| # modify it under the terms of the GNU General Public License as | ||||
| # published by the Free Software Foundation; either version 2 of | ||||
| # the License, or (at your option) any later version. | ||||
| # | ||||
| # This program is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with this program; if not, write to the Free Software | ||||
| # Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||||
| # MA 02111-1307 USA | ||||
|  | ||||
| set -e | ||||
|  | ||||
| # Run U-Boot and report the result | ||||
| # Args: | ||||
| #	$1:	Test message | ||||
| run_uboot() { | ||||
| 	echo -n "Test Verified Boot Run: $1: " | ||||
| 	${uboot} -d sandbox-u-boot.dtb >${tmp} -c ' | ||||
| sb load host 0 100 test.fit; | ||||
| fdt addr 100; | ||||
| bootm 100; | ||||
| reset' | ||||
| 	if ! grep -q "$2" ${tmp}; then | ||||
| 		echo | ||||
| 		echo "Verified boot key check failed, output follows:" | ||||
| 		cat ${tmp} | ||||
| 		false | ||||
| 	else | ||||
| 		echo "OK" | ||||
| 	fi | ||||
| } | ||||
|  | ||||
| echo "Simple Verified Boot Test" | ||||
| echo "=========================" | ||||
| echo | ||||
| echo "Please see doc/uImage.FIT/verified-boot.txt for more information" | ||||
| echo | ||||
|  | ||||
| err=0 | ||||
| tmp=/tmp/vboot_test.$$ | ||||
|  | ||||
| dir=$(dirname $0) | ||||
|  | ||||
| if [ -z ${O} ]; then | ||||
| 	O=. | ||||
| fi | ||||
| O=$(readlink -f ${O}) | ||||
|  | ||||
| dtc="-I dts -O dtb -p 2000" | ||||
| uboot="${O}/u-boot" | ||||
| mkimage="${O}/tools/mkimage" | ||||
| keys="${dir}/dev-keys" | ||||
| echo ${mkimage} -D "${dtc}" | ||||
|  | ||||
| echo "Build keys" | ||||
| mkdir -p ${keys} | ||||
|  | ||||
| # Create an RSA key pair | ||||
| openssl genrsa -F4 -out ${keys}/dev.key 2048 2>/dev/null | ||||
|  | ||||
| # Create a certificate containing the public key | ||||
| openssl req -batch -new -x509 -key ${keys}/dev.key -out ${keys}/dev.crt | ||||
|  | ||||
| pushd ${dir} >/dev/null | ||||
|  | ||||
| # Compile our device tree files for kernel and U-Boot (CONFIG_OF_CONTROL) | ||||
| dtc -p 0x1000 sandbox-kernel.dts -O dtb -o sandbox-kernel.dtb | ||||
| dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb | ||||
|  | ||||
| # Create a number kernel image with zeroes | ||||
| head -c 5000 /dev/zero >test-kernel.bin | ||||
|  | ||||
| # Build the FIT, but don't sign anything yet | ||||
| echo Build FIT with signed images | ||||
| ${mkimage} -D "${dtc}" -f sign-images.its test.fit >${tmp} | ||||
|  | ||||
| run_uboot "unsigned signatures:" "dev-" | ||||
|  | ||||
| # Sign images with our dev keys | ||||
| echo Sign images | ||||
| ${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp} | ||||
|  | ||||
| run_uboot "signed images" "dev+" | ||||
|  | ||||
|  | ||||
| # Create a fresh .dtb without the public keys | ||||
| dtc -p 0x1000 sandbox-u-boot.dts -O dtb -o sandbox-u-boot.dtb | ||||
|  | ||||
| echo Build FIT with signed configuration | ||||
| ${mkimage} -D "${dtc}" -f sign-configs.its test.fit >${tmp} | ||||
|  | ||||
| run_uboot "unsigned config" "sha1+ OK" | ||||
|  | ||||
| # Sign images with our dev keys | ||||
| echo Sign images | ||||
| ${mkimage} -D "${dtc}" -F -k dev-keys -K sandbox-u-boot.dtb -r test.fit >${tmp} | ||||
|  | ||||
| run_uboot "signed config" "dev+" | ||||
|  | ||||
| # Increment the first byte of the signature, which should cause failure | ||||
| sig=$(fdtget -t bx test.fit /configurations/conf@1/signature@1 value) | ||||
| newbyte=$(printf %x $((0x${sig:0:2} + 1))) | ||||
| sig="${newbyte} ${sig:2}" | ||||
| fdtput -t bx test.fit /configurations/conf@1/signature@1 value ${sig} | ||||
|  | ||||
| run_uboot "signed config with bad hash" "Bad Data Hash" | ||||
|  | ||||
| popd >/dev/null | ||||
|  | ||||
| echo | ||||
| if ${ok}; then | ||||
| 	echo "Test passed" | ||||
| else | ||||
| 	echo "Test failed" | ||||
| fi | ||||
		Reference in New Issue
	
	Block a user