OLD | NEW |
1 #!/bin/bash | 1 #!/bin/bash |
2 | 2 |
3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 # Sign the final build image using the "official" keys. | 7 # Sign the final build image using the "official" keys. |
8 | 8 # |
| 9 # Prerequisite tools needed in the system path: |
| 10 # |
| 11 # gbb_utility (from src/platform/vboot_reference) |
| 12 # vbutil_kernel (from src/platform/vboot_reference) |
| 13 # cgpt (from src/platform/vboot_reference) |
| 14 # dump_kernel_config (from src/platform/vboot_reference) |
| 15 # verity (from src/platform/verity) |
| 16 # |
9 # Usage: sign_for_ssd.sh <type> input_image /path/to/keys/dir output_image | 17 # Usage: sign_for_ssd.sh <type> input_image /path/to/keys/dir output_image |
10 # | 18 # |
11 # where <type> is one of: | 19 # where <type> is one of: |
12 # ssd (sign an SSD image) | 20 # ssd (sign an SSD image) |
13 # recovery (sign a USB recovery image) | 21 # recovery (sign a USB recovery image) |
14 # install (sign a factory install image) | 22 # install (sign a factory install image) |
15 | 23 |
16 # Load common constants and variables. | 24 # Load common constants and variables. |
17 . "$(dirname "$0")/common.sh" | 25 . "$(dirname "$0")/common.sh" |
18 | 26 |
19 if [ $# -ne 4 ]; then | 27 if [ $# -ne 4 ]; then |
20 cat <<EOF | 28 cat <<EOF |
21 Usage: $0 <type> input_image /path/to/keys/dir output_image" | 29 Usage: $0 <type> input_image /path/to/keys/dir output_image" |
22 where <type> is one of: | 30 where <type> is one of: |
23 ssd (sign an SSD image) | 31 ssd (sign an SSD image) |
24 recovery (sign a USB recovery image) | 32 recovery (sign a USB recovery image) |
25 install (sign a factory install image) | 33 install (sign a factory install image) |
26 EOF | 34 EOF |
27 exit 1 | 35 exit 1 |
28 fi | 36 fi |
29 | 37 |
30 # Abort on errors. | 38 # Abort on errors. |
31 set -e | 39 set -e |
32 | 40 |
33 TYPE=$1 | 41 TYPE=$1 |
34 INPUT_IMAGE=$2 | 42 INPUT_IMAGE=$2 |
35 KEY_DIR=$3 | 43 KEY_DIR=$3 |
36 OUTPUT_IMAGE=$4 | 44 OUTPUT_IMAGE=$4 |
37 | 45 |
| 46 # Re-calculate rootfs hash, update rootfs and kernel command line. |
| 47 # Args: IMAGE KEYBLOCK PRIVATEKEY |
| 48 recalculate_rootfs_hash() { |
| 49 local image=$1 # Input image. |
| 50 local keyblock=$2 # Keyblock for re-generating signed kernel partition |
| 51 local signprivate=$3 # Private key to use for signing. |
| 52 |
| 53 # First, grab the existing kernel partition and get the kernel config. |
| 54 temp_kimage=$(make_temp_file) |
| 55 extract_image_partition ${image} 2 ${temp_kimage} |
| 56 local kernel_config=$(sudo dump_kernel_config ${temp_kimage}) |
| 57 local dm_config=$(echo $kernel_config | |
| 58 sed -e 's/.*dm="\([^"]*\)".*/\1/g' | |
| 59 cut -f2- -d,) |
| 60 # We extract dm=... portion of the config command line. Here's an example: |
| 61 # |
| 62 # dm="0 2097152 verity ROOT_DEV HASH_DEV 2097152 1 \ |
| 63 # sha1 63b7ad16cb9db4b70b28593f825aa6b7825fdcf2" |
| 64 # |
| 65 |
| 66 if [ -z ${dm_config} ]; then |
| 67 echo "WARNING: Couldn't grab dm_config. Aborting rootfs hash calculation" |
| 68 return |
| 69 fi |
| 70 local rootfs_sectors=$(echo ${dm_config} | cut -f2 -d' ') |
| 71 local root_dev=$(echo ${dm_config} | cut -f4 -d ' ') |
| 72 local hash_dev=$(echo ${dm_config} | cut -f5 -d ' ') |
| 73 local verity_depth=$(echo ${dm_config} | cut -f7 -d' ') |
| 74 local verity_algorithm=$(echo ${dm_config} | cut -f8 -d' ') |
| 75 |
| 76 # Mount the rootfs and run the verity tool on it. |
| 77 local hash_image=$(make_temp_file) |
| 78 local rootfs_img=$(make_temp_file) |
| 79 extract_image_partition ${image} 3 ${rootfs_img} |
| 80 local table="vroot none ro,"$(sudo verity create \ |
| 81 ${verity_depth} \ |
| 82 ${verity_algorithm} \ |
| 83 ${rootfs_img} \ |
| 84 $((rootfs_sectors / 8)) \ |
| 85 ${hash_image}) |
| 86 # Reconstruct new kernel config command line and replace placeholders. |
| 87 table="$(echo "$table" | |
| 88 sed -s "s|ROOT_DEV|${root_dev}|g;s|HASH_DEV|${hash_dev}|")" |
| 89 kernel_config=$(echo ${kernel_config} | |
| 90 sed -e 's#\(.*dm="\)\([^"]*\)\(".*\)'"#\1${table}\3#g") |
| 91 |
| 92 # Overwrite the appended hashes in the rootfs |
| 93 local temp_config=$(make_temp_file) |
| 94 echo ${kernel_config} >${temp_config} |
| 95 dd if=${hash_image} of=${rootfs_img} bs=512 \ |
| 96 seek=${rootfs_sectors} conv=notrunc |
| 97 |
| 98 # Re-calculate kernel partition signature and command line. |
| 99 local updated_kimage=$(make_temp_file) |
| 100 vbutil_kernel --repack ${updated_kimage} \ |
| 101 --keyblock ${keyblock} \ |
| 102 --signprivate ${signprivate} \ |
| 103 --oldblob ${temp_kimage} \ |
| 104 --config ${temp_config} |
| 105 |
| 106 replace_image_partition ${image} 2 ${updated_kimage} |
| 107 replace_image_partition ${image} 3 ${rootfs_img} |
| 108 } |
| 109 |
| 110 # Extracts the firmware update binaries from the a firmware update |
| 111 # shell ball (generated by src/platform/firmware/pack_firmware.sh) |
| 112 # Args: INPUT_SCRIPT OUTPUT_DIR |
| 113 get_firmwarebin_from_shellball() { |
| 114 local input=$1 |
| 115 local output_dir=$2 |
| 116 uudecode -o - ${input} | tar -C ${output_dir} -zxf - 2>/dev/null || \ |
| 117 echo "Extracting firmware autoupdate failed. |
| 118 Try re-running with FW_NOUPDATE=1." && exit 1 |
| 119 } |
| 120 |
| 121 # Re-sign the firmware AU payload inside the image rootfs with a new keys. |
| 122 # Args: IMAGE |
| 123 resign_firmware_payload() { |
| 124 local image=$1 |
| 125 |
| 126 # Grab firmware image from the autoupdate shellball. |
| 127 local rootfs_dir=$(make_temp_dir) |
| 128 mount_image_partition ${image} 3 ${rootfs_dir} |
| 129 |
| 130 local shellball_dir=$(make_temp_dir) |
| 131 get_firmwarebin_from_shellball \ |
| 132 ${rootfs_dir}/usr/sbin/chromeos-firmwareupdate ${shellball_dir} |
| 133 |
| 134 temp_outfd=$(make_temp_file) |
| 135 # Replace the root key in the GBB |
| 136 # TODO(gauravsh): Remove when we lock down the R/O portion of firmware. |
| 137 gbb_utility -s \ |
| 138 --rootkey=${KEY_DIR}/root_key.vbpubk \ |
| 139 --recoverykey=${KEY_DIR}/recovery_key.vbpubk \ |
| 140 ${shellball_dir}/bios.bin ${temp_outfd} |
| 141 |
| 142 # Resign the firmware with new keys |
| 143 ${SCRIPT_DIR}/resign_firmwarefd.sh ${temp_outfd} ${temp_dir}/bios.bin \ |
| 144 ${KEY_DIR}/firmware_data_key.vbprivk \ |
| 145 ${KEY_DIR}/firmware.keyblock \ |
| 146 ${KEY_DIR}/kernel_subkey.vbpubk |
| 147 |
| 148 # Replace MD5 checksum in the firmware update payload |
| 149 newfd_checksum=$(md5sum ${shellball_dir}/bios.bin | cut -f 1 -d ' ') |
| 150 temp_version=$(make_temp_file) |
| 151 cat ${shellball_dir}/VERSION | |
| 152 sed -e "s#\(.*\)\ \(.*bios.bin.*\)#${newfd_checksum}\ \2#" > ${temp_version} |
| 153 sudo cp ${temp_version} ${shellball_dir}/VERSION |
| 154 |
| 155 # Re-generate firmware_update.tgz and copy over encoded archive in |
| 156 # the original shell ball. |
| 157 new_fwblob=$(make_temp_file) |
| 158 tar zcf - -C ${shellball_dir} . | \ |
| 159 uuencode firmware_package.tgz > ${new_fwblob} |
| 160 new_shellball=$(make_temp_file) |
| 161 cat ${rootfs_dir}/usr/sbin/chromeos-firmwareupdate | \ |
| 162 sed -e '/^begin .*firmware_package/,/end/D' | \ |
| 163 cat - ${new_fwblob} >${new_shellball} |
| 164 sudo cp ${new_shellball} ${rootfs_dir}/usr/sbin/chromeos-firmwareupdate |
| 165 # Force unmount of the image as it is needed later. |
| 166 sudo umount -d ${rootfs_dir} |
| 167 echo "Re-signed firmware AU payload in $image" |
| 168 } |
38 | 169 |
39 # Generate the SSD image | 170 # Generate the SSD image |
40 sign_for_ssd() { | 171 sign_for_ssd() { |
41 ${SCRIPT_DIR}/resign_image.sh ${INPUT_IMAGE} ${OUTPUT_IMAGE} \ | 172 ${SCRIPT_DIR}/resign_image.sh ${INPUT_IMAGE} ${OUTPUT_IMAGE} \ |
42 ${KEY_DIR}/kernel_data_key.vbprivk \ | 173 ${KEY_DIR}/kernel_data_key.vbprivk \ |
43 ${KEY_DIR}/kernel.keyblock | 174 ${KEY_DIR}/kernel.keyblock |
44 echo "Output signed SSD image to ${OUTPUT_IMAGE}" | 175 echo "Output signed SSD image to ${OUTPUT_IMAGE}" |
45 } | 176 } |
46 | 177 |
47 # Generate the USB (recovery + install) image | 178 # Generate the USB (recovery + install) image |
48 sign_for_recovery() { | 179 sign_for_recovery() { |
49 ${SCRIPT_DIR}/resign_image.sh ${INPUT_IMAGE} ${OUTPUT_IMAGE} \ | 180 ${SCRIPT_DIR}/resign_image.sh ${INPUT_IMAGE} ${OUTPUT_IMAGE} \ |
50 ${KEY_DIR}/recovery_kernel_data_key.vbprivk \ | 181 ${KEY_DIR}/recovery_kernel_data_key.vbprivk \ |
51 ${KEY_DIR}/recovery_kernel.keyblock | 182 ${KEY_DIR}/recovery_kernel.keyblock |
52 | 183 |
53 # Now generate the installer vblock with the SSD keys. | 184 # Now generate the installer vblock with the SSD keys. |
54 temp_kimage=$(mktemp) | 185 temp_kimage=$(make_temp_file) |
55 trap "rm -f ${temp_kimage}" EXIT | 186 temp_out_vb=$(make_temp_file) |
56 temp_out_vb=$(mktemp) | |
57 trap "rm -f ${temp_out_vb}" EXIT | |
58 extract_image_partition ${OUTPUT_IMAGE} 2 ${temp_kimage} | 187 extract_image_partition ${OUTPUT_IMAGE} 2 ${temp_kimage} |
59 ${SCRIPT_DIR}/resign_kernel_partition.sh ${temp_kimage} ${temp_out_vb} \ | 188 ${SCRIPT_DIR}/resign_kernel_partition.sh ${temp_kimage} ${temp_out_vb} \ |
60 ${KEY_DIR}/kernel_data_key.vbprivk \ | 189 ${KEY_DIR}/kernel_data_key.vbprivk \ |
61 ${KEY_DIR}/kernel.keyblock | 190 ${KEY_DIR}/kernel.keyblock |
62 | 191 |
63 # Copy the installer vblock to the stateful partition. | 192 # Copy the installer vblock to the stateful partition. |
64 local stateful_dir=$(mktemp -d) | 193 local stateful_dir=$(make_temp_dir) |
65 trap "sudo umount -d $stateful_dir; rm -rf $stateful_dir" EXIT | |
66 mount_image_partition ${OUTPUT_IMAGE} 1 ${stateful_dir} | 194 mount_image_partition ${OUTPUT_IMAGE} 1 ${stateful_dir} |
67 sudo cp ${temp_out_vb} ${stateful_dir}/vmlinuz_hd.vblock | 195 sudo cp ${temp_out_vb} ${stateful_dir}/vmlinuz_hd.vblock |
68 | 196 |
69 echo "Output signed recovery image to ${OUTPUT_IMAGE}" | 197 echo "Output signed recovery image to ${OUTPUT_IMAGE}" |
70 } | 198 } |
71 | 199 |
72 # Generate the factory install image. | 200 # Generate the factory install image. |
73 sign_for_factory_install() { | 201 sign_for_factory_install() { |
74 ${SCRIPT_DIR}/resign_image.sh ${INPUT_IMAGE} ${OUTPUT_IMAGE} \ | 202 ${SCRIPT_DIR}/resign_image.sh ${INPUT_IMAGE} ${OUTPUT_IMAGE} \ |
75 ${KEY_DIR}/recovery_kernel_data_key.vbprivk \ | 203 ${KEY_DIR}/recovery_kernel_data_key.vbprivk \ |
76 ${KEY_DIR}/installer_kernel.keyblock | 204 ${KEY_DIR}/installer_kernel.keyblock |
77 echo "Output signed factory install image to ${OUTPUT_IMAGE}" | 205 echo "Output signed factory install image to ${OUTPUT_IMAGE}" |
78 } | 206 } |
79 | 207 |
| 208 if [ ! "${FW_NOUPDATE}" == "1" ]; then |
| 209 resign_firmware_payload ${INPUT_IMAGE} |
| 210 fi |
| 211 |
80 if [ "${TYPE}" == "ssd" ]; then | 212 if [ "${TYPE}" == "ssd" ]; then |
| 213 recalculate_rootfs_hash ${INPUT_IMAGE} \ |
| 214 ${KEY_DIR}/kernel.keyblock \ |
| 215 ${KEY_DIR}/kernel_data_key.vbprivk |
81 sign_for_ssd | 216 sign_for_ssd |
82 elif [ "${TYPE}" == "recovery" ]; then | 217 elif [ "${TYPE}" == "recovery" ]; then |
| 218 recalculate_rootfs_hash ${INPUT_IMAGE} \ |
| 219 ${KEY_DIR}/recovery_kernel.keyblock \ |
| 220 ${KEY_DIR}/recovery_kernel_data_key.vbprivk |
83 sign_for_recovery | 221 sign_for_recovery |
84 elif [ "${TYPE}" == "install" ]; then | 222 elif [ "${TYPE}" == "install" ]; then |
| 223 recalculate_rootfs_hash ${INPUT_IMAGE} \ |
| 224 ${KEY_DIR}/installer_kernel.keyblock \ |
| 225 ${KEY_DIR}/recovery_kernel_data_key.vbprivk |
85 sign_for_factory_install | 226 sign_for_factory_install |
86 else | 227 else |
87 echo "Invalid type ${TYPE}" | 228 echo "Invalid type ${TYPE}" |
88 exit 1 | 229 exit 1 |
89 fi | 230 fi |
90 | |
91 | |
OLD | NEW |