sign_official_build: support new firmware updater repacking method

To prevent hard-coding the procedure to repack a firmware updater, this CL
supports using new "--sb_repack" mode supported by updater so that signer does
not need to care about how the updater is packed anymore.

BUG=chromium-os:20027
TEST=./sign_official_build.sh ssd \
     ~/trunk/src/build/images/x86-zgb/latest/chromiumos_image.bin \
     ../../tests/devkeys \
     ~/trunk/src/build/images/x86-zgb/latest/chromiumos_new_image.bin
     # success

Change-Id: I035dfaa86b05b85748e69ec039769b0c08d33f64
Reviewed-on: http://gerrit.chromium.org/gerrit/7311
Tested-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
diff --git a/scripts/image_signing/sign_official_build.sh b/scripts/image_signing/sign_official_build.sh
index 8a1b4eb..3c026e8 100755
--- a/scripts/image_signing/sign_official_build.sh
+++ b/scripts/image_signing/sign_official_build.sh
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
+# 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.
 
@@ -241,17 +241,51 @@
     { echo "Root file system has errors!" && exit 1;}
 }
 
-# Extracts the firmware update binaries from the a firmware update
-# shell ball (generated by src/platform/firmware/pack_firmware.sh)
-# Args: INPUT_SCRIPT OUTPUT_DIR
-get_firmwarebin_from_shellball() {
-  local input=$1
-  local output_dir=$2
-  if [ -s "${input}" ]; then
-    uudecode -o - ${input} | tar -C ${output_dir} -zxf - 2>/dev/null || \
-      { echo "Extracting firmware autoupdate failed." && exit 1; }
-  else
+# Extracts a firmware updater bundle (for firmware image binaries) file
+# (generated by src/platform/firmware/pack_firmware.sh).
+# Args: INPUT_FILE OUTPUT_DIR
+extract_firmware_bundle() {
+  local input="$(readlink -f "$1")"
+  local output_dir="$2"
+  if [ ! -s "${input}" ]; then
     return 1
+  elif grep -q '^##CUTHERE##' "${input}"; then
+    # Bundle supports self-extraction.
+    "$input" --sb_extract "${output_dir}" ||
+      die "Extracting firmware autoupdate (--sb_extract) failed."
+  else
+    # Legacy bundle - try uudecode.
+    uudecode -o - ${input} | tar -C ${output_dir} -zxf - 2>/dev/null ||
+      die "Extracting firmware autoupdate failed."
+  fi
+}
+
+# Repacks firmware updater bundle content from given folder.
+# Args: INPUT_DIR TARGET_SCRIPT
+repack_firmware_bundle() {
+  local input_dir="$1"
+  local target="$(readlink -f "$2")"
+
+  if [ ! -s "${target}" ]; then
+    return 1
+  elif grep -q '^##CUTHERE##' "${target}"; then
+    # Bundle supports repacking.
+    "$target" --sb_repack "${input_dir}" ||
+      die "Updating firmware autoupdate (--sb_repack) failed."
+  else
+    # Legacy bundle using uuencode + tar.gz.
+    # Replace MD5 checksum in the firmware update payload.
+    local newfd_checksum="$(md5sum ${input_dir}/bios.bin | cut -f 1 -d ' ')"
+    local temp_version="$(make_temp_file)"
+    cat ${input_dir}/VERSION |
+    sed -e "s#\(.*\)\ \(.*bios.bin.*\)#${newfd_checksum}\ \2#" > ${temp_version}
+    mv ${temp_version} ${input_dir}/VERSION
+
+    # Re-generate firmware_update.tgz and copy over encoded archive in
+    # the original shell ball.
+    sed -ine '/^begin .*firmware_package/,/end/D' "$target"
+    tar zcf - -C "${input_dir}" . |
+      uuencode firmware_package.tgz >>"${target}"
   fi
 }
 
@@ -265,23 +299,22 @@
     return
   fi
 
-  # Grab firmware image from the autoupdate shellball.
+  # Grab firmware image from the autoupdate bundle (shellball).
   local rootfs_dir=$(make_temp_dir)
   mount_image_partition ${image} 3 ${rootfs_dir}
   # Force unmount of the rootfs on function exit as it is needed later.
   trap "sudo umount -d ${rootfs_dir}" RETURN
-
+  local firmware_bundle="${rootfs_dir}/usr/sbin/chromeos-firmwareupdate"
   local shellball_dir=$(make_temp_dir)
-  # get_firmwarebin_from_shellball can fail if the image has no
-  # firmware update.
-  get_firmwarebin_from_shellball \
-    ${rootfs_dir}/usr/sbin/chromeos-firmwareupdate ${shellball_dir} || \
+
+  # extract_firmware_bundle can fail if the image has no firmware update.
+  extract_firmware_bundle "${firmware_bundle}" "${shellball_dir}" ||
     { echo "Didn't find a firmware update. Not signing firmware."
     return; }
   echo "Found a valid firmware update shellball."
 
   temp_outfd=$(make_temp_file)
-  # Replace the root key in the GBB
+  # Replace the root key in the GBB.
   # TODO(gauravsh): Remove when we lock down the R/O portion of firmware.
   if [ -e "${KEY_DIR}/hwid" ]; then
     # Only update the hwid if we see one in the key directory.
@@ -296,7 +329,7 @@
       --recoverykey=${KEY_DIR}/recovery_key.vbpubk \
       ${shellball_dir}/bios.bin ${temp_outfd}
   fi
-  # Resign the firmware with new keys
+  # Resign the firmware with new keys.
   ${SCRIPT_DIR}/resign_firmwarefd.sh ${temp_outfd} ${shellball_dir}/bios.bin \
     ${KEY_DIR}/firmware_data_key.vbprivk \
     ${KEY_DIR}/firmware.keyblock \
@@ -304,24 +337,15 @@
     ${KEY_DIR}/dev_firmware.keyblock \
     ${KEY_DIR}/kernel_subkey.vbpubk \
     ${FIRMWARE_VERSION}
+  local signer_notes="${shellball_dir}/VERSION.signer"
+  echo "" >"$signer_notes"
+  echo "Signed with keyset in $(readlink -f "${KEY_DIR}") ." >>"$signer_notes"
 
-  # Replace MD5 checksum in the firmware update payload
-  newfd_checksum=$(md5sum ${shellball_dir}/bios.bin | cut -f 1 -d ' ')
-  temp_version=$(make_temp_file)
-  cat ${shellball_dir}/VERSION |
-  sed -e "s#\(.*\)\ \(.*bios.bin.*\)#${newfd_checksum}\ \2#" > ${temp_version}
-  sudo cp ${temp_version} ${shellball_dir}/VERSION
-
-  # Re-generate firmware_update.tgz and copy over encoded archive in
-  # the original shell ball.
-  new_fwblob=$(make_temp_file)
-  tar zcf - -C ${shellball_dir} . | \
-    uuencode firmware_package.tgz > ${new_fwblob}
   new_shellball=$(make_temp_file)
-  cat ${rootfs_dir}/usr/sbin/chromeos-firmwareupdate | \
-    sed -e '/^begin .*firmware_package/,/end/D' | \
-    cat - ${new_fwblob} >${new_shellball}
-  sudo cp ${new_shellball} ${rootfs_dir}/usr/sbin/chromeos-firmwareupdate
+  cp -f "${firmware_bundle}" "${new_shellball}"
+  repack_firmware_bundle "${shellball_dir}" "${new_shellball}"
+  sudo cp -f "${new_shellball}" "${firmware_bundle}"
+  sudo chmod a+rx "${firmware_bundle}"
   echo "Re-signed firmware AU payload in $image"
 }
 
@@ -333,7 +357,7 @@
   local hash_image=$(make_temp_file)
   local type=""
 
-  # First, perform RootFS verification
+  # First, perform RootFS verification.
   echo "Verifying RootFS hash..."
   local new_kernel_config=$(calculate_rootfs_hash "${rootfs_image}" \
     "${kernel_config}" "${hash_image}")