blob: 42ed9dc97bd45b4abcf30bba8f9761e65bde1408 [file] [log] [blame]
#!/bin/sh
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Derived from dev_debug_vboot.
#
# This script checks if system firmware and SSD images are ready for verified
# booting.
#
. "$(dirname "$0")/common.sh" || exit 1
if [ "$#" != "2" ]; then
alert "ERROR: Usage: $0 kernel_device main_firmware"
exit 1
fi
DEVKEYS="/usr/share/vboot/devkeys"
TMPDIR="$(mktemp -d)"
KERN_DEV="$(readlink -f "$1")"
FIRMWARE_IMAGE="$(readlink -f "$2")"
RETURN=0
invoke() {
# Usage: invoke "message" "shell-command"
result=0
message="$1"
shift
eval "$@" >_stdout 2>_stderr || result=$?
if [ "$result" != 0 ]; then
alert "ERROR: Failed to $message"
alert "Command detail: $@"
cat _stdout _stderr 1>&2
RETURN=1
fi
}
detect_section_name() {
# Usage: detect_section_name official_name alias_name
if [ -f "$2" ]; then
echo "$2"
else
echo "$1"
fi
}
verify_keys() {
# Usage: verify_keys kernel_device main_firmware
# Define section names
GBB="$(detect_section_name GBB GBB_Area)"
FW_MAIN_A="$(detect_section_name FW_MAIN_A Firmware_A_Data)"
FW_MAIN_B="$(detect_section_name FW_MAIN_B Firmware_B_Data)"
VBLOCK_A="$(detect_section_name VBLOCK_A Firmware_A_Key)"
VBLOCK_B="$(detect_section_name VBLOCK_B Firmware_B_Key)"
invoke "dump kernel" dd if="$1" bs=1M count=64 of=hd_kern.blob
invoke "extract firmware" dump_fmap -x "$2"
invoke "get keys from firmware" \
gbb_utility -g --rootkey rootkey.vbpubk \
--recoverykey recoverykey.vbpubk "$GBB"
invoke "unpack rootkey" \
vbutil_key --unpack rootkey.vbpubk
invoke "unpack recovery key" \
vbutil_key --unpack recoverykey.vbpubk
# check if rootkey is developer key. 130 is the magic number for DEV key
local key
local rootkey_hash="$(od "rootkey.vbpubk" |
head -130 |
md5sum |
sed 's/ .*$//' 2>/dev/null || true)"
if [ "$rootkey_hash" = "a13642246ef93daaf75bd791446fec9b" ]; then
alert "ERROR: YOU ARE TRYING TO FINALIZE WITH DEV ROOTKEY."
fi
# Verify firmware A/B with root key
invoke "verify VBLOCK_A with FW_MAIN_A" \
vbutil_firmware --verify "$VBLOCK_A" --signpubkey rootkey.vbpubk \
--fv "$FW_MAIN_A" --kernelkey kernel_subkey_a.vbpubk
invoke "verify VBLOCK_B with FW_MAIN_B" \
vbutil_firmware --verify "$VBLOCK_B" --signpubkey rootkey.vbpubk \
--fv "$FW_MAIN_B" --kernelkey kernel_subkey_b.vbpubk
# Unpack keys and keyblocks
for key in kernel_subkey_a.vbpubk kernel_subkey_b.vbpubk; do
invoke "unpack $key" vbutil_key --unpack $key
done
for keyblock in *kern*.blob; do
invoke "unpack $keyblock" vbutil_keyblock --unpack $keyblock
done
# Test each kernel by each key
for key in kernel_subkey_a.vbpubk kernel_subkey_b.vbpubk
do
for kern in *kern*.blob; do
invoke "verify $kern by $key" \
vbutil_kernel --verify $kern --signpubkey $key
done
done
if [ "$RETURN" != "0" ]; then
# Error encountered. Let's try if we can provide more information.
key="recoverykey.vbpubk"
vbutil_kernel --verify "$kern" --signpubkey "$key" >/dev/null 2>&1 &&
alert "ERROR: YOU ARE USING A RECOVERY KEY SIGNED IMAGE." ||
true
for key in recovery_key.vbpubk kernel_subkey.vbpubk; do
if [ -f "$DEVKEYS/$key" ]; then
vbutil_kernel --verify "$kern" \
--signpubkey "$DEVKEYS/$key" >/dev/null 2>&1 &&
alert "ERROR: YOU ARE FINALIZING WITH DEV-SIGNED IMAGE ($key)." ||
true
fi
done
alert "ERROR: Verification failed."
else
alert "SUCCESS: Verification complete."
fi
return $RETURN
}
# verify_keys is run inside a sub-shell, so we need to check its return value
# instead of reading the global variable RETURN.
( cd "$TMPDIR"
alert "Checking firmware and kernel partition keys for $KERN_DEV..."
verify_keys "$KERN_DEV" "$FIRMWARE_IMAGE" ) || RETURN=1
/bin/rm -rf "$TMPDIR"
exit $RETURN