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:
Simon Glass 2013-06-13 15:10:11 -07:00 committed by Tom Rini
parent 74378cf8e7
commit 041bca5ba3
7 changed files with 334 additions and 0 deletions

View 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
View File

@ -0,0 +1,3 @@
/*.dtb
/test.fit
/dev-keys

View File

@ -0,0 +1,7 @@
/dts-v1/;
/ {
model = "Sandbox Verified Boot Test";
compatible = "sandbox";
};

View File

@ -0,0 +1,7 @@
/dts-v1/;
/ {
model = "Sandbox Verified Boot Test";
compatible = "sandbox";
};

View 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";
};
};
};
};

View 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
View 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