137522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah#!/bin/bash
237522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
39137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
437522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah# Use of this source code is governed by a BSD-style license that can be
537522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah# found in the LICENSE file.
637522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
737522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah# Sign the final build image using the "official" keys.
80c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah#
90c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah# Prerequisite tools needed in the system path:
100c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah#
110c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah#  gbb_utility (from src/platform/vboot_reference)
120c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah#  vbutil_kernel (from src/platform/vboot_reference)
130c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah#  cgpt (from src/platform/vboot_reference)
140c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah#  dump_kernel_config (from src/platform/vboot_reference)
150c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah#  verity (from src/platform/verity)
161cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah#  load_kernel_test (from src/platform/vboot_reference)
171a2e6fc765a13b636d3dd75dc7cae709e9e8d218Gaurav Shah#  dumpe2fs
18d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah#  sha1sum
1937522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
2037522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah# Load common constants and variables.
2137522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah. "$(dirname "$0")/common.sh"
2237522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
231cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah# Print usage string
241cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shahusage() {
2537522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah  cat <<EOF
268ae7b0e41a1252f98e6662a298efb97624431c44Gaurav ShahUsage: $PROG <type> input_image /path/to/keys/dir [output_image] [version_file]
2737522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shahwhere <type> is one of:
2837522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah             ssd  (sign an SSD image)
291cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah             recovery (sign a USB recovery image)
3022bd8b0c29b485ccdaa4f63e6fdac9f097b60aabMike Frysinger             factory (sign a factory install image)
3122bd8b0c29b485ccdaa4f63e6fdac9f097b60aabMike Frysinger             install (old alias to "factory")
32283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger             update_payload (sign a delta update hash)
339c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah             firmware (sign a firmware image)
3464bd77e1d8b16f6f182184092114a0d8779bdf52Bill Richardson             usb  (sign an image to boot directly from USB)
351cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah             verify (verify an image including rootfs hashes)
361cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
378ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shahoutput_image: File name of the signed output image
388ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shahversion_file: File name of where to read the kernel and firmware versions.
398ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah
408ae7b0e41a1252f98e6662a298efb97624431c44Gaurav ShahIf you are signing an image, you must specify an [output_image] and
418ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shahoptionally, a [version_file].
428ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah
4337522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav ShahEOF
44b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  if [[ $# -gt 0 ]]; then
45b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    error "$*"
46b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    exit 1
47b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  fi
48b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  exit 0
491cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah}
501cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
51b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger# Verify we have as many arguments as we expect, else show usage & quit.
52b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger# Usage:
53b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger#  check_argc <number args> <exact number>
54b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger#  check_argc <number args> <lower bound> <upper bound>
55b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysingercheck_argc() {
56b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  case $# in
57b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  2)
58b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    if [[ $1 -ne $2 ]]; then
59b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger      usage "command takes exactly $2 args"
60b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    fi
61b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    ;;
62b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  3)
63b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    if [[ $1 -lt $2 || $1 -gt $3 ]]; then
64b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger      usage "command takes $2 to $3 args"
65b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    fi
66b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    ;;
67b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  *)
68b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    die "check_argc: incorrect number of arguments"
69b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  esac
70b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger}
7137522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
7237522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah# Abort on errors.
7337522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shahset -e
7437522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
759dc90d36f8f2e2029adbfece0831c1a840e899caGaurav Shah# Add to the path since some tools reside here and may not be in the non-root
769dc90d36f8f2e2029adbfece0831c1a840e899caGaurav Shah# system path.
779dc90d36f8f2e2029adbfece0831c1a840e899caGaurav ShahPATH=$PATH:/usr/sbin:/sbin
789dc90d36f8f2e2029adbfece0831c1a840e899caGaurav Shah
790500524edda44c770690bb942e916522f1eca5cdGaurav Shah# Make sure the tools we need are available.
801cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shahfor prereqs in gbb_utility vbutil_kernel cgpt dump_kernel_config verity \
81ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  load_kernel_test dumpe2fs sha1sum e2fsck; do
820500524edda44c770690bb942e916522f1eca5cdGaurav Shah  type -P "${prereqs}" &>/dev/null || \
830500524edda44c770690bb942e916522f1eca5cdGaurav Shah    { echo "${prereqs} tool not found."; exit 1; }
840500524edda44c770690bb942e916522f1eca5cdGaurav Shahdone
850500524edda44c770690bb942e916522f1eca5cdGaurav Shah
8637522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav ShahTYPE=$1
8737522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav ShahINPUT_IMAGE=$2
8837522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav ShahKEY_DIR=$3
8937522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav ShahOUTPUT_IMAGE=$4
908ae7b0e41a1252f98e6662a298efb97624431c44Gaurav ShahVERSION_FILE=$5
918ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah
928ae7b0e41a1252f98e6662a298efb97624431c44Gaurav ShahFIRMWARE_VERSION=1
938ae7b0e41a1252f98e6662a298efb97624431c44Gaurav ShahKERNEL_VERSION=1
9437522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
951cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah# Get current rootfs hash and kernel command line
96d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah# ARGS: IMAGE KERNELPART
971cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shahgrab_kernel_config() {
981cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local image=$1
99d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah  local kernelpart=$2  # Kernel partition number to grab.
1001cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  # Grab the existing kernel partition and get the kernel config.
1010c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  temp_kimage=$(make_temp_file)
102d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah  extract_image_partition ${image} ${kernelpart} ${temp_kimage}
1031cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  dump_kernel_config ${temp_kimage}
1041cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah}
1051cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
10669b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah# TODO(gauravsh): These are duplicated from chromeos-setimage. We need
10769b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah# to move all signing and rootfs code to one single place where it can be
10869b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah# reused. crosbug.com/19543
10969b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah
11069b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah# get_verity_arg <commandline> <key> -> <value>
11169b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shahget_verity_arg() {
112132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah  echo "$1" | sed -n "s/.*\b$2=\([^ \"]*\).*/\1/p"
11369b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah}
11469b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah
11569b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shahis_old_verity_argv() {
11669b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  local depth=$(echo "$1" | cut -f7 -d' ')
11769b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  if [ "$depth" = "0" ]; then
11869b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah    return 0
11969b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  fi
12069b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  return 1
12169b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah}
12269b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah
123ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah# Get the dmparams parameters from a kernel config.
124ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shahget_dmparams_from_config() {
125ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  local kernel_config=$1
12696d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  echo ${kernel_config} | sed -nre 's/.*dm="([^"]*)".*/\1/p'
127ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah}
128c0911e27b93eae772088ed09d7a41561b7a5b0b6Gaurav Shah# Get the verity root digest hash from a kernel config command line.
129c0911e27b93eae772088ed09d7a41561b7a5b0b6Gaurav Shahget_hash_from_config() {
130c0911e27b93eae772088ed09d7a41561b7a5b0b6Gaurav Shah  local kernel_config=$1
131ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  local dm_config=$(get_dmparams_from_config "${kernel_config}")
132c8c8dfd90992808a91ce85110218cf1f78fd7f92Paul Taysom  local vroot_dev=$(get_dm_slave "${dm_config}" vroot)
13396d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  if is_old_verity_argv "${vroot_dev}"; then
13496d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    echo ${vroot_dev} | cut -f9 -d ' '
135c0911e27b93eae772088ed09d7a41561b7a5b0b6Gaurav Shah  else
13696d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    echo $(get_verity_arg "${vroot_dev}" root_hexdigest)
137c0911e27b93eae772088ed09d7a41561b7a5b0b6Gaurav Shah  fi
138c0911e27b93eae772088ed09d7a41561b7a5b0b6Gaurav Shah}
139c0911e27b93eae772088ed09d7a41561b7a5b0b6Gaurav Shah
14096d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom# Get the slave device and its args
14196d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom# get_dm_ags $dm_config [vboot|vroot]
14296d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom# Assumes we have only one slave device per device
14396d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysomget_dm_slave() {
14496d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  local dm=$1
14596d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  local device=$2
14696d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  echo $(echo "${dm}" | sed -nre "s/.*${device}[^,]*,([^,]*).*/\1/p")
14796d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom}
14896d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom
14996d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom# Set the slave device and its args for a device
15096d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom# get_dm_ags $dm_config [vboot|vroot] args
15196d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom# Assumes we have only one slave device per device
15296d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysomset_dm_slave() {
15396d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  local dm=$1
15496d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  local device=$2
15596d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  local slave=$3
15696d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  echo $(echo "${dm}" |
157f5c62bd7dc1ef3d76d6e5f9119ad73ec95a926d7Paul Taysom    sed -nre "s#(.*${device}[^,]*,)([^,]*)(.*)#\1${slave}\3#p")
15896d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom}
15996d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom
160ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav ShahCALCULATED_KERNEL_CONFIG=
161e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te LinCALCULATED_DM_ARGS=
1621cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah# Calculate rootfs hash of an image
1631cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah# Args: ROOTFS_IMAGE KERNEL_CONFIG HASH_IMAGE
1641cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah#
1651cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah# rootfs calculation parameters are grabbed from KERNEL_CONFIG
1661cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah#
167e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# Updated dm-verity arguments (to be replaced in kernel config command line)
168e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# with the new hash is stored in $CALCULATED_DM_ARGS and the new hash image is
169e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# written to the file HASH_IMAGE.
1701cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shahcalculate_rootfs_hash() {
1711cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local rootfs_image=$1
1721cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local kernel_config=$2
1731cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local hash_image=$3
174ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  local dm_config=$(get_dmparams_from_config "${kernel_config}")
1750c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
17633c44fc14f6981601d0f0743d0705587d5f11c56Gaurav Shah  if [ -z "${dm_config}" ]; then
177ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    echo "WARNING: Couldn't grab dm_config. Aborting rootfs hash calculation."
178ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    return 1
1790c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  fi
18096d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  local vroot_dev=$(get_dm_slave "${dm_config}" vroot)
18169b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah
18269b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  local rootfs_sectors
18369b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  local verity_depth
18469b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  local verity_algorithm
18569b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  local root_dev
18669b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  local hash_dev
187132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah  local verity_bin="verity"
18896d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  if is_old_verity_argv "${vroot_dev}"; then
18969b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah    # dm="0 2097152 verity ROOT_DEV HASH_DEV 2097152 1 \
19069b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah    # sha1 63b7ad16cb9db4b70b28593f825aa6b7825fdcf2"
19196d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    rootfs_sectors=$(echo ${vroot_dev} | cut -f2 -d' ')
19296d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    verity_depth=$(echo ${vroot_dev} | cut -f7 -d' ')
19396d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    verity_algorithm=$(echo ${vroot_dev} | cut -f8 -d' ')
19496d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    root_dev=$(echo ${vroot_dev} | cut -f4 -d ' ')
19596d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    hash_dev=$(echo ${vroot_dev} | cut -f5 -d ' ')
196132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah    # Hack around the fact that the signer needs to use the old version of
197132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah    # verity to generate legacy verity kernel parameters. If we find it,
198132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah    # we use it.
199132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah    type -P "verity-old" &>/dev/null && verity_bin="verity-old"
20069b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  else
20169b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah    # Key-value parameters.
20296d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    rootfs_sectors=$(get_verity_arg "${vroot_dev}" hashstart)
20369b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah    verity_depth=0
20496d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    verity_algorithm=$(get_verity_arg "${vroot_dev}" alg)
20596d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    root_dev=$(get_verity_arg "${vroot_dev}" payload)
20696d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    hash_dev=$(get_verity_arg "${vroot_dev}" hashtree)
20796d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom    salt=$(get_verity_arg "${vroot_dev}" salt)
208132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah  fi
209132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah
210132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah  local salt_arg
211132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah  if [ -n "$salt" ]; then
212132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah    salt_arg="salt=$salt"
21369b88dc99b0c3ed12ad66f8df7b65ecc3682204fGaurav Shah  fi
2140c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
2151cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  # Run the verity tool on the rootfs partition.
21696d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  local slave=$(sudo ${verity_bin} mode=create \
217cba0e83d91b33c3ef9c71fc7dc24c1370e7f3e9aGaurav Shah    alg=${verity_algorithm} \
218cba0e83d91b33c3ef9c71fc7dc24c1370e7f3e9aGaurav Shah    payload="${rootfs_image}" \
219cba0e83d91b33c3ef9c71fc7dc24c1370e7f3e9aGaurav Shah    payload_blocks=$((rootfs_sectors / 8)) \
220132e6e0c8cfa49a470199374e2331e3bb2ea21d6Gaurav Shah    hashtree="${hash_image}" ${salt_arg})
2210c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  # Reconstruct new kernel config command line and replace placeholders.
22296d16de52ebb6785f7d34dcecc030d1b4e3f9c09Paul Taysom  slave="$(echo "${slave}" |
2230c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah    sed -s "s|ROOT_DEV|${root_dev}|g;s|HASH_DEV|${hash_dev}|")"
224e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  CALCULATED_DM_ARGS="$(set_dm_slave "${dm_config}" vroot "${slave}")"
225e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  CALCULATED_KERNEL_CONFIG="$(echo "${kernel_config}" |
226e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    sed -e 's#\(.*dm="\)\([^"]*\)\(".*\)'"#\1${CALCULATED_DM_ARGS}\3#g")"
2271cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah}
2281cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
229e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# Re-calculate rootfs hash, update rootfs and kernel command line(s).
230e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# Args: IMAGE DM_PARTNO KERN_A_KEYBLOCK KERN_A_PRIVKEY KERN_B_KEYBLOCK \
231e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin#       KERN_B_PRIVKEY
232e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin#
233e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# The rootfs is hashed by tool 'verity', and the hash data is stored after the
234e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# rootfs. A hash of those hash data (also known as final verity hash) may be
235e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# contained in kernel 2 or kernel 4 command line.
236e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin#
237e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# This function reads dm-verity configuration from DM_PARTNO, rebuilds rootfs
238e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# hash, and then resigns kernel A & B by their keyblock and private key files.
2391cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shahupdate_rootfs_hash() {
2401cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local image=$1  # Input image.
241e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local dm_partno="$2"  # Partition number of kernel that contains verity args.
242e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kern_a_keyblock="$3"  # Keyblock file for kernel A.
243e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kern_a_privkey="$4"  # Private key file for kernel A.
244e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kern_b_keyblock="$5"  # Keyblock file for kernel B.
245e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kern_b_privkey="$6"  # Private key file for kernel A.
246d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah
247e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # Note even though there are two kernels, there is one place (after rootfs)
248e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # for hash data, so we must assume both kernel use same hash algorithm (i.e.,
249e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # DM config).
250e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  echo "Updating rootfs hash and updating config for Kernel partitions"
2511cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
252ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  # If we can't find dm parameters in the kernel config, bail out now.
253e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kernel_config=$(grab_kernel_config "${image}" "${dm_partno}")
254ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  local dm_config=$(get_dmparams_from_config "${kernel_config}")
255ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  if [ -z "${dm_config}" ]; then
256e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    echo "ERROR: Couldn't grab dm_config from kernel partition ${dm_partno}"
257e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    echo " (config: ${kernel_config})"
258e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    return 1
259ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  fi
260ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah
26104c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin  # check and clear need_to_resign tag
26204c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin  local rootfs_dir=$(make_temp_dir)
26304c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin  mount_image_partition_ro "${image}" 3 "${rootfs_dir}"
26404c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin  if has_needs_to_be_resigned_tag "${rootfs_dir}"; then
26504c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin    # remount as RW
266d170a9d542dd4770c25d5ed82429a55391d88218Gaurav Shah    sudo umount "${rootfs_dir}"
26704c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin    mount_image_partition "${image}" 3 "${rootfs_dir}"
26804c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin    sudo rm -f "${rootfs_dir}/${TAG_NEEDS_TO_BE_SIGNED}"
26904c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin  fi
270d170a9d542dd4770c25d5ed82429a55391d88218Gaurav Shah  sudo umount "${rootfs_dir}"
27104c00e19c6fd1d9ad09d2bf5e06518c249d62b31Hung-Te Lin
2721cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local rootfs_image=$(make_temp_file)
2731cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  extract_image_partition ${image} 3 ${rootfs_image}
2741cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local hash_image=$(make_temp_file)
2751cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
276aaae959412acc95ba2f4a0b5af44d67186c7a3d2Will Drewry  # Disable rw mount support prior to hashing.
277aaae959412acc95ba2f4a0b5af44d67186c7a3d2Will Drewry  disable_rw_mount "${rootfs_image}"
278aaae959412acc95ba2f4a0b5af44d67186c7a3d2Will Drewry
279ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  if ! calculate_rootfs_hash "${rootfs_image}"  "${kernel_config}" \
280ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    "${hash_image}"; then
281ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    echo "calculate_rootfs_hash failed!"
282ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    echo "Aborting rootfs hash update!"
283e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    return 1
284ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  fi
285ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah
2861a2e6fc765a13b636d3dd75dc7cae709e9e8d218Gaurav Shah  local rootfs_blocks=$(sudo dumpe2fs "${rootfs_image}" 2> /dev/null |
2871cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    grep "Block count" |
2881cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    tr -d ' ' |
2891cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    cut -f2 -d:)
2901cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local rootfs_sectors=$((rootfs_blocks * 8))
2910c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
2920c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  # Overwrite the appended hashes in the rootfs
2931cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  dd if=${hash_image} of=${rootfs_image} bs=512 \
2946bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah    seek=${rootfs_sectors} conv=notrunc 2>/dev/null
295e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  replace_image_partition ${image} 3 ${rootfs_image}
2960c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
297e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # Update kernel command lines
298e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local dm_args="${CALCULATED_DM_ARGS}"
299e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local temp_config=$(make_temp_file)
3001cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local temp_kimage=$(make_temp_file)
3010c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  local updated_kimage=$(make_temp_file)
302e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kernelpart=
303e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local keyblock=
304e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local priv_key=
305b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin  local new_kernel_config=
306e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin
307e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  for kernelpart in 2 4; do
308b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    if ! new_kernel_config="$(
309b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin         grab_kernel_config "${image}" "${kernelpart}" 2>/dev/null)" &&
310b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin       [[ "${kernelpart}" == 4 ]]; then
311b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin      # Legacy images don't have partition 4.
312b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin      echo "Skipping empty kernel partition 4 (legacy images)."
313b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin      continue
314b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    fi
315b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    new_kernel_config="$(echo "${new_kernel_config}" |
316b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin      sed -e 's#\(.*dm="\)\([^"]*\)\(".*\)'"#\1${dm_args}\3#g")"
317e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    echo "New config for kernel partition ${kernelpart} is:"
318e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    echo "${new_kernel_config}" | tee "${temp_config}"
319e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    extract_image_partition "${image}" "${kernelpart}" "${temp_kimage}"
320e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    # Re-calculate kernel partition signature and command line.
321e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    if [[ "$kernelpart" == 2 ]]; then
322e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      keyblock="${kern_a_keyblock}"
323e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      priv_key="${kern_a_privkey}"
324e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    else
325e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      keyblock="${kern_b_keyblock}"
326e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      priv_key="${kern_b_privkey}"
327e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    fi
328e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    vbutil_kernel --repack ${updated_kimage} \
329e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      --keyblock ${keyblock} \
330e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      --signprivate ${priv_key} \
331e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      --version "${KERNEL_VERSION}" \
332e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      --oldblob ${temp_kimage} \
333e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin      --config ${temp_config}
334e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    replace_image_partition ${image} ${kernelpart} ${updated_kimage}
335e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  done
336e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin}
33733c44fc14f6981601d0f0743d0705587d5f11c56Gaurav Shah
338e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# Update the SSD install-able vblock file on stateful partition.
339e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# ARGS: Image
340b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin# This is deprecated because all new images should have a SSD boot-able kernel
341b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin# in partition 4. However, the signer needs to be able to sign new & old images
342b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin# (crbug.com/449450#c13) so we will probably never remove this.
343e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linupdate_stateful_partition_vblock() {
344e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local image="$1"
345e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kernb_image="$(make_temp_file)"
346e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local temp_out_vb="$(make_temp_file)"
347b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin
348e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  extract_image_partition "${image}" 4 "${kernb_image}"
349b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin  if [[ "$(dump_kernel_config "${kernb_image}" 2>/dev/null)" == "" ]]; then
350b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    echo "Building vmlinuz_hd.vblock from legacy image partition 2."
351b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    extract_image_partition "${image}" 2 "${kernb_image}"
352b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin  fi
353b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin
354b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin  # vblock should always use kernel keyblock.
355b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin  vbutil_kernel --repack "${temp_out_vb}" \
356b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    --keyblock "${KEY_DIR}/kernel.keyblock" \
357b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    --signprivate "${KEY_DIR}/kernel_data_key.vbprivk" \
358b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    --oldblob "${kernb_image}" \
359b6ebb1ab1c5a181f08b80f9a77434134645bc294Hung-Te Lin    --vblockonly
360e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin
361e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # Copy the installer vblock to the stateful partition.
362e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local stateful_dir=$(make_temp_dir)
363e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  mount_image_partition "${image}" 1 "${stateful_dir}"
364e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  sudo cp ${temp_out_vb} ${stateful_dir}/vmlinuz_hd.vblock
365e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  sudo umount "${stateful_dir}"
3660c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah}
3670c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
3685f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah# Do a sanity check on the image's rootfs
3695f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah# ARGS: Image
3705f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shahverify_image_rootfs() {
3715f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  local image=$1
3725f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  local rootfs_image=$(make_temp_file)
3735f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  extract_image_partition ${image} 3 ${rootfs_image}
3745f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  # This flips the read-only compatibility flag, so that e2fsck does not
3755f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  # complain about unknown file system capabilities.
3765f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  enable_rw_mount ${rootfs_image}
3775f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  echo "Running e2fsck to check root file system for errors"
3785f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  sudo e2fsck -fn "${rootfs_image}" ||
3795f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah    { echo "Root file system has errors!" && exit 1;}
3805f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah}
3818ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah
3829137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin# Extracts a firmware updater bundle (for firmware image binaries) file
3839137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin# (generated by src/platform/firmware/pack_firmware.sh).
3849137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin# Args: INPUT_FILE OUTPUT_DIR
3859137e8df481906c7de15d92f639a6129adedd892Hung-Te Linextract_firmware_bundle() {
3869137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  local input="$(readlink -f "$1")"
3879137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  local output_dir="$2"
3889137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  if [ ! -s "${input}" ]; then
3899137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    return 1
3909137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  elif grep -q '^##CUTHERE##' "${input}"; then
3919137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    # Bundle supports self-extraction.
3929137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    "$input" --sb_extract "${output_dir}" ||
3939137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin      die "Extracting firmware autoupdate (--sb_extract) failed."
39471bff41d6f0ff9912b9c56d14ba2ea0dd0331a9cGaurav Shah  else
3959137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    # Legacy bundle - try uudecode.
3969137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    uudecode -o - ${input} | tar -C ${output_dir} -zxf - 2>/dev/null ||
3979137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin      die "Extracting firmware autoupdate failed."
3989137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  fi
3999137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin}
4009137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin
4019137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin# Repacks firmware updater bundle content from given folder.
4029137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin# Args: INPUT_DIR TARGET_SCRIPT
4039137e8df481906c7de15d92f639a6129adedd892Hung-Te Linrepack_firmware_bundle() {
4049137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  local input_dir="$1"
4059137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  local target="$(readlink -f "$2")"
4069137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin
4079137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  if [ ! -s "${target}" ]; then
40871bff41d6f0ff9912b9c56d14ba2ea0dd0331a9cGaurav Shah    return 1
4099137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  elif grep -q '^##CUTHERE##' "${target}"; then
4109137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    # Bundle supports repacking.
4114edc75daa696f9e6fa39205117233ed68dcbed43Mike Frysinger    # Workaround issue crosbug.com/p/33719
4124edc75daa696f9e6fa39205117233ed68dcbed43Mike Frysinger    sed -i \
4134edc75daa696f9e6fa39205117233ed68dcbed43Mike Frysinger      's/shar -Q -q -x -m -w/shar -Q -q -x -m --no-character-count/' \
4144edc75daa696f9e6fa39205117233ed68dcbed43Mike Frysinger      "${target}"
4159137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    "$target" --sb_repack "${input_dir}" ||
4169137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin      die "Updating firmware autoupdate (--sb_repack) failed."
4179137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  else
4189137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    # Legacy bundle using uuencode + tar.gz.
4199137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    # Replace MD5 checksum in the firmware update payload.
4209137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    local newfd_checksum="$(md5sum ${input_dir}/bios.bin | cut -f 1 -d ' ')"
4219137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    local temp_version="$(make_temp_file)"
4229137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    cat ${input_dir}/VERSION |
4239137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    sed -e "s#\(.*\)\ \(.*bios.bin.*\)#${newfd_checksum}\ \2#" > ${temp_version}
4249137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    mv ${temp_version} ${input_dir}/VERSION
4259137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin
4269137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    # Re-generate firmware_update.tgz and copy over encoded archive in
4279137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    # the original shell ball.
4289137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    sed -ine '/^begin .*firmware_package/,/end/D' "$target"
4299137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin    tar zcf - -C "${input_dir}" . |
4309137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin      uuencode firmware_package.tgz >>"${target}"
43171bff41d6f0ff9912b9c56d14ba2ea0dd0331a9cGaurav Shah  fi
4320c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah}
4330c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
4349c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah# Sign a firmware in-place with the given keys.
435aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger# Args: FIRMWARE_IMAGE KEY_DIR FIRMWARE_VERSION [LOEM_OUTPUT_DIR]
4369c783ce3c132491e28efe84751b20d82fc571560Gaurav Shahsign_firmware() {
4379c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  local image=$1
4389c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  local key_dir=$2
4399c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  local firmware_version=$3
440aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger  local loem_output_dir=${4:-}
4419c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah
4429c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  local temp_firmware=$(make_temp_file)
4439c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  # Resign the firmware with new keys, also replacing the root and recovery
4449c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  # public keys in the GBB.
445aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger  "${SCRIPT_DIR}/sign_firmware.sh" "${image}" "${key_dir}" "${temp_firmware}" \
446aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger    "${firmware_version}" "${loem_output_dir}"
4479c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  # Note: Although sign_firmware.sh may correctly handle specifying the same
4489c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  # output file as the input file, we do not want to rely on it correctly
4499c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  # handing that. Hence, the use of a temporary file.
4509c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  mv ${temp_firmware} ${image}
4519c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  echo "Signed firmware image output to ${image}"
4529c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah}
4539c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah
454283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger# Sign a delta update payload (usually created by paygen).
455283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger# Args: INPUT_IMAGE KEY_DIR OUTPUT_IMAGE
456283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysingersign_update_payload() {
457283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  local image=$1
458283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  local key_dir=$2
459283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  local output=$3
460283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  local key_size key_file="${key_dir}/update_key.pem"
461e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # Maps key size to verified boot's algorithm id (for pad_digest_utility).
462e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # Hashing algorithm is always SHA-256.
463283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  local algo algos=(
464283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger    [1024]=1
465283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger    [2048]=4
466283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger    [4096]=7
467283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger    [8192]=10
468283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  )
469283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger
470283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  key_size=$(openssl rsa -text -noout -in "${key_file}" | \
471283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger    sed -n -r '1{s/Private-Key: \(([0-9]*) bit\)/\1/p}')
472283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  algo=${algos[${key_size}]}
473283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  if [[ -z ${algo} ]]; then
474283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger    die "Unknown algorithm specified by key_size=${key_size}"
475283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  fi
476283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger
477283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  pad_digest_utility ${algo} "${image}" | \
478283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger    openssl rsautl -sign -pkcs -inkey "${key_file}" -out "${output}"
479283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger}
480283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger
4810c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah# Re-sign the firmware AU payload inside the image rootfs with a new keys.
4820c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah# Args: IMAGE
4830c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shahresign_firmware_payload() {
4840c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  local image=$1
4850c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
486815193daeeef8913dce878e36c6608adb1c56bb5Gaurav Shah  if [ -n "${NO_FWUPDATE}" ]; then
487815193daeeef8913dce878e36c6608adb1c56bb5Gaurav Shah    echo "Skipping firmware update."
488815193daeeef8913dce878e36c6608adb1c56bb5Gaurav Shah    return
489815193daeeef8913dce878e36c6608adb1c56bb5Gaurav Shah  fi
490815193daeeef8913dce878e36c6608adb1c56bb5Gaurav Shah
4919137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  # Grab firmware image from the autoupdate bundle (shellball).
4920c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  local rootfs_dir=$(make_temp_dir)
4930c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  mount_image_partition ${image} 3 ${rootfs_dir}
4949137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  local firmware_bundle="${rootfs_dir}/usr/sbin/chromeos-firmwareupdate"
4950c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  local shellball_dir=$(make_temp_dir)
4969137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin
4979137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  # extract_firmware_bundle can fail if the image has no firmware update.
49840837258677fca4b9bfb37b7bfb288baf40831e0Hung-Te Lin  if ! extract_firmware_bundle "${firmware_bundle}" "${shellball_dir}"; then
49940837258677fca4b9bfb37b7bfb288baf40831e0Hung-Te Lin    # Unmount now to prevent changes.
50040837258677fca4b9bfb37b7bfb288baf40831e0Hung-Te Lin    sudo umount "${rootfs_dir}"
50140837258677fca4b9bfb37b7bfb288baf40831e0Hung-Te Lin    echo "Didn't find a firmware update. Not signing firmware."
50240837258677fca4b9bfb37b7bfb288baf40831e0Hung-Te Lin    return
50340837258677fca4b9bfb37b7bfb288baf40831e0Hung-Te Lin  fi
50471bff41d6f0ff9912b9c56d14ba2ea0dd0331a9cGaurav Shah  echo "Found a valid firmware update shellball."
5050c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
506aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger  local image_file sign_args=() loem_sfx loem_output_dir
507ca8c372e60d249cc49ecaf1d33ace2d53caadfaeHung-Te Lin  for image_file in "${shellball_dir}"/bios*.bin; do
508aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger    if [[ -e "${KEY_DIR}/loem.ini" ]]; then
509aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger      # Extract the extended details from "bios.bin" and use that in the
510aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger      # subdir for the keyset.
511aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger      loem_sfx=$(sed -r 's:.*/bios([^/]*)[.]bin$:\1:' <<<"${image_file}")
512aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger      loem_output_dir="${shellball_dir}/keyset${loem_sfx}"
513aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger      sign_args=( "${loem_output_dir}" )
514aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger      mkdir -p "${loem_output_dir}"
515aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger    fi
516aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger    sign_firmware "${image_file}" "${KEY_DIR}" "${FIRMWARE_VERSION}" \
517aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger      "${sign_args[@]}"
518ca8c372e60d249cc49ecaf1d33ace2d53caadfaeHung-Te Lin  done
51942d23c664dbd1334c82b48b504b7d8499955963dGaurav Shah
5209137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  local signer_notes="${shellball_dir}/VERSION.signer"
5219137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  echo "" >"$signer_notes"
5229137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  echo "Signed with keyset in $(readlink -f "${KEY_DIR}") ." >>"$signer_notes"
5230c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah
5240c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  new_shellball=$(make_temp_file)
5259137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  cp -f "${firmware_bundle}" "${new_shellball}"
526bd3dad01b0c2d934462d70eeabb31abcd0310b3fHung-Te Lin  chmod a+rx "${new_shellball}"
5279137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  repack_firmware_bundle "${shellball_dir}" "${new_shellball}"
5289137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  sudo cp -f "${new_shellball}" "${firmware_bundle}"
5299137e8df481906c7de15d92f639a6129adedd892Hung-Te Lin  sudo chmod a+rx "${firmware_bundle}"
530e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # Unmount now to flush changes.
531e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  sudo umount "${rootfs_dir}"
5320c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah  echo "Re-signed firmware AU payload in $image"
5330c4c9bac3c390445066f08010a753ce76ccb4a5eGaurav Shah}
53437522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
5351cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah# Verify an image including rootfs hash using the specified keys.
5361cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shahverify_image() {
5371cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local rootfs_image=$(make_temp_file)
5381cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  extract_image_partition ${INPUT_IMAGE} 3 ${rootfs_image}
5391cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
5401cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  echo "Verifying RootFS hash..."
541ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  # What we get from image.
542ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  local kernel_config
543ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  # What we calculate from the rootfs.
544ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  local new_kernel_config
545ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  # Depending on the type of image, the verity parameters may
546ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  # exist in either kernel partition 2 or kernel partition 4
547ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  local partnum
548ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  for partnum in 2 4; do
549ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    echo "Considering Kernel partition $partnum"
550ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    kernel_config=$(grab_kernel_config ${INPUT_IMAGE} $partnum)
551ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    local hash_image=$(make_temp_file)
552ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    if ! calculate_rootfs_hash "${rootfs_image}" "${kernel_config}" \
553ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah      "${hash_image}"; then
554ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah      echo "Trying next kernel partition."
555ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah      continue
556ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    fi
557ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    new_kernel_config="$CALCULATED_KERNEL_CONFIG"
558ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    break
559ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  done
560ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah
561ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  # Note: If calculate_rootfs_hash succeeded above, these should
562ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  # be non-empty.
563ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  expected_hash=$(get_hash_from_config "${new_kernel_config}")
564ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  got_hash=$(get_hash_from_config "${kernel_config}")
565ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah
566ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah  if [ -z "${expected_hash}" ] || [ -z "${got_hash}" ]; then
567ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah    echo "FAILURE: Couldn't verify RootFS hash on the image."
568c3fe59f72c95597a2d5becc8511e9d5eaf97c391Gaurav Shah    exit 1
569c3fe59f72c95597a2d5becc8511e9d5eaf97c391Gaurav Shah  fi
570ce6649250583a8f3a7aeac78ee3a00679cf6223dGaurav Shah
5711cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  if [ ! "${got_hash}" = "${expected_hash}" ]; then
5721cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    cat <<EOF
5731cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav ShahFAILED: RootFS hash is incorrect.
5741cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav ShahExpected: ${expected_hash}
5751cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav ShahGot: ${got_hash}
5761cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav ShahEOF
577c3fe59f72c95597a2d5becc8511e9d5eaf97c391Gaurav Shah    exit 1
5781cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  else
5791cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    echo "PASS: RootFS hash is correct (${expected_hash})"
5801cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  fi
5811cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
5821cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  # Now try and verify kernel partition signature.
5831cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  set +e
5841cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  local try_key=${KEY_DIR}/recovery_key.vbpubk
5851cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  echo "Testing key verification..."
5861cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  # The recovery key is only used in the recovery mode.
5871cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  echo -n "With Recovery Key (Recovery Mode ON, Dev Mode OFF): " && \
5881cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  { load_kernel_test "${INPUT_IMAGE}" "${try_key}" -b 2 >/dev/null 2>&1 && \
5891cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    echo "YES"; } || echo "NO"
5901cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  echo -n "With Recovery Key (Recovery Mode ON, Dev Mode ON): " && \
5911cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  { load_kernel_test "${INPUT_IMAGE}" "${try_key}" -b 3 >/dev/null 2>&1 && \
5921cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    echo "YES"; } || echo "NO"
5931cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
5941cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  try_key=${KEY_DIR}/kernel_subkey.vbpubk
5951cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  # The SSD key is only used in non-recovery mode.
5961cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  echo -n "With SSD Key (Recovery Mode OFF, Dev Mode OFF): " && \
5971cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  { load_kernel_test "${INPUT_IMAGE}" "${try_key}" -b 0 >/dev/null 2>&1  && \
5981cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    echo "YES"; } || echo "NO"
5991cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  echo -n "With SSD Key (Recovery Mode OFF, Dev Mode ON): " && \
6001cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  { load_kernel_test "${INPUT_IMAGE}" "${try_key}" -b 1 >/dev/null 2>&1 && \
6011cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah    echo "YES"; } || echo "NO"
6021cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  set -e
6031cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
6045f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah  verify_image_rootfs "${INPUT_IMAGE}"
6055f500b19ba0cdc174a47a68e40f939a4ed69861cGaurav Shah
6061cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  # TODO(gauravsh): Check embedded firmware AU signatures.
6071cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah}
6081cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
609e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# Re-calculate recovery kernel hash.
610e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# Args: IMAGE_BIN
611e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linupdate_recovery_kernel_hash() {
612276f846a142a3c2c7c2c575d4403c71eca18a92aGaurav Shah  image_bin=$1
6136bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah
6146bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah  # Update the Kernel B hash in Kernel A command line
6156bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah  local old_kerna_config=$(grab_kernel_config "${image_bin}" 2)
6166bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah  local new_kernb=$(make_temp_file)
6176bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah  extract_image_partition ${image_bin} 4 ${new_kernb}
6186bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah  local new_kernb_hash=$(sha1sum ${new_kernb} | cut -f1 -d' ')
6196bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah
6206bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah  new_kerna_config=$(make_temp_file)
6216bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah  echo "$old_kerna_config" |
6226bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah    sed -e "s#\(kern_b_hash=\)[a-z0-9]*#\1${new_kernb_hash}#" \
6236bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah      > ${new_kerna_config}
624d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah  echo "New config for kernel partition 2 is"
6256bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah  cat ${new_kerna_config}
626d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah
627d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah  local temp_kimagea=$(make_temp_file)
628276f846a142a3c2c7c2c575d4403c71eca18a92aGaurav Shah  extract_image_partition ${image_bin} 2 ${temp_kimagea}
6296bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah
630d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah  # Re-calculate kernel partition signature and command line.
631d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah  local updated_kimagea=$(make_temp_file)
632d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah  vbutil_kernel --repack ${updated_kimagea} \
633d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah    --keyblock ${KEY_DIR}/recovery_kernel.keyblock \
634d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah    --signprivate ${KEY_DIR}/recovery_kernel_data_key.vbprivk \
6358ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah    --version "${KERNEL_VERSION}" \
636d7947a197edc905d3f0a14a661de83573dd6c650Gaurav Shah    --oldblob ${temp_kimagea} \
6376bd03d4a88fa049bd72cf18fec701cec1dfc042bGaurav Shah    --config ${new_kerna_config}
6388ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah
639276f846a142a3c2c7c2c575d4403c71eca18a92aGaurav Shah  replace_image_partition ${image_bin} 2 ${updated_kimagea}
64037522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah}
64137522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
642e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# Sign an image file with proper keys.
643e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# Args: IMAGE_TYPE INPUT OUTPUT DM_PARTNO KERN_A_KEYBLOCK KERN_A_PRIVKEY \
644e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin#       KERN_B_KEYBLOCK KERN_B_PRIVKEY
645e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin#
646e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# A ChromiumOS image file (INPUT) always contains 2 partitions (kernel A & B).
647e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# This function will rebuild hash data by DM_PARTNO, resign kernel partitions by
648e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# their KEYBLOCK and PRIVKEY files, and then write to OUTPUT file. Note some
649e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# special images (specified by IMAGE_TYPE, like 'recovery' or 'factory_install')
650e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# may have additional steps (ex, tweaking verity hash or not stripping files)
651e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin# when generating output file.
652e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linsign_image_file() {
653e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local image_type="$1"
654e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local input="$2"
655e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local output="$3"
656e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local dm_partno="$4"
657e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kernA_keyblock="$5"
658e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kernA_privkey="$6"
659e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kernB_keyblock="$7"
660e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  local kernB_privkey="$8"
661e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  echo "Preparing ${image_type} image..."
662e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  cp "${input}" "${output}"
663e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  resign_firmware_payload "${output}"
664e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # We do NOT strip /boot for factory installer, since some devices need it to
665e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  # boot EFI. crbug.com/260512 would obsolete this requirement.
666e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  if [[ "${image_type}" != "factory_install" ]]; then
667e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${SCRIPT_DIR}/strip_boot_from_image.sh" --image "${output}"
668e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  fi
669e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  update_rootfs_hash "${output}" "${dm_partno}" \
670e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${kernA_keyblock}" "${kernA_privkey}" \
671e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${kernB_keyblock}" "${kernB_privkey}"
672e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  update_stateful_partition_vblock "${output}"
673e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  if [[ "${image_type}" == "recovery" ]]; then
674e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    update_recovery_kernel_hash "${output}"
675e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  fi
676e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  echo "Signed ${image_type} image output to ${output}"
67737522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah}
67837522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah
6791cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah# Verification
680b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysingercase ${TYPE} in
681b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysingerdump_config)
682b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  check_argc $# 2
683b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  for partnum in 2 4; do
684b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    echo "kernel config in partition number ${partnum}:"
685b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    grab_kernel_config "${INPUT_IMAGE}" ${partnum}
686b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    echo
687b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  done
688b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  exit 0
689b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  ;;
690b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysingerverify)
691b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  check_argc $# 2
6921cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah  verify_image
693527612e3565be00030a082c262204a0562bc0d4aGaurav Shah  exit 0
694b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  ;;
695b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger*)
696b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  # All other signing commands take 4 to 5 args.
697b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  if [ -z "${OUTPUT_IMAGE}" ]; then
698b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    # Friendlier message.
699b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger    usage "Missing output image name"
700b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  fi
701b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  check_argc $# 4 5
702b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysinger  ;;
703b55c538fca8939e58d20c127a9f42ce4eba7282cMike Frysingeresac
7041cd4cdbbae7cd51d0c0ab247aab53ebc6a8cc8a9Gaurav Shah
7058ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah# If a version file was specified, read the firmware and kernel
7068ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah# versions from there.
7078ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shahif [ -n "${VERSION_FILE}" ]; then
7088ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah  FIRMWARE_VERSION=$(sed -n 's#^firmware_version=\(.*\)#\1#pg' ${VERSION_FILE})
7098ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shah  KERNEL_VERSION=$(sed -n 's#^kernel_version=\(.*\)#\1#pg' ${VERSION_FILE})
7108ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shahfi
7118ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shahecho "Using firmware version: ${FIRMWARE_VERSION}"
7128ae7b0e41a1252f98e6662a298efb97624431c44Gaurav Shahecho "Using kernel version: ${KERNEL_VERSION}"
71371bff41d6f0ff9912b9c56d14ba2ea0dd0331a9cGaurav Shah
714276f846a142a3c2c7c2c575d4403c71eca18a92aGaurav Shah# Make all modifications on output copy.
715e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linif [[ "${TYPE}" == "ssd" ]]; then
716e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  sign_image_file "SSD" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 2 \
717e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/kernel.keyblock" "${KEY_DIR}/kernel_data_key.vbprivk" \
718e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/kernel.keyblock" "${KEY_DIR}/kernel_data_key.vbprivk"
719e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linelif [[ "${TYPE}" == "usb" ]]; then
720e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  sign_image_file "USB" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 2 \
721e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/recovery_kernel.keyblock" \
722e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/recovery_kernel_data_key.vbprivk" \
723e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/kernel.keyblock" \
724e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/kernel_data_key.vbprivk"
725e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linelif [[ "${TYPE}" == "recovery" ]]; then
726e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  sign_image_file "recovery" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 4 \
727e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/recovery_kernel.keyblock" \
728e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/recovery_kernel_data_key.vbprivk" \
729e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/kernel.keyblock" \
730e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/kernel_data_key.vbprivk"
731e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linelif [[ "${TYPE}" == "factory" ]] || [[ "${TYPE}" == "install" ]]; then
732e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin  sign_image_file "factory_install" "${INPUT_IMAGE}" "${OUTPUT_IMAGE}" 2 \
733e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/installer_kernel.keyblock" \
734e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/installer_kernel_data_key.vbprivk" \
735e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/kernel.keyblock" \
736e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Lin    "${KEY_DIR}/kernel_data_key.vbprivk"
737e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linelif [[ "${TYPE}" == "firmware" ]]; then
738aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger  if [[ -e "${KEY_DIR}/loem.ini" ]]; then
739aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger    echo "LOEM signing not implemented yet for firmware images"
740aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger    exit 1
741aa888463b860c2852f3fcb17baf8de395fcca294Mike Frysinger  fi
7429c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  cp ${INPUT_IMAGE} ${OUTPUT_IMAGE}
7439c783ce3c132491e28efe84751b20d82fc571560Gaurav Shah  sign_firmware ${OUTPUT_IMAGE} ${KEY_DIR} ${FIRMWARE_VERSION}
744e54e656b9f1b8f8f1bbcad86569b4aaf9e8bd594Hung-Te Linelif [[ "${TYPE}" == "update_payload" ]]; then
745283cbf89a9893f3a024809eb7d6c84ed353df6b4Mike Frysinger  sign_update_payload ${INPUT_IMAGE} ${KEY_DIR} ${OUTPUT_IMAGE}
74637522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shahelse
74737522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah  echo "Invalid type ${TYPE}"
74837522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shah  exit 1
74937522c9c0ccf48e63e0ab6c2b35b50948d15a003Gaurav Shahfi
750