diff options
| -rw-r--r-- | doc/uImage.FIT/verified-boot.txt | 104 | ||||
| -rw-r--r-- | test/vboot/.gitignore | 3 | ||||
| -rw-r--r-- | test/vboot/sandbox-kernel.dts | 7 | ||||
| -rw-r--r-- | test/vboot/sandbox-u-boot.dts | 7 | ||||
| -rw-r--r-- | test/vboot/sign-configs.its | 45 | ||||
| -rw-r--r-- | test/vboot/sign-images.its | 42 | ||||
| -rwxr-xr-x | test/vboot/vboot_test.sh | 126 | 
7 files changed, 334 insertions, 0 deletions
| diff --git a/doc/uImage.FIT/verified-boot.txt b/doc/uImage.FIT/verified-boot.txt new file mode 100644 index 000000000..3c83fbc2c --- /dev/null +++ b/doc/uImage.FIT/verified-boot.txt @@ -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 diff --git a/test/vboot/.gitignore b/test/vboot/.gitignore new file mode 100644 index 000000000..463124270 --- /dev/null +++ b/test/vboot/.gitignore @@ -0,0 +1,3 @@ +/*.dtb +/test.fit +/dev-keys diff --git a/test/vboot/sandbox-kernel.dts b/test/vboot/sandbox-kernel.dts new file mode 100644 index 000000000..a1e853c9c --- /dev/null +++ b/test/vboot/sandbox-kernel.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { +	model = "Sandbox Verified Boot Test"; +	compatible = "sandbox"; + +}; diff --git a/test/vboot/sandbox-u-boot.dts b/test/vboot/sandbox-u-boot.dts new file mode 100644 index 000000000..a1e853c9c --- /dev/null +++ b/test/vboot/sandbox-u-boot.dts @@ -0,0 +1,7 @@ +/dts-v1/; + +/ { +	model = "Sandbox Verified Boot Test"; +	compatible = "sandbox"; + +}; diff --git a/test/vboot/sign-configs.its b/test/vboot/sign-configs.its new file mode 100644 index 000000000..db2ed7935 --- /dev/null +++ b/test/vboot/sign-configs.its @@ -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"; +			}; +		}; +	}; +}; diff --git a/test/vboot/sign-images.its b/test/vboot/sign-images.its new file mode 100644 index 000000000..f69326a39 --- /dev/null +++ b/test/vboot/sign-images.its @@ -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"; +		}; +	}; +}; diff --git a/test/vboot/vboot_test.sh b/test/vboot/vboot_test.sh new file mode 100755 index 000000000..c3cfadeb1 --- /dev/null +++ b/test/vboot/vboot_test.sh @@ -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 |