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>
diff --git a/doc/uImage.FIT/verified-boot.txt b/doc/uImage.FIT/verified-boot.txt
new file mode 100644
index 0000000..3c83fbc
--- /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 0000000..4631242
--- /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 0000000..a1e853c
--- /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 0000000..a1e853c
--- /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 0000000..db2ed79
--- /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 0000000..f69326a
--- /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 0000000..c3cfade
--- /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