firmware/coreboot: Subtree merged vboot

Signed-off-by: David Hendricks <dhendricks@fb.com>
This commit is contained in:
David Hendricks
2018-06-14 15:19:54 -07:00
1243 changed files with 109589 additions and 1 deletions

View File

@@ -0,0 +1,3 @@
gauravsh@chromium.org
rcui@chromium.org
vapier@chromium.org

View File

@@ -0,0 +1,33 @@
#!/bin/bash
#
# Copyright (c) 2014 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.
#
# Generate version information
if ghash=$(git rev-parse --short --verify HEAD 2>/dev/null); then
if gdesc=$(git describe --dirty --match='v*' 2>/dev/null); then
IFS="-" fields=($gdesc)
tag="${fields[0]}"
IFS="." vernum=($tag)
numcommits=$((${vernum[2]}+${fields[1]:-0}))
ver_major="${vernum[0]}"
ver_branch="${vernum[1]}"
else
numcommits=$(git rev-list HEAD | wc -l)
ver_major="v0"
ver_branch="0"
fi
# avoid putting the -dirty attribute if only the timestamp
# changed
dirty=$(sh -c "[ '$(git diff-index --name-only HEAD)' ] \
&& echo '-dirty'")
ver="${ver_major}.${ver_branch}.${numcommits}-${ghash}${dirty}"
else
ver="unknown"
fi
date=$(date '+%F %T')
echo "const char futility_version[] = \"${ver} ${date} ${USER}\";";

View File

@@ -0,0 +1,150 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Script to preserve the on-disk file layout of the specified image and
# the latest shipping image. This is accomplished by copying the new rootfs
# over a template rootfs (aka the latest shipping image) to preserve as much
# of the metadata from the shipping rootfs as possible. This will ensure
# minimal disk shuffling when applying the auto-update.
#
# Note: This script does not recompute the rootfs hash.
# Load common library. This should be the first executable line.
# The path to common.sh should be relative to your script's location.
. "$(dirname "$0")/common.sh"
load_shflags
# Flags.
DEFINE_string image "" \
"The image that needs to be aligned to the latest shipping image."
DEFINE_string src_image "" \
"The image to align against."
# Copies the rootfs from |SRC_IMAGE| to the |DST_ROOT_FS| and preserves as
# much of the file system metadata in |DST_ROOT_FS| as possible.
# Args: SRC_IMAGE DST_ROOT_FS
copy_root_fs() {
local src_image=$1
local dst_root_fs=$2
# Mount the src and dst rootfs.
local src_root_fs_dir=$(mktemp -d "/tmp/align_root_fs_src_mount_dir.XXXX")
add_cleanup_action "sudo rm -rf \"${src_root_fs_dir}\""
mount_image_partition_ro "${src_image}" 3 "${src_root_fs_dir}"
add_cleanup_action "sudo umount \"${src_root_fs_dir}\""
local dst_root_fs_dir=$(mktemp -d "/tmp/align_root_fs_dst_mount_dir.XXXX")
add_cleanup_action "sudo rm -rf \"${dst_root_fs_dir}\""
sudo mount -o loop "${dst_root_fs}" "${dst_root_fs_dir}" -o loop
add_cleanup_action "sudo umount \"${dst_root_fs_dir}\""
# Temporarily make immutable files on the dst rootfs mutable.
# We'll need to track these files in ${immutable_files} so we can make them
# mutable again.
local immutable_files=()
sudo find "${dst_root_fs_dir}" -xdev -type f |
while read -r file; do
immutable=$(sudo lsattr "${file}" | cut -d' ' -f1 | grep -q i ; echo $?)
if [ $immutable -eq 0 ]; then
immutable_files=("${immutable_files[@]}" "${file}")
sudo chattr -i "${file}"
fi
done
# Copy files from the src rootfs over top of dst rootfs.
# Use the --inplace flag to preserve as much of the file system metadata
# as possible.
sudo rsync -v -a -H -A -x --force --inplace --numeric-ids --delete \
"${src_root_fs_dir}"/ "${dst_root_fs_dir}"
# Make immutable files immutable again.
for file in ${immutable_files[*]} ; do
sudo chattr +i "${file}"
done
# Unmount the src and dst root fs so that we can replace the rootfs later.
perform_latest_cleanup_action
perform_latest_cleanup_action
perform_latest_cleanup_action
perform_latest_cleanup_action
}
# Zeroes the rootfs free space in the specified image.
# Args: IMAGE
zero_root_fs_free_space() {
local image=$1
local root_fs_dir=$(mktemp -d "/tmp/align_rootfs_zero_free_space_dir.XXXX")
add_cleanup_action "sudo rm -rf \"${root_fs_dir}\""
mount_image_partition "${image}" 3 "${root_fs_dir}"
add_cleanup_action "sudo umount \"${root_fs_dir}\""
info "Zeroing free space in rootfs"
sudo dd if=/dev/zero of="${root_fs_dir}/filler" oflag=sync bs=4096 || true
sudo rm -f "${root_fs_dir}/filler"
sudo sync
perform_latest_cleanup_action
perform_latest_cleanup_action
}
main() {
# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# Only now can we die on error. shflags functions leak non-zero error codes,
# so will die prematurely if 'set -e' is specified before now.
set -e
# Make sure we have the required parameters.
if [ -z "${FLAGS_image}" ]; then
die "--image is required."
fi
if [ ! -f "${FLAGS_image}" ]; then
die "Cannot find the specified image."
fi
if [ -z "${FLAGS_src_image}" ]; then
die "--src_image is required."
fi
if [ ! -f "${FLAGS_src_image}" ]; then
die "Cannot find the specified source image."
fi
# Make sure the two rootfs are the same size.
# If they are not, then there is nothing for us to do.
# Note: Exit with a zero code so we do not break the build workflow.
local src_root_fs_size=$(partsize "${FLAGS_src_image}" 3)
local new_root_fs_size=$(partsize "${FLAGS_image}" 3)
if [ ${src_root_fs_size} -ne ${new_root_fs_size} ]; then
warn "The source rootfs and the new rootfs are not the same size."
exit 0
fi
# Extract the rootfs from the src image and use this as a template
# for the new image.
temp_root_fs=$(mktemp "/tmp/align_rootfs_temp_rootfs.XXXX")
add_cleanup_action "sudo rm -f \"${temp_root_fs}\""
info "Extracting rootfs from src image"
extract_image_partition "${FLAGS_src_image}" 3 "${temp_root_fs}"
enable_rw_mount "${temp_root_fs}"
# Perform actual copy of the two root file systems.
info "Copying rootfs"
copy_root_fs "${FLAGS_image}" "${temp_root_fs}"
# Replace the rootfs in the new image with the aligned version.
info "Replacing rootfs"
replace_image_partition "${FLAGS_image}" 3 "${temp_root_fs}"
# Zero rootfs free space.
zero_root_fs_free_space "${FLAGS_image}"
}
main "$@"

View File

@@ -0,0 +1,152 @@
#!/bin/bash
#
# 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.
. "$(dirname "$0")/common_minimal.sh"
CROS_LOG_PREFIX="${PROG}: "
# Array of actions that are executed during the clean up process.
declare -a cleanup_actions
# Adds an action to be executed during the clean up process.
# Actions are executed in the reverse order of when they were added.
# ARGS: ACTION
add_cleanup_action() {
cleanup_actions[${#cleanup_actions[*]}]=$1
}
# Performs the latest clean up action and removes it from the list.
perform_latest_cleanup_action() {
local num_actions=${#cleanup_actions[*]}
if [ ${num_actions} -gt 0 ]; then
eval "${cleanup_actions[$num_actions-1]}" > /dev/null 2>&1
unset cleanup_actions[$num_actions-1]
fi
}
# Performs clean up by executing actions in the cleanup_actions array in
# reversed order.
cleanup() {
set +e
while [ ${#cleanup_actions[*]} -gt 0 ]; do
perform_latest_cleanup_action
done
set -e
}
# ANSI color codes used when displaying messages.
# Taken from src/scripts/common.sh.
V_RED="\e[31m"
V_YELLOW="\e[33m"
V_BOLD_GREEN="\e[1;32m"
V_BOLD_RED="\e[1;31m"
V_BOLD_YELLOW="\e[1;33m"
V_VIDOFF="\e[0m"
# Prints an informational message.
# Taken from src/scripts/common.sh.
# Arg: MESSAGE
info() {
echo -e >&2 "${V_BOLD_GREEN}${CROS_LOG_PREFIX:-}INFO : $*${V_VIDOFF}"
}
# Prints a warning message.
# Taken from src/scripts/common.sh.
# Arg: MESSAGE
warn() {
echo -e >&2 "${V_BOLD_YELLOW}${CROS_LOG_PREFIX:-}WARNING: $*${V_VIDOFF}"
}
# Prints the specified error and exit the script with an error code.
# Taken from src/scripts/common.sh.
# Args: MESSAGE
error() {
echo -e >&2 "${V_BOLD_RED}${CROS_LOG_PREFIX:-}ERROR : $*${V_VIDOFF}"
}
TEMP_LOOP_LIST=$(mktemp)
# Setup a loopback device for a file and scan for partitions, with retries.
#
# $1 - The file to back the new loopback device.
# $2-$N - Additional arguments to pass to losetup.
loopback_partscan() {
local lb_dev image="$1"
shift
# We know partition scanning & dev node creation can be racy with udev and
# the kernel, and the kernel does not sleep/wait for it to finish. We have
# to use the partx tool manually as it will sleep until things are finished.
lb_dev=$(sudo losetup --show -f "$@" "${image}")
# Cache the path so we can clean it up.
echo "${lb_dev}" >>"${TEMP_LOOP_LIST}"
# Ignore problems deleting existing partitions. There shouldn't be any
# which will upset partx, but that's actually ok.
sudo partx -d "${lb_dev}" 2>/dev/null || true
sudo partx -a "${lb_dev}"
echo "${lb_dev}"
}
# Detach a loopback device set up earlier.
#
# $1 - The loop device to detach.
# $2-$N - Additional arguments to pass to losetup.
loopback_detach() {
# Retry the deletes before we detach. crbug.com/469259
local i
for (( i = 0; i < 10; i++ )); do
if sudo partx -d "$1"; then
break
fi
warn "Sleeping & retrying ..."
sync
sleep 1
done
sudo losetup --detach "$@"
}
# Clear out all loopback devices we setup.
cleanup_loopbacks() {
local line
while read -r line; do
loopback_detach "${line}" 2>/dev/null
done <"${TEMP_LOOP_LIST}"
rm -f "${TEMP_LOOP_LIST}"
}
# Usage: lsbval path-to-lsb-file key
# Returns the value for the given lsb-release file variable.
lsbval() {
local lsbfile="$1"
local key="$2"
grep "^${key}=" "${lsbfile}" | sed "s/^${key}=//"
}
# Usage: get_board_from_lsb_release rootfs
# Returns the exact board name from /etc/lsb-release. This may contain
# dashes or other characters not suitable for variable names. See the
# next function for that.
get_board_from_lsb_release() {
local rootfs="$1"
lsbval "${rootfs}/etc/lsb-release" CHROMEOS_RELEASE_BOARD
}
# Usage: get_boardvar_from_lsb_release rootfs
# Returns the board name from /etc/lsb-release in a mangled form that can
# be used in variable names. e.g. dashes are turned into underscores.
get_boardvar_from_lsb_release() {
get_board_from_lsb_release "$@" | sed 's:[-]:_:g'
}
# This will override the trap set in common_minmal.sh
trap "cleanup" INT TERM EXIT
add_cleanup_action "cleanup_temps_and_mounts"
add_cleanup_action "cleanup_loopbacks"

View File

@@ -0,0 +1,480 @@
#!/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.
#
# Note: This file must be written in dash compatible way as scripts that use
# this may run in the Chrome OS client enviornment.
# Determine script directory
SCRIPT_DIR=$(dirname $0)
PROG=$(basename $0)
: ${GPT:=cgpt}
: ${FUTILITY:=futility}
# The tag when the rootfs is changed.
TAG_NEEDS_TO_BE_SIGNED="/root/.need_to_be_signed"
# List of Temporary files and mount points.
TEMP_FILE_LIST=$(mktemp)
TEMP_DIR_LIST=$(mktemp)
# Finds and loads the 'shflags' library, or return as failed.
load_shflags() {
# Load shflags
if [ -f /usr/share/misc/shflags ]; then
. /usr/share/misc/shflags
elif [ -f "${SCRIPT_DIR}/lib/shflags/shflags" ]; then
. "${SCRIPT_DIR}/lib/shflags/shflags"
else
echo "ERROR: Cannot find the required shflags library."
return 1
fi
# Add debug option for debug output below
DEFINE_boolean debug $FLAGS_FALSE "Provide debug messages" "d"
}
# Functions for debug output
# ----------------------------------------------------------------------------
# These helpers are for runtime systems. For scripts using common.sh,
# they'll get better definitions that will clobber these ones.
info() {
echo "${PROG}: INFO: $*" >&2
}
warn() {
echo "${PROG}: WARN: $*" >&2
}
error() {
echo "${PROG}: ERROR: $*" >&2
}
# Reports error message and exit(1)
# Args: error message
die() {
error "$@"
exit 1
}
# Returns true if we're running in debug mode.
#
# Note that if you don't set up shflags by calling load_shflags(), you
# must set $FLAGS_debug and $FLAGS_TRUE yourself. The default
# behavior is that debug will be off if you define neither $FLAGS_TRUE
# nor $FLAGS_debug.
is_debug_mode() {
[ "${FLAGS_debug:-not$FLAGS_TRUE}" = "$FLAGS_TRUE" ]
}
# Prints messages (in parameters) in debug mode
# Args: debug message
debug_msg() {
if is_debug_mode; then
echo "DEBUG: $*" 1>&2
fi
}
# Functions for temporary files and directories
# ----------------------------------------------------------------------------
# Create a new temporary file and return its name.
# File is automatically cleaned when cleanup_temps_and_mounts() is called.
make_temp_file() {
local tempfile=$(mktemp)
echo "$tempfile" >> $TEMP_FILE_LIST
echo $tempfile
}
# Create a new temporary directory and return its name.
# Directory is automatically deleted and any filesystem mounted on it unmounted
# when cleanup_temps_and_mounts() is called.
make_temp_dir() {
local tempdir=$(mktemp -d)
echo "$tempdir" >> $TEMP_DIR_LIST
echo $tempdir
}
cleanup_temps_and_mounts() {
for i in $(cat $TEMP_FILE_LIST); do
rm -f $i
done
set +e # umount may fail for unmounted directories
for i in $(cat $TEMP_DIR_LIST); do
if [ -n "$i" ]; then
if has_needs_to_be_resigned_tag "$i"; then
echo "Warning: image may be modified. Please resign image."
fi
sudo umount $i 2>/dev/null
rm -rf $i
fi
done
set -e
rm -rf $TEMP_DIR_LIST $TEMP_FILE_LIST
}
trap "cleanup_temps_and_mounts" EXIT
# Functions for partition management
# ----------------------------------------------------------------------------
# Construct a partition device name from a whole disk block device and a
# partition number.
# This works for [/dev/sda, 3] (-> /dev/sda3) as well as [/dev/mmcblk0, 2]
# (-> /dev/mmcblk0p2).
make_partition_dev() {
local block="$1"
local num="$2"
# If the disk block device ends with a number, we add a 'p' before the
# partition number.
if [ "${block%[0-9]}" = "${block}" ]; then
echo "${block}${num}"
else
echo "${block}p${num}"
fi
}
# Read GPT table to find the starting location of a specific partition.
# Args: DEVICE PARTNUM
# Returns: offset (in sectors) of partition PARTNUM
partoffset() {
sudo $GPT show -b -i $2 $1
}
# Read GPT table to find the size of a specific partition.
# Args: DEVICE PARTNUM
# Returns: size (in sectors) of partition PARTNUM
partsize() {
sudo $GPT show -s -i $2 $1
}
# Tags a file system as "needs to be resigned".
# Args: MOUNTDIRECTORY
tag_as_needs_to_be_resigned() {
local mount_dir="$1"
sudo touch "$mount_dir/$TAG_NEEDS_TO_BE_SIGNED"
}
# Determines if the target file system has the tag for resign
# Args: MOUNTDIRECTORY
# Returns: true if the tag is there otherwise false
has_needs_to_be_resigned_tag() {
local mount_dir="$1"
[ -f "$mount_dir/$TAG_NEEDS_TO_BE_SIGNED" ]
}
# Determines if the target file system is a Chrome OS root fs
# Args: MOUNTDIRECTORY
# Returns: true if MOUNTDIRECTORY looks like root fs, otherwise false
is_rootfs_partition() {
local mount_dir="$1"
[ -f "$mount_dir/$(dirname "$TAG_NEEDS_TO_BE_SIGNED")" ]
}
# If the kernel is buggy and is unable to loop+mount quickly,
# retry the operation a few times.
# Args: IMAGE PARTNUM MOUNTDIRECTORY [ro]
#
# This function does not check whether the partition is allowed to be mounted as
# RW. Callers must ensure the partition can be mounted as RW before calling
# this function without |ro| argument.
_mount_image_partition_retry() {
local image=$1
local partnum=$2
local mount_dir=$3
local ro=$4
local offset=$(( $(partoffset "${image}" "${partnum}") * 512 ))
local out try
set -- sudo LC_ALL=C mount -o loop,offset=${offset},${ro} \
"${image}" "${mount_dir}"
try=1
while [ ${try} -le 5 ]; do
if ! out=$("$@" 2>&1); then
if [ "${out}" = "mount: you must specify the filesystem type" ]; then
printf 'WARNING: mounting %s at %s failed (try %i); retrying\n' \
"${image}" "${mount_dir}" "${try}"
# Try to "quiet" the disks and sleep a little to reduce contention.
sync
sleep $(( try * 5 ))
else
# Failed for a different reason; abort!
break
fi
else
# It worked!
return 0
fi
: $(( try += 1 ))
done
echo "ERROR: mounting ${image} at ${mount_dir} failed:"
echo "${out}"
# We don't preserve the exact exit code of `mount`, but since
# no one in this code base seems to check it, it's a moot point.
return 1
}
# If called without 'ro', make sure the partition is allowed to be mounted as
# 'rw' before actually mounting it.
# Args: IMAGE PARTNUM MOUNTDIRECTORY [ro]
_mount_image_partition() {
local image=$1
local partnum=$2
local mount_dir=$3
local ro=$4
local offset=$(( $(partoffset "${image}" "${partnum}") * 512 ))
if [ "$ro" != "ro" ]; then
# Forcibly call enable_rw_mount. It should fail on unsupported
# filesystems and be idempotent on ext*.
enable_rw_mount "${image}" ${offset} 2> /dev/null
fi
_mount_image_partition_retry "$@"
}
# If called without 'ro', make sure the partition is allowed to be mounted as
# 'rw' before actually mounting it.
# Args: LOOPDEV PARTNUM MOUNTDIRECTORY [ro]
_mount_loop_image_partition() {
local loopdev=$1
local partnum=$2
local mount_dir=$3
local ro=$4
local loop_rootfs="${loopdev}p${partnum}"
if [ "$ro" != "ro" ]; then
# Forcibly call enable_rw_mount. It should fail on unsupported
# filesystems and be idempotent on ext*.
enable_rw_mount "${loop_rootfs}" 2>/dev/null
fi
sudo mount -o "${ro}" "${loop_rootfs}" "${mount_dir}"
}
# Mount a partition read-only from an image into a local directory
# Args: IMAGE PARTNUM MOUNTDIRECTORY
mount_image_partition_ro() {
_mount_image_partition "$@" "ro"
}
# Mount a partition read-only from an image into a local directory
# Args: LOOPDEV PARTNUM MOUNTDIRECTORY
mount_loop_image_partition_ro() {
_mount_loop_image_partition "$@" "ro"
}
# Mount a partition from an image into a local directory
# Args: IMAGE PARTNUM MOUNTDIRECTORY
mount_image_partition() {
local mount_dir=$3
_mount_image_partition "$@"
if is_rootfs_partition "${mount_dir}"; then
tag_as_needs_to_be_resigned "${mount_dir}"
fi
}
# Mount a partition from an image into a local directory
# Args: LOOPDEV PARTNUM MOUNTDIRECTORY
mount_loop_image_partition() {
local mount_dir=$3
_mount_loop_image_partition "$@"
if is_rootfs_partition "${mount_dir}"; then
tag_as_needs_to_be_resigned "${mount_dir}"
fi
}
# Mount the image's ESP (EFI System Partition) on a newly created temporary
# directory.
# Prints out the newly created temporary directory path if succeeded.
# If the image doens't have an ESP partition, returns 0 without print anything.
# Args: LOOPDEV
# Returns: 0 if succeeded, 1 otherwise.
mount_image_esp() {
local loopdev="$1"
local ESP_PARTNUM=12
local loop_esp="${loopdev}p${ESP_PARTNUM}"
local esp_offset=$(( $(partoffset "${loopdev}" "${ESP_PARTNUM}") ))
# Check if the image has an ESP partition.
if [[ "${esp_offset}" == "0" ]]; then
return 0
fi
local esp_dir="$(make_temp_dir)"
if ! sudo mount -o "${ro}" "${loop_esp}" "${esp_dir}"; then
return 1
fi
echo "${esp_dir}"
return 0
}
# Extract a partition to a file
# Args: IMAGE PARTNUM OUTPUTFILE
extract_image_partition() {
local image=$1
local partnum=$2
local output_file=$3
local offset=$(partoffset "$image" "$partnum")
local size=$(partsize "$image" "$partnum")
dd if=$image of=$output_file bs=512 skip=$offset count=$size \
conv=notrunc 2>/dev/null
}
# Replace a partition in an image from file
# Args: IMAGE PARTNUM INPUTFILE
replace_image_partition() {
local image=$1
local partnum=$2
local input_file=$3
local offset=$(partoffset "$image" "$partnum")
local size=$(partsize "$image" "$partnum")
dd if=$input_file of=$image bs=512 seek=$offset count=$size \
conv=notrunc 2>/dev/null
}
# For details, see crosutils.git/common.sh
enable_rw_mount() {
local rootfs="$1"
local offset="${2-0}"
# Make sure we're checking an ext2 image
if ! is_ext2 "$rootfs" $offset; then
echo "enable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2
return 1
fi
local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte
# Dash can't do echo -ne, but it can do printf "\NNN"
# We could use /dev/zero here, but this matches what would be
# needed for disable_rw_mount (printf '\377').
printf '\000' |
sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \
conv=notrunc count=1 bs=1 2>/dev/null
}
# For details, see crosutils.git/common.sh
is_ext2() {
local rootfs="$1"
local offset="${2-0}"
# Make sure we're checking an ext2 image
local sb_magic_offset=$((0x438))
local sb_value=$(sudo dd if="$rootfs" skip=$((offset + sb_magic_offset)) \
count=2 bs=1 2>/dev/null)
local expected_sb_value=$(printf '\123\357')
if [ "$sb_value" = "$expected_sb_value" ]; then
return 0
fi
return 1
}
disable_rw_mount() {
local rootfs="$1"
local offset="${2-0}"
# Make sure we're checking an ext2 image
if ! is_ext2 "$rootfs" $offset; then
echo "disable_rw_mount called on non-ext2 filesystem: $rootfs $offset" 1>&2
return 1
fi
local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte
# Dash can't do echo -ne, but it can do printf "\NNN"
# We could use /dev/zero here, but this matches what would be
# needed for disable_rw_mount (printf '\377').
printf '\377' |
sudo dd of="$rootfs" seek=$((offset + ro_compat_offset)) \
conv=notrunc count=1 bs=1 2>/dev/null
}
rw_mount_disabled() {
local rootfs="$1"
local offset="${2-0}"
# Make sure we're checking an ext2 image
if ! is_ext2 "$rootfs" $offset; then
return 2
fi
local ro_compat_offset=$((0x464 + 3)) # Set 'highest' byte
local ro_value=$(sudo dd if="$rootfs" skip=$((offset + ro_compat_offset)) \
count=1 bs=1 2>/dev/null)
local expected_ro_value=$(printf '\377')
if [ "$ro_value" = "$expected_ro_value" ]; then
return 0
fi
return 1
}
# Functions for CBFS management
# ----------------------------------------------------------------------------
# Get the compression algorithm used for the given CBFS file.
# Args: INPUT_CBFS_IMAGE CBFS_FILE_NAME
get_cbfs_compression() {
cbfstool "$1" print -r "FW_MAIN_A" | awk -vname="$2" '$1 == name {print $5}'
}
# Store a file in CBFS.
# Args: INPUT_CBFS_IMAGE INPUT_FILE CBFS_FILE_NAME
store_file_in_cbfs() {
local image="$1"
local file="$2"
local name="$3"
local compression=$(get_cbfs_compression "$1" "${name}")
cbfstool "${image}" remove -r "FW_MAIN_A,FW_MAIN_B" -n "${name}" || return
# This add can fail if
# 1. Size of a signature after compression is larger
# 2. CBFS is full
# These conditions extremely unlikely become true at the same time.
cbfstool "${image}" add -r "FW_MAIN_A,FW_MAIN_B" -t "raw" \
-c "${compression}" -f "${file}" -n "${name}" || return
}
# Misc functions
# ----------------------------------------------------------------------------
# Parses the version file containing key=value lines
# Args: key file
# Returns: value
get_version() {
local key="$1"
local file="$2"
awk -F= -vkey="${key}" '$1 == key { print $NF }' "${file}"
}
# Returns true if all files in parameters exist.
# Args: List of files
ensure_files_exist() {
local filename return_value=0
for filename in "$@"; do
if [ ! -f "$filename" -a ! -b "$filename" ]; then
echo "ERROR: Cannot find required file: $filename"
return_value=1
fi
done
return $return_value
}
# Check if the 'chronos' user already has a password
# Args: rootfs
no_chronos_password() {
local rootfs=$1
# Make sure the chronos user actually exists.
if grep -qs '^chronos:' "${rootfs}/etc/passwd"; then
sudo grep -q '^chronos:\*:' "${rootfs}/etc/shadow"
fi
}
# Returns true if given ec.bin is signed or false if not.
is_ec_rw_signed() {
${FUTILITY} dump_fmap "$1" | grep -q KEY_RO
}
trap "cleanup_temps_and_mounts" EXIT

View File

@@ -0,0 +1,75 @@
#!/bin/bash
# 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.
# Script to convert a recovery image into an SSD image usable by factory.
# TODO(gauravsh): crosbug.com/14790 (Merge this with
# convert_recovery_to_ssd.sh)
# Load common constants and variables.
. "$(dirname "$0")/common_minimal.sh"
usage() {
cat <<EOF
Usage: $PROG <signed_recovery_image> <original_image_zip> <output_ssd_image>
Converts <signed_recovery_image> into a full SSD image usable by factory. Uses
stateful partition from SSD image <original_image_zip>.
EOF
}
if [ $# -ne 3 ]; then
usage
exit 1
fi
type -P cgpt &>/dev/null ||
{ echo "cgpt tool must be in the path"; exit 1; }
# Abort on errors.
set -e
RECOVERY_IMAGE=$1
IMAGE_ZIP=$2
SSD_IMAGE=$3
work_dir=$(make_temp_dir)
echo "Extracting original SSD image."
unzip -o $IMAGE_ZIP chromiumos_base_image.bin -d ${work_dir}
mv ${work_dir}/chromiumos_base_image.bin ${SSD_IMAGE}
kerna_offset=$(partoffset ${RECOVERY_IMAGE} 2)
kernb_offset=$(partoffset ${RECOVERY_IMAGE} 4)
# Kernel partition sizes should be the same.
kern_size=$(partsize ${RECOVERY_IMAGE} 2)
rootfs=$(make_temp_file)
echo "Replacing RootFS on the SSD with that of the RECOVERY image"
extract_image_partition ${RECOVERY_IMAGE} 3 ${rootfs}
replace_image_partition ${SSD_IMAGE} 3 ${rootfs}
kerna=$(make_temp_file)
echo "Replacing KernelA on the SSD with that of the RECOVERY image"
extract_image_partition ${RECOVERY_IMAGE} 4 ${kerna}
replace_image_partition ${SSD_IMAGE} 2 ${kerna}
# Overwrite the kernel vblock on the created SSD image.
stateful_dir=$(make_temp_dir)
tmp_vblock=$(make_temp_file)
mount_image_partition_ro ${RECOVERY_IMAGE} 1 ${stateful_dir}
sudo cp ${stateful_dir}/vmlinuz_hd.vblock ${tmp_vblock}
echo "Overwriting kernel vblock with SSD kernel vblock"
sudo dd if=${tmp_vblock} of=${SSD_IMAGE} seek=${kerna_offset} bs=512 \
conv=notrunc
sudo umount ${stateful_dir}
# Zero out Kernel B partition.
echo "Zeroing out Kernel partition B"
sudo dd if=/dev/zero of=${SSD_IMAGE} seek=${kernb_offset} bs=512 \
count=${kern_size} conv=notrunc
echo "${RECOVERY_IMAGE} was converted to a factory SSD image: ${SSD_IMAGE}"

View File

@@ -0,0 +1,71 @@
#!/bin/bash
# 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.
usage() {
cat <<EOF
Usage: $PROG <image> [--force]
In-place converts recovery <image> into an SSD image. With --force, does not
ask for confirmation from the user.
EOF
exit 1
}
if [ $# -lt 1 ] || [ $# -gt 3 ]; then
usage
else
IMAGE=$1
shift
fi
for arg in "$@"; do
case "$arg" in
--force)
IS_FORCE=${arg}
;;
*)
usage
;;
esac
done
# Load common constants (and use GPT if set above) and variables.
. "$(dirname "$0")/common.sh"
# Abort on errors.
set -e
if [ "${IS_FORCE}" != "--force" ]; then
echo "This will modify ${IMAGE} in-place and convert it into an SSD image."
read -p "Are you sure you want to continue (y/N)? " SURE
SURE="${SURE:0:1}"
[ "${SURE}" != "y" ] && exit 1
fi
loopdev=$(loopback_partscan "${IMAGE}")
loop_kerna="${loopdev}p2"
loop_kernb="${loopdev}p4"
# Move Kernel B to Kernel A.
info "Replacing Kernel partition A with Kernel partition B"
sudo cp "${loop_kernb}" "${loop_kerna}"
# Overwrite the vblock.
info "Overwriting kernel partition A vblock with SSD vblock"
stateful_dir=$(make_temp_dir)
tmp_vblock=$(make_temp_file)
sudo mount -o ro "${loopdev}p1" "${stateful_dir}"
sudo cp "${stateful_dir}/vmlinuz_hd.vblock" "${tmp_vblock}"
# Unmount before overwriting image to avoid sync issues.
sudo umount "${stateful_dir}"
sudo dd if="${tmp_vblock}" of="${loop_kerna}" bs=512 conv=notrunc
# Zero out Kernel B partition.
info "Zeroing out Kernel partition B"
# This will throw a "disk is full" error, so ignore it.
sudo cp /dev/zero "${loop_kernb}" 2>/dev/null || :
info "${IMAGE} was converted to an SSD image."

View File

@@ -0,0 +1,66 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Abort on error.
set -e
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
usage() {
echo "Usage $PROG image [config]"
}
main() {
# We want to catch all the discrepancies, not just the first one.
# So, any time we find one, we set testfail=1 and continue.
# When finished we will use testfail to determine our exit value.
local testfail=0
if [[ $# -ne 1 ]] && [[ $# -ne 2 ]]; then
usage
exit 1
fi
local image="$1"
# Default config location: same name/directory as this script,
# with a .config file extension, ie ensure_no_nonrelease_files.config.
local configfile="$(dirname "$0")/${0/%.sh/.config}"
# Or, maybe a config was provided on the command line.
if [[ $# -eq 2 ]]; then
configfile="$2"
fi
# Either way, load test-expectations data from config.
. "${configfile}" || return 1
local rootfs=$(make_temp_dir)
mount_image_partition_ro "${image}" 3 "${rootfs}"
# Pick the right set of test-expectation data to use.
local boardvar=$(get_boardvar_from_lsb_release "${rootfs}")
eval "release_file_blacklist=(\"\${RELEASE_FILE_BLACKLIST_${boardvar}[@]}\")"
for file in ${release_file_blacklist}; do
if [ -e "${rootfs}/${file}" ]; then
error "${file} exists in this image!"
ls -al "${rootfs}/${file}"
testfail=1
fi
done
# Verify that session_manager isn't configured to pass additional
# environment variables or command-line arguments to Chrome.
local config_path="${rootfs}/etc/chrome_dev.conf"
local matches=$(grep -s "^[^#]" "${config_path}")
if [ -n "${matches}" ]; then
error "Found commands in ${config_path}:"
error "${matches}"
testfail=1
fi
exit ${testfail}
}
main "$@"

View File

@@ -0,0 +1,33 @@
#!/bin/bash
# Copyright (c) 2010 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.
# abort on error
set -e
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
main() {
if [[ $# -ne 1 ]]; then
echo "Usage $0 <image>"
exit 1
fi
local image="$1"
local rootfs
if [[ -d "${image}" ]]; then
rootfs="${image}"
else
rootfs=$(make_temp_dir)
mount_image_partition_ro "${image}" 3 "${rootfs}"
fi
if ! no_chronos_password "${rootfs}"; then
die "chronos password is set! Shouldn't be for release builds."
fi
}
main "$@"

View File

@@ -0,0 +1,35 @@
#!/bin/bash
# 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.
# Abort on error.
set -e
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
usage() {
echo "Usage $PROG image"
}
main() {
if [ $# -ne 1 ]; then
usage
exit 1
fi
local image="$1"
local rootfs=$(make_temp_dir)
mount_image_partition_ro "$image" 3 "$rootfs"
# This mirrors the check performed in the platform_ToolchainOptions
# autotest.
if readelf -s "$rootfs/opt/google/chrome/chrome" | \
grep -q __asan_init; then
exit 1
fi
}
main "$@"

View File

@@ -0,0 +1,166 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Abort on error.
set -e
LSB_FILE=/etc/lsb-release
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
usage() {
echo "Usage $PROG image [config]"
}
# Usage: lsbequals path-to-lsb-file key expected-value
# Returns 0 if they match, 1 otherwise.
# Also outputs a warning message if they don't match.
lsbequals() {
local lsbfile="$1"
local key="$2"
local expectval="$3"
local realval=$(lsbval "$lsbfile" $key)
if [ "$realval" != "$expectval" ]; then
error "${key} mismatch. Expected '${expectval}'," \
"image contains '${realval}'"
return 1
fi
return 0
}
# Usage: check_keyval_in_list lsbfile lsbkey [list of values]
# Extracts the lsb-release value for the specified key, and confirms it
# matches one of the whitelisted values specified in value_array.
# Implementation note:
# You can't really pass bash arrays to functions. Best you can do is either
# serialize to string/pass/deserialize (e.g. using whitspace/IFS hacks), or,
# let the array contents be received as multiple arguments to the target
# function. We take the latter approach here, hence the shift's to get the
# first 2 arguments out, before we process the rest of the varargs.
check_keyval_in_list() {
local lsbfile="$1"
shift
local lsbkey="$1"
shift
local lsbval=$(lsbval "$lsbfile" "$lsbkey")
while [ $# -gt 0 ]; do
if [ "$lsbval" == "$1" ]; then
return 0
fi
shift
done
# If we get here, it wasn't found
error "${lsbkey}: Value '${lsbval}' was not recognized"
return 1
}
# Usage: lsb_syntaxcheck path-to-lsb-file
# Enforces a number of basic sanity checks on the overall format and contents
# of the lsb-release file:
# - Every line is "key=value".
# - No space after key, no space before value.
# - key is all A-Z or _, but not starting with _.
# - value is made up of printable characters, or is empty.
# - Each line is a reasonable size (<255 bytes).
# - The whole file is a reasonable size (4kb).
lsb_syntaxcheck() {
local lsbfile="$1"
syntaxbad=0
# Checks for key being A-Z_, 1 or more characters, not starting with _.
# Also checks for = with no spaces on either side.
# Checks that the value contains printables (and not starting with space).
# Alternatively, the value is permitted to be empty (0 chars) too.
# Allow comments to start with #.
badlines=$(grep -Ev \
-e '^[A-Z][A-Z_]*=([[:graph:]][[:print:]]*)?$' \
-e '^[[:space:]]*#' "${lsbfile}")
if [ -n "$badlines" ]; then
syntaxbad=1
error "${lsbfile}: Some lines seem non-well-formed:"
error "${badlines}"
fi
# Checks for a lines exceeding a reasonable overall length.
badlines=$(grep -E '^.{255}' "$lsbfile")
if [ -n "$badlines" ]; then
syntaxbad=1
error "${lsbfile}: Some lsb-release lines seem unreasonably long:"
error "${badlines}"
fi
# Overall file size check:
size=$(ls -sk "$lsbfile" | cut -d ' ' -f 1)
if [ $size -gt 4 ]; then
syntaxbad=1
error "${lsbfile}: This file exceeds 4kb"
fi
return $syntaxbad
}
main() {
# We want to catch all the discrepancies, not just the first one.
# So, any time we find one, we set testfail=1 and continue.
# When finished we will use testfail to determine our exit value.
local testfail=0
if [ $# -ne 1 ] && [ $# -ne 2 ]; then
usage
exit 1
fi
local image="$1"
# Default config location: same directory as this script.
local configfile="$(dirname "$0")/default_lsb_release.config"
# Or, maybe a config was provided on the command line.
if [ $# -eq 2 ]; then
configfile="$2"
fi
# Either way, load test-expectations data from config.
info "Loading config from ${configfile}"
. "$configfile" || return 1
local rootfs
if [[ -d "${image}" ]]; then
# We're given a mounted rootfs.
rootfs="${image}"
else
# Mount the disk image.
rootfs=$(make_temp_dir)
mount_image_partition_ro "$image" 3 "$rootfs"
fi
local lsb="$rootfs/$LSB_FILE"
# Basic syntax check first.
lsb_syntaxcheck "$lsb" || testfail=1
lsbequals $lsb CHROMEOS_AUSERVER "$expected_auserver" || testfail=1
lsbequals $lsb CHROMEOS_RELEASE_NAME "$expected_release_name" || testfail=1
check_keyval_in_list $lsb CHROMEOS_RELEASE_TRACK \
"${expected_release_tracks[@]}" || testfail=1
local board=$(get_board_from_lsb_release "${rootfs}")
if check_keyval_in_list $lsb CHROMEOS_RELEASE_BOARD \
"${expected_boards[@]}"; then
local boardvar=$(get_boardvar_from_lsb_release "${rootfs}")
channel=$(lsbval $lsb CHROMEOS_RELEASE_TRACK)
# For a canary or dogfood channel, appid maybe a different default value.
if [[ "${channel}" == 'canary-channel' ||
"${channel}" == 'dogfood-channel' ]]; then
eval "expected_appid=\"\$expected_appid_${channel%\-channel}\""
else
eval "expected_appid=\"\$expected_appid_$boardvar\""
fi
lsbequals $lsb CHROMEOS_RELEASE_APPID "$expected_appid" || testfail=1
else # unrecognized board
testfail=1
error "Unknown board: ${board}"
fi
exit $testfail
}
main "$@"

View File

@@ -0,0 +1,218 @@
#!/bin/bash
# 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.
# Abort on error.
set -e
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
# Given a kernel boot param string which includes ...dm="dmstuff"...
# this returns the dmstuff by itself.
get_dmparams() {
echo "$1" | sed 's/^.*\ dm="\([^"]*\)".*/\1/'
}
# Given a kernel boot param string which includes ...dm="stuff"...
# this returns the param string with the dm="..." section removed.
# Useful in conjunction with get_dmparams to divide and process
# the two sections of parameters in seperate passes
kparams_remove_dm() {
echo "$1" | sed 's/dm="[^"]*"//'
}
# Given a dm param string which includes dynamic values, return the
# same string with these values replaced by a magic string placeholder.
# This same magic placeholder is used in the config file, for comparison
# purposes.
dmparams_mangle() {
local dmparams=$1
# First handle new key-value style verity parameters.
dmparams=$(echo "$dmparams" |
sed -e 's/root_hexdigest=[0-9a-fA-F]*/root_hexdigest=MAGIC_HASH/' |
sed -e 's/salt=[0-9a-fA-F]*/salt=MAGIC_SALT'/)
# If we didn't substitute the MAGIC_HASH yet, these are the old
# verity parameter format.
if [[ $dmparams != *MAGIC_HASH* ]]; then
dmparams=$(echo $dmparams | sed 's/sha1 [0-9a-fA-F]*/sha1 MAGIC_HASH/')
fi
# If we have bootcache enabled, replace its copy of the root_hexdigest
# with MAGIC_HASH. The parameter is positional.
if [[ $dmparams == *bootcache* ]]; then
dmparams=$(echo $dmparams |
sed -r 's:(bootcache (PARTUUID=)?%U(/PARTNROFF=|\+)1 [0-9]+) [0-9a-fA-F]+:\1 MAGIC_HASH:')
fi
echo $dmparams
}
# This escapes any non-alphanum character, since many such characters
# are regex metacharacters.
escape_regexmetas() {
echo "$1" | sed 's/\([^a-zA-Z0-9]\)/\\\1/g'
}
usage() {
echo "Usage $PROG image [config]"
}
main() {
# We want to catch all the discrepancies, not just the first one.
# So, any time we find one, we set testfail=1 and continue.
# When finished we will use testfail to determine our exit value.
local testfail=0
# A buffer to include useful information that we dump when things fail.
local output
# Copy of a string before it has been through sed
local pre_sed
# Where the disk image is mounted.
local loopdev
if [[ $# -ne 1 ]] && [[ $# -ne 2 ]]; then
usage
exit 1
fi
local image="$1"
# A byte that should not appear in the command line to use as a sed
# marker when doing regular expression replacements.
local M=$'\001'
# Default config location: same name/directory as this script,
# with a .config file extension, ie ensure_secure_kernelparams.config.
local configfile="$(dirname "$0")/${0/%.sh/.config}"
# Or, maybe a config was provided on the command line.
if [[ $# -eq 2 ]]; then
configfile="$2"
fi
# Either way, load test-expectations data from config.
. "$configfile" || return 1
# Set up the image on a loopback device so it's faster to access.
local loopdev
loopdev=$(loopback_partscan "${image}")
# TODO(jimhebert): Perform the kernel security tests on both the kernel
# partitions. Here, we just run it on kernel partition 4
# which is the install kernel on the recovery image.
# crosbug.com/24274
local loop_kern="${loopdev}p4"
local loop_rootfs="${loopdev}p3"
local rootfs=$(make_temp_dir)
sudo mount -o ro "${loop_rootfs}" "${rootfs}"
# Pick the right set of test-expectation data to use.
local boardvar=$(get_boardvar_from_lsb_release "${rootfs}")
eval "required_kparams=(\"\${required_kparams_${boardvar}[@]}\")"
eval "required_kparams_regex=(\"\${required_kparams_regex_${boardvar}[@]}\")"
eval "optional_kparams=(\"\${optional_kparams_${boardvar}[@]}\")"
eval "optional_kparams_regex=(\"\${optional_kparams_regex_${boardvar}[@]}\")"
eval "required_dmparams=(\"\${required_dmparams_${boardvar}[@]}\")"
eval "required_dmparams_regex=(\"\${required_dmparams_regex_${boardvar}[@]}\")"
output+="required_kparams=(\n"
output+="$(printf "\t'%s'\n" "${required_kparams[@]}")\n)\n"
output+="required_kparams_regex=(\n"
output+="$(printf "\t'%s'\n" "${required_kparams_regex[@]}")\n)\n"
output+="optional_kparams=(\n"
output+="$(printf "\t'%s'\n" "${optional_kparams[@]}")\n)\n"
output+="optional_kparams_regex=(\n"
output+="$(printf "\t'%s'\n" "${optional_kparams_regex[@]}")\n)\n"
output+="required_dmparams=(\n"
output+="$(printf "\t'%s'\n" "${required_dmparams[@]}")\n)\n"
output+="required_dmparams_regex=(\n"
output+="$(printf "\t'%s'\n" "${required_dmparams_regex[@]}")\n)\n"
# Divide the dm params from the rest and process seperately.
local kparams=$(sudo dump_kernel_config "${loop_kern}")
local dmparams=$(get_dmparams "$kparams")
local kparams_nodm=$(kparams_remove_dm "$kparams")
output+="\nkparams='${kparams}'\n"
output+="\ndmparams='${dmparams}'\n"
output+="\nkparams_nodm='${kparams_nodm}'\n"
mangled_dmparams=$(dmparams_mangle "${dmparams}")
output+="\nmangled_dmparams='${mangled_dmparams}'\n"
# Special-case handling of the dm= param:
testfail=1
for expected_dmparams in "${required_dmparams[@]}"; do
# Filter out all dynamic parameters.
if [ "$mangled_dmparams" = "$expected_dmparams" ]; then
testfail=0
break
fi
done
for expected_dmparams in "${required_dmparams_regex[@]}"; do
if [[ -z $(echo "${mangled_dmparams}" | \
sed "s${M}^${expected_dmparams}\$${M}${M}") ]]; then
testfail=0
break
fi
done
if [ $testfail -eq 1 ]; then
echo "Kernel dm= parameter does not match any expected values!"
echo "Actual: $dmparams"
echo "Expected: ${required_dmparams[*]}"
echo "Expected (regex): ${required_dmparams_regex[*]}"
fi
# Ensure all other required params are present.
for param in "${required_kparams[@]}"; do
if [[ "$kparams_nodm" != *$param* ]]; then
echo "Kernel parameters missing required value: $param"
testfail=1
else
# Remove matched params as we go. If all goes well, kparams_nodm
# will be nothing left but whitespace by the end.
param=$(escape_regexmetas "$param")
kparams_nodm=$(echo " ${kparams_nodm} " |
sed "s${M} ${param} ${M} ${M}")
fi
done
# Ensure all other required regex params are present.
for param in "${required_kparams_regex[@]}"; do
pre_sed=" ${kparams_nodm} "
kparams_nodm=$(echo "${pre_sed}" | sed "s${M} ${param} ${M} ${M}")
if [[ "${pre_sed}" == "${kparams_nodm}" ]]; then
echo "Kernel parameters missing required value: ${param}"
testfail=1
fi
done
# Check-off each of the allowed-but-optional params that were present.
for param in "${optional_kparams[@]}"; do
param=$(escape_regexmetas "$param")
kparams_nodm=$(echo " ${kparams_nodm} " |
sed "s${M} ${param} ${M} ${M}")
done
# Check-off each of the allowed-but-optional params that were present.
for param in "${optional_kparams_regex[@]}"; do
kparams_nodm=$(echo " ${kparams_nodm} " |
sed "s${M} ${param} ${M} ${M}")
done
# This section enforces the default-deny for any unexpected params
# not already processed by one of the above loops.
if [[ ! -z ${kparams_nodm// /} ]]; then
echo "Unexpected kernel parameters found:"
echo " $(echo "${kparams_nodm}" | sed -r 's: +: :g')"
testfail=1
fi
if [[ ${testfail} -eq 1 ]]; then
echo "Debug output:"
printf '%b\n' "${output}"
echo "(actual error will be at the top of output)"
fi
exit $testfail
}
main $@

View File

@@ -0,0 +1,34 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Verify that update payload verification is enabled.
# Abort on error.
set -e
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
usage() {
echo "Usage: $PROG image"
}
main() {
if [ $# -ne 1 ]; then
usage
exit 1
fi
local image=$1
local rootfs=$(make_temp_dir)
local key_location="/usr/share/update_engine/update-payload-key.pub.pem"
mount_image_partition_ro "$image" 3 "$rootfs"
if [ ! -e "$rootfs/$key_location" ]; then
die "Update payload verification key not found at $key_location"
fi
}
main "$@"

View File

@@ -0,0 +1,101 @@
#!/bin/bash -eux
# Copyright (c) 2010 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.
# Refer to the Google Chrome OS Main Processor Firmware Specification for what
# the pieces are.
# This script generates different firmware binaries with different
# configurations.
# Syntax: ./firmware_boot.sh <Firmware name without .fd extension>.
# Usage of the script.
usage()
{
cat <<EOF
$0 firmware_name
firmware_name - name of the firmware.
EOF
}
if [ $# != 1 ]; then
usage
exit 0
fi
base=$1
input=${base}.fd
if [ ! -f $input ]; then
echo "$input file does not exists."
exit 0
fi
# First, run dump_fmap $input | ./x to compute these values:
# dev-mode BIOS is in firmware A
rw_a_offset=$(dump_fmap -p ${input} | grep 'RW_SECTION_A' | cut -d' ' -f2)
rw_a_size=$(dump_fmap -p ${input} | grep 'RW_SECTION_A' | cut -d' ' -f3)
# normal-mode BIOS is in firmware B
rw_b_offset=$(dump_fmap -p ${input} | grep 'RW_SECTION_B' | cut -d' ' -f2)
rw_b_size=$(dump_fmap -p ${input} | grep 'RW_SECTION_B' | cut -d' ' -f3)
# Extract the RW BIOS chunks
dd if=${input} of=dev.bin bs=1 skip=${rw_a_offset} count=${rw_a_size}
dd if=${input} of=nor.bin bs=1 skip=${rw_b_offset} count=${rw_b_size}
# Garble one to make it fail the signature. I know that we reserve 64K at the
# start of the section for the signature and headers, so we'll make a random
# payload and put the normal header on the front.
dd if=/dev/urandom of=bad.bin bs=1 count=${rw_b_size}
dd if=nor.bin of=bad.bin conv=notrunc bs=1 count=65536
# A:Normal B:Normal
output=${base}-NN.fd
cp ${input} ${output}
dd if=nor.bin of=${output} conv=notrunc bs=1 seek=${rw_a_offset}
dd if=nor.bin of=${output} conv=notrunc bs=1 seek=${rw_b_offset}
# A:Dev B:Dev
output=${base}-DD.fd
cp ${input} ${output}
dd if=dev.bin of=${output} conv=notrunc bs=1 seek=${rw_a_offset}
dd if=dev.bin of=${output} conv=notrunc bs=1 seek=${rw_b_offset}
# A:Normal B:Dev
output=${base}-ND.fd
cp ${input} ${output}
dd if=nor.bin of=${output} conv=notrunc bs=1 seek=${rw_a_offset}
dd if=dev.bin of=${output} conv=notrunc bs=1 seek=${rw_b_offset}
# A:Dev B:Normal
output=${base}-DN.fd
cp ${input} ${output}
dd if=dev.bin of=${output} conv=notrunc bs=1 seek=${rw_a_offset}
dd if=nor.bin of=${output} conv=notrunc bs=1 seek=${rw_b_offset}
# A:Normal B:Bad
output=${base}-NB.fd
cp ${input} ${output}
dd if=nor.bin of=${output} conv=notrunc bs=1 seek=${rw_a_offset}
dd if=bad.bin of=${output} conv=notrunc bs=1 seek=${rw_b_offset}
# A:Bad B:Normal
output=${base}-BN.fd
cp ${input} ${output}
dd if=bad.bin of=${output} conv=notrunc bs=1 seek=${rw_a_offset}
dd if=nor.bin of=${output} conv=notrunc bs=1 seek=${rw_b_offset}
# A:Dev B:Bad
output=${base}-DB.fd
cp ${input} ${output}
dd if=dev.bin of=${output} conv=notrunc bs=1 seek=${rw_a_offset}
dd if=bad.bin of=${output} conv=notrunc bs=1 seek=${rw_b_offset}
# A:Bad B:Dev
output=${base}-BD.fd
cp ${input} ${output}
dd if=bad.bin of=${output} conv=notrunc bs=1 seek=${rw_a_offset}
dd if=dev.bin of=${output} conv=notrunc bs=1 seek=${rw_b_offset}

View File

@@ -0,0 +1,60 @@
#!/bin/sh
#
# Copyright 2017 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.
#
# This script provides tools to read or change GBB flags on a live system.
SCRIPT_BASE="$(dirname "$0")"
. "${SCRIPT_BASE}/common_minimal.sh"
load_shflags || exit 1
# Globals
# ----------------------------------------------------------------------------
# Values from vboot_reference/firmware/include/gbb_header.h
GBBFLAGS_DESCRIPTION_PREFIX="
Defined flags (some values may be not supported by all systems):
"
GBBFLAGS_LIST="
GBB_FLAG_DEV_SCREEN_SHORT_DELAY 0x00000001
GBB_FLAG_LOAD_OPTION_ROMS 0x00000002
GBB_FLAG_ENABLE_ALTERNATE_OS 0x00000004
GBB_FLAG_FORCE_DEV_SWITCH_ON 0x00000008
GBB_FLAG_FORCE_DEV_BOOT_USB 0x00000010
GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK 0x00000020
GBB_FLAG_ENTER_TRIGGERS_TONORM 0x00000040
GBB_FLAG_FORCE_DEV_BOOT_LEGACY 0x00000080
GBB_FLAG_FAFT_KEY_OVERIDE 0x00000100
GBB_FLAG_DISABLE_EC_SOFTWARE_SYNC 0x00000200
GBB_FLAG_DEFAULT_DEV_BOOT_LEGACY 0x00000400
GBB_FLAG_DISABLE_PD_SOFTWARE_SYNC 0x00000800
GBB_FLAG_DISABLE_LID_SHUTDOWN 0x00001000
GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP 0x00002000
GBB_FLAG_FORCE_MANUAL_RECOVERY 0x00004000
GBB_FLAG_DISABLE_FWMP 0x00008000
GBB_FLAG_ENABLE_UDC 0x00010000
"
GBBFLAGS_DESCRIPTION_SUFFIX="
To get a developer-friendly device, try 0x11 (short_delay + boot_usb).
For factory-related tests (always DEV), try 0x39.
For early development (disable EC/PD software sync), try 0xa39.
"
GBBFLAGS_DESCRIPTION="${GBBFLAGS_DESCRIPTION_PREFIX}${GBBFLAGS_LIST}"
GBBFLAGS_DESCRIPTION="${GBBFLAGS_DESCRIPTION}${GBBFLAGS_DESCRIPTION_SUFFIX}"
FLAGS_HELP="Manages Chrome OS Firmware GBB Flags value.
Usage: $0 [option_flags] GBB_FLAGS_VALUE
${GBBFLAGS_DESCRIPTION}"
flashrom_read() {
flashrom -p host -i GBB -r "$@"
}
flashrom_write() {
flashrom -p host -i GBB --fast-verify -w "$@"
}

View File

@@ -0,0 +1,54 @@
#!/bin/sh
#
# Copyright 2017 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.
#
# This script can change GBB flags in system live firmware or a given image
# file.
SCRIPT_BASE="$(dirname "$0")"
. "${SCRIPT_BASE}/gbb_flags_common.sh"
# DEFINE_string name default_value description flag
DEFINE_string file "" "Path to firmware image. Default to system firmware." "f"
DEFINE_boolean explicit ${FLAGS_FALSE} "Print list of what flags are set." "e"
set -e
main() {
if [ $# -ne 0 ]; then
flags_help
exit 1
fi
local image_file="${FLAGS_file}"
if [ -z "${FLAGS_file}" ]; then
image_file="$(make_temp_file)"
flashrom_read "${image_file}"
fi
# Process file.
# Keep 'local' declaration split from assignment so return code is checked.
local gbb_flags
gbb_flags="$(futility gbb -g --flags "${image_file}")"
local raw_gbb_flags="$(echo "${gbb_flags}" | egrep -o "0x[0-9]+")"
printf "Chrome OS GBB set ${gbb_flags}\n"
if [ "${FLAGS_explicit}" = "${FLAGS_TRUE}" ]; then
printf "Chrome OS GBB set flags listed:\n"
echo "${GBBFLAGS_LIST}" | while read -r flag code; do
if [ $((code & raw_gbb_flags)) -ne 0 ]; then
printf "${flag}\n"
fi
done
fi
}
# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
main "$@"

View File

@@ -0,0 +1,34 @@
#!/bin/bash
# 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.
# Install an update payload verification public key to the image.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
main() {
set -e
local image="$1"
local pub_key="$2"
if [ $# -ne 2 ]; then
cat <<EOF
Usage: $PROG <image.bin> <au_public_key.pem>
Installs the update verification public key <au_public_key.pem> to <image.bin>.
EOF
exit 1
fi
local rootfs=$(make_temp_dir)
local key_location="/usr/share/update_engine/"
mount_image_partition "$image" 3 "$rootfs"
sudo mkdir -p "$rootfs/$key_location"
sudo cp "$pub_key" "$rootfs/$key_location/update-payload-key.pub.pem"
sudo chown root:root "$rootfs/$key_location/update-payload-key.pub.pem"
sudo chmod 644 "$rootfs/$key_location/update-payload-key.pub.pem"
echo "AU verification key was installed. Do not forget to resign the image!"
}
main "$@"

View File

@@ -0,0 +1,53 @@
#!/bin/bash
# Copyright 2017 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.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
load_shflags || exit 1
FLAGS_HELP="Usage: ${PROG} <image.bin|rootfs_dir> <public_key.pem>
Installs the container verification public key <public_key.pem> to
<image.bin|rootfs_dir>.
"
# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# Abort on error.
set -e
main() {
if [[ $# -ne 2 ]]; then
flags_help
exit 1
fi
local image="$1"
local pub_key="$2"
local rootfs
local key_location="/usr/share/misc/"
if [[ -d "${image}" ]]; then
rootfs="${image}"
else
rootfs=$(make_temp_dir)
mount_image_partition "${image}" 3 "${rootfs}"
fi
# Imageloader likes DER as a runtime format as it's easier to read.
local tmpfile=$(make_temp_file)
openssl pkey -pubin -in "${pub_key}" -out "${tmpfile}" -pubout -outform DER
sudo install \
-D -o root -g root -m 644 \
"${tmpfile}" "${rootfs}/${key_location}/oci-container-key-pub.der"
info "Container verification key was installed." \
"Do not forget to resign the image!"
}
main "$@"

View File

@@ -0,0 +1,72 @@
#!/bin/bash
# Copyright 2018 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.
. "$(dirname "$0")/common.sh"
set -e
usage() {
cat <<EOF
Usage: $PROG /path/to/esp/dir /path/to/keys/dir
Install UEFI certs in GSetup directory in ESP.
EOF
if [[ $# -gt 0 ]]; then
error "$*"
exit 1
fi
exit 0
}
# Installs the specified UEFI cert in GSetup directory, if the cert exists.
# Args: KEY_TYPE CERT GSETUP_DIR
install_gsetup_cert() {
local key_type="$1"
local cert="$2"
local gsetup_dir="$3"
if [[ -f "${cert}" ]]; then
info "Putting ${key_type} cert: ${cert}"
local cert_basename="$(basename "${cert}")"
local der_filename="${cert_basename%.*}.der"
sudo mkdir -p "${gsetup_dir}/${key_type}"
sudo openssl x509 -in "${cert}" -inform PEM \
-out "${gsetup_dir}/${key_type}/${der_filename}" -outform DER
else
info "No ${key_type} cert: ${cert}"
fi
}
main() {
local esp_dir="$1"
local key_dir="$2"
if [[ $# -ne 2 ]]; then
usage "command takes exactly 2 args"
fi
local gsetup_dir="${esp_dir}/EFI/Google/GSetup"
local pk_cert="${key_dir}/pk/pk.pem"
if [[ ! -f "${pk_cert}" ]]; then
die "No PK cert: ${pk_cert}"
fi
install_gsetup_cert pk "${pk_cert}" "${gsetup_dir}"
local db_cert="${key_dir}/db/db.pem"
if [[ ! -f "${db_cert}" ]]; then
die "No DB cert: ${db_cert}"
fi
install_gsetup_cert db "${db_cert}" "${gsetup_dir}"
local kek_cert="${key_dir}/kek/kek.pem"
install_gsetup_cert kek "${kek_cert}" "${gsetup_dir}"
local dbx_cert
for dbx_cert in "${key_dir}"/dbx/*.pem; do
install_gsetup_cert dbx "${dbx_cert}" "${gsetup_dir}"
done
}
main "$@"

View File

@@ -0,0 +1 @@
This is r137 of shflags

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,133 @@
#!/bin/bash
# Copyright 2018 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.
. "$(dirname "$0")/common.sh"
#######################################
# Return name according to the current signing debug key. The name is used to
# select key files.
# Globals:
# None
# Arguments:
# sha1: signature of the APK.
# keyset: "cheets" or "aosp" build?
# Outputs:
# Writes the name of the key to stdout.
# Returns:
# 0 on success, non-zero on error.
#######################################
android_choose_key() {
local sha1="$1"
local keyset="$2"
if [[ "${keyset}" != "aosp" && "${keyset}" != "cheets" ]]; then
error "Unknown Android build keyset '${keyset}'."
return 1
fi
# Fingerprints below are generated by:
# 'cheets' keyset:
# $ keytool -file vendor/google/certs/cheetskeys/$NAME.x509.pem -printcert \
# | grep SHA1:
# 'aosp' keyset:
# $ keytool -file build/target/product/security/$NAME.x509.pem -printcert \
# | grep SHA1:
declare -A platform_sha=(
['cheets']='AA:04:E0:5F:82:9C:7E:D1:B9:F8:FC:99:6C:5A:54:43:83:D9:F5:BC'
['aosp']='27:19:6E:38:6B:87:5E:76:AD:F7:00:E7:EA:84:E4:C6:EE:E3:3D:FA'
)
declare -A media_sha=(
['cheets']='D4:C4:2D:E0:B9:1B:15:72:FA:7D:A7:21:E0:A6:09:94:B4:4C:B5:AE'
['aosp']='B7:9D:F4:A8:2E:90:B5:7E:A7:65:25:AB:70:37:AB:23:8A:42:F5:D3'
)
declare -A shared_sha=(
['cheets']='38:B6:2C:E1:75:98:E3:E1:1C:CC:F6:6B:83:BB:97:0E:2D:40:6C:AE'
['aosp']='5B:36:8C:FF:2D:A2:68:69:96:BC:95:EA:C1:90:EA:A4:F5:63:0F:E5'
)
declare -A release_sha=(
['cheets']='EC:63:36:20:23:B7:CB:66:18:70:D3:39:3C:A9:AE:7E:EF:A9:32:42'
['aosp']='61:ED:37:7E:85:D3:86:A8:DF:EE:6B:86:4B:D8:5B:0B:FA:A5:AF:81'
)
case "${sha1}" in
"${platform_sha["${keyset}"]}")
echo "platform"
;;
"${media_sha["${keyset}"]}")
echo "media"
;;
"${shared_sha["${keyset}"]}")
echo "shared"
;;
"${release_sha["${keyset}"]}")
# The release_sha[] fingerprint is from devkey. Translate to releasekey.
echo "releasekey"
;;
*)
# Not a framework apk. Do not re-sign.
echo ""
;;
esac
return 0
}
#######################################
# Extract 'ro.build.flavor' property from build property file.
# Globals:
# None
# Arguments:
# build_prop_file: path to build property file.
# Outputs:
# Writes the value of the property to stdout.
# Returns:
# 0 on success, non-zero on error.
#######################################
android_get_build_flavor_prop() {
local build_prop_file="$1"
local flavor_prop=""
if ! flavor_prop=$(grep -a "^ro\.build\.flavor=" "${build_prop_file}"); then
return 1
fi
flavor_prop=$(echo "${flavor_prop}" | cut -d "=" -f2)
echo "${flavor_prop}"
return 0
}
#######################################
# Pick the expected keyset ('cheets', 'aosp') depending on the build flavor.
# Globals:
# None
# Arguments:
# flavor_prop: the value of the build flavor property.
# Outputs:
# Writes the name of the keyset to stdout.
# Returns:
# 0 on success, non-zero on error.
#######################################
android_choose_signing_keyset() {
local flavor_prop="$1"
# Property ro.build.flavor follows those patterns:
# - cheets builds:
# ro.build.flavor=cheets_${arch}-user(debug)
# - SDK builds:
# ro.build.flavor=sdk_google_cheets_${arch}-user(debug)
# - AOSP builds:
# ro.build.flavor=aosp_cheets_${arch}-user(debug)
# "cheets" and "SDK" builds both use the same signing keys, cheetskeys. "AOSP"
# builds use the public AOSP signing keys.
if [[ "${flavor_prop}" == aosp_cheets_* ]]; then
keyset="aosp"
elif [[ "${flavor_prop}" == cheets_* ||
"${flavor_prop}" == sdk_google_cheets_* ]]; then
keyset="cheets"
else
return 1
fi
echo "${keyset}"
return 0
}

View File

@@ -0,0 +1,464 @@
#!/bin/sh
#
# Copyright (c) 2012 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.
#
# This script can change key (usually developer keys) in a firmware binary
# image or system live firmware (EEPROM), and assign proper HWID, FLAGS as well.
SCRIPT_BASE="$(dirname "$0")"
. "$SCRIPT_BASE/common_minimal.sh"
load_shflags || exit 1
# Constants used by DEFINE_*
VBOOT_BASE='/usr/share/vboot'
DEFAULT_KEYS_FOLDER="$VBOOT_BASE/devkeys"
DEFAULT_BACKUP_FOLDER='/mnt/stateful_partition/backups'
# DEFINE_string name default_value description flag
DEFINE_string from "" "Path of input BIOS file (empty for system live BIOS)" "f"
DEFINE_string to "" "Path of output BIOS file (empty for system live BIOS)" "t"
DEFINE_string ec_from "" "Path of input EC file (empty for system live EC)" "e"
DEFINE_string ec_to "" "Path of output EC file (empty for system live EC)" "o"
DEFINE_string keys "$DEFAULT_KEYS_FOLDER" "Path to folder of dev keys" "k"
DEFINE_string preamble_flags "" "Override preamble flags value. Known values:
0: None. (Using RW to boot in normal. aka, two-stop)
1: VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL (one-stop)" "p"
DEFINE_boolean mod_hwid \
$FLAGS_TRUE "Modify HWID to indicate this is a modified firmware" ""
DEFINE_boolean mod_gbb_flags \
$FLAGS_TRUE "Modify GBB flags to enable developer friendly features" ""
DEFINE_boolean change_ec \
$FLAGS_FALSE "Change the key in the EC binary if EC uses EFS boot" ""
DEFINE_boolean force_backup \
$FLAGS_TRUE "Create backup even if source is not live" ""
DEFINE_string backup_dir \
"$DEFAULT_BACKUP_FOLDER" "Path of directory to store firmware backups" ""
# Parse command line
FLAGS "$@" || exit 1
eval set -- "$FLAGS_ARGV"
# Globals
# ----------------------------------------------------------------------------
set -e
# the image we are (temporary) working with
IMAGE_BIOS="$(make_temp_file)"
IMAGE_BIOS="$(readlink -f "${IMAGE_BIOS}")"
if [ "${FLAGS_change_ec}" = "${FLAGS_TRUE}" ]; then
IMAGE_EC="$(make_temp_file)"
IMAGE_EC="$(readlink -f "${IMAGE_EC}")"
fi
# a log file to keep the output results of executed command
EXEC_LOG="$(make_temp_file)"
# Functions
# ----------------------------------------------------------------------------
flashrom_bios() {
if is_debug_mode; then
flashrom -V -p host "$@"
else
flashrom -p host "$@"
fi
}
flashrom_ec() {
if is_debug_mode; then
flashrom -V -p ec "$@"
else
flashrom -p ec "$@"
fi
}
# Execute the given command and log its output to the file ${EXEC_LOG}.
# If is_debug_mode, also print the output directly.
execute() {
if is_debug_mode; then
"$@" 2>&1 | tee "${EXEC_LOG}"
else
"$@" >"${EXEC_LOG}" 2>&1
fi
}
# Disables write protection status registers
disable_write_protection() {
# No need to change WP status in file mode
if [ -n "$FLAGS_to" ]; then
return $FLAGS_TRUE
fi
# --wp-disable command may return success even if WP is still enabled,
# so we should use --wp-status to verify the results.
echo "Disabling system software write protection status..."
(flashrom_bios --wp-disable && flashrom_bios --wp-status) 2>&1 |
tee "$EXEC_LOG" |
grep -q '^WP: .* is disabled\.$'
}
# Reads ${IMAGE_BIOS} from ${FLAGS_from} and ${IMAGE_EC} from ${FLAGS_ec_from}
read_image() {
if [ -z "$FLAGS_from" ]; then
echo "Reading system live BIOS firmware..."
execute flashrom_bios -r "${IMAGE_BIOS}"
else
debug_msg "reading from file: ${FLAGS_from}"
cp -f "${FLAGS_from}" "${IMAGE_BIOS}"
fi
if [ "${FLAGS_change_ec}" = "${FLAGS_TRUE}" ]; then
if [ -z "${FLAGS_ec_from}" ]; then
echo "Reading system live EC firmware..."
execute flashrom_ec -r "${IMAGE_EC}"
else
debug_msg "reading from file: ${FLAGS_ec_from}"
cp -f "${FLAGS_ec_from}" "${IMAGE_EC}"
fi
fi
}
# Writes ${IMAGE_BIOS} to ${FLAGS_to} and ${IMAGE_EC} to ${FLAGS_ec_to}
write_image() {
if [ -z "${FLAGS_to}" ]; then
echo "Writing system live BIOS firmware..."
# TODO(hungte) we can enable partial write to make this faster
execute flashrom_bios -w "${IMAGE_BIOS}"
else
debug_msg "writing to file: ${FLAGS_to}"
cp -f "${IMAGE_BIOS}" "${FLAGS_to}"
chmod a+r "${FLAGS_to}"
fi
if [ "${FLAGS_change_ec}" = "${FLAGS_TRUE}" ]; then
if [ -z "${FLAGS_ec_to}" ]; then
echo "Writing system live EC firmware..."
# TODO(hungte) we can enable partial write to make this faster
execute flashrom_ec -w "${IMAGE_EC}"
else
debug_msg "writing to file: ${FLAGS_ec_to}"
cp -f "${IMAGE_EC}" "${FLAGS_ec_to}"
chmod a+r "${FLAGS_ec_to}"
fi
fi
}
# Converts HWID from $1 to proper format with "DEV" extension
echo_dev_hwid() {
local hwid="$1"
local hwid_no_dev="${hwid% DEV}"
# NOTE: Some DEV firmware image files may put GUID in HWID.
# These are not officially supported and they will see "{GUID} DEV".
if [ "$hwid" != "$hwid_no_dev" ]; then
hwid="$hwid_no_dev"
fi
local hwid_dev="$hwid DEV"
debug_msg "echo_dev_hwid: [$1] -> [$hwid_dev]"
echo "$hwid_dev"
}
# Main
# ----------------------------------------------------------------------------
main() {
# Check parameters
local root_pubkey="${FLAGS_keys}/root_key.vbpubk"
local recovery_pubkey="${FLAGS_keys}/recovery_key.vbpubk"
local firmware_keyblock="${FLAGS_keys}/firmware.keyblock"
local firmware_prvkey="${FLAGS_keys}/firmware_data_key.vbprivk"
local dev_firmware_keyblock="${FLAGS_keys}/dev_firmware.keyblock"
local dev_firmware_prvkey="${FLAGS_keys}/dev_firmware_data_key.vbprivk"
local kernel_sub_pubkey="${FLAGS_keys}/kernel_subkey.vbpubk"
local ec_efs_pubkey="${FLAGS_keys}/key_ec_efs.vbpubk2"
local ec_efs_prvkey="${FLAGS_keys}/key_ec_efs.vbprik2"
local is_from_live=0
local backup_bios_image=''
local backup_ec_image=''
debug_msg "Prerequisite check"
ensure_files_exist \
"${root_pubkey}" \
"${recovery_pubkey}" \
"${firmware_keyblock}" \
"${firmware_prvkey}" \
"${kernel_sub_pubkey}" \
"${ec_efs_pubkey}" \
"${ec_efs_prvkey}" ||
exit 1
if [ -z "${FLAGS_from}" ]; then
is_from_live=1
else
ensure_files_exist "${FLAGS_from}" || exit 1
fi
if [ -z "${FLAGS_ec_from}" ]; then
is_from_live=1
else
ensure_files_exist "${FLAGS_ec_from}" || exit 1
fi
debug_msg "Checking software write protection status"
disable_write_protection ||
if is_debug_mode; then
die "Failed to disable WP. Diagnose Message: $(cat "${EXEC_LOG}")"
else
die "Write protection is still enabled. " \
"Please verify that hardware write protection is disabled."
fi
debug_msg "Pulling image"
(read_image &&
[ -s "${IMAGE_BIOS}" ] &&
[ "${FLAGS_change_ec}" = "${FLAGS_FALSE}" -o -s "${IMAGE_EC}" ]) ||
die "Failed to read image. Error message: $(cat "${EXEC_LOG}")"
debug_msg "Prepare to backup the file"
if [ -n "${is_from_live}" -o ${FLAGS_force_backup} = ${FLAGS_TRUE} ]; then
backup_bios_image="$(make_temp_file)"
debug_msg "Creating BIOS backup file to ${backup_bios_image}..."
cp -f "${IMAGE_BIOS}" "${backup_bios_image}"
if [ "${FLAGS_change_ec}" = "${FLAGS_TRUE}" ]; then
backup_ec_image="$(make_temp_file)"
debug_msg "Creating EC backup file to ${backup_ec_image}..."
cp -f "${IMAGE_EC}" "${backup_ec_image}"
fi
fi
local expanded_firmware_dir="$(make_temp_dir)"
if [ "${FLAGS_change_ec}" = "${FLAGS_TRUE}" ]; then
if is_ec_rw_signed "${IMAGE_EC}"; then
# TODO(waihong): These are duplicated from sign_official_build.sh. We need
# to move them to a single place for share.
debug_msg "Resign EC firmware with new EC EFS key"
local rw_bin="EC_RW.bin"
local rw_hash="EC_RW.hash"
# futility writes byproduct files to CWD, so we cd to temp dir.
local old_cwd=$(pwd)
cd "${expanded_firmware_dir}"
${FUTILITY} sign --type rwsig --prikey "${ec_efs_prvkey}" "${IMAGE_EC}" ||
die "Failed to sign EC image"
# Above command produces EC_RW.bin. Compute its hash.
openssl dgst -sha256 -binary "${rw_bin}" > "${rw_hash}"
debug_msg "Store ecrw and its hash to BIOS firmware"
store_file_in_cbfs "${IMAGE_BIOS}" "${rw_bin}" "ecrw" ||
die "Failed to store ecrw in BIOS image"
store_file_in_cbfs "${IMAGE_BIOS}" "${rw_hash}" "ecrw.hash" ||
die "Failed to store ecrw.hash in BIOS image"
cd "${old_cwd}"
# Continuous the code below to resign the BIOS image.
else
echo "EC image is not signed. Skip changing its key."
fi
fi
debug_msg "Detecting developer firmware keyblock"
local use_devfw_keyblock="$FLAGS_FALSE"
(cd "${expanded_firmware_dir}"; dump_fmap -x "${IMAGE_BIOS}" \
>/dev/null 2>&1) || die "Failed to extract firmware image."
if [ -f "$expanded_firmware_dir/VBLOCK_A" ]; then
local has_dev=$FLAGS_TRUE has_norm=$FLAGS_TRUE
# In output of vbutil_keyblock, "!DEV" means "bootable on normal mode" and
# "DEV" means "bootable on developer mode". Here we try to match the pattern
# in output of vbutil_block, and disable the flags (has_dev, has_norm) if
# the pattern was not found.
vbutil_keyblock --unpack "$expanded_firmware_dir/VBLOCK_A" |
grep -qw '!DEV' || has_norm=$FLAGS_FALSE
vbutil_keyblock --unpack "$expanded_firmware_dir/VBLOCK_A" |
grep -qw '[^!]DEV' || has_dev=$FLAGS_FALSE
if [ "$has_norm" = "$FLAGS_FALSE" -a "$has_dev" = "$FLAGS_TRUE" ]; then
use_devfw_keyblock=$FLAGS_TRUE
fi
fi
if [ "$use_devfw_keyblock" = "$FLAGS_TRUE" ]; then
echo "Using keyblocks (developer, normal)..."
else
echo "Using keyblocks (normal, normal)..."
dev_firmware_prvkey="$firmware_prvkey"
dev_firmware_keyblock="$firmware_keyblock"
fi
debug_msg "Extract firmware version and data key version"
${FUTILITY} gbb -g --rootkey="${expanded_firmware_dir}/rootkey" \
"${IMAGE_BIOS}" >/dev/null 2>&1
local data_key_version firmware_version
# When we are going to flash directly from or to system, the versions stored
# in TPM can be found by crossystem; otherwise we'll need to guess from source
# firmware (FLAGS_from).
if [ -z "$FLAGS_to" -o -z "$FLAGS_from" ]; then
debug_msg "Reading TPM version from crossystem tpm_fwver."
data_key_version="$(( $(crossystem tpm_fwver) >> 16 ))"
firmware_version="$(( $(crossystem tpm_fwver) & 0xFFFF ))"
else
# TODO(hungte) On Vboot2, A/B slot may contain different firmware so we may
# need to check both and decide from largest number.
debug_msg "Guessing TPM version from original firmware."
local fw_info="$(vbutil_firmware \
--verify "${expanded_firmware_dir}/VBLOCK_A" \
--signpubkey "${expanded_firmware_dir}/rootkey" \
--fv "${expanded_firmware_dir}/FW_MAIN_A" 2>/dev/null)" ||
die "Failed to verify firmware slot A."
data_key_version="$(
echo "$fw_info" | sed -n '/^ *Data key version:/s/.*:[ \t]*//p')"
firmware_version="$(
echo "$fw_info" | sed -n '/^ *Firmware version:/s/.*:[ \t]*//p')"
fi
local new_data_key_version="$(
vbutil_keyblock --unpack "$firmware_keyblock" |
sed -n '/^ *Data key version:/s/.*:[ \t]*//p')"
# TODO(hungte) Change key block by data_key_version.
if [ "$data_key_version" -gt "$new_data_key_version" ]; then
echo "$(tput bold)$(tput setaf 1)
Warning: firmware data key version <$new_data_key_version> in your new keys
[$FLAGS_keys] is smaller than original firmware <$data_key_version> and
will boot into only recovery mode due to TPM anti-rollback detection.
After reboot with dev recovery key, you will need to reset TPM by booting a
test or dev image in recovery mode (NOT Ctrl-U), switch to VT2 and run
command <chromeos-tpm-recovery>; or use a factory install shim image
(build_image factory_install).
$(tput sgr 0)" >&2
fi
echo "Signing with Data Key Version: $data_key_version, " \
"Firmware Version: $firmware_version"
echo "Preparing new firmware image..."
debug_msg "Resign the firmware code (A/B) with new keys"
# Note resign_firmwarefd.sh needs the original rootkey to determine firmware
# body size, so we must resign image before changing GBB rootkey.
local unsigned_image="$(make_temp_file)"
local optional_opts=""
if [ -n "$FLAGS_preamble_flags" ]; then
debug_msg "Setting FLAGS=$FLAGS_preamble_flags"
optional_opts="$FLAGS_preamble_flags"
fi
cp -f "${IMAGE_BIOS}" "$unsigned_image"
execute "$SCRIPT_BASE/resign_firmwarefd.sh" \
"${unsigned_image}" \
"${IMAGE_BIOS}" \
"${firmware_prvkey}" \
"${firmware_keyblock}" \
"${dev_firmware_prvkey}" \
"${dev_firmware_keyblock}" \
"${kernel_sub_pubkey}" \
"${firmware_version}" \
${optional_opts} ||
die "Failed to re-sign firmware. (message: $(cat "${EXEC_LOG}"))"
debug_msg "Extract current HWID"
local old_hwid
old_hwid="$(${FUTILITY} gbb --get --hwid "${IMAGE_BIOS}" 2>"${EXEC_LOG}" |
sed -rne 's/^hardware_id: (.*)$/\1/p')"
debug_msg "Decide new HWID"
[ -z "$old_hwid" ] &&
die "Cannot find current HWID. (message: $(cat "${EXEC_LOG}"))"
local new_hwid="$old_hwid"
if [ "$FLAGS_mod_hwid" = "$FLAGS_TRUE" ]; then
new_hwid="$(echo_dev_hwid "$old_hwid")"
fi
local old_gbb_flags
old_gbb_flags="$(${FUTILITY} gbb --get --flags "${IMAGE_BIOS}" \
2>"${EXEC_LOG}" | sed -rne 's/^flags: (.*)$/\1/p')"
debug_msg "Decide new GBB flags from: $old_gbb_flags"
[ -z "$old_gbb_flags" ] &&
die "Cannot find GBB flags. (message: $(cat "${EXEC_LOG}"))"
# 0x30: GBB_FLAG_FORCE_DEV_BOOT_USB | GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK
local new_gbb_flags="$((old_gbb_flags | 0x30))"
debug_msg "Replace GBB parts (futility gbb allows changing on-the-fly)"
${FUTILITY} gbb --set \
--hwid="${new_hwid}" \
--rootkey="${root_pubkey}" \
--recoverykey="${recovery_pubkey}" \
"${IMAGE_BIOS}" >"${EXEC_LOG}" 2>&1 ||
die "Failed to change GBB Data. (message: $(cat "${EXEC_LOG}"))"
# Old firmware does not support GBB flags, so let's make it an exception.
if [ "${FLAGS_mod_gbb_flags}" = "${FLAGS_TRUE}" ]; then
debug_msg "Changing GBB flags from ${old_gbb_flags} to ${new_gbb_flags}"
${FUTILITY} gbb --set \
--flags="${new_gbb_flags}" \
"${IMAGE_BIOS}" >"${EXEC_LOG}" 2>&1 ||
echo "Warning: Can't set GBB flags ${old_gbb_flags} -> ${new_gbb_flags}."
fi
# TODO(hungte) compare if the image really needs to be changed.
debug_msg "Check if we need to make backup file(s)"
if [ -n "${backup_bios_image}" ]; then
local backup_hwid_name="$(echo "${old_hwid}" | sed 's/ /_/g')"
local backup_date_time="$(date +'%Y%m%d_%H%M%S')"
local backup_bios_name="bios_${backup_hwid_name}_${backup_date_time}.fd"
local backup_bios_path="${FLAGS_backup_dir}/${backup_bios_name}"
local backup_ec_name="ec_${backup_hwid_name}_${backup_date_time}.fd"
local backup_ec_path=''
if mkdir -p "${FLAGS_backup_dir}" &&
cp -f "${backup_bios_image}" "${backup_bios_path}"; then
if [ -n "${backup_ec_image}" ]; then
backup_ec_path="${FLAGS_backup_dir}/${backup_ec_name}"
cp -f "${backup_ec_image}" "${backup_ec_path}"
fi
elif cp -f "${backup_bios_image}" "/tmp/${backup_bios_name}"; then
backup_bios_path="/tmp/${backup_bios_name}"
if [ -n "${backup_ec_image}" ]; then
cp -f "${backup_ec_image}" "/tmp/${backup_ec_name}"
backup_ec_path="/tmp/${backup_ec_name}"
fi
else
backup_bios_path=''
fi
if [ -n "${backup_bios_path}" ]; then
# TODO(hungte) maybe we can wrap the flashrom by 'make_dev_firmware.sh -r'
# so that the only command to remember would be make_dev_firmware.sh.
echo "
Backup of current firmware image is stored in:
${backup_bios_path}
${backup_ec_path}
Please copy the backup file to a safe place ASAP.
To stop using devkeys and restore original BIOS, execute command:
flashrom -p bios -w [PATH_TO_BACKUP_BIOS]
Ex: flashrom -p bios -w ${backup_bios_path}"
if [ -n "${backup_ec_image}" ]; then
echo "
To stop using devkeys and restore original EC, execute command:
flashrom -p ec -w [PATH_TO_BACKUP_EC]
Ex: flashrom -p ec -w ${backup_ec_path}"
fi
echo ""
else
echo "WARNING: Can't create file in ${FLAGS_backup_dir}. Ignore backups."
fi
fi
# TODO(hungte) use vbutil_firmware to check if the new firmware is valid.
# Or, do verification in resign_firmwarefd.sh and trust it.
debug_msg "Write the image"
write_image ||
die "Failed to write image. Error message: $(cat "${EXEC_LOG}")"
debug_msg "Complete."
if [ -z "$FLAGS_to" ]; then
echo "Successfully changed firmware to Developer Keys. New HWID: $new_hwid"
else
echo "Firmware '$FLAGS_to' now uses Developer Keys. New HWID: $new_hwid"
fi
}
main

View File

@@ -0,0 +1,505 @@
#!/bin/sh
#
# Copyright (c) 2012 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.
#
# This script can change key (usually developer keys) and kernel config
# of kernels on an disk image (usually for SSD but also works for USB).
SCRIPT_BASE="$(dirname "$0")"
. "$SCRIPT_BASE/common_minimal.sh"
load_shflags || exit 1
# Constants used by DEFINE_*
VBOOT_BASE='/usr/share/vboot'
DEFAULT_KEYS_FOLDER="$VBOOT_BASE/devkeys"
DEFAULT_BACKUP_FOLDER='/mnt/stateful_partition/backups'
DEFAULT_PARTITIONS='2 4'
# TODO(hungte) The default image selection is no longer a SSD, so the script
# works more like "make_dev_image". We may change the file name in future.
ROOTDEV="$(rootdev -s 2>/dev/null)"
ROOTDEV_PARTITION="$(echo $ROOTDEV | sed -n 's/.*\([0-9][0-9]*\)$/\1/p')"
ROOTDEV_DISK="$(rootdev -s -d 2>/dev/null)"
ROOTDEV_KERNEL="$((ROOTDEV_PARTITION - 1))"
# DEFINE_string name default_value description flag
DEFINE_string image "$ROOTDEV_DISK" "Path to device or image file" "i"
DEFINE_string keys "$DEFAULT_KEYS_FOLDER" "Path to folder of dev keys" "k"
DEFINE_boolean remove_rootfs_verification \
$FLAGS_FALSE "Modify kernel boot config to disable rootfs verification" ""
DEFINE_string backup_dir \
"$DEFAULT_BACKUP_FOLDER" "Path of directory to store kernel backups" ""
DEFINE_string save_config "" \
"Base filename to store kernel configs to, instead of resigning." ""
DEFINE_string set_config "" \
"Base filename to load kernel configs from" ""
DEFINE_boolean edit_config "${FLAGS_FALSE}" \
"Edit kernel config in-place." ""
DEFINE_string partitions "" \
"List of partitions to examine (default: $DEFAULT_PARTITIONS)" ""
DEFINE_boolean recovery_key "$FLAGS_FALSE" \
"Use recovery key to sign image (to boot from USB)" ""
DEFINE_boolean force "$FLAGS_FALSE" "Skip sanity checks and make the change" "f"
# Parse command line
FLAGS "$@" || exit 1
ORIGINAL_CMD="$0"
ORIGINAL_PARAMS="$@"
eval set -- "$FLAGS_ARGV"
ORIGINAL_PARTITIONS="$FLAGS_partitions"
: ${FLAGS_partitions:=$DEFAULT_PARTITIONS}
# Globals
# ----------------------------------------------------------------------------
set -e
# a log file to keep the output results of executed command
EXEC_LOG="$(make_temp_file)"
# Functions
# ----------------------------------------------------------------------------
# Removes rootfs verification from kernel boot parameter
# And strip out bootcache args if it exists
remove_rootfs_verification() {
local new_root="PARTUUID=%U/PARTNROFF=1"
# the first line in sed is to strip out bootcache details
echo "$*" | sed '
s| dm=\"2 [^"]*bootcache[^"]* vroot | dm=\"1 vroot |
s| root=/dev/dm-[0-9] | root='"$new_root"' |
s| dm_verity.dev_wait=1 | dm_verity.dev_wait=0 |
s| payload=PARTUUID=%U/PARTNROFF=1 | payload=ROOT_DEV |
s| hashtree=PARTUUID=%U/PARTNROFF=1 | hashtree=HASH_DEV |
s| ro | rw |'
}
remove_legacy_boot_rootfs_verification() {
# See src/scripts/create_legacy_bootloader_templates
local image="$1"
local mount_point="$(make_temp_dir)"
local config_file
debug_msg "Removing rootfs verification for legacy boot configuration."
mount_image_partition "$image" 12 "$mount_point" || return $FLAGS_FALSE
config_file="$mount_point/efi/boot/grub.cfg"
[ ! -f "$config_file" ] ||
sudo sed -i 's/^ *set default=2 *$/set default=0/g' "$config_file"
config_file="$mount_point/syslinux/default.cfg"
[ ! -f "$config_file" ] ||
sudo sed -i 's/-vusb/-usb/g; s/-vhd/-hd/g' "$config_file"
sudo umount "$mount_point"
}
# Wrapped version of dd
mydd() {
# oflag=sync is safer, but since we need bs=512, syncing every block would be
# very slow.
dd "$@" >"$EXEC_LOG" 2>&1 ||
die "Failed in [dd $*], Message: $(cat "${EXEC_LOG}")"
}
# Prints a more friendly name from kernel index number
cros_kernel_name() {
case $1 in
2)
echo "Kernel A"
;;
4)
echo "Kernel B"
;;
6)
echo "Kernel C"
;;
*)
echo "Partition $1"
esac
}
find_valid_kernel_partitions() {
local part_id
local valid_partitions=""
for part_id in $*; do
local name="$(cros_kernel_name $part_id)"
local kernel_part="$(make_partition_dev "$FLAGS_image" "$part_id")"
if [ -z "$(dump_kernel_config "$kernel_part" 2>"$EXEC_LOG")" ]; then
info "${name}: no kernel boot information, ignored." >&2
else
[ -z "$valid_partitions" ] &&
valid_partitions="$part_id" ||
valid_partitions="$valid_partitions $part_id"
continue
fi
done
debug_msg "find_valid_kernel_partitions: [$*] -> [$valid_partitions]"
echo "$valid_partitions"
}
# Resigns a kernel on SSD or image.
resign_ssd_kernel() {
# bs=512 is the fixed block size for dd and cgpt
local bs=512
local ssd_device="$1"
# reasonable size for current kernel partition
local min_kernel_size=16000
local max_kernel_size=65536
local resigned_kernels=0
for kernel_index in $FLAGS_partitions; do
local old_blob="$(make_temp_file)"
local new_blob="$(make_temp_file)"
local name="$(cros_kernel_name $kernel_index)"
local rootfs_index="$(($kernel_index + 1))"
debug_msg "Probing $name information"
local offset size
offset="$(partoffset "$ssd_device" "$kernel_index")" ||
die "Failed to get partition ${kernel_index} offset from ${ssd_device}"
size="$(partsize "$ssd_device" "$kernel_index")" ||
die "Failed to get partition ${kernel_index} size from ${ssd_device}"
if [ ! $size -gt $min_kernel_size ]; then
info "${name} seems too small (${size}), ignored."
continue
fi
if [ ! $size -le $max_kernel_size ]; then
info "${name} seems too large (${size}), ignored."
continue
fi
debug_msg "Reading $name from partition $kernel_index"
mydd if="$ssd_device" of="$old_blob" bs=$bs skip=$offset count=$size
debug_msg "Checking if $name is valid"
local kernel_config
if ! kernel_config="$(dump_kernel_config "$old_blob" 2>"$EXEC_LOG")"; then
debug_msg "dump_kernel_config error message: $(cat "$EXEC_LOG")"
info "${name}: no kernel boot information, ignored."
continue
fi
if [ -n "${FLAGS_save_config}" ]; then
# Save current kernel config
local old_config_file
old_config_file="${FLAGS_save_config}.$kernel_index"
info "Saving ${name} config to ${old_config_file}"
echo "$kernel_config" > "$old_config_file"
# Just save; don't resign
continue
fi
if [ -n "${FLAGS_set_config}" ]; then
# Set new kernel config from file
local new_config_file
new_config_file="${FLAGS_set_config}.$kernel_index"
kernel_config="$(cat "$new_config_file")" ||
die "Failed to read new kernel config from ${new_config_file}"
debug_msg "New kernel config: $kernel_config)"
info "${name}: Replaced config from ${new_config_file}"
fi
if [ "${FLAGS_edit_config}" = ${FLAGS_TRUE} ]; then
debug_msg "Editing kernel config file."
local new_config_file="$(make_temp_file)"
echo "${kernel_config}" >"${new_config_file}"
local old_md5sum="$(md5sum "${new_config_file}")"
local editor="${VISUAL:-${EDITOR:-vi}}"
info "${name}: Editing kernel config:"
# On ChromiumOS, some builds may come with broken EDITOR that refers to
# nano so we want to check again if the editor really exists.
if type "${editor}" >/dev/null 2>&1; then
"${editor}" "${new_config_file}"
else
# This script runs under dash but we want readline in bash to support
# editing in in console.
bash -c "read -e -i '${kernel_config}' &&
echo \"\${REPLY}\" >${new_config_file}" ||
die "Failed to run editor. Please specify editor name by VISUAL."
fi
kernel_config="$(cat "${new_config_file}")"
if [ "$(md5sum "${new_config_file}")" = "${old_md5sum}" ]; then
info "${name}: Config not changed."
else
debug_msg "New kernel config: ${kernel_config})"
info "${name}: Config updated"
fi
fi
if [ ${FLAGS_remove_rootfs_verification} = $FLAGS_FALSE ]; then
debug_msg "Bypassing rootfs verification check"
else
debug_msg "Changing boot parameter to remove rootfs verification"
kernel_config="$(remove_rootfs_verification "$kernel_config")"
debug_msg "New kernel config: $kernel_config"
info "${name}: Disabled rootfs verification."
remove_legacy_boot_rootfs_verification "$ssd_device"
fi
local new_kernel_config_file="$(make_temp_file)"
echo -n "$kernel_config" >"$new_kernel_config_file"
debug_msg "Re-signing $name from $old_blob to $new_blob"
debug_msg "Using key: $KERNEL_DATAKEY"
vbutil_kernel \
--repack "$new_blob" \
--keyblock "$KERNEL_KEYBLOCK" \
--config "$new_kernel_config_file" \
--signprivate "$KERNEL_DATAKEY" \
--oldblob "$old_blob" >"$EXEC_LOG" 2>&1 ||
die "Failed to resign ${name}. Message: $(cat "${EXEC_LOG}")"
debug_msg "Creating new kernel image (vboot+code+config)"
local new_kern="$(make_temp_file)"
cp "$old_blob" "$new_kern"
mydd if="$new_blob" of="$new_kern" conv=notrunc
if is_debug_mode; then
debug_msg "for debug purposes, check *.dbgbin"
cp "$old_blob" old_blob.dbgbin
cp "$new_blob" new_blob.dbgbin
cp "$new_kern" new_kern.dbgbin
fi
debug_msg "Verifying new kernel and keys"
vbutil_kernel \
--verify "$new_kern" \
--signpubkey "$KERNEL_PUBKEY" --verbose >"$EXEC_LOG" 2>&1 ||
die "Failed to verify new ${name}. Message: $(cat "${EXEC_LOG}")"
debug_msg "Backup old kernel blob"
local backup_date_time="$(date +'%Y%m%d_%H%M%S')"
local backup_name="$(echo "$name" | sed 's/ /_/g; s/^K/k/')"
local backup_file_name="${backup_name}_${backup_date_time}.bin"
local backup_file_path="$FLAGS_backup_dir/$backup_file_name"
if mkdir -p "$FLAGS_backup_dir" &&
cp -f "$old_blob" "$backup_file_path"; then
info "Backup of ${name} is stored in: ${backup_file_path}"
else
warning "Cannot create file in ${FLAGS_backup_dir} ... Ignore backups."
fi
debug_msg "Writing $name to partition $kernel_index"
mydd \
if="$new_kern" \
of="$ssd_device" \
seek=$offset \
bs=$bs \
count=$size \
conv=notrunc
resigned_kernels=$(($resigned_kernels + 1))
debug_msg "Make the root file system writable if needed."
# TODO(hungte) for safety concern, a more robust way would be to:
# (1) change kernel config to ro
# (2) check if we can enable rw mount
# (3) change kernel config to rw
if [ ${FLAGS_remove_rootfs_verification} = $FLAGS_TRUE ]; then
local root_offset_sector=$(partoffset "$ssd_device" $rootfs_index)
local root_offset_bytes=$((root_offset_sector * 512))
if ! is_ext2 "$ssd_device" "$root_offset_bytes"; then
debug_msg "Non-ext2 partition: $ssd_device$rootfs_index, skip."
elif ! rw_mount_disabled "$ssd_device" "$root_offset_bytes"; then
debug_msg "Root file system is writable. No need to modify."
else
# disable the RO ext2 hack
debug_msg "Disabling rootfs ext2 RO bit hack"
enable_rw_mount "$ssd_device" "$root_offset_bytes" >"$EXEC_LOG" 2>&1 ||
die "Failed turning off rootfs RO bit. OS may be corrupted. " \
"Message: $(cat "${EXEC_LOG}")"
fi
fi
# Sometimes doing "dump_kernel_config" or other I/O now (or after return to
# shell) will get the data before modification. Not a problem now, but for
# safety, let's try to sync more.
sync; sync; sync
info "${name}: Re-signed with developer keys successfully."
done
# If we saved the kernel config, exit now so we don't print an error
if [ -n "${FLAGS_save_config}" ]; then
info "(Kernels have not been resigned.)"
exit 0
fi
return $resigned_kernels
}
sanity_check_crossystem_flags() {
debug_msg "crossystem sanity check"
if [ -n "${FLAGS_save_config}" ]; then
debug_msg "not resigning kernel."
return
fi
if [ "$(crossystem dev_boot_signed_only)" = "0" ]; then
debug_msg "dev_boot_signed_only not set - safe."
return
fi
echo "
ERROR: YOUR FIRMWARE WILL ONLY BOOT SIGNED IMAGES.
Modifying the kernel or root filesystem will result in an unusable system. If
you really want to make this change, allow the firmware to boot self-signed
images by running:
sudo crossystem dev_boot_signed_only=0
before re-executing this command.
"
return $FLAGS_FALSE
}
sanity_check_live_partitions() {
debug_msg "Partition sanity check"
if [ "$FLAGS_partitions" = "$ROOTDEV_KERNEL" ]; then
debug_msg "only for current active partition - safe."
return
fi
if [ "$ORIGINAL_PARTITIONS" != "" ]; then
debug_msg "user has assigned partitions - provide more info."
info "Making change to ${FLAGS_partitions} on ${FLAGS_image}."
return
fi
echo "
ERROR: YOU ARE TRYING TO MODIFY THE LIVE SYSTEM IMAGE $FLAGS_image.
The system may become unusable after that change, especially when you have
some auto updates in progress. To make it safer, we suggest you to only
change the partition you have booted with. To do that, re-execute this command
as:
sudo $ORIGINAL_CMD $ORIGINAL_PARAMS --partitions $ROOTDEV_KERNEL
If you are sure to modify other partition, please invoke the command again and
explicitly assign only one target partition for each time (--partitions N )
"
return $FLAGS_FALSE
}
sanity_check_live_firmware() {
debug_msg "Firmware compatibility sanity check"
if [ "$(crossystem mainfw_type)" = "developer" ]; then
debug_msg "developer type firmware in active."
return
fi
debug_msg "Loading firmware to check root key..."
local bios_image="$(make_temp_file)"
local rootkey_file="$(make_temp_file)"
info "checking system firmware..."
sudo flashrom -p host -i GBB -r "$bios_image" >/dev/null 2>&1
futility gbb -g --rootkey="$rootkey_file" "$bios_image" >/dev/null 2>&1
if [ ! -s "$rootkey_file" ]; then
debug_msg "failed to read root key from system firmware..."
else
# The magic 130 is counted by "od dev-rootkey" for the lines until the body
# of key is reached. Trailing bytes (0x00 or 0xFF - both may appear, and
# that's why we need to skip them) are started at line 131.
# TODO(hungte) compare with rootkey in $VBOOT_BASE directly.
local rootkey_hash="$(od "$rootkey_file" |
head -130 | md5sum |
sed 's/ .*$//' )"
if [ "$rootkey_hash" = "a13642246ef93daaf75bd791446fec9b" ]; then
debug_msg "detected DEV root key in firmware."
return
else
debug_msg "non-devkey hash: $rootkey_hash"
fi
fi
echo "
ERROR: YOU ARE NOT USING DEVELOPER FIRMWARE, AND RUNNING THIS COMMAND MAY
THROW YOUR CHROMEOS DEVICE INTO UN-BOOTABLE STATE.
You need to either install developer firmware, or change system root key.
- To install developer firmware: type command
sudo chromeos-firmwareupdate --mode=todev
- To change system rootkey: disable firmware write protection (a hardware
switch) and then type command:
sudo $SCRIPT_BASE/make_dev_firmware.sh
If you are sure that you want to make such image without developer
firmware or you've already changed system root keys, please run this
command again with --force paramemeter:
sudo $ORIGINAL_CMD --force $ORIGINAL_PARAMS
"
return $FLAGS_FALSE
}
# Main
# ----------------------------------------------------------------------------
main() {
local num_signed=0
local num_given=$(echo "$FLAGS_partitions" | wc -w)
# Check parameters
if [ "$FLAGS_recovery_key" = "$FLAGS_TRUE" ]; then
KERNEL_KEYBLOCK="$FLAGS_keys/recovery_kernel.keyblock"
KERNEL_DATAKEY="$FLAGS_keys/recovery_kernel_data_key.vbprivk"
KERNEL_PUBKEY="$FLAGS_keys/recovery_key.vbpubk"
else
KERNEL_KEYBLOCK="$FLAGS_keys/kernel.keyblock"
KERNEL_DATAKEY="$FLAGS_keys/kernel_data_key.vbprivk"
KERNEL_PUBKEY="$FLAGS_keys/kernel_subkey.vbpubk"
fi
debug_msg "Prerequisite check"
ensure_files_exist \
"$KERNEL_KEYBLOCK" \
"$KERNEL_DATAKEY" \
"$KERNEL_PUBKEY" \
"$FLAGS_image" ||
exit 1
# checks for running on a live system image.
if [ "$FLAGS_image" = "$ROOTDEV_DISK" ]; then
debug_msg "check valid kernel partitions for live system"
local valid_partitions="$(find_valid_kernel_partitions $FLAGS_partitions)"
[ -n "$valid_partitions" ] ||
die "No valid kernel partitions on ${FLAGS_image} (${FLAGS_partitions})."
FLAGS_partitions="$valid_partitions"
# Sanity checks
if [ "$FLAGS_force" = "$FLAGS_TRUE" ]; then
echo "
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! INFO: ALL SANITY CHECKS WERE BYPASSED. YOU ARE ON YOUR OWN. !
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
" >&2
local i
for i in $(seq 5 -1 1); do
echo -n "\rStart in $i second(s) (^C to abort)... " >&2
sleep 1
done
echo ""
elif ! sanity_check_live_firmware ||
! sanity_check_live_partitions ||
! sanity_check_crossystem_flags; then
die "IMAGE ${FLAGS_image} IS NOT MODIFIED."
fi
fi
resign_ssd_kernel "$FLAGS_image" || num_signed=$?
debug_msg "Complete."
if [ $num_signed -gt 0 -a $num_signed -le $num_given ]; then
# signed something at least
info "Successfully re-signed ${num_signed} of ${num_given} kernel(s)" \
" on device ${FLAGS_image}."
else
die "Failed re-signing kernels."
fi
}
# People using this to process images may forget to add "-i",
# so adding parameter check is safer.
if [ "$#" -gt 0 ]; then
flags_help
die "Unknown parameters: $*"
fi
main

View File

@@ -0,0 +1,18 @@
#!/bin/bash
# Copyright (c) 2010 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.
# Remove the test label from lsb-release to prepare an image for
# signing using the official keys.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
set -e
image=$1
rootfs=$(make_temp_dir)
mount_image_partition ${image} 3 ${rootfs}
sed -i 's/test//' "${rootfs}/etc/lsb-release"

View File

@@ -0,0 +1,58 @@
#!/bin/sh
# Copyright (c) 2014 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.
# Abort on error
set -e
# This script is obsolete. The required functionality is now provided by the
# compiled futility executable, so all this does is invoke that. This wrapper
# should go away Real Soon Now.
# Which futility to run?
[ -z "$FUTILITY" ] && FUTILITY=futility
# required
SRC_FD=$1
DST_FD=$2
FIRMWARE_DATAKEY=$3
FIRMWARE_KEYBLOCK=$4
DEV_FIRMWARE_DATAKEY=$5
DEV_FIRMWARE_KEYBLOCK=$6
KERNEL_SUBKEY=$7
# optional
VERSION=$8
PREAMBLE_FLAG=$9
LOEM_OUTPUT_DIR=${10}
LOEMID=${11}
if [ ! -e $DEV_FIRMWARE_KEYBLOCK ] || [ ! -e $DEV_FIRMWARE_DATAKEY ] ; then
echo "No dev firmware keyblock/datakey found. Reusing normal keys."
DEV_FIRMWARE_KEYBLOCK="$FIRMWARE_KEYBLOCK"
DEV_FIRMWARE_DATAKEY="$FIRMWARE_DATAKEY"
fi
# pass optional args
[ -n "$VERSION" ] && VERSION="--version $VERSION"
[ -n "$PREAMBLE_FLAG" ] && PREAMBLE_FLAG="--flags $PREAMBLE_FLAG"
[ -n "$LOEM_OUTPUT_DIR" ] && LOEM_OUTPUT_DIR="--loemdir $LOEM_OUTPUT_DIR"
[ -n "$LOEMID" ] && LOEMID="--loemid $LOEMID"
exec ${FUTILITY} sign \
--signprivate $FIRMWARE_DATAKEY \
--keyblock $FIRMWARE_KEYBLOCK \
--devsign $DEV_FIRMWARE_DATAKEY \
--devkeyblock $DEV_FIRMWARE_KEYBLOCK \
--kernelkey $KERNEL_SUBKEY \
$VERSION \
$PREAMBLE_FLAG \
$LOEM_OUTPUT_DIR \
$LOEMID \
$SRC_FD \
$DST_FD
echo UNABLE TO EXEC FUTILITY 1>&2
exit 1

View File

@@ -0,0 +1,46 @@
#!/bin/bash
# Copyright (c) 2010 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.
# Script that just takes in a kernel partition and outputs a new vblock
# signed with the specific keys. For use on signing servers.
# vbutil_kernel must be in the system path.
SCRIPT_DIR=$(dirname $0)
# Abort on error
set -e
# Check arguments
if [ $# -lt 4 ] || [ $# -gt 5 ]; then
echo "usage: $0 src_kpart dst_vblock kernel_datakey kernel_keyblock [version]"
exit 1
fi
# Make sure the tools we need are available.
type -P vbutil_kernel &>/dev/null || \
( echo "vbutil_kernel tool not found."; exit 1; )
SRC_KPART=$1
DST_VBLOCK=$2
KERNEL_DATAKEY=$3
KERNEL_KEYBLOCK=$4
VERSION=$5
if [ -z $VERSION ]; then
VERSION=1
fi
echo "Using kernel version: $VERSION"
vbutil_kernel --repack "${DST_VBLOCK}" \
--vblockonly \
--keyblock "${KERNEL_KEYBLOCK}" \
--signprivate "${KERNEL_DATAKEY}" \
--version "${VERSION}" \
--oldblob "${SRC_KPART}"
echo "New kernel vblock was output to ${DST_VBLOCK}"

View File

@@ -0,0 +1,4 @@
These are sample configurations used with the test scripts located in the
parent directory. Note that these are not maintained in this git with complete
or necessarily current production data for Chrome OS. They serve to provide
examples of the configuraiton syntax.

View File

@@ -0,0 +1,19 @@
#!/bin/bash
# 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.
# Files/directories that should never be present in a clean,
# standard release build.
RELEASE_FILE_BLACKLIST=(
# Flag-file indicating "developer mode", crosh offers "shell" if present:
/root/.dev_mode
# Should not ship with a local account pre-set on the system
/opt/google/chrome/localaccount
# Generation of this should happen on-device. Don't want to introduce
# any cryptohome-related weaknesses e.g. everyone using the same salt.
/home/.shadow
)

View File

@@ -0,0 +1,31 @@
#!/bin/bash
# Copyright (c) 2012 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.
expected_auserver="https://tools.google.com/service/update2"
expected_release_name="Chrome OS"
# List boards here
expected_boards=(
x86-mario
x86-alex-signed-mp-v3keys
)
# List track names here
expected_release_tracks=(
canary-channel
dogfood-channel
beta-channel
dev-channel
)
# Associate board names with APPID's by creating a series
# of variables here. Variables should be named based on
# expected boards (above), with hyphens transposed to
# underscores (to be legal in variable names).
expected_appid_x86_mario="{87efface-864d-49a5-9bb3-4b050a7c227a}"
expected_appid_x86_alex="{C776D42E-287A-435E-8BA7-E770BD30B46D}"
expected_appid_canary="{90F229CE-83E2-4FAF-8479-E368A34938B1}"
expected_appid_dogfood="{4897842343-83E2-4FAF-8479-E368A34938B1}"

View File

@@ -0,0 +1,42 @@
#!/bin/bash
# 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.
#
# COMMON
#
required_kparams_common=( quiet console=tty2 init=/sbin/init add_efi_memmap
boot=local rootwait ro noresume noswap i915.modeset=1
loglevel=1 cros_secure kern_guid=%U tpm_tis.force=1
tpm_tis.interrupts=0 root=/dev/dm-0
dm_verity.error_behavior=3 dm_verity.max_bios=-1
dm_verity.dev_wait=1 noinitrd )
optional_kparams_common=( )
optional_kparams_regex_common=( )
# use "MAGIC_HASH" in place of the unpredictable sha1 hash, comparison
# functions later take care of the rest.... This set of dmparams
# taken from observation of current builds. In particular we may see
# the size of the filesystem creep over time. That size is denoted by
# the large number that appears a couple times in this string.
dmparams_common_list=('vroot none ro,0 1740800 verity %U+1 %U+1 1740800 0 sha1 MAGIC_HASH'
'vroot none ro,0 1740800 verity payload=%U+1 hashtree=%U+1 hashstart=1740800 alg=sha1 root_hexdigest=MAGIC_HASH'
'vroot none ro,0 1740800 verity payload=%U+1 hashtree=%U+1 hashstart=1740800 alg=sha1 root_hexdigest=MAGIC_HASH salt=MAGIC_SALT'
)
#
# x86-mario
#
required_kparams_x86_mario=( ${required_kparams_common[@]} )
optional_kparams_x86_mario=( ${optional_kparams_common[@]} )
optional_kparams_regex_x86_mario=( ${optional_kparams_regex_common[@]} )
required_dmparams_x86_mario=("${required_dmparams_common[@]}")
# Set up additional boards here. The "common" variables are
# not directly consulted by the test script, they're only
# here for your convenience in building up the board-specific
# configuration variables like the 3 shown above.

View File

@@ -0,0 +1,46 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Changes the channel on a Chrome OS image.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
set -e
if [ $# -ne 2 ]; then
cat <<EOF
Usage: $PROG <image.bin> <channel>
<image.bin>: Path to image.
<channel>: The new channel of the image.
EOF
exit 1
fi
main() {
local image=$1
local to=$2
local rootfs lsb
rootfs=$(make_temp_dir)
lsb="${rootfs}/etc/lsb-release"
mount_image_partition "${image}" 3 "${rootfs}"
# Get the current channel on the image.
local from=$(lsbval "${lsb}" 'CHROMEOS_RELEASE_TRACK')
from=${from%"-channel"}
echo "Current channel is '${from}'. Changing to '${to}'."
local sudo
if [[ ! -w ${lsb} ]] ; then
sudo="sudo"
fi
${sudo} sed -i "s/\b${from}\b/${to}/" "${lsb}" &&
echo "Channel change successful."
cat "${lsb}"
}
main "$@"

View File

@@ -0,0 +1,53 @@
#!/bin/bash
# Copyright (c) 2010 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.
# Customizes a Chrome OS release image by setting the chronos user password.
# Usage: ./set_chronos_password.sh <image.bin> <chronos_password> [--force]
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
change_chronos_password() {
local rootfs=$1
local password=$2
echo "Setting chronos password..."
local crypted_password="$(echo $password | openssl passwd -1 -stdin)"
local temp_shadow="$rootfs/etc/tempshadow"
echo "chronos:$crypted_password:14500:0:99999::::" \
| sudo tee "$temp_shadow" > /dev/null
sudo grep -Ev ^chronos: "$rootfs/etc/shadow" \
| sudo tee -a "$temp_shadow" > /dev/null
sudo mv -f "$temp_shadow" "$rootfs/etc/shadow"
}
main() {
set -e
local image=$1
local chronos_password=$2
if [ $# -ne 2 ] && [ $# -ne 3 ] || [ ! $3 = "--force" ] ; then
echo "Usage: $PROG <image.bin> <chronos_password> [--force]"
exit 1
fi
local rootfs=$(make_temp_dir)
if [ $# -eq 2 ]; then
mount_image_partition_ro "$image" 3 "$rootfs"
if ! no_chronos_password "$rootfs"; then
echo "Password is already set [use --force if you'd like to update it]"
exit 1
fi
# Prepare for remounting read/write.
sudo umount $rootfs
fi
mount_image_partition "$image" 3 "$rootfs"
change_chronos_password "$rootfs" "$chronos_password"
touch "$image" # Updates the image modification time.
echo "Password Set."
}
main $@

View File

@@ -0,0 +1,80 @@
#!/bin/sh
#
# Copyright (c) 2012 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.
#
# This script can change GBB flags in system live firmware or a given image
# file.
SCRIPT_BASE="$(dirname "$0")"
. "${SCRIPT_BASE}/gbb_flags_common.sh"
# DEFINE_string name default_value description flag
DEFINE_string file "" "Path to firmware image. Default to system firmware." "f"
DEFINE_boolean check_wp ${FLAGS_TRUE} "Check write protection states first." ""
set -e
# Check write protection
# ----------------------------------------------------------------------------
check_write_protection() {
local hw_wp="" sw_wp=""
if ! crossystem "wpsw_boot?0"; then
hw_wp="on"
fi
# Keep 'local' declaration split from assignment so return code is checked.
local wp_states
wp_states="$(flashrom -p host --wp-status 2>/dev/null | grep WP)"
local wp_disabled="$(echo "${wp_states}" | grep "WP:.*is disabled.")"
local wp_zero_len="$(echo "${wp_states}" | grep "WP:.*, len=0x00000000")"
if [ -z "${wp_disabled}" -a -z "${wp_zero_len}" ]; then
sw_wp="on"
fi
if [ -n "${hw_wp}" -a -n "${sw_wp}" ]; then
return ${FLAGS_FALSE}
fi
return ${FLAGS_TRUE}
}
# Main
# ----------------------------------------------------------------------------
main() {
if [ "$#" != "1" ]; then
flags_help
exit 1
fi
local value="$(($1))"
local image_file="${FLAGS_file}"
if [ -z "${FLAGS_file}" ]; then
image_file="$(make_temp_file)"
flashrom_read "${image_file}"
fi
# Process file
# Keep 'local' declaration split from assignment so return code is checked.
local old_value
old_value="$(futility gbb -g --flags "${image_file}")"
printf "Setting GBB flags from %s to 0x%x.." "${old_value}" "${value}"
futility gbb -s --flags="${value}" "${image_file}"
if [ -z "${FLAGS_file}" ]; then
if [ "${FLAGS_check_wp}" = "${FLAGS_TRUE}" ]; then
if ! check_write_protection; then
echo ""
echo "WARNING: System GBB Flags are NOT changed!!!"
echo "ERROR: You must disable write protection before setting flags."
exit 1
fi
fi
flashrom_write "$image_file"
fi
}
# Parse command line
FLAGS "$@" || exit 1
eval set -- "$FLAGS_ARGV"
main "$@"

View File

@@ -0,0 +1,71 @@
#!/bin/bash
# Copyright (c) 2010 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.
# Customizes a Chrome OS release image by setting /etc/lsb-release values.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
set_lsb_release_keyval() {
local rootfs=$1
local key=$2
local value=$3
local temp_lsb_release="$rootfs/etc/temp-lsb-release"
echo "$key=$value" | sudo tee "$temp_lsb_release" > /dev/null
grep -Ev "^$key=" "$rootfs/etc/lsb-release" \
| sudo tee -a "$temp_lsb_release" > /dev/null
sudo sort -o "$rootfs/etc/lsb-release" "$temp_lsb_release"
sudo rm -f "$temp_lsb_release"
}
main() {
set -e
if [[ $(( $# % 2 )) -eq 0 ]]; then
cat <<EOF
Usage: $PROG <image.bin> [<key> <value> [<key> <value> ...]]
Examples:
$ $PROG chromiumos_image.bin
Dumps /etc/lsb-release from chromiumos_image.bin to stdout.
$ $PROG chromiumos_image.bin CHROMEOS_RELEASE_DESCRIPTION "New description"
Sets the CHROMEOS_RELEASE_DESCRIPTION key's value to "New description"
in /etc/lsb-release in chromiumos_image.bin, sorts the keys and dumps
the updated file to stdout.
EOF
exit 1
fi
local image=$1
shift
local rootfs=$(make_temp_dir)
# If there are no key/value pairs to process, we don't need write access.
if [[ $# -eq 0 ]]; then
mount_image_partition_ro "${image}" 3 "${rootfs}"
else
mount_image_partition "${image}" 3 "${rootfs}"
touch "${image}" # Updates the image modification time.
fi
# Process all the key/value pairs.
local key value
while [[ $# -ne 0 ]]; do
key=$1 value=$2
shift 2
set_lsb_release_keyval "${rootfs}" "${key}" "${value}"
done
# Dump the final state.
cat "${rootfs}/etc/lsb-release"
}
main "$@"

View File

@@ -0,0 +1,293 @@
#!/bin/bash
# Copyright 2016 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.
. "$(dirname "$0")/common.sh"
. "$(dirname "$0")/lib/sign_android_lib.sh"
set -e
# Print usage string
usage() {
cat <<EOF
Usage: $PROG /path/to/cros_root_fs/dir /path/to/keys/dir
Re-sign framework apks in an Android system image. The image itself does not
need to be signed since it is shipped with Chrome OS image, which is already
signed.
Android has many "framework apks" that are signed with 4 different framework
keys, depends on the purpose of the apk. During development, apks are signed
with the debug one. This script is to re-sign those apks with corresponding
release key. It also handles some of the consequences of the key changes, such
as sepolicy update.
EOF
if [[ $# -gt 0 ]]; then
error "$*"
exit 1
fi
exit 0
}
# Re-sign framework apks with the corresponding release keys. Only apk with
# known key fingerprint are re-signed. We should not re-sign non-framework
# apks.
sign_framework_apks() {
local system_mnt="$1"
local key_dir="$2"
local flavor_prop=""
local keyset=""
if ! flavor_prop=$(android_get_build_flavor_prop \
"${system_mnt}/system/build.prop"); then
die "Failed to extract build flavor property from \
'${system_mnt}/system/build.prop'."
fi
info "Found build flavor property '${flavor_prop}'."
if ! keyset=$(android_choose_signing_keyset "${flavor_prop}"); then
die "Unknown build flavor property '${flavor_prop}'."
fi
info "Expecting signing keyset '${keyset}'."
info "Start signing framework apks"
# Counters for sanity check.
local counter_platform=0
local counter_media=0
local counter_shared=0
local counter_releasekey=0
local counter_total=0
local apk
while read -d $'\0' -r apk; do
local sha1=""
local keyname=""
sha1=$(unzip -p "${apk}" META-INF/CERT.RSA | \
keytool -printcert | awk '/^\s*SHA1:/ {print $2}')
if ! keyname=$(android_choose_key "${sha1}" "${keyset}"); then
die "Failed to choose signing key for APK '${apk}' (SHA1 '${sha1}') in \
build flavor '${flavor_prop}'."
fi
if [[ -z "${keyname}" ]]; then
continue
fi
info "Re-signing (${keyname}) ${apk}"
local temp_dir="$(make_temp_dir)"
local temp_apk="${temp_dir}/temp.apk"
local signed_apk="${temp_dir}/signed.apk"
# Follow the standard manual signing process. See
# https://developer.android.com/studio/publish/app-signing.html.
cp -a "${apk}" "${temp_apk}"
# Explicitly remove existing signature.
zip -q "${temp_apk}" -d "META-INF/*"
# Signapk now creates signature of APK Signature Scheme v2. No further APK
# changes should happen afterward. Also note that signapk now takes care of
# zipalign.
signapk "${key_dir}/$keyname.x509.pem" "${key_dir}/$keyname.pk8" \
"${temp_apk}" "${signed_apk}" > /dev/null
# Copy the content instead of mv to avoid owner/mode changes.
sudo cp "${signed_apk}" "${apk}" && rm -f "${signed_apk}"
# Set timestamp rounded to second since squash file system has resolution
# in seconds. Required in order for the packages cache generator output is
# compatible with the packed file system.
sudo touch "${apk}" -t "$(date +%m%d%H%M.%S)"
: $(( counter_${keyname} += 1 ))
: $(( counter_total += 1 ))
done < <(find "${system_mnt}/system" -type f -name '*.apk' -print0)
info "Found ${counter_platform} platform APKs."
info "Found ${counter_media} media APKs."
info "Found ${counter_shared} shared APKs."
info "Found ${counter_releasekey} release APKs."
info "Found ${counter_total} total APKs."
# Sanity check.
if [[ ${counter_platform} -lt 2 || ${counter_media} -lt 2 ||
${counter_shared} -lt 2 || ${counter_releasekey} -lt 2 ||
${counter_total} -lt 25 ]]; then
die "Number of re-signed package seems to be wrong"
fi
}
# Platform key is part of the SELinux policy. Since we are re-signing framework
# apks, we need to replace the key in the policy as well.
update_sepolicy() {
local system_mnt=$1
local key_dir=$2
# Only platform is used at this time.
local public_platform_key="${key_dir}/platform.x509.pem"
info "Start updating sepolicy"
local new_cert=$(sed -E '/(BEGIN|END) CERTIFICATE/d' \
"${public_platform_key}" | tr -d '\n' \
| base64 --decode | hexdump -v -e '/1 "%02x"')
if [[ -z "${new_cert}" ]]; then
die "Unable to get the public platform key"
fi
shopt -s nullglob
local xml_list=( "${system_mnt}"/system/etc/**/*mac_permissions.xml )
shopt -u nullglob
if [[ "${#xml_list[@]}" -ne 1 ]]; then
die "Unexpected number of *mac_permissions.xml: ${#xml_list[@]}\n \
${xml_list[*]}"
fi
local xml="${xml_list[0]}"
local orig=$(make_temp_file)
local pattern='(<signer signature=")\w+("><seinfo value="platform)'
cp "${xml}" "${orig}"
sudo sed -i -E "s/${pattern}/\1${new_cert}"'\2/g' "${xml}"
# Sanity check.
if cmp "${xml}" "${orig}"; then
die "Failed to replace SELinux policy cert"
fi
}
# Replace the debug key in OTA cert with release key.
replace_ota_cert() {
local system_mnt=$1
local release_cert=$2
local ota_zip="${system_mnt}/system/etc/security/otacerts.zip"
info "Replacing OTA cert"
local temp_dir=$(make_temp_dir)
pushd "${temp_dir}" > /dev/null
cp "${release_cert}" .
local temp_zip=$(make_temp_file)
zip -q -r "${temp_zip}.zip" .
# Copy the content instead of mv to avoid owner/mode changes.
sudo cp "${temp_zip}.zip" "${ota_zip}"
popd > /dev/null
}
# Restore SELinux context. This has to run after all file changes, before
# creating the new squashfs image.
reapply_file_security_context() {
local system_mnt=$1
local root_fs_dir=$2
info "Reapplying file security context"
sudo /sbin/setfiles -v -r "${system_mnt}" \
"${root_fs_dir}/etc/selinux/arc/contexts/files/android_file_contexts" \
"${system_mnt}"
}
# Snapshot file properties in a directory recursively.
snapshot_file_properties() {
local dir=$1
sudo find "${dir}" -exec stat -c '%n:%u:%g:%a:%C' {} + | sort
}
main() {
local root_fs_dir=$1
local key_dir=$2
local android_dir="${root_fs_dir}/opt/google/containers/android"
local system_img="${android_dir}/system.raw.img"
# Use the versions in $PATH rather than the system ones.
local unsquashfs=$(which unsquashfs)
local mksquashfs=$(which mksquashfs)
if [[ $# -ne 2 ]]; then
usage "command takes exactly 2 args"
fi
if [[ ! -f "${system_img}" ]]; then
die "System image does not exist: ${system_img}"
fi
if ! type -P zipalign &>/dev/null || ! type -P signapk &>/dev/null; then
# TODO(victorhsieh): Make this an error. This is not treating as error
# just to make an unrelated test pass by skipping this signing.
warn "Skip signing Android apks (some of executables are not found)."
exit 0
fi
local working_dir=$(make_temp_dir)
local system_mnt="${working_dir}/mnt"
local compression_method=$(sudo unsquashfs -s "${system_img}" | \
awk '$1 == "Compression" { print $2 }')
info "Unpacking squashfs system image to ${system_mnt}"
sudo "${unsquashfs}" -x -f -no-progress -d "${system_mnt}" "${system_img}"
snapshot_file_properties "${system_mnt}" > "${working_dir}/properties.orig"
sign_framework_apks "${system_mnt}" "${key_dir}"
update_sepolicy "${system_mnt}" "${key_dir}"
replace_ota_cert "${system_mnt}" "${key_dir}/releasekey.x509.pem"
reapply_file_security_context "${system_mnt}" "${root_fs_dir}"
# Sanity check.
snapshot_file_properties "${system_mnt}" > "${working_dir}/properties.new"
local d
if ! d=$(diff "${working_dir}"/properties.{orig,new}); then
die "Unexpected change of file property, diff\n${d}"
fi
# Packages cache needs to be regenerated when the key and timestamp are
# changed for apks.
local packages_cache="${system_mnt}/system/etc/packages_cache.xml"
if [[ -f "${packages_cache}" ]]; then
if type -P aapt &>/dev/null; then
info "Regenerating packages cache ${packages_cache}"
# For the sanity check.
local packages_before=$(grep "<package " "${packages_cache}" | wc -l)
local vendor_mnt=$(make_temp_dir)
local vendor_img="${android_dir}/vendor.raw.img"
local jar_lib="lib/arc-cache-builder/org.chromium.arc.cachebuilder.jar"
info "Unpacking squashfs vendor image to ${vendor_mnt}/vendor"
# Vendor image is not updated during this step. However we have to include
# vendor apks to re-generated packages cache which exists in one file for
# both system and vendor images.
sudo "${unsquashfs}" -x -f -no-progress -d "${vendor_mnt}/vendor" \
"${vendor_img}"
if ! arc_generate_packages_cache "${system_mnt}" "${vendor_mnt}" \
"${working_dir}/packages_cache.xml"; then
die "Failed to generate packages cache."
fi
sudo cp "${working_dir}/packages_cache.xml" "${packages_cache}"
# Set android-root as an owner.
sudo chown 655360:655360 "${packages_cache}"
local packages_after=$(grep "<package " "${packages_cache}" | wc -l)
if [[ "${packages_before}" != "${packages_after}" ]]; then
die "failed to verify the packages count after the regeneration of " \
"the packages cache. Expected ${packages_before} but found " \
"${packages_after} packages in pacakges_cache.xml"
fi
else
warn "aapt tool could not be found. Could not regenerate the packages " \
"cache. Outdated pacakges_cache.xml is removed."
sudo rm "${packages_cache}"
fi
else
info "Packages cache ${packages_cache} does not exist. Skip regeneration."
fi
info "Repacking squashfs image"
local old_size=$(stat -c '%s' "${system_img}")
# Overwrite the original image.
sudo "${mksquashfs}" "${system_mnt}" "${system_img}" \
-no-progress -comp "${compression_method}" -noappend
local new_size=$(stat -c '%s' "${system_img}")
info "Android system image size change: ${old_size} -> ${new_size}"
}
main "$@"

View File

@@ -0,0 +1,210 @@
#!/bin/bash
# Copyright 2018 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.
. "$(dirname "$0")/lib/sign_android_lib.sh"
# Expected APK signatures depending on the type of APK and the type of build.
declare -A platform_sha=(
['cheets']='AA:04:E0:5F:82:9C:7E:D1:B9:F8:FC:99:6C:5A:54:43:83:D9:F5:BC'
['aosp']='27:19:6E:38:6B:87:5E:76:AD:F7:00:E7:EA:84:E4:C6:EE:E3:3D:FA'
)
declare -A media_sha=(
['cheets']='D4:C4:2D:E0:B9:1B:15:72:FA:7D:A7:21:E0:A6:09:94:B4:4C:B5:AE'
['aosp']='B7:9D:F4:A8:2E:90:B5:7E:A7:65:25:AB:70:37:AB:23:8A:42:F5:D3'
)
declare -A shared_sha=(
['cheets']='38:B6:2C:E1:75:98:E3:E1:1C:CC:F6:6B:83:BB:97:0E:2D:40:6C:AE'
['aosp']='5B:36:8C:FF:2D:A2:68:69:96:BC:95:EA:C1:90:EA:A4:F5:63:0F:E5'
)
declare -A release_sha=(
['cheets']='EC:63:36:20:23:B7:CB:66:18:70:D3:39:3C:A9:AE:7E:EF:A9:32:42'
['aosp']='61:ED:37:7E:85:D3:86:A8:DF:EE:6B:86:4B:D8:5B:0B:FA:A5:AF:81'
)
test_android_choose_key_invalid_keyset() {
local keyname
local keyset
local keysets=("invalid_keyset" " " "")
for keyset in "${keysets[@]}"; do
echo "TEST: Detection of invalid keyset '${keyset}'."
if keyname=$(android_choose_key "ignored_sha1" "${keyset}"); then
: $(( NUM_TEST_FAILURES += 1 ))
echo "ERROR: Failed to detect invalid keyset '${keyset}'."
else
echo "PASS: Detected invalid keyset '${keyset}'."
fi
done
}
android_choose_key_test_helper() {
local sha1="$1"
local keyset="$2"
local expected_keyname="$3"
local keyname="invalid_key"
echo "TEST: Detect '${expected_keyname}' key name for '${keyset}' keyset."
keyname=$(android_choose_key "${sha1}" "${keyset}")
if [[ "${keyname}" != "${expected_keyname}" ]]; then
: $(( NUM_TEST_FAILURES += 1 ))
echo "ERROR: Incorrect key name '${keyname}' returned."
else
echo "PASS: Correct key name '${keyname}' returned."
fi
}
test_android_choose_key() {
local keyset
local expected_keyname
local keysets=("cheets" "aosp")
for keyset in "${keysets[@]}"; do
expected_keyname="platform"
android_choose_key_test_helper "${platform_sha[${keyset}]}" "${keyset}" \
"${expected_keyname}"
expected_keyname="media"
android_choose_key_test_helper "${media_sha[${keyset}]}" "${keyset}" \
"${expected_keyname}"
expected_keyname="shared"
android_choose_key_test_helper "${shared_sha[${keyset}]}" "${keyset}" \
"${expected_keyname}"
expected_keyname="releasekey"
android_choose_key_test_helper "${release_sha[${keyset}]}" "${keyset}" \
"${expected_keyname}"
done
}
build_flavor_test_helper() {
local prop_file="${BUILD}/build.prop"
local prop_content="$1"
local expected_flavor_prop="$2"
local flavor_prop=""
echo "${prop_content}" > "${prop_file}"
flavor_prop=$(android_get_build_flavor_prop "${prop_file}")
if [[ "${flavor_prop}" != "${expected_flavor_prop}" ]]; then
: $(( NUM_TEST_FAILURES += 1 ))
echo "ERROR: Incorrect build flavor '${flavor_prop}' returned."
else
echo "PASS: Correct key name '${flavor_prop}' returned."
fi
rm "${prop_file}"
}
test_android_get_build_flavor_prop() {
local prop_file="${BUILD}/build.prop"
local prop_content=""
local flavor_prop=""
echo "TEST: Extract ro.build.flavor property."
prop_content="ro.random.prop=foo
other.prop=bar
x=foobar
ro.build.flavor=cheets_x86-user
another.prop=barfoo"
build_flavor_test_helper "${prop_content}" "cheets_x86-user"
echo "TEST: Extract single ro.build.flavor property."
prop_content="ro.build.flavor=cheets_x86-user"
build_flavor_test_helper "${prop_content}" "cheets_x86-user"
echo "TEST: Avoid commented out ro.build.flavor property."
prop_content="ro.random.prop=foo
other.prop=bar
x=foobar
#ro.build.flavor=commented_out
ro.build.flavor=cheets_x86-user
another.prop=barfoo"
build_flavor_test_helper "${prop_content}" "cheets_x86-user"
# Missing ro.build.flavor property.
echo "TEST: Detect missing ro.build.flavor property."
echo "ro.random.prop=foo" > "${prop_file}"
if flavor_prop=$(android_get_build_flavor_prop "${prop_file}"); then
: $(( NUM_TEST_FAILURES += 1 ))
echo "ERROR: Failed to detect missing ro.build.flavor property."
else
echo "PASS: Detected missing ro.build.flavor property."
fi
rm "${prop_file}"
}
choose_signing_keyset_test_helper() {
local flavor_prop="$1"
local expected_keyset="$2"
local keyset=""
keyset=$(android_choose_signing_keyset "${flavor_prop}")
if [[ "${keyset}" != "${expected_keyset}" ]]; then
: $(( NUM_TEST_FAILURES += 1 ))
echo "ERROR: Incorrect keyset '${keyset}' returned instead of \
'${expected_keyset}'."
else
echo "PASS: Correct keyset '${keyset}' returned."
fi
}
choose_signing_keyset_test_invalid_flavors() {
local flavor="$1"
echo "TEST: Detect invalid build flavor '${flavor}'."
if android_choose_signing_keyset "${flavor}"; then
: $(( NUM_TEST_FAILURES += 1 ))
echo "ERROR: Failed to detect invalid build flavor '${flavor}'."
else
echo "PASS: Detected invalid build flavor '${flavor}'."
fi
}
test_android_choose_signing_keyset() {
echo "TEST: Keyset for aosp_cheets build."
choose_signing_keyset_test_helper "aosp_cheets_x86-userdebug" "aosp"
echo "TEST: Keyset for sdk_google_cheets build."
choose_signing_keyset_test_helper "sdk_google_cheets_x86-userdebug" "cheets"
echo "TEST: Keyset for cheets_x86 build."
choose_signing_keyset_test_helper "cheets_x86-user" "cheets"
echo "TEST: Keyset for cheets_arm build."
choose_signing_keyset_test_helper "cheets_arm-user" "cheets"
echo "TEST: Keyset for cheets_x86_64 build."
choose_signing_keyset_test_helper "cheets_x86_64-user" "cheets"
echo "TEST: Keyset for userdebug build."
choose_signing_keyset_test_helper "cheets_x86-userdebug" "cheets"
choose_signing_keyset_test_invalid_flavors "aosp"
choose_signing_keyset_test_invalid_flavors "cheets"
choose_signing_keyset_test_invalid_flavors ""
choose_signing_keyset_test_invalid_flavors " "
}
main() {
if [[ $# -ne 0 ]]; then
echo "FAIL: unexpected arguments '$@'."
return 1
fi
BUILD=$(mktemp -d)
echo "Setting temporary build directory as '${BUILD}'."
test_android_choose_key_invalid_keyset
test_android_choose_key
test_android_get_build_flavor_prop
test_android_choose_signing_keyset
echo "Deleting temporary build directory '${BUILD}'."
rmdir "${BUILD}"
if [[ ${NUM_TEST_FAILURES} -gt 0 ]]; then
echo "FAIL: found ${NUM_TEST_FAILURES} failed :(."
return 1
fi
echo "PASS: all tests passed :)."
return 0
}
# Global incremented by each test when they fail.
NUM_TEST_FAILURES=0
main "$@"

View File

@@ -0,0 +1,143 @@
#!/bin/bash
# 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.
# Wrapper script for re-signing a firmware image.
# Determine script directory.
SCRIPT_DIR=$(dirname "$0")
# Load common constants and variables.
. "${SCRIPT_DIR}/common_minimal.sh"
# Abort on error.
set -e
usage() {
cat<<EOF
Usage: $0 <input_firmware> <key_dir> <output_firmware> [firmware_version] \
[loem_output_dir]
Signs <input_firmware> with keys in <key_dir>, setting firmware version
to <firmware_version>. Outputs signed firmware to <output_firmware>.
The <input_firmware> and <output_firmware> paths may be the same.
If no firmware version is specified, it is set as 1.
EOF
exit 1
}
gbb_update() {
local in_firmware="$1"
local key_dir="$2"
local out_firmware="$3"
local rootkey="$4"
# Replace the root and recovery key in the Google Binary Block of the
# firmware. Note: This needs to happen after calling resign_firmwarefd.sh
# since it needs to be able to verify the firmware using the root key to
# determine the preamble flags.
futility gbb \
-s \
--recoverykey="${key_dir}/recovery_key.vbpubk" \
--rootkey="${rootkey}" \
"${in_firmware}" \
"${out_firmware}"
}
# Sign a single firmware image.
# ARGS: [loem_key] [loemid]
sign_one() {
local loem_key="$1"
local loemid="$2"
# Resign the firmware with new keys.
"${SCRIPT_DIR}/resign_firmwarefd.sh" \
"${in_firmware}" \
"${temp_fw}" \
"${key_dir}/firmware_data_key${loem_key}.vbprivk" \
"${key_dir}/firmware${loem_key}.keyblock" \
"${key_dir}/dev_firmware_data_key${loem_key}.vbprivk" \
"${key_dir}/dev_firmware${loem_key}.keyblock" \
"${key_dir}/kernel_subkey.vbpubk" \
"${firmware_version}" \
"" \
"${loem_output_dir}" \
"${loemid}"
}
# Process all the keysets in the loem.ini file.
sign_loems() {
local line loem_section=false loem_index loemid
local rootkey
while read line; do
# Find the [loem] section.
if ! ${loem_section}; then
if grep -q "^ *\[loem\] *$" <<<"${line}"; then
loem_section=true
fi
continue
# Abort when we hit the next section.
elif [[ ${line} == *"["* ]]; then
break
fi
# Strip comments/whitespace.
line=$(sed -e 's:#.*::' -e 's:^ *::' -e 's: *$::' <<<"${line}")
if [[ -z "${line}" ]]; then
# Skip blank lines.
continue
fi
loem_index=$(cut -d= -f1 <<<"${line}" | sed 's: *$::')
loemid=$(cut -d= -f2 <<<"${line}" | sed 's:^ *::')
echo "### Processing LOEM ${loem_index} ${loemid}"
sign_one ".loem${loem_index}" "${loemid}"
rootkey="${key_dir}/root_key.loem${loem_index}.vbpubk"
cp "${rootkey}" "${loem_output_dir}/rootkey.${loemid}"
if [[ ${loem_index} == "1" ]]; then
gbb_update "${temp_fw}" "${key_dir}" "${out_firmware}" "${rootkey}"
fi
echo
done <"${key_dir}/loem.ini"
}
main() {
if [[ $# -lt 3 || $# -gt 5 ]]; then
usage
fi
local in_firmware=$1
local key_dir=$2
local out_firmware=$3
local firmware_version=${4:-1}
local loem_output_dir=${5:-}
local temp_fw=$(make_temp_file)
if [[ -e ${key_dir}/loem.ini ]]; then
if [[ -z ${loem_output_dir} ]]; then
die "need loem_output_dir w/loem keysets"
fi
sign_loems
else
sign_one
gbb_update "${temp_fw}" "${key_dir}" "${out_firmware}" \
"${key_dir}/root_key.vbpubk"
# Additional signing step for nVidia T210 SoC.
# Currently, cbootimage is unable to handle path with double slash.
if [[ -e ${key_dir}/nv_pkc.pem ]]; then
"${SCRIPT_DIR}/sign_nv_cbootimage.sh" \
"bootloader" \
"${key_dir%/}/nv_pkc.pem" \
"${out_firmware}" \
tegra210
fi
fi
}
main "$@"

View File

@@ -0,0 +1,262 @@
#!/bin/bash
# Copyright 2015 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.
# Wrapper script for signing firmware image using cbootimage.
# Determine script directory.
SCRIPT_DIR=$(dirname "$0")
# Load common constants and variables.
. "${SCRIPT_DIR}/common_minimal.sh"
# Abort on error.
set -e
usage() {
cat<<EOF
Usage: $0 <type> <pkc_key> <firmware_image> <soc>
Signs <firmware_image> of <type> with <pkc_key> using cbootimage for <soc>.
where type is one of
bootloader = sign bootloader image
lp0_firmware = sign lp0 firmware
EOF
exit 1
}
# Signs bootloader image using pkc_key provided for given soc
# Args: TYPE=bootloader PKC_KEY FIRMWARE_IMAGE SOC
sign_bootloader() {
local type=$1
local pkc_key="$(readlink -f "$2")"
local firmware_image="$(readlink -f "$3")"
local soc=$4
local work_dir=$(make_temp_dir)
local config_file=$(make_temp_file)
local signed_fw=$(make_temp_file)
pushd "${work_dir}" >/dev/null
# Get bootloader length.
#
# Example:
# $ bct_dump image.fastboot.bin
# Version = 0x00210001;
# BlockSize = 0x00008000;
# ...
# ...
# # Bootloader[0].Length = 69324;
# ...
# ...
#
# then, bl_length=69324 (size of bootloader that needs to be signed)
local bl_length=$(bct_dump "${firmware_image}" | \
sed -n '/Bootloader\[0\].Length/{ s/.*=\s*//; s/;//; p; q}')
# Extract bootloader to sign.
dd \
if="${firmware_image}" \
of="${signed_fw}.bl.tosig" \
count="${bl_length}" \
ibs=1 \
skip=32768 >/dev/null 2>&1
# Calculate rsa signature for bootloader.
openssl \
dgst -sha256 \
-sigopt rsa_padding_mode:pss \
-sigopt rsa_pss_saltlen:-1 \
-sign "${pkc_key}" \
-out "${signed_fw}.bl.sig" \
"${signed_fw}.bl.tosig"
# Update bootloader's rsa signature, aes hash and bct's aes hash.
echo "RsaPssSigBlFile = ${signed_fw}.bl.sig;" > "${config_file}"
echo "RehashBl;" >> "${config_file}"
cbootimage \
-s "${soc}" \
-u "${config_file}" \
"${firmware_image}" \
"${signed_fw}.tmp" >/dev/null
# Extract the part of bct which needs to be rsa signed.
dd \
if="${signed_fw}.tmp" \
of="${signed_fw}.bct.tosig" \
count=8944 \
ibs=1 \
skip=1296 >/dev/null 2>&1
# Calculate rsa signature for bct.
openssl \
dgst -sha256 \
-sigopt rsa_padding_mode:pss \
-sigopt rsa_pss_saltlen:-1 \
-sign "${pkc_key}" \
-out "${signed_fw}.bct.sig" \
"${signed_fw}.bct.tosig"
# Create public key modulus from key file.
openssl \
rsa -in "${pkc_key}" \
-noout \
-modulus \
-out "${signed_fw}.key.mod"
# Remove prefix.
cut \
-d= \
-f2 "${signed_fw}.key.mod" > "${signed_fw}.key.mod.tmp1"
dd \
if="${signed_fw}.key.mod.tmp1" \
of="${signed_fw}.key.mod.tmp" \
count=512 \
ibs=1 >/dev/null 2>&1
# Convert from hexdecimal to binary.
perl -pe 's/([0-9a-f]{2})/chr hex $1/gie' \
< "${signed_fw}.key.mod.tmp" \
> "${signed_fw}.key.mod.bin"
# Update bct's rsa signature and modulus.
echo "RsaPssSigBctFile = ${signed_fw}.bct.sig;" > "${config_file}"
echo "RsaKeyModulusFile = ${signed_fw}.key.mod.bin;" >> "${config_file}"
cbootimage \
-s "${soc}" \
-u "${config_file}" \
"${signed_fw}.tmp" \
"${signed_fw}" >/dev/null
# Calculate hash of public key modulus.
objcopy \
-I binary \
--reverse-bytes=256 \
"${signed_fw}.key.mod.bin" \
"${signed_fw}.key.mod.bin.rev"
openssl \
dgst -sha256 \
-binary \
-out "${signed_fw}.key.sha" \
"${signed_fw}.key.mod.bin.rev"
popd >/dev/null
# Copy signed firmware image and public key hash to current directory..
mv "${signed_fw}" "${firmware_image}"
mv "${signed_fw}.key.sha" "${firmware_image}.pubkey.sha"
}
# Signs lp0 firmware image using pkc_key provided for given soc
# Args: TYPE=lp0_firmware PKC_KEY FIRMWARE_IMAGE SOC
sign_lp0_firmware() {
local type=$1
local pkc_key="$(readlink -f "$2")"
local firmware_image="$(readlink -f "$3")"
local soc=$4
local work_dir=$(make_temp_dir)
local signed_fw=$(make_temp_file)
pushd "${work_dir}" >/dev/null
cp "${firmware_image}" "${signed_fw}"
# Extract the part of the binary which needs to be signed.
dd \
if="${firmware_image}" \
of="${signed_fw}.tosig" \
ibs=1 \
skip=544 >/dev/null 2>&1
# Calculate rsa-pss signature.
openssl \
dgst -sha256 \
-sigopt rsa_padding_mode:pss \
-sigopt rsa_pss_saltlen:-1 \
-sign "${pkc_key}" \
-out "${signed_fw}.rsa.sig" \
"${signed_fw}.tosig"
# Reverse rsa signature to meet tegra soc ordering requirement.
objcopy \
-I binary \
--reverse-bytes=256 \
"${signed_fw}.rsa.sig" \
"${signed_fw}.rsa.sig.rev"
# Inject rsa-pss signature into the binary image's header.
dd \
if="${signed_fw}.rsa.sig.rev" \
of="${signed_fw}" \
count=256 \
obs=1 \
seek=288 \
conv=notrunc >/dev/null 2>&1
# Generate public key modulus from key file.
openssl \
rsa -in "${pkc_key}" \
-noout \
-modulus \
-out "${signed_fw}.key.mod"
# Remove prefix.
cut \
-d= \
-f2 "${signed_fw}.key.mod" > "${signed_fw}.key.mod.tmp1"
dd \
if="${signed_fw}.key.mod.tmp1" \
of="${signed_fw}.key.mod.tmp" \
count=512 \
ibs=1 >/dev/null 2>&1
# Convert from hexdecimal to binary.
perl -pe 's/([0-9a-f]{2})/chr hex $1/gie' \
< "${signed_fw}.key.mod.tmp" \
> "${signed_fw}.key.mod.bin"
# Reverse byte order.
objcopy \
-I binary \
--reverse-bytes=256 \
"${signed_fw}.key.mod.bin" \
"${signed_fw}.key.mod.bin.rev"
# Inject public key modulus into the binary image's header.
dd \
if="${signed_fw}.key.mod.bin.rev" \
of="${signed_fw}" \
count=256 \
obs=1 \
seek=16 \
conv=notrunc >/dev/null 2>&1
popd >/dev/null
mv "${signed_fw}" "${firmware_image}"
}
main() {
if [[ $# -ne 4 ]]; then
usage
fi
local type=$1
case ${type} in
bootloader)
sign_bootloader "$@"
;;
lp0_firmware)
sign_lp0_firmware "$@"
;;
*)
usage
;;
esac
}
main "$@"

View File

@@ -0,0 +1,97 @@
#!/bin/bash
# Copyright 2017 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.
. "$(dirname "$0")/common.sh"
load_shflags || exit 1
DEFINE_string output "" \
"Where to write signed output to (default: sign in-place)"
FLAGS_HELP="Usage: ${PROG} [options] <input_image> <key_dir>
Signs <input_image> with keys in <key_dir>. Should have an imageloader.json
file which imageloader can understand and will use to mount the squashfs
image that provides the container's rootfs and OCI configuration.
Input can be an unpacked imageloader image, or a CRX/ZIP file.
"
# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# Abort on error.
set -e
# Sign the directory holding OCI container(s). We look for an imageloader.json
# file.
sign_oci_container() {
[[ $# -eq 3 ]] || die "Usage: sign_oci_container <input> <key> <output>"
local input="${1%/}"
local key_file="$2"
local output="$3"
if [[ "${input}" != "${output}" ]]; then
rsync -a "${input}/" "${output}/"
fi
local manifest out_manifest
while read -d $'\0' -r manifest; do
out_manifest="${output}/${manifest%.json}.sig.2"
manifest="${input}/${manifest}"
info "Signing: ${manifest}"
if ! openssl dgst -sha256 -sign "${key_file}" \
-out "${out_manifest}" "${manifest}"; then
die "Failed to sign"
fi
done < <(find "${input}/" -name imageloader.json -printf '%P\0')
}
# Sign the crx/zip holding OCI container(s). We look for an imageloader.json
# file.
sign_oci_container_zip() {
[[ $# -eq 3 ]] || die "Usage: sign_oci_container_zip <input> <key> <output>"
local input="$1"
local key_file="$2"
local output="$3"
local tempdir=$(make_temp_dir)
info "Unpacking archive: ${input}"
unzip -q "${input}" -d "${tempdir}"
sign_oci_container "${tempdir}" "${key_file}" "${tempdir}"
rm -f "${output}"
info "Packing archive: ${output}"
(
cd "${tempdir}"
zip -q -r - ./
) >"${output}"
}
main() {
if [[ $# -ne 2 ]]; then
flags_help
exit 1
fi
local input="${1%/}"
local key_dir="$2"
local key_file="${key_dir}/cros-oci-container.pem"
if [[ ! -e "${key_file}" ]]; then
die "Missing key file: ${key_file}"
fi
: "${FLAGS_output:=${input}}"
if [[ -f "${input}" ]]; then
sign_oci_container_zip "${input}" "${key_file}" "${FLAGS_output}"
else
sign_oci_container "${input}" "${key_file}" "${FLAGS_output}"
fi
}
main "$@"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
#!/bin/bash
# Copyright 2018 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.
. "$(dirname "$0")/common.sh"
set -e
usage() {
cat <<EOF
Usage: $PROG /path/to/target/dir /path/to/uefi/keys/dir
Sign the UEFI binaries in the target directory.
The target directory can be either the root of ESP or /boot of root filesystem.
EOF
if [[ $# -gt 0 ]]; then
error "$*"
exit 1
fi
exit 0
}
# Signs an EFI binary file, if possible.
# Args: TARGET_FILE TEMP_DIR PRIVATE_KEY SIGN_CERT VERIFY_CERT
sign_efi_file() {
local target="$1"
local temp_dir="$2"
local priv_key="$3"
local sign_cert="$4"
local verify_cert="$5"
if [[ -z "${verify_cert}" ]]; then
verify_cert="${sign_cert}"
fi
info "Signing efi file ${target}"
sudo sbattach --remove "${target}" || true
local signed_file="${temp_dir}/$(basename "${target}")"
sbsign --key="${priv_key}" --cert="${sign_cert}" \
--output="${signed_file}" "${target}" || warn "Cannot sign ${target}"
if [[ -f "${signed_file}" ]]; then
sudo cp -f "${signed_file}" "${target}"
sbverify --cert "${verify_cert}" "${target}" || die "Verification failed"
fi
}
main() {
local target_dir="$1"
local key_dir="$2"
if [[ $# -ne 2 ]]; then
usage "command takes exactly 2 args"
fi
if ! type -P sbattach &>/dev/null; then
die "Cannot sign UEFI binaries (sbattach not found)."
fi
if ! type -P sbsign &>/dev/null; then
die "Cannot sign UEFI binaries (sbsign not found)."
fi
if ! type -P sbverify &>/dev/null; then
die "Cannot sign UEFI binaries (sbverify not found)."
fi
local bootloader_dir="${target_dir}/efi/boot"
local syslinux_dir="${target_dir}/syslinux"
local kernel_dir="${target_dir}"
local verify_cert="${key_dir}/db/db.pem"
if [[ ! -f "${verify_cert}" ]]; then
die "No verification cert: ${verify_cert}"
fi
local sign_cert="${key_dir}/db/db.children/db_child.pem"
if [[ ! -f "${sign_cert}" ]]; then
die "No signing cert: ${sign_cert}"
fi
local sign_key="${key_dir}/db/db.children/db_child.rsa"
if [[ ! -f "${sign_key}" ]]; then
die "No signing key: ${sign_key}"
fi
local working_dir="$(make_temp_dir)"
local efi_file
for efi_file in "${bootloader_dir}"/*.efi; do
if [[ ! -f "${efi_file}" ]]; then
continue
fi
sign_efi_file "${efi_file}" "${working_dir}" \
"${sign_key}" "${sign_cert}" "${verify_cert}"
done
local syslinux_kernel_file
for syslinux_kernel_file in "${syslinux_dir}"/vmlinuz.?; do
if [[ ! -f "${syslinux_kernel_file}" ]]; then
continue
fi
sign_efi_file "${syslinux_kernel_file}" "${working_dir}" \
"${sign_key}" "${sign_cert}" "${verify_cert}"
done
local kernel_file="$(readlink -f "${kernel_dir}/vmlinuz")"
if [[ -f "${kernel_file}" ]]; then
sign_efi_file "${kernel_file}" "${working_dir}" \
"${sign_key}" "${sign_cert}" "${verify_cert}"
fi
}
main "$@"

View File

@@ -0,0 +1,61 @@
#!/bin/bash
# Copyright (c) 2013 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.
# Script to remove /boot directory from an image.
# Load common constants. This should be the first executable line.
# The path to common.sh should be relative to your script's location.
. "$(dirname "$0")/common.sh"
load_shflags
DEFINE_string image "chromiumos_image.bin" \
"Input file name of Chrome OS image to strip /boot from."
# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# Abort on error.
set -e
if [ -z "${FLAGS_image}" ] || [ ! -s "${FLAGS_image}" ] ; then
die "Error: need a valid file by --image"
fi
# Swiped/modifed from $SRC/src/scripts/base_library/base_image_util.sh.
zero_free_space() {
local rootfs="$1"
info "Zeroing freespace in ${rootfs}"
sudo fstrim -v "${rootfs}"
}
strip_boot() {
local image=$1
# Mount image so we can modify it.
local rootfs_dir=$(make_temp_dir)
mount_image_partition ${image} 3 ${rootfs_dir}
sudo rm -rf "${rootfs_dir}/boot" &&
info "/boot directory was removed."
# To prevent the files we just removed from the FS from remaining as non-
# zero trash blocks that bloat payload sizes, need to zero them. This was
# done when the image was built, but needs to be repeated now that we've
# modified it in a non-trivial way.
zero_free_space "${rootfs_dir}"
}
IMAGE=$(readlink -f "${FLAGS_image}")
if [[ -z "${IMAGE}" || ! -f "${IMAGE}" ]]; then
die "Missing required argument: --from (image to update)"
fi
strip_boot "${IMAGE}"

View File

@@ -0,0 +1,222 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Script to manipulate the tag files in the output of build_image
# Load common constants. This should be the first executable line.
# The path to common.sh should be relative to your script's location.
. "$(dirname "$0")/common.sh"
load_shflags
DEFINE_string from "chromiumos_image.bin" \
"Input file name of Chrome OS image to tag/stamp."
DEFINE_string dev_mode "" \
"(build-info) Tag as a developer mode build (1 to enable, 0 to disable)"
DEFINE_string update_firmware "" \
"(auto-update) Force updating firmware (1 to enable, 0 to disable)"
DEFINE_string leave_firmware_alone "" \
"(auto-update) For BIOS development use ONLY (1 to enable, 0 to disable)"
DEFINE_string leave_core "" \
"(crash-reporter) Leave core dumps (1 to enable, 0 to disable)"
# Parameters for manipulating /etc/lsb-release.
DEFINE_boolean remove_test_label false \
"(build-info) Remove 'test' suffix in /etc/lsb-release"
DEFINE_boolean change_dev_to_beta false \
"(build-info) Change 'dev' -> 'beta' in /etc/lsb-release"
# TODO(hungte) we can add factory_installer and factory_test,
# but I don't see any reason to tweak/check these values.
# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"
# Abort on error.
set -e
if [ -z "${FLAGS_from}" ] || [ ! -s "${FLAGS_from}" ] ; then
echo "Error: need a valid file by --from"
exit 1
fi
# Global variable to track if the image is modified.
g_modified=${FLAGS_FALSE}
# Processes (enable, disable, or simply report) a tag file.
# Args: DO_MODIFICATION NAME ROOT TAG_FILE ACTION
#
# When DO_MODIFICATION=${FLAGS_TRUE},
# Creates (ACTION=1) the TAG_FILE in ROOT, or
# removes (ACTION=0) the TAG_FILE in ROOT, then
# reports the status (and change) to the tag file.
# When DO_MODIFICATION=${FLAGS_FALSE},
# make a dry-run and only change ${g_modified}
function process_tag() {
local tag_status_text=""
local do_modification="$1"
local name="$2"
local root="$3"
local tag_file_path="$3/$4"
local action="$5"
local do_enable=${FLAGS_FALSE}
local do_disable=${FLAGS_FALSE}
# only 1, 0, and "" are valid params to action.
case "${action}" in
"1" )
do_enable=${FLAGS_TRUE}
;;
"0" )
do_disable=${FLAGS_TRUE}
;;
"" )
;;
* )
echo "Error: invalid param to ${name}: ${action} (must be 1 or 0)."
exit 1
;;
esac
if [ -f "${tag_file_path}" ]; then
tag_status_text="ENABLED"
if [ "${do_disable}" = ${FLAGS_TRUE} ]; then
# disable the tag
if [ "${do_modification}" = ${FLAGS_TRUE} ]; then
sudo rm "${tag_file_path}"
fi
g_modified=${FLAGS_TRUE}
tag_status_text="${tag_status_text} => disabled"
elif [ "${do_disable}" != ${FLAGS_FALSE} ]; then
# internal error
echo "Internal error for tag ${name}: need disable param." 1>&2
exit 1
fi
else
tag_status_text="disabled"
if [ "${do_enable}" = ${FLAGS_TRUE} ]; then
# enable the tag
if [ "${do_modification}" = ${FLAGS_TRUE} ]; then
sudo touch "${tag_file_path}"
fi
g_modified=${FLAGS_TRUE}
tag_status_text="${tag_status_text} => ENABLED"
elif [ "${do_enable}" != ${FLAGS_FALSE} ]; then
# internal error
echo "Internal error for tag ${name}: need enable param." 1>&2
exit 1
fi
fi
# report tag status
if [ "${do_modification}" != ${FLAGS_TRUE} ]; then
echo "${name}: ${tag_status_text}"
fi
}
# Iterates all tags to a given partition root.
# Args: ROOTFS DO_MODIFICATION
#
# Check process_tag for the meaning of parameters.
process_all_tags() {
local rootfs="$1"
local do_modification="$2"
process_tag "${do_modification}" \
"(build-info) dev_mode" \
"${rootfs}" \
/root/.dev_mode \
"${FLAGS_dev_mode}"
process_tag "${do_modification}" \
"(auto-update) update_firmware" \
"${rootfs}" \
/root/.force_update_firmware \
"${FLAGS_update_firmware}"
process_tag "${do_modification}" \
"(auto-update) leave_firmware_alone" \
"${rootfs}" \
/root/.leave_firmware_alone \
"${FLAGS_leave_firmware_alone}"
process_tag "${do_modification}" \
"(crash-reporter) leave_core" \
"${rootfs}" \
/root/.leave_core \
"${FLAGS_leave_core}"
}
# Iterates through all options for manipulating the lsb-release.
# Args: ROOTFS DO_MODIFICATION
process_all_lsb_mods() {
local rootfs="$1"
local do_modifications="$2"
local lsb="${rootfs}/etc/lsb-release"
local sudo
if [ ! -w "${lsb}" ]; then
sudo="sudo"
fi
if [ ${FLAGS_remove_test_label} = ${FLAGS_TRUE} ]; then
if grep -wq "test" "${lsb}"; then
g_modified=${FLAGS_TRUE}
fi
if [ ${do_modifications} = ${FLAGS_TRUE} ]; then
${sudo} sed -i 's/\btest\b//' "${lsb}" &&
echo "Test Label removed from /etc/lsb-release"
fi
fi
if [ ${FLAGS_change_dev_to_beta} = ${FLAGS_TRUE} ]; then
if grep -wq "dev" "${lsb}"; then
g_modified=${FLAGS_TRUE}
fi
if [ ${do_modifications} = ${FLAGS_TRUE} ]; then
${sudo} sed -i 's/\bdev\b/beta/' "${lsb}" &&
echo "Dev Channel Label was changed to Beta"
fi
fi
}
IMAGE=$(readlink -f "${FLAGS_from}")
if [[ -z "${IMAGE}" || ! -f "${IMAGE}" ]]; then
echo "Missing required argument: --from (image to update)"
usage
exit 1
fi
# First round, mount as read-only and check if we need any modifications.
rootfs=$(make_temp_dir)
mount_image_partition_ro "${IMAGE}" 3 "${rootfs}"
# we don't have tags in stateful partition yet...
# stateful_dir=$(make_temp_dir)
# mount_image_partition ${IMAGE} 1 ${stateful_dir}
process_all_tags "${rootfs}" ${FLAGS_FALSE}
process_all_lsb_mods "${rootfs}" ${FLAGS_FALSE}
if [ ${g_modified} = ${FLAGS_TRUE} ]; then
# remount as RW (we can't use mount -o rw,remount because of loop device)
sudo umount "${rootfs}"
mount_image_partition "${IMAGE}" 3 "${rootfs}"
# second round, apply the modification to image.
process_all_tags "${rootfs}" ${FLAGS_TRUE}
process_all_lsb_mods "${rootfs}" ${FLAGS_TRUE}
# this is supposed to be automatically done in mount_image_partition,
# but it's no harm to explicitly make it again here.
tag_as_needs_to_be_resigned "${rootfs}"
echo "IMAGE IS MODIFIED. PLEASE REMEMBER TO RESIGN YOUR IMAGE."
else
echo "Image is not modified."
fi

View File

@@ -0,0 +1,185 @@
#!/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.
#
# This script converts a Chrome OS device to a pre-factory-install state:
# * Firmware write protect disabled
# * H2O BIOS, with RO VPD area copied from the current BIOS
# * Original EC firmware
# * Blank SSD (no GPT)
#
# Minimal usage:
# tofactory.sh -b H2OBIOS.bin -e ec_shellball.sh
SCRIPT_BASE="$(dirname "$0")"
. "$SCRIPT_BASE/common_minimal.sh"
load_shflags || exit 1
# Constants used by DEFINE_*
VBOOT_BASE='/usr/share/vboot'
# DEFINE_string name default_value description flag
DEFINE_string bios "" "Path of system firmware (BIOS) binary to write" "b"
DEFINE_string ec "" "Path of EC shellball to execute" "e"
DEFINE_string backup_dir "" "Path of directory in whoch to store backups" "k"
DEFINE_string asset_tag "unspecified_tag" \
"Asset tag of device, used to name backups" "a"
DEFINE_string ssd "/dev/sda" "Path to SSD / target drive" "s"
DEFINE_boolean wipe_ssd $FLAGS_TRUE "Wipe SSD after firmware updates" ""
DEFINE_boolean nothing $FLAGS_FALSE \
"Print commands but do not modify device" "n"
# Parse command line
FLAGS "$@" || exit 1
eval set -- "$FLAGS_ARGV"
# Globals
# ----------------------------------------------------------------------------
set -e
# Flashrom commands with device overrides
FLASHROM_BIOS="flashrom -p host"
FLASHROM_EC="flashrom -p ec"
# A log file to keep the output results of executed command
EXEC_LOG="$(make_temp_file)"
# Temporary Work directory
WORK_DIR="$(make_temp_dir)"
OLD_BIOS="$WORK_DIR/old_bios.bin"
NEW_BIOS="$WORK_DIR/new_bios.bin"
# Functions
# ----------------------------------------------------------------------------
# Error message for write protect disable failure, with reminder
wp_error() {
local which_rom=$1
shift
echo "ERROR: Unable to disable $which_rom write protect: $*" 1>&2
echo "Is hardware write protect still enabled?" 1>&2
exit 1
}
# Disable write protect for an EEPROM
disable_wp() {
local which_rom=$1 # EC or BIOS
shift
local flash_rom="$*" # Flashrom command to use
debug_msg "Disabling $which_rom write protect"
$NOTHING ${flash_rom} --wp-disable || wp_error "$which_rom" "--wp-disable"
$NOTHING ${flash_rom} --wp-range 0 0 || wp_error "$which_rom" "--wp-range"
# WP status bits should report WP: status: 0x00
local wp_status="$(${flash_rom} --wp-status | grep "WP: status:")"
if [ "$wp_status" != "WP: status: 0x00" ]; then
if [ "$FLAGS_nothing" = $FLAGS_FALSE ]; then
wp_error "$which_rom" "$wp_status"
fi
fi
}
# Back up current firmware and partition table
make_backups() {
debug_msg "Backing up current firmware to $FLAGS_backup_dir"
mkdir -p "$FLAGS_backup_dir"
cp "$OLD_BIOS" "$FLAGS_backup_dir/$FLAGS_asset_tag.bios.bin"
${FLASHROM_EC} -r "$FLAGS_backup_dir/$FLAGS_asset_tag.ec.bin"
# Copy the VPD info from RAM, since we can't extract it as text
# from the BIOS binary. Failure of this is only a warning, since
# the information is still in the old BIOS.
mosys vpd print all > "$FLAGS_backup_dir/$FLAGS_asset_tag.vpd.txt" ||
echo "WARNING: unable to save VPD as text."
# Copy the first part of the drive, so we can recreate the partition
# table.
local gpt_backup="$FLAGS_backup_dir/$FLAGS_asset_tag.gpt.bin"
debug_msg "Backing up current GPT table."
dd if="$FLAGS_ssd" of="$gpt_backup" bs=512 count=34
# Add a script to restore the BIOS and GPT
local restore_script="$FLAGS_backup_dir/$FLAGS_asset_tag.restore.sh"
cat >"$restore_script" <<EOF
#!/bin/sh
echo "Restoring BIOS"
${FLASHROM_BIOS} -w "$FLAGS_asset_tag.bios.bin"
echo "Restoring EC"
${FLASHROM_EC} -w "$FLAGS_asset_tag.ec.bin"
echo "Restoring GPT"
dd of="$FLAGS_ssd" if="$FLAGS_asset_tag.gpt.bin" conv=notrunc
EOF
echo "To restore original BIOS and SSD:"
echo " cd $FLAGS_backup_dir && sh $FLAGS_asset_tag.restore.sh"
}
# Main
# ----------------------------------------------------------------------------
main() {
# Make sure the files we were passed exist
[ -n "$FLAGS_bios" ] || die "Please specify a BIOS file (-b bios.bin)"
[ -n "$FLAGS_ec" ] || die "Please specify an EC updater (-e updater.sh)"
ensure_files_exist "$FLAGS_bios" "$FLAGS_ec" || exit 1
# If --nothing was specified, keep flashrom from writing
if [ "$FLAGS_nothing" = $FLAGS_TRUE ]; then
NOTHING="echo Not executing: "
fi
# Stop update engine before calling flashrom. Multiple copies of flashrom
# interfere with each other.
debug_msg "Stopping update engine"
initctl stop update-engine
# Read the current firmware
debug_msg "Reading BIOS from EEPROM"
${FLASHROM_BIOS} -r "$OLD_BIOS"
# Copy current info to the backup dir, if specified
if [ -n "$FLAGS_backup_dir" ]; then
make_backups
fi
# Find the RO VPD area in the current firmware
local t="$(mosys -k eeprom map "$OLD_BIOS" | grep 'RO VPD')"
local vpd_offset="$(echo $t | sed 's/.*area_offset="\([^"]*\)" .*/\1/' )"
local vpd_size="$(echo $t | sed 's/.*area_size="\([^"]*\)" .*/\1/' )"
debug_msg "Found VPD at offset $vpd_offset size $vpd_size"
# Convert offset and size to decimal, since dd doesn't grok hex
vpd_offset="$(printf "%d" $vpd_offset)"
vpd_size="$(printf "%d" $vpd_size)"
debug_msg "In decimal, VPD is at offset $vpd_offset size $vpd_size"
# Copy the RO VPD from the old firmware to the new firmware
debug_msg "Copying VPD from old firmware to new firmware"
cp "$FLAGS_bios" "$NEW_BIOS"
dd bs=1 seek=$vpd_offset skip=$vpd_offset count=$vpd_size conv=notrunc \
if="$OLD_BIOS" of="$NEW_BIOS" || die "Unable to copy RO VPD"
# Disable write protect
disable_wp "EC" ${FLASHROM_EC}
disable_wp "BIOS" ${FLASHROM_BIOS}
# Write new firmware
debug_msg "Writing EC"
# TODO: if EC file ends in .bin, use flashrom to write it directly?
$NOTHING sh "$FLAGS_ec" --factory || die "Unable to write EC"
debug_msg "Writing BIOS"
$NOTHING ${FLASHROM_BIOS} -w "$NEW_BIOS" || die "Unable to write BIOS"
# Wipe SSD
if [ "$FLAGS_wipe_ssd" = $FLAGS_TRUE ]; then
debug_msg "Wiping SSD"
$NOTHING cgpt create -z "$FLAGS_ssd" || die "Unable to wipe SSD"
fi
# Leave the update engine stopped. We've mucked with the firmware
# and SSD contents, so we shouldn't be attempting an autoupdate this
# boot anyway.
}
main

View File

@@ -0,0 +1,69 @@
#!/bin/bash
# Copyright (c) 2010 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.
# Script that unpacks a firmware image (in .fd format) into its component
# pieces. Only outputs firmware A and B data, vblocks and the GBB.
# The mosys tool must be in the system path.
# Abort on error
set -e
# Check arguments
if [ $# -ne 1 ] ; then
echo "Usage: $0 src_fd"
echo "Outputs firmware.gbb, firmware[A|B].[data|vblock]"
exit 1
fi
# Make sure the tools we need are available.
type -P mosys &>/dev/null || \
{ echo "mosys tool not found."; exit 1; }
src_fd=$1
# Grab GBB Area offset and size
match_str="GBB Area"
line=$(mosys -f -k eeprom map $1 | grep "$match_str")
offset="$(echo $line | sed -e 's/.*area_offset=\"\([a-f0-9x]*\)\".*/\1/')"
let gbb_offset="$offset"
size="$(echo $line | sed -e 's/.*area_size=\"\([a-f0-9x]*\)\".*/\1/')"
let gbb_size="$size"
# Grab Firmware A and B offset and size
for i in "A" "B"
do
match_str="$i Key"
line=$(mosys -f -k eeprom map $1 | grep "$match_str")
offset="$(echo $line | sed -e 's/.*area_offset=\"\([a-f0-9x]*\)\".*/\1/')"
eval let \
fw${i}_vblock_offset="$offset"
size="$(echo $line | sed -e 's/.*area_size=\"\([a-f0-9x]*\)\".*/\1/')"
eval let \
fw${i}_vblock_size="$size"
match_str="$i Data"
line=$(mosys -f -k eeprom map $1 | grep "$match_str")
offset="$(echo $line | sed -e 's/.*area_offset=\"\([a-f0-9x]*\)\".*/\1/')"
eval let \
fw${i}_offset="$offset"
size="$(echo $line | sed -e 's/.*area_size=\"\([a-f0-9x]*\)\".*/\1/')"
eval let \
fw${i}_size="$size"
done
echo "Extracting GBB"
dd if="${src_fd}" of="firmware.gbb" skip="${gbb_offset}" bs=1 \
count="${gbb_size}"
echo "Extracting Firmware data and vblock(s)"
dd if="${src_fd}" of="firmwareA.data" skip="${fwA_offset}" bs=1 \
count="${fwA_size}"
dd if="${src_fd}" of="firmwareA.vblock" skip="${fwA_vblock_offset}" bs=1 \
count="${fwA_vblock_size}"
dd if="${src_fd}" of="firmwareB.data" skip="${fwB_offset}" bs=1 \
count="${fwB_size}"
dd if="${src_fd}" of="firmwareB.vblock" skip="${fwB_vblock_offset}" bs=1 \
count="${fwB_vblock_size}"

View File

@@ -0,0 +1,87 @@
#!/bin/bash
# Copyright 2018 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.
. "$(dirname "$0")/common.sh"
set -e
usage() {
cat <<EOF
Usage: $PROG /path/to/target/dir /path/to/esp/dir /path/to/uefi/keys/dir
Verify signatures of UEFI binaries in the target directory.
EOF
if [[ $# -gt 0 ]]; then
error "$*"
exit 1
fi
exit 0
}
main() {
local target_dir="$1"
local esp_dir="$2"
local key_dir="$3"
if [[ $# -ne 3 ]]; then
usage "command takes exactly 3 args"
fi
if ! type -P sbverify &>/dev/null; then
die "Cannot verify UEFI signatures (sbverify not found)."
fi
local bootloader_dir="${target_dir}/efi/boot"
local syslinux_dir="${target_dir}/syslinux"
local kernel_dir="${target_dir}"
local gsetup_dir="${esp_dir}/EFI/Google/GSetup"
if [[ ! -f "${gsetup_dir}/pk/pk.der" ]]; then
die "No PK cert"
fi
local db_cert_der="${gsetup_dir}/db/db.der"
if [[ ! -f "${db_cert_der}" ]]; then
die "No DB cert"
fi
local cert="${key_dir}/db/db.pem"
local working_dir="$(make_temp_dir)"
local gsetup_cert="${working_dir}/cert.pem"
openssl x509 -in "${db_cert_der}" -inform DER \
-out "${gsetup_cert}" -outform PEM
for efi_file in "${bootloader_dir}"/*.efi; do
if [[ ! -f "${efi_file}" ]]; then
continue
fi
sbverify --cert "${cert}" "${efi_file}" ||
die "Verification failed. file:${efi_file} cert:${cert}"
sbverify --cert "${gsetup_cert}" "${efi_file}" ||
die "Verification failed. file:${efi_file} cert:${gsetup_cert}"
done
for syslinux_kernel_file in "${syslinux_dir}"/vmlinuz.?; do
if [[ ! -f "${syslinux_kernel_file}" ]]; then
continue
fi
sbverify --cert "${cert}" "${syslinux_kernel_file}" ||
warn "Verification failed. file:${syslinux_kernel_file} cert:${cert}"
sbverify --cert "${gsetup_cert}" "${syslinux_kernel_file}" ||
warn "Verification failed. file:${syslinux_kernel_file}" \
"cert:${gsetup_cert}"
done
local kernel_file="$(readlink -f "${kernel_dir}/vmlinuz")"
if [[ -f "${kernel_file}" ]]; then
sbverify --cert "${cert}" "${kernel_file}" ||
warn "Verification failed: file:${kernel_file} cert:${cert}"
sbverify --cert "${gsetup_cert}" "${kernel_file}" ||
warn "Verification failed: file:${kernel_file} cert:${gsetup_cert}"
fi
}
main "$@"

View File

@@ -0,0 +1,7 @@
# sign_official_build.sh can (optionally) take a file name from which to read
# firmware and kernel versions to set during the signing process.
# This is a sample version file template.
firmware_version=1
kernel_version=1

View File

@@ -0,0 +1,69 @@
#!/bin/bash
# Copyright 2017 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.
# Load common constants and functions.
. "$(dirname "$0")/../common.sh"
usage() {
cat <<EOF
Usage: ${PROG} [options]
Options:
-o, --output_dir <dir>: Where to write the keys (default is cwd)
EOF
if [[ $# -ne 0 ]]; then
die "$*"
else
exit 0
fi
}
generate_rsa3072_exp3_key() {
local output_dir="$1"
local key_name="$2"
# Generate RSA key.
openssl genrsa -3 -out "${output_dir}/temp.pem" 3072
# Create a keypair from an RSA .pem file generated above.
futility create "${output_dir}/temp.pem" "${output_dir}/key_${key_name}"
# Best attempt to securely delete the temp.pem file.
shred --remove "${output_dir}/temp.pem"
}
# To generate a keypair with the same algorithm of Hammer and rename the kepair
# to specific accessory's name.
leverage_hammer_to_create_key() {
local output_dir="${PWD}"
local key_name="$1"
shift
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
;;
-o|--output_dir)
output_dir="$2"
if [[ ! -d "${output_dir}" ]]; then
die "output dir ("${output_dir}") doesn't exist."
fi
shift
;;
-*)
usage "Unknown option: "$1""
;;
*)
usage "Unknown argument "$1""
;;
esac
shift
done
generate_rsa3072_exp3_key "${output_dir}" "${key_name}"
}

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Copyright 2017 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.
# Load common constants and functions.
. "$(dirname "$0")/common_leverage_hammer.sh"
main() {
set -e
leverage_hammer_to_create_key "ec_efs" "$@"
}
main "$@"

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Copyright 2017 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.
# Load common constants and functions.
. "$(dirname "$0")/common_leverage_hammer.sh"
main() {
set -e
leverage_hammer_to_create_key "hammer" "$@"
}
main "$@"

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Copyright 2017 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.
# Load common constants and functions.
. "$(dirname "$0")/common_leverage_hammer.sh"
main() {
set -e
leverage_hammer_to_create_key "rose" "$@"
}
main "$@"

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Copyright 2017 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.
# Load common constants and functions.
. "$(dirname "$0")/common_leverage_hammer.sh"
main() {
set -e
leverage_hammer_to_create_key "staff" "$@"
}
main "$@"

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Copyright 2017 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.
# Load common constants and functions.
. "$(dirname "$0")/common_leverage_hammer.sh"
main() {
set -e
leverage_hammer_to_create_key "wand" "$@"
}
main "$@"

View File

@@ -0,0 +1,16 @@
#!/bin/bash
# Copyright 2018 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.
# Load common constants and functions.
. "$(dirname "$0")/common_leverage_hammer.sh"
main() {
set -e
leverage_hammer_to_create_key "whiskers" "$@"
}
main "$@"

View File

@@ -0,0 +1,83 @@
#!/bin/bash
# Copyright 2015 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.
# Load common constants and functions.
. "$(dirname "$0")/common.sh"
usage() {
cat <<EOF
Usage: ${PROG} <number of loem keys to add>
If the existing keyset is not set up for loem usage, it will be converted.
Note: Use 0 if you want to just convert an existing keyset.
EOF
exit ${1:-0}
}
convert_keyset_to_loem() {
local f
printf "Converting to loem keyset; continue? (y/N) "
read f
[[ ${f} == [yY] ]]
for f in {firmware_data,root}_key.vb{pub,priv}k firmware.keyblock; do
if [[ ${f} == "root_key.vbprivk" && ! -e ${f} ]]; then
# For official keys, we won't have the private half of the root key.
echo "Skipping ${f} for official keys"
continue
fi
if [[ ${f} == *.vbprivk && ! -e ${f} ]]; then
# For official keys, will be gpg wrapped.
f+=".gpg"
fi
mv -i "${f}" "${f/./.loem1.}"
done
echo "[loem]" > loem.ini
}
main() {
set -e -u
if [[ $# -ne 1 || $1 == -* ]]; then
usage
fi
# Keep `local` and assignment split so return values are checked.
local firmware_key_version
local num_keys highest_key k
if [[ ! -e ${VERSION_FILE} ]]; then
die "missing ${VERSION_FILE} in ${PWD}; please create one"
fi
firmware_key_version=$(get_version "firmware_key_version")
# See if we need to convert the keyset first.
if [[ -e root_key.vbpubk ]]; then
convert_keyset_to_loem
fi
num_keys=$1
highest_key=$(printf '%s\n' firmware.loem*.keyblock |
sed -r 's:firmware.loem(.*).keyblock:\1:' |
sort -n | tail -1)
echo "There are ${highest_key} loem keys; ading ${num_keys} more"
for ((k = highest_key + 1; k < highest_key + 1 + num_keys; ++k)); do
echo "Generating LOEM ${k}"
make_pair root_key.loem${k} ${ROOT_KEY_ALGOID}
make_pair firmware_data_key.loem${k} ${FIRMWARE_DATAKEY_ALGOID} \
${firmware_key_version}
make_keyblock firmware.loem${k} ${FIRMWARE_KEYBLOCK_MODE} \
firmware_data_key.loem${k} root_key.loem${k}
done
echo
echo "Don't forget to update loem.ini to allocate the keys!"
}
main "$@"

View File

@@ -0,0 +1,261 @@
#!/bin/bash
# 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.
# Common key generation functions.
SCRIPT_DIR="$(dirname "$(readlink -f -- "$0")")"
PROG=$(basename "$0")
CROS_LOG_PREFIX="${PROG}: "
# Prints an informational message.
info() {
echo "${CROS_LOG_PREFIX}INFO: $*" >&2
}
# Prints a warning message.
warn() {
echo "${CROS_LOG_PREFIX}WARNING: $*" >&2
}
# Prints an error message.
error() {
echo "${CROS_LOG_PREFIX}ERROR: $*" >&2
}
# Print an error message and then exit the script.
die() {
error "$@"
exit 1
}
# Algorithm ID mappings:
RSA1024_SHA1_ALGOID=0
RSA1024_SHA256_ALGOID=1
RSA1024_SHA512_ALGOID=2
RSA2048_SHA1_ALGOID=3
RSA2048_SHA256_ALGOID=4
RSA2048_SHA512_ALGOID=5
RSA4096_SHA1_ALGOID=6
RSA4096_SHA256_ALGOID=7
RSA4096_SHA512_ALGOID=8
RSA8192_SHA1_ALGOID=9
RSA8192_SHA256_ALGOID=10
RSA8192_SHA512_ALGOID=11
alg_to_keylen() {
echo $(( 1 << (10 + ($1 / 3)) ))
}
# Default algorithms.
EC_ROOT_KEY_ALGOID=${RSA4096_SHA256_ALGOID}
EC_DATAKEY_ALGOID=${RSA4096_SHA256_ALGOID}
ROOT_KEY_ALGOID=${RSA8192_SHA512_ALGOID}
RECOVERY_KEY_ALGOID=${RSA8192_SHA512_ALGOID}
FIRMWARE_DATAKEY_ALGOID=${RSA4096_SHA256_ALGOID}
DEV_FIRMWARE_DATAKEY_ALGOID=${RSA4096_SHA256_ALGOID}
RECOVERY_KERNEL_ALGOID=${RSA8192_SHA512_ALGOID}
INSTALLER_KERNEL_ALGOID=${RSA8192_SHA512_ALGOID}
KERNEL_SUBKEY_ALGOID=${RSA4096_SHA256_ALGOID}
KERNEL_DATAKEY_ALGOID=${RSA2048_SHA256_ALGOID}
# Keyblock modes determine which boot modes a signing key is valid for use
# in verification.
EC_KEYBLOCK_MODE=7 # Only allow RW EC firmware in non-recovery.
FIRMWARE_KEYBLOCK_MODE=7 # Only allow RW firmware in non-recovery.
DEV_FIRMWARE_KEYBLOCK_MODE=6 # Only allow in dev mode.
RECOVERY_KERNEL_KEYBLOCK_MODE=11 # Only in recovery mode.
KERNEL_KEYBLOCK_MODE=7 # Only allow in non-recovery.
INSTALLER_KERNEL_KEYBLOCK_MODE=10 # Only allow in Dev + Recovery.
# Emit .vbpubk and .vbprivk using given basename and algorithm
# NOTE: This function also appears in ../../utility/dev_make_keypair. Making
# the two implementations the same would require some common.sh, which is more
# likely to cause problems than just keeping an eye out for any differences. If
# you feel the need to change this file, check the history of that other file
# to see what may need updating here too.
make_pair() {
local base=$1
local alg=$2
local key_version=${3:-1}
local len=$(alg_to_keylen $alg)
echo "creating $base keypair (version = $key_version)..."
# make the RSA keypair
openssl genrsa -F4 -out "${base}_${len}.pem" $len
# create a self-signed certificate
openssl req -batch -new -x509 -key "${base}_${len}.pem" \
-out "${base}_${len}.crt"
# generate pre-processed RSA public key
dumpRSAPublicKey -cert "${base}_${len}.crt" > "${base}_${len}.keyb"
# wrap the public key
vbutil_key \
--pack "${base}.vbpubk" \
--key "${base}_${len}.keyb" \
--version "${key_version}" \
--algorithm $alg
# wrap the private key
vbutil_key \
--pack "${base}.vbprivk" \
--key "${base}_${len}.pem" \
--algorithm $alg
# remove intermediate files
rm -f "${base}_${len}.pem" "${base}_${len}.crt" "${base}_${len}.keyb"
}
# Emit a .keyblock containing flags and a public key, signed by a private key
# flags are the bitwise OR of these (passed in decimal, though)
# 0x01 Developer switch off
# 0x02 Developer switch on
# 0x04 Not recovery mode
# 0x08 Recovery mode
make_keyblock() {
local base=$1
local flags=$2
local pubkey=$3
local signkey=$4
echo "creating $base keyblock..."
# create it
vbutil_keyblock \
--pack "${base}.keyblock" \
--flags $flags \
--datapubkey "${pubkey}.vbpubk" \
--signprivate "${signkey}.vbprivk"
# verify it
vbutil_keyblock \
--unpack "${base}.keyblock" \
--signpubkey "${signkey}.vbpubk"
}
# File to read current versions from.
VERSION_FILE="key.versions"
# ARGS: <VERSION_TYPE> [VERSION_FILE]
get_version() {
local key="$1"
local file="${2:-${VERSION_FILE}}"
awk -F= -vkey="${key}" '$1 == key { print $NF }' "${file}"
}
# Loads the current versions prints them to stdout and sets the global version
# variables: CURR_FIRMKEY_VER CURR_FIRM_VER CURR_KERNKEY_VER CURR_KERN_VER
load_current_versions() {
local key_dir=$1
local VERSION_FILE="${key_dir}/${VERSION_FILE}"
if [[ ! -f ${VERSION_FILE} ]]; then
return 1
fi
CURR_FIRMKEY_VER=$(get_version "firmware_key_version")
# Firmware version is the kernel subkey version.
CURR_FIRM_VER=$(get_version "firmware_version")
# Kernel data key version is the kernel key version.
CURR_KERNKEY_VER=$(get_version "kernel_key_version")
CURR_KERN_VER=$(get_version "kernel_version")
cat <<EOF
Current Firmware key version: ${CURR_FIRMKEY_VER}
Current Firmware version: ${CURR_FIRM_VER}
Current Kernel key version: ${CURR_KERNKEY_VER}
Current Kernel version: ${CURR_KERN_VER}
EOF
}
# Make backups of existing kernel subkeys and keyblocks that will be revved.
# Backup format:
# for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock
# Args: SUBKEY_VERSION DATAKEY_VERSION
backup_existing_kernel_keyblock() {
if [[ ! -e kernel.keyblock ]]; then
return
fi
mv --no-clobber kernel.{keyblock,"v$2.v$1.keyblock"}
}
# Make backups of existing kernel subkeys and keyblocks that will be revved.
# Backup format:
# for keys: <key_name>.v<version>.vb{pub|priv}k
# for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock
# Args: SUBKEY_VERSION DATAKEY_VERSION
backup_existing_kernel_subkeys() {
local subkey_ver=$1
local datakey_ver=$2
# --no-clobber to prevent accidentally overwriting existing
# backups.
mv --no-clobber kernel_subkey.{vbprivk,"v${subkey_ver}.vbprivk"}
mv --no-clobber kernel_subkey.{vbpubk,"v${subkey_ver}.vbpubk"}
backup_existing_kernel_keyblock ${subkey_ver} ${datakey_ver}
}
# Make backups of existing kernel data keys and keyblocks that will be revved.
# Backup format:
# for keys: <key_name>.v<version>.vb{pub|priv}k
# for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock
# Args: SUBKEY_VERSION DATAKEY_VERSION
backup_existing_kernel_data_keys() {
local subkey_ver=$1
local datakey_ver=$2
# --no-clobber to prevent accidentally overwriting existing
# backups.
mv --no-clobber kernel_data_key.{vbprivk,"v${datakey_ver}.vbprivk"}
mv --no-clobber kernel_data_key.{vbpubk,"v${datakey_ver}.vbpubk"}
backup_existing_kernel_keyblock ${subkey_ver} ${datakey_ver}
}
# Make backups of existing firmware keys and keyblocks that will be revved.
# Backup format:
# for keys: <key_name>.v<version>.vb{pub|priv}k
# for keyblocks: <keyblock_name>.v<datakey version>.v<subkey version>.keyblock
# Args: SUBKEY_VERSION DATAKEY_VERSION
backup_existing_firmware_keys() {
local subkey_ver=$1
local datakey_ver=$2
mv --no-clobber firmware_data_key.{vbprivk,"v${subkey_ver}.vbprivk"}
mv --no-clobber firmware_data_key.{vbpubk,"v${subkey_ver}.vbpubk"}
mv --no-clobber firmware.{keyblock,"v${datakey_ver}.v${subkey_ver}.keyblock"}
}
# Write new key version file with the updated key versions.
# Args: FIRMWARE_KEY_VERSION FIRMWARE_VERSION KERNEL_KEY_VERSION
# KERNEL_VERSION
write_updated_version_file() {
local firmware_key_version=$1
local firmware_version=$2
local kernel_key_version=$3
local kernel_version=$4
cat > ${VERSION_FILE} <<EOF
firmware_key_version=${firmware_key_version}
firmware_version=${firmware_version}
kernel_key_version=${kernel_key_version}
kernel_version=${kernel_version}
EOF
}
# Returns the incremented version number of the passed in key from the version
# file. The options are "firmware_key_version", "firmware_version",
# "kernel_key_version", or "kernel_version".
# ARGS: KEY_DIR <key_name>
increment_version() {
local key_dir=$1
local VERSION_FILE="${key_dir}/${VERSION_FILE}"
local old_version=$(get_version $2)
local new_version=$(( ${old_version} + 1 ))
if [[ ${new_version} -gt 0xffff ]]; then
echo "Version overflow!" >&2
return 1
fi
echo ${new_version}
}

View File

@@ -0,0 +1,80 @@
#!/bin/bash
# Copyright 2016 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.
# Load common constants and functions.
. "$(dirname "$0")/common.sh"
usage() {
cat <<EOF
Usage: ${PROG} DIR
Generate Android's 4 framework key pairs at DIR. For detail, please refer to
"Certificates and private keys" and "Manually generating keys" in
https://source.android.com/devices/tech/ota/sign_builds.html.
EOF
if [[ $# -ne 0 ]]; then
die "$*"
else
exit 0
fi
}
# Use the same SUBJECT used in Nexus.
SUBJECT='/C=US/ST=California/L=Mountain View/O=Google Inc./OU=Android/CN=Android'
# Generate .pk8 and .x509.pem at the given directory.
make_pair() {
local dir=$1
local name=$2
# Generate RSA key.
openssl genrsa -3 -out "${dir}/temp.pem" 2048
# Create a certificate with the public part of the key.
openssl req -new -x509 -key "${dir}/temp.pem" -out "${dir}/${name}.x509.pem" \
-days 10000 -subj "${SUBJECT}"
# Create a PKCS#8-formatted version of the private key.
openssl pkcs8 -in "${dir}/temp.pem" -topk8 -outform DER \
-out "${dir}/${name}.pk8" -nocrypt
# Best attempt to securely delete the temp.pem file.
shred --remove "${dir}/temp.pem"
}
main() {
set -e
local dir
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
;;
-*)
usage "Unknown option: $1"
;;
*)
break
;;
esac
done
if [[ $# -ne 1 ]]; then
usage "Missing output directory"
fi
dir=$1
make_pair "${dir}" platform
make_pair "${dir}" shared
make_pair "${dir}" media
make_pair "${dir}" releasekey
}
main "$@"

View File

@@ -0,0 +1,193 @@
#!/bin/bash
# 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.
#
# Generate .vbpubk and .vbprivk pairs for use by developer builds. These should
# be exactly like the real keys except that the private keys aren't secret.
# Load common constants and functions.
. "$(dirname "$0")/common.sh"
usage() {
cat <<EOF
Usage: ${PROG} [options]
Options:
--devkeyblock Also generate developer firmware keyblock and data key
--android Also generate android keys
--uefi Also generate UEFI keys
--4k Use 4k keys instead of 8k (enables options below)
--4k-root Use 4k key size for the root key
--4k-recovery Use 4k key size for the recovery key
--4k-recovery-kernel Use 4k key size for the recovery kernel data
--4k-installer-kernel Use 4k key size for the installer kernel data
--key-name <name> Name of the keyset (for key.versions)
--output <dir> Where to write the keys (default is cwd)
EOF
if [[ $# -ne 0 ]]; then
die "unknown option $*"
else
exit 0
fi
}
main() {
set -e
# Flag to indicate whether we should be generating a developer keyblock flag.
local dev_keyblock="false"
local android_keys="false"
local uefi_keys="false"
local root_key_algoid=${ROOT_KEY_ALGOID}
local recovery_key_algoid=${RECOVERY_KEY_ALGOID}
local recovery_kernel_algoid=${RECOVERY_KERNEL_ALGOID}
local installer_kernel_algoid=${INSTALLER_KERNEL_ALGOID}
local keyname
local output_dir="${PWD}" setperms="false"
while [[ $# -gt 0 ]]; do
case $1 in
--devkeyblock)
echo "Will also generate developer firmware keyblock and data key."
dev_keyblock="true"
;;
--android)
echo "Will also generate Android keys."
android_keys="true"
;;
--uefi)
echo "Will also generate UEFI keys."
uefi_keys="true"
;;
--4k)
root_key_algoid=${RSA4096_SHA512_ALGOID}
recovery_key_algoid=${RSA4096_SHA512_ALGOID}
recovery_kernel_algoid=${RSA4096_SHA512_ALGOID}
installer_kernel_algoid=${RSA4096_SHA512_ALGOID}
;;
--4k-root)
root_key_algoid=${RSA4096_SHA512_ALGOID}
;;
--4k-recovery)
recovery_key_algoid=${RSA4096_SHA512_ALGOID}
;;
--4k-recovery-kernel)
recovery_kernel_algoid=${RSA4096_SHA512_ALGOID}
;;
--4k-installer-kernel)
installer_kernel_algoid=${RSA4096_SHA512_ALGOID}
;;
--key-name)
keyname="$2"
shift
;;
--output)
output_dir="$2"
setperms="true"
if [[ -d "${output_dir}" ]]; then
die "output dir (${output_dir}) already exists"
fi
shift
;;
-h|--help)
usage
;;
*)
usage "$1"
;;
esac
shift
done
mkdir -p "${output_dir}"
cd "${output_dir}"
if [[ "${setperms}" == "true" ]]; then
chmod 700 .
fi
if [[ ! -e "${VERSION_FILE}" ]]; then
echo "No version file found. Creating default ${VERSION_FILE}."
(
if [[ -n "${keyname}" ]]; then
echo "name=${keyname}"
fi
printf '%s_version=1\n' {firmware,kernel}{_key,}
) > "${VERSION_FILE}"
fi
local eckey_version fkey_version ksubkey_version kdatakey_version
# Get the key versions for normal keypairs
eckey_version=$(get_version "ec_key_version")
fkey_version=$(get_version "firmware_key_version")
# Firmware version is the kernel subkey version.
ksubkey_version=$(get_version "firmware_version")
# Kernel data key version is the kernel key version.
kdatakey_version=$(get_version "kernel_key_version")
# Create the normal keypairs
make_pair ec_root_key ${EC_ROOT_KEY_ALGOID}
make_pair ec_data_key ${EC_DATAKEY_ALGOID} ${eckey_version}
make_pair root_key ${root_key_algoid}
make_pair firmware_data_key ${FIRMWARE_DATAKEY_ALGOID} ${fkey_version}
if [[ "${dev_keyblock}" == "true" ]]; then
make_pair dev_firmware_data_key ${DEV_FIRMWARE_DATAKEY_ALGOID} ${fkey_version}
fi
make_pair kernel_subkey ${KERNEL_SUBKEY_ALGOID} ${ksubkey_version}
make_pair kernel_data_key ${KERNEL_DATAKEY_ALGOID} ${kdatakey_version}
# Create the recovery and factory installer keypairs
make_pair recovery_key ${recovery_key_algoid}
make_pair recovery_kernel_data_key ${recovery_kernel_algoid}
make_pair installer_kernel_data_key ${installer_kernel_algoid}
# Create the firmware keyblock for use only in Normal mode. This is redundant,
# since it's never even checked during Recovery mode.
make_keyblock firmware ${FIRMWARE_KEYBLOCK_MODE} firmware_data_key root_key
# Ditto EC keyblock
make_keyblock ec ${EC_KEYBLOCK_MODE} ec_data_key ec_root_key
if [[ "${dev_keyblock}" == "true" ]]; then
# Create the dev firmware keyblock for use only in Developer mode.
make_keyblock dev_firmware ${DEV_FIRMWARE_KEYBLOCK_MODE} dev_firmware_data_key root_key
fi
# Create the recovery kernel keyblock for use only in Recovery mode.
make_keyblock recovery_kernel ${RECOVERY_KERNEL_KEYBLOCK_MODE} recovery_kernel_data_key recovery_key
# Create the normal kernel keyblock for use only in Normal mode.
make_keyblock kernel ${KERNEL_KEYBLOCK_MODE} kernel_data_key kernel_subkey
# Create the installer keyblock for use in Developer + Recovery mode
# For use in Factory Install and Developer Mode install shims.
make_keyblock installer_kernel ${INSTALLER_KERNEL_KEYBLOCK_MODE} installer_kernel_data_key recovery_key
if [[ "${android_keys}" == "true" ]]; then
mkdir android
"${SCRIPT_DIR}"/create_new_android_keys.sh android
fi
if [[ "${uefi_keys}" == "true" ]]; then
mkdir -p uefi
"${SCRIPT_DIR}"/uefi/create_new_uefi_keys.sh --output uefi
fi
if [[ "${setperms}" == "true" ]]; then
find -type f -exec chmod 400 {} +
find -type d -exec chmod 500 {} +
fi
# CAUTION: The public parts of most of these blobs must be compiled into the
# firmware, which is built separately (and some of which can't be changed after
# manufacturing). If you update these keys, you must coordinate the changes
# with the BIOS people or you'll be unable to boot the resulting images.
}
main "$@"

View File

@@ -0,0 +1,45 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Script to increment firmware version key for firmware updates.
# Used when revving versions for a firmware update.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Increments the firmware version in the specified keyset.
EOF
exit 1
fi
KEY_DIR=$1
main() {
load_current_versions "${KEY_DIR}"
new_firmkey_ver=$(increment_version "${KEY_DIR}" "firmware_key_version")
cd "${KEY_DIR}"
backup_existing_firmware_keys ${CURR_FIRM_VER} ${CURR_FIRMKEY_VER}
cat <<EOF
Generating new firmware version key.
New Firmware key version (due to firmware key change): ${new_firmkey_ver}.
EOF
make_pair firmware_data_key ${FIRMWARE_DATAKEY_ALGOID} ${new_firmkey_ver}
make_keyblock firmware ${FIRMWARE_KEYBLOCK_MODE} firmware_data_key root_key
write_updated_version_file ${new_firmkey_ver} ${CURR_FIRM_VER} \
${CURR_KERNKEY_VER} ${CURR_KERN_VER}
}
main "$@"

View File

@@ -0,0 +1,45 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Script to increment kernel data key for firmware updates.
# Used when revving versions for a firmware update.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Increments the kernel data key in the specified keyset.
EOF
exit 1
fi
KEY_DIR=$1
main() {
load_current_versions "${KEY_DIR}"
new_kernkey_ver=$(increment_version "${KEY_DIR}" "kernel_key_version")
cd "${KEY_DIR}"
backup_existing_kernel_data_keys ${CURR_FIRM_VER} ${CURR_KERNKEY_VER}
cat <<EOF
Generating new kernel data version, and new kernel keyblock.
New Kernel data key version: ${new_kernkey_ver}.
EOF
make_pair kernel_data_key ${KERNEL_DATAKEY_ALGOID} ${new_kernkey_ver}
make_keyblock kernel ${KERNEL_KEYBLOCK_MODE} kernel_data_key kernel_subkey
write_updated_version_file ${CURR_FIRMKEY_VER} ${CURR_FIRM_VER} \
${new_kernkey_ver} ${CURR_KERN_VER}
}
main "$@"

View File

@@ -0,0 +1,45 @@
#!/bin/bash
# Copyright (c) 2012 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.
# Script to increment kernel subkey for firmware updates.
# Used when revving versions for a firmware update.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Increments the kernel subkey in the specified keyset.
EOF
exit 1
fi
KEY_DIR=$1
main() {
load_current_versions "${KEY_DIR}"
new_firm_ver=$(increment_version "${KEY_DIR}" "firmware_version")
cd "${KEY_DIR}"
backup_existing_kernel_subkeys ${CURR_FIRM_VER} ${CURR_KERNKEY_VER}
cat <<EOF
Generating new kernel subkey and new kernel keyblock.
New Firmware version (due to kernel subkey change): ${new_firm_ver}.
EOF
make_pair kernel_subkey ${KERNEL_SUBKEY_ALGOID} ${new_firm_ver}
make_keyblock kernel $KERNEL_KEYBLOCK_MODE kernel_data_key kernel_subkey
write_updated_version_file ${CURR_FIRMKEY_VER} ${new_firm_ver} \
${CURR_KERNKEY_VER} ${CURR_KERN_VER}
}
main "$@"

View File

@@ -0,0 +1,50 @@
#!/bin/bash
# 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.
# Script to increment kernel subkey and datakey for firmware updates.
# Used when revving versions for a firmware update.
# Load common constants and variables.
. "${0%/*}"/common.sh
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Increments the kernel subkey, data key and firmware version in the
specified keyset.
EOF
exit 1
fi
KEY_DIR=$1
main() {
load_current_versions "${KEY_DIR}"
new_kernkey_ver=$(increment_version "${KEY_DIR}" "kernel_key_version")
new_firm_ver=$(increment_version "${KEY_DIR}" "firmware_version")
cd "${KEY_DIR}"
backup_existing_kernel_subkeys ${CURR_FIRM_VER} ${CURR_KERNKEY_VER}
backup_existing_kernel_data_keys ${CURR_FIRM_VER} ${CURR_KERNKEY_VER}
cat <<EOF
Generating new kernel subkey, data keys and new kernel keyblock.
New Firmware version (due to kernel subkey change): ${new_firm_ver}.
New Kernel key version (due to kernel datakey change): ${new_kernkey_ver}.
EOF
make_pair kernel_subkey ${KERNEL_SUBKEY_ALGOID} ${new_firm_ver}
make_pair kernel_data_key ${KERNEL_DATAKEY_ALGOID} ${new_kernkey_ver}
make_keyblock kernel ${KERNEL_KEYBLOCK_MODE} kernel_data_key kernel_subkey
write_updated_version_file ${CURR_FIRMKEY_VER} ${new_firm_ver} \
${new_kernkey_ver} ${CURR_KERN_VER}
}
main "$@"

View File

@@ -0,0 +1,118 @@
#!/bin/bash
# Copyright 2014 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.
# Script that sanity checks a keyset to ensure actual key versions
# match those set in key.versions.
# Load common constants and variables.
. "$(dirname "$0")/common.sh"
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Sanity check a keyset directory for key versions.
EOF
exit 1
fi
KEY_DIR="$1"
VERSION_FILE="${KEY_DIR}/key.versions"
keyblock_version() {
local keyblock="$1"
echo "$(vbutil_keyblock --unpack "${keyblock}" | grep 'Data key version' |
cut -f 2 -d : | tr -d ' ')"
}
key_version() {
local key="$1"
echo "$(vbutil_key --unpack "${key}" | grep 'Key Version' | cut -f 2 -d : |
tr -d ' ')"
}
# Compare versions and print out error if there is a mismatch.
check_versions() {
local expected="$1"
local got="$2"
local expected_label="$3"
local got_label="$4"
if [[ ${expected} != ${got} ]]; then
echo "ERROR: ${expected_label} version does not match ${got_label} version"
echo "EXPECTED (${expected_label} version): ${expected}"
echo "GOT (${got_label} version): ${got}"
return 1
fi
return 0
}
# Check the key.versions against firmware.keyblock and firmware_data_key.vbpubk.
check_firmware_keyblock() {
local fkey_keyblock="$1" fkey="$2"
local got_fkey_keyblock="$(keyblock_version "${fkey_keyblock}")"
local got_fkey="$(key_version "${fkey}")"
check_versions "${got_fkey_keyblock}" "${got_fkey}" \
"${fkey_keyblock##*/} keyblock key" "firmware key" || testfail=1
check_versions "${expected_fkey}" "${got_fkey}" "${fkey##*/} key" \
"firmware key" || testfail=1
}
# Validate the firmware keys in an loem keyset.
check_loem_keyset() {
local line loem_index
while read line; do
loem_index=$(cut -d= -f1 <<<"${line}" | sed 's: *$::')
check_firmware_keyblock \
"${KEY_DIR}/firmware.loem${loem_index}.keyblock" \
"${KEY_DIR}/firmware_data_key.loem${loem_index}.vbpubk"
done < <(grep = "${KEY_DIR}"/loem.ini)
}
# Validate the firmware keys in a non-loem keyset.
check_non_loem_keyset() {
check_firmware_keyblock \
"${KEY_DIR}/firmware.keyblock" \
"${KEY_DIR}/firmware_data_key.vbpubk"
}
main() {
local testfail=0
local expected_kkey="$(get_version kernel_key_version)"
local expected_fkey="$(get_version firmware_key_version)"
local expected_firmware="$(get_version firmware_version)"
local expected_kernel="$(get_version kernel_version)"
check_versions "${expected_firmware}" "${expected_kkey}" \
"firmware" "kernel key" || testfail=1
local got_kkey_keyblock="$(keyblock_version ${KEY_DIR}/kernel.keyblock)"
local got_ksubkey="$(key_version ${KEY_DIR}/kernel_subkey.vbpubk)"
local got_kdatakey="$(key_version ${KEY_DIR}/kernel_data_key.vbpubk)"
if [[ -f "${KEY_DIR}"/loem.ini ]]; then
check_loem_keyset
else
check_non_loem_keyset
fi
check_versions "${got_kkey_keyblock}" "${got_ksubkey}" "kernel keyblock key" \
"kernel subkey" || testfail=1
check_versions "${got_kdatakey}" "${got_ksubkey}" "kernel data key" \
"kernel subkey" || testfail=1
check_versions "${expected_kkey}" "${got_kdatakey}" "key.versions kernel key" \
"kernel datakey" || testfail=1
check_versions "${expected_kkey}" "${got_ksubkey}" "key.versions kernel key" \
"kernel subkey" || testfail=1
exit ${testfail}
}
main "$@"

View File

@@ -0,0 +1,27 @@
#!/bin/bash
# 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.
#
# Generates a keyblock containing a public key and signed using the given
# signing key.
# Load common constants and functions.
. "$(dirname "$0")/common.sh"
if [ $# -ne 4 ]; then
cat <<EOF
Usage: $0 <in_public_key> <in_signing_key> <flags> <out_keyblock>
Emits <out_keyblock>.keyblock containing <in_public_key>.vbpubk signed with
<in_signing_key>.vbprivk with the given keyblock <flags>.
EOF
exit 1
fi
in_pubkey=$1
in_signkey=$2
keyblock_flags=$3
out_keyblock=$4
make_keyblock $out_keyblock $keyblock_flags $in_pubkey $in_signkey

View File

@@ -0,0 +1,23 @@
#!/bin/bash
# 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.
#
# Generate .vbpubk and .vbprivk pairs with the given algorithm id.
# Load common constants and functions.
. "$(dirname "$0")/common.sh"
if [ $# -ne 2 ]; then
cat <<EOF
Usage: $0 <algoid> <out_keypair>
Output: <out_keypair>.vbprivk and <out_keypair>.vbpubk
EOF
exit 1
fi
algoid=$1
out_keypair=$2
make_pair $out_keypair $algoid

View File

@@ -0,0 +1,80 @@
#!/bin/bash
# Copyright 2018 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.
# Load common constants and functions.
. "$(dirname "$0")/uefi_common.sh"
usage() {
cat <<EOF
Usage: ${PROG} [options]
Generate key pairs for UEFI secure boot.
Options:
--output <dir> Where to write the keys (default is cwd).
The base name must be '.../uefi'.
--no-pk Do not generate PK.
EOF
if [[ $# -ne 0 ]]; then
die "unknown option $*"
else
exit 0
fi
}
main() {
set -e
local generate_pk="true"
local output_dir="${PWD}"
while [[ $# -gt 0 ]]; do
case $1 in
--output)
output_dir="$2"
shift
;;
--no-pk)
info "Will not generate PK."
generate_pk="false"
;;
-h|--help)
usage
;;
*)
usage "Unknown option: $1"
;;
esac
shift
done
check_uefi_key_dir_name "${output_dir}"
pushd "${output_dir}" >/dev/null || die "Wrong output directory name"
if [[ ! -e "${UEFI_VERSION_FILE}" ]]; then
echo "No version file found. Creating default ${UEFI_VERSION_FILE}."
printf '%s_key_version=1\n' {pk,kek,db,db_child} > "${UEFI_VERSION_FILE}"
fi
local pk_key_version kek_key_version db_key_version db_child_key_version
# Get the key versions for normal keypairs
pk_key_version=$(get_uefi_version "pk_key_version")
kek_key_version=$(get_uefi_version "kek_key_version")
db_key_version=$(get_uefi_version "db_key_version")
db_child_key_version=$(get_uefi_version "db_child_key_version")
if [[ "${generate_pk}" == "true" ]]; then
make_pk_keypair "${pk_key_version}"
fi
make_kek_keypair "${kek_key_version}"
make_db_keypair "${db_key_version}"
make_db_child_keypair "${db_key_version}" "${db_child_key_version}"
popd >/dev/null
}
main "$@"

View File

@@ -0,0 +1,45 @@
#!/bin/bash
# Copyright 2018 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.
# Script to increment UEFI DB child key.
# Load common constants and variables.
. "$(dirname "$0")/uefi_common.sh"
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Increments the UEFI DB child key in the specified keyset.
EOF
exit 1
fi
KEY_DIR="$1"
main() {
check_uefi_key_dir_name "${KEY_DIR}"
load_current_uefi_key_versions "${KEY_DIR}"
new_db_child_key_ver=$(increment_uefi_version "${KEY_DIR}" \
"db_child_key_version")
cd "${KEY_DIR}"
backup_db_child_keypair "${CURR_DB_CHILD_KEY_VER}"
cat <<EOF
Generating new UEFI DB child key version.
New DB child key version: ${new_db_child_key_ver}.
EOF
make_db_child_keypair "${CURR_DB_KEY_VER}" "${new_db_child_key_ver}"
write_updated_uefi_version_file "${CURR_PK_KEY_VER}" "${CURR_KEK_KEY_VER}" \
"${CURR_DB_KEY_VER}" "${new_db_child_key_ver}"
}
main "$@"

View File

@@ -0,0 +1,46 @@
#!/bin/bash
# Copyright 2018 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.
# Script to increment UEFI DB key.
# Load common constants and variables.
. "$(dirname "$0")/uefi_common.sh"
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Increments the UEFI DB key in the specified keyset.
EOF
exit 1
fi
KEY_DIR="$1"
main() {
check_uefi_key_dir_name "${KEY_DIR}"
load_current_uefi_key_versions "${KEY_DIR}"
new_db_key_ver=$(increment_uefi_version "${KEY_DIR}" "db_key_version")
new_db_child_key_ver=1
cd "${KEY_DIR}"
backup_db_keypair_and_children "${CURR_DB_KEY_VER}"
cat <<EOF
Generating new UEFI DB key version.
New DB key version: ${new_db_key_ver}.
EOF
make_db_keypair "${new_db_key_ver}"
make_db_child_keypair "${new_db_key_ver}" "${new_db_child_key_ver}"
write_updated_uefi_version_file "${CURR_PK_KEY_VER}" "${CURR_KEK_KEY_VER}" \
"${new_db_key_ver}" "${new_db_child_key_ver}"
}
main "$@"

View File

@@ -0,0 +1,44 @@
#!/bin/bash
# Copyright 2018 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.
# Script to increment UEFI Key Exchange Key (KEK).
# Load common constants and variables.
. "$(dirname "$0")/uefi_common.sh"
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Increments the UEFI Key Exchange Key (KEK) in the specified keyset.
EOF
exit 1
fi
KEY_DIR="$1"
main() {
check_uefi_key_dir_name "${KEY_DIR}"
load_current_uefi_key_versions "${KEY_DIR}"
new_kek_key_ver=$(increment_uefi_version "${KEY_DIR}" "kek_key_version")
cd "${KEY_DIR}"
backup_kek_keypair "${CURR_KEK_KEY_VER}"
cat <<EOF
Generating new UEFI Key Exchange Key (KEK) version.
New Key Exchange Key version: ${new_kek_key_ver}.
EOF
make_kek_keypair "${new_kek_key_ver}"
write_updated_uefi_version_file "${CURR_PK_KEY_VER}" "${new_kek_key_ver}" \
"${CURR_DB_KEY_VER}" "${CURR_DB_CHILD_KEY_VER}"
}
main "$@"

View File

@@ -0,0 +1,44 @@
#!/bin/bash
# Copyright 2018 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.
# Script to increment UEFI Platform Key (PK).
# Load common constants and variables.
. "$(dirname "$0")/uefi_common.sh"
# Abort on errors.
set -e
if [ $# -ne 1 ]; then
cat <<EOF
Usage: $0 <keyset directory>
Increments the UEFI Platform Key (PK) in the specified keyset.
EOF
exit 1
fi
KEY_DIR="$1"
main() {
check_uefi_key_dir_name "${KEY_DIR}"
load_current_uefi_key_versions "${KEY_DIR}"
new_pk_key_ver=$(increment_uefi_version "${KEY_DIR}" "pk_key_version")
cd "${KEY_DIR}"
backup_pk_keypair "${CURR_PK_KEY_VER}"
cat <<EOF
Generating new UEFI Platform Key (PK) version.
New Platform Key version: ${new_pk_key_ver}.
EOF
make_pk_keypair "${new_pk_key_ver}"
write_updated_uefi_version_file "${new_pk_key_ver}" "${CURR_KEK_KEY_VER}" \
"${CURR_DB_KEY_VER}" "${CURR_DB_CHILD_KEY_VER}"
}
main "$@"

View File

@@ -0,0 +1,253 @@
#!/bin/bash
# Copyright 2018 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.
# Common UEFI key generation functions.
. "$(dirname "$0")/../common.sh"
# Checks whether the given key directory name is "uefi".
# Dies if it isn't.
# ARGS: KEY_DIR
check_uefi_key_dir_name() {
local key_dir="$1"
local key_dir_fullpath="$(readlink -f "${key_dir}")"
local key_dir_basename="$(basename "${key_dir_fullpath}")"
if [[ "${key_dir_basename}" != "uefi" ]]; then
die "Key directory base name is not \"uefi\""
fi
}
# File to read current versions from.
UEFI_VERSION_FILE="uefi_key.versions"
# Prints the version value for the given VERSION_TYPE, from UEFI_VERSION_FILE.
# ARGS: <VERSION_TYPE> [UEFI_VERSION_FILE]
get_uefi_version() {
local key="$1"
local file="${2:-${UEFI_VERSION_FILE}}"
awk -F= -vkey="${key}" '$1 == key { print $NF }' "${file}"
}
# Loads the current versions, prints them to stdout, and sets the global version
# variables: CURR_PK_KEY_VER CURR_KEK_KEY_VER CURR_DB_KEY_VER
# CURR_DB_CHILD_KEY_VER
# ARGS: KEY_DIR
load_current_uefi_key_versions() {
local key_dir="$1"
local UEFI_VERSION_FILE="${key_dir}/${UEFI_VERSION_FILE}"
if [[ ! -f "${UEFI_VERSION_FILE}" ]]; then
return 1
fi
CURR_PK_KEY_VER=$(get_uefi_version "pk_key_version")
CURR_KEK_KEY_VER=$(get_uefi_version "kek_key_version")
CURR_DB_KEY_VER=$(get_uefi_version "db_key_version")
CURR_DB_CHILD_KEY_VER=$(get_uefi_version "db_child_key_version")
cat <<EOF
Current UEFI Platform Key (PK) version: ${CURR_PK_KEY_VER}
Current UEFI Key Exchange Key (KEK) version: ${CURR_KEK_KEY_VER}
Current UEFI DB key version: ${CURR_DB_KEY_VER}
Current UEFI DB child key version: ${CURR_DB_CHILD_KEY_VER}
EOF
}
# The common part for the subject of a UEFI key.
_CHROMIUM_OS_SUBJECT=\
'/C=US/ST=California/L=Mountain View/O=Google LLC./OU=Chromium OS'
# Prints a UEFI key subject.
# ARGS: TITLE VERSION
_get_subj() {
local title="$1"
local version="$2"
echo "${_CHROMIUM_OS_SUBJECT}/CN=${title} v${version}"
}
# Generates a pair of a private key and a self-signed cert at the current
# directory. Generated files are
# $1/$1.rsa: The private key
# $1/$1.pem: The self-signed cert in PEM format
# ARGS: KEY_NAME SUBJECT
_make_self_signed_pair() {
local key_name="$1"
local subj="$2"
mkdir -p "${key_name}"
pushd "${key_name}" >/dev/null || return 1
openssl req -new -x509 -nodes -newkey rsa:2048 -sha256 \
-keyout "${key_name}.rsa" -out "${key_name}.pem" \
-subj "${subj}" -days 3650
popd >/dev/null
}
# Generates a pair of a private key and a cert signed by the given CA.
# "$1" (the first argument) is the CA file name without extension.
# The results are signed by "$1/$1.{rsa,pem}", and are generated in
# "$1/$1.children" directory under the current directory. Generated files are
# $1/$1.children/$2.rsa: The private key
# $1/$1.children/$2.csr: The Certificate Signing Request
# $1/$1.children/$2.pem: The certificate signed by "$1.{rsa,pem}"
# ARGS: CA_NAME CHILD_KEY_NAME SUBJECT
_make_child_pair() {
local ca_name="$1" # Base filename without extension.
local child_key_name="$2"
local subj="$3"
mkdir -p "${ca_name}/${ca_name}.children"
pushd "${ca_name}/${ca_name}.children" >/dev/null || return 1
openssl req -new -nodes -newkey rsa:2048 -sha256 \
-keyout "${child_key_name}.rsa" -out "${child_key_name}.csr" \
-subj "${subj}"
openssl x509 -req -sha256 -CA "../${ca_name}.pem" -CAkey "../${ca_name}.rsa" \
-CAcreateserial -in "${child_key_name}.csr" \
-out "${child_key_name}.pem" -days 3650
popd >/dev/null
}
# Makes a PK (Platform Key) keypair.
# Generated files are
# pk/pk.rsa: The private key
# pk/pk.pem: The self-signed cert in PEM format
# ARGS: VERSION
make_pk_keypair() {
local version="$1"
_make_self_signed_pair pk \
"$(_get_subj "UEFI Platform Key" "${version}")"
}
# Makes a KEK (Key Exchange Key) keypair.
# Generated files are
# kek/kek.rsa: The private key
# kek/kek.pem: The self-signed cert in PEM format
# ARGS: VERSION
make_kek_keypair() {
local version="$1"
_make_self_signed_pair kek \
"$(_get_subj "UEFI Key Exchange Key" "${version}")"
}
# Makes a DB keypair.
# Generated files are
# db/db.rsa: The private key
# db/db.pem: The self-signed cert in PEM format
# ARGS: VERSION
make_db_keypair() {
local version="$1"
_make_self_signed_pair db \
"$(_get_subj "UEFI DB Key" "${version}")"
}
# Makes a DB child keypair (a keypair signed by the db key).
# Generated files are
# db/db.children/db_child.rsa: The private key
# db/db.children/db_child.csr: The Certificate Signing Request
# db/db.children/db_child.pem: The certificate signed by "db/db.{rsa,pem}"
# ARGS: DB_KEY_VERSION CHILD_KEY_VERSION
make_db_child_keypair() {
local db_key_version="$1"
local child_key_version="$2"
_make_child_pair db db_child \
"$(_get_subj "UEFI DB Child Key" \
"${db_key_version}.${child_key_version}")"
}
# Makes a backup of a self-signed keypair.
# ARGS: KEY_NAME VERSION
_backup_self_signed_pair() {
local key_name="$1"
local version="$2"
pushd "${key_name}" >/dev/null || return 1
mv --no-clobber "${key_name}".{rsa,"v${version}.rsa"}
mv --no-clobber "${key_name}".{pem,"v${version}.pem"}
popd >/dev/null
}
# Makes a backup of a self-signed keypair and its child keys.
# ARGS: KEY_NAME VERSION
_backup_self_signed_pair_and_children() {
local key_name="$1"
local version="$2"
_backup_self_signed_pair "${key_name}" "${version}"
pushd "${key_name}" >/dev/null || return 1
mv --no-clobber "${key_name}".{children,"v${version}.children"}
popd >/dev/null
}
# Makes a backup of a child keypair signed by a CA.
# ARGS: CA_NAME CHILD_KEY_NAME CHILD_KEY_VERSION
_backup_child_pair() {
local ca_name="$1"
local child_key_name="$2"
local child_key_version="$3"
pushd "${ca_name}/${ca_name}.children" >/dev/null || return 1
mv --no-clobber "${child_key_name}".{rsa,"v${child_key_version}.rsa"}
mv --no-clobber "${child_key_name}".{csr,"v${child_key_version}.csr"}
mv --no-clobber "${child_key_name}".{pem,"v${child_key_version}.pem"}
popd >/dev/null
}
# Makes a backup of the PK (Platform Key) keypair.
# Backup format: pk.v<pk key version>.{rsa,pem}
# ARGS: PK_KEY_VERSION
backup_pk_keypair() {
local pk_key_version="$1"
_backup_self_signed_pair pk "${pk_key_version}"
}
# Makes a backup of the KEK (Key Exchange Key) keypair.
# Backup format: kek.v<kek key version>.{rsa,pem}
# ARGS: KEK_KEY_VERSION
backup_kek_keypair() {
local kek_key_version="$1"
_backup_self_signed_pair kek "${kek_key_version}"
}
# Makes a backup of the DB keypair and its children.
# Backup format:
# for db keypair: db.v<db key version>.{rsa,pem}
# for child keypair: db.v<db key version>.childern/child*.{rsa,csr,pem}
# ARGS: DB_KEY_VERSION
backup_db_keypair_and_children() {
local db_key_version="$1"
_backup_self_signed_pair_and_children db "${db_key_version}"
}
# Makes a backup of the DB child keypair.
# Backup format: db.children/child.v<db child key version>.{rsa,csr,pem}
# ARGS: DB_CHILD_KEY_VERSION
backup_db_child_keypair() {
local db_child_key_version="$1"
_backup_child_pair db db_child "${db_child_key_version}"
}
# Writes new key version file with the updated key versions.
# Args: PK_KEY_VERSION KEK_KEY_VERSION DB_KEY_VERSION DB_CHILD_KEY_VERSION
write_updated_uefi_version_file() {
local pk_key_version="$1"
local kek_key_version="$2"
local db_key_version="$3"
local db_child_key_version="$4"
cat > "${UEFI_VERSION_FILE}" <<EOF
pk_key_version=${pk_key_version}
kek_key_version=${kek_key_version}
db_key_version=${db_key_version}
db_child_key_version=${db_child_key_version}
EOF
}
# Returns the incremented version number of the passed in key from the version
# file. The options are "pk_key_version", "kek_key_version", "db_key_version",
# or "db_child_key_version".
# ARGS: KEY_DIR <key_name>
increment_uefi_version() {
local key_dir="$1"
local UEFI_VERSION_FILE="${key_dir}/${UEFI_VERSION_FILE}"
local old_version=$(get_uefi_version "$2")
local new_version=$(( old_version + 1 ))
echo "${new_version}"
}

View File

@@ -0,0 +1,2 @@
Firmware bitmaps genereation is now moved to ~/trunk/src/platform/bmpblk.