signing script: Resign just firmware body, not the entire section

The signing script extracted firmware body sections FW_MAIN_{A,B} and
resigned the whole section instead of just firmware body.

As a result, read-only firmware spends more time loading read-write
firmware from SPI flash.

Since vblock has firmware body size information, signing script should
retrieve it and use it to sign just firmware body.

This may reduce boot time for ~560ms, depending on firmware image size,
section size and SPI flash/bus throughput.

Signed-off-by: Che-Liang Chiou <clchiou@chromium.org>

BRANCH=snow,link
BUG=chrome-os-partner:13094
TEST=For Snow (or boards that use cros_bundle_firmware), check that
       after resigning, VBLOCK_{A,B} and FW_MAIN_{A,B} are unchanged
     For Alex and ZGB, check that old and new resign_firmwarefd.sh
       generates identical output

(Test for Snow; repeat for A and B)

dump_fmap -x image.bin VBLOCK_A FW_MAIN_A
mv VBLOCK_A VBLOCK_A.orig
mv FW_MAIN_A FW_MAIN_A.orig

resign_firmwarefd.sh image.bin image-resigned.bin \
  firmware_data_key.vbprivk \
  firmware.keyblock \
  dev_firmware_data_key.vbprivk \
  dev_firmware.keyblock \
  kernel_subkey.vbpubk

dump_fmap -x image-resigned.bin VBLOCK_A FW_MAIN_A
cmp VBLOCK_A.orig VBLOCK_A
cmp FW_MAIN_A.orig FW_MAIN_A

(Test for Alex and ZGB; repeat for old and new resign_firmwarefd.sh)

resign_firmwarefd.sh image.bin image-resigned-{old or new}.bin \
  firmware_data_key.vbprivk \
  firmware.keyblock \
  dev_firmware_data_key.vbprivk \
  dev_firmware.keyblock \
  kernel_subkey.vbpubk

cmp image-resigned-old.bin image-resigned-new.bin

Change-Id: Ie70b6c91614343ad9f991ae369a0f8e74ec213fe
Reviewed-on: https://gerrit.chromium.org/gerrit/31572
Commit-Ready: Che-Liang Chiou <clchiou@chromium.org>
Tested-by: Che-Liang Chiou <clchiou@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
diff --git a/scripts/image_signing/resign_firmwarefd.sh b/scripts/image_signing/resign_firmwarefd.sh
index 3626fa8..2dc261b 100755
--- a/scripts/image_signing/resign_firmwarefd.sh
+++ b/scripts/image_signing/resign_firmwarefd.sh
@@ -86,6 +86,38 @@
   [ "$hash1" = "$hash2" ]
 }
 
+# Extract firmware body section from SRC_FD and truncate it to its body size
+extract_firmware_image() {
+  local label="$1"
+  local root_key="$2"
+  local vblock_offset="$3"
+  local vblock_size="$4"
+  local vblock_image="$5"
+  local fw_offset="$6"
+  local fw_size="$7"
+  local fw_image="$8"
+  local fw_body_size=""
+
+  dd if="${SRC_FD}" of="${vblock_image}" skip="${vblock_offset}" bs=1 \
+    count="${vblock_size}" 2>/dev/null
+  dd if="${SRC_FD}" of="${fw_image}" skip="${fw_offset}" bs=1 \
+    count="${fw_size}" 2>/dev/null
+  fw_body_size="$(vbutil_firmware \
+    --verify "${vblock_image}" \
+    --signpubkey "${root_key}" \
+    --fv "${fw_image}" |
+    grep "Firmware body size:" |
+    sed 's/.*: *//')" || fw_body_size="${fw_size}"
+  if [ "${fw_body_size}" -gt "${fw_size}" ]; then
+    echo -n "Firmware ${label} body size exceeds its section: "
+    echo    "${fw_body_size} > ${fw_size}"
+    return 1
+  elif [ "${fw_body_size}" -lt "${fw_size}" ]; then
+    dd if="${SRC_FD}" of="${fw_image}" skip="${fw_offset}" bs=1 \
+      count="${fw_body_size}" 2>/dev/null
+  fi
+}
+
 if [ -z "$VERSION" ]; then
   VERSION=1
 fi
@@ -123,19 +155,23 @@
 temp_fwimage_a=$(make_temp_file)
 temp_fwimage_b=$(make_temp_file)
 temp_out_vb=$(make_temp_file)
+temp_root_key=$(make_temp_file)
+
+echo "Reading Root Key from GBB"
+gbb_utility -g --rootkey="$temp_root_key" "${SRC_FD}"
 
 echo "Extracting Firmware A and B"
-dd if="${SRC_FD}" of="${temp_fwimage_a}" skip="${fwA_offset}" bs=1 \
-  count="${fwA_size}" 2>/dev/null
-dd if="${SRC_FD}" of="${temp_fwimage_b}" skip="${fwB_offset}" bs=1 \
-  count="${fwB_size}" 2>/dev/null
+extract_firmware_image "A" "${temp_root_key}" \
+  "${fwA_vblock_offset}" "${fwA_vblock_size}" "${temp_out_vb}" \
+  "${fwA_offset}" "${fwA_size}" "${temp_fwimage_a}"
+extract_firmware_image "B" "${temp_root_key}" \
+  "${fwB_vblock_offset}" "${fwB_vblock_size}" "${temp_out_vb}" \
+  "${fwB_offset}" "${fwB_size}" "${temp_fwimage_b}"
 
 echo "Determining preamble flag from existing firmware"
 if [ -n "$PREAMBLE_FLAG" ]; then
   PREAMBLE_FLAG="--flag $PREAMBLE_FLAG"
 else
-  temp_root_key=$(make_temp_file)
-  gbb_utility -g --rootkey="$temp_root_key" "${SRC_FD}"
   dd if="${SRC_FD}" of="${temp_out_vb}" skip="${fwA_vblock_offset}" bs=1 \
     count="${fwA_vblock_size}" 2>/dev/null
   flag="$(vbutil_firmware \