summaryrefslogtreecommitdiff
path: root/scripts/image_signing/resign_firmwarefd.sh
blob: 363347181f6dcf3fc4dc34f763f26a30495382ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/bin/sh

# 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 to resign a firmware image using a different set of keys
# for use on signing servers.
#
# arguments: src_fd, dst_fd, firmware_datakey, and firmware_keyblock
#
# src_fd: Input firmware image (in .fd format)
# dst_fd: output firmware image name
# firmware_datakey: Key used to sign firmware data (in .vbprivk format)
# firmware_keyblock: Key block for firmware data key (in .keyblock format)
#
# Both the mosys tool and vbutil_firmware should be in the system path.
#
# This script parses the output of mosys tool from
# http://code.google.com/p/mosys
#
# to determine the regions in the image containing "Firmware [A|B] Data" and
# "Firmware [A|B] Key", which contain firmware data and firmware vblocks
# respectively. It will then generate new vblocks using the set of keys
# passed as arguments and output a new firmware image, with this new firmware
# vblocks the old ones.
#
# Here is an example output of mosys:
#
# area_offset="0x001c0000" area_size="0x00040000" area_name="Boot Stub" \
#   area_flags_raw="0x01" area_flags="static"
# area_offset="0x001a0000" area_size="0x00020000" area_name="GBB Area" \
#   area_flags_raw="0x01" area_flags="static"
# area_offset="0x00008000" area_size="0x00002000" area_name="Firmware A Key" \
#   area_flags_raw="0x01" area_flags="static"
# area_offset="0x0000a000" area_size="0x0009e000" area_name="Firmware A Data" \
#  area_flags_raw="0x03" area_flags="static,compressed"
# area_offset="0x000a8000" area_size="0x00002000" area_name="Firmware B Key" \
#  area_flags_raw="0x01" area_flags="static"
# area_offset="0x000aa000" area_size="0x0002e000" area_name="Firmware B Data" \
#  area_flags_raw="0x03" area_flags="static,compressed"
# area_offset="0x00005200" area_size="0x00001000" area_name="RW VPD" \
#  area_flags_raw="0x00" area_flags=""
#
# This shows that Firmware A Data is at offset 0x0000a0000 in the .fd image
# and is of size 0x0009e000 bytes. This can be extracted to generate new vblocks
# which can then replace old vblock for Firmware A ("Firmware A Key" region at
# offset 0x00008000 and size 0x00002000).

# Load common constants and variables.
. "$(dirname "$0")/common_minimal.sh"

# Abort on error
set -e

# Check arguments
if [ $# -lt 5 ] || [ $# -gt 6 ]; then
  echo "Usage: $PROG src_fd dst_fd firmware_datakey firmware_keyblock"\
   "kernel_subkey [version]"
  exit 1
fi

# Make sure the tools we need are available.
for prog in mosys vbutil_firmware; do
  type "${prog}" &>/dev/null || \
    { echo "${prog} tool not found."; exit 1; }
done

SRC_FD=$1
DST_FD=$2
FIRMWARE_DATAKEY=$3
FIRMWARE_KEYBLOCK=$4
KERNEL_SUBKEY=$5
VERSION=$6

if [ -z $VERSION ]; then
  VERSION=1
fi
echo "Using firmware version: $VERSION"

# Parse offsets and size of firmware data and vblocks
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 fw${i}_vblock_offset=$((offset))
  size="$(echo $line | sed -e 's/.*area_size=\"\([a-f0-9x]*\)\".*/\1/')"
  eval 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 fw${i}_offset=$((offset))
  size="$(echo $line | sed -e 's/.*area_size=\"\([a-f0-9x]*\)\".*/\1/')"
  eval fw${i}_size=$((size))
done

temp_fwimage=$(make_temp_file)
temp_out_vb=$(make_temp_file)

# Extract out Firmware A data and generate signature using the right keys
dd if="${SRC_FD}" of="${temp_fwimage}" skip="${fwA_offset}" bs=1 \
  count="${fwA_size}"

echo "Re-calculating Firmware A vblock"
vbutil_firmware \
  --vblock "${temp_out_vb}" \
  --keyblock "${FIRMWARE_KEYBLOCK}" \
  --signprivate "${FIRMWARE_DATAKEY}" \
  --version "${VERSION}" \
  --fv "${temp_fwimage}" \
  --kernelkey "${KERNEL_SUBKEY}"

# Create a copy of the input image and put in the new vblock for firmware A
cp "${SRC_FD}" "${DST_FD}"
dd if="${temp_out_vb}" of="${DST_FD}" seek="${fwA_vblock_offset}" bs=1 \
  count="${fwA_vblock_size}" conv=notrunc

# Repeat for firmware B
dd if="${SRC_FD}" of="${temp_fwimage}" skip="${fwB_offset}" bs=1 \
  count="${fwB_size}"
echo "Re-calculating Firmware B vblock"
vbutil_firmware \
  --vblock "${temp_out_vb}" \
  --keyblock "${FIRMWARE_KEYBLOCK}" \
  --signprivate "${FIRMWARE_DATAKEY}" \
  --version "${VERSION}" \
  --fv "${temp_fwimage}" \
  --kernelkey "${KERNEL_SUBKEY}"

# Destination image has already been created.
dd if="${temp_out_vb}" of="${DST_FD}" seek="${fwB_vblock_offset}" bs=1 \
  count="${fwB_vblock_size}" conv=notrunc

echo "New signed image was output to ${DST_FD}"