Add script for signing PSP Verstage

This script will sign the psp_veratage.bin file and modify the fields as required.

BUG=b:166095736
TEST=create verstage signed with test key.

Change-Id: I234d7902f950a60a816dd5f4d46d3d5afd105489
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/vboot_reference/+/2390825
Tested-by: Martin Roth <martinroth@google.com>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Martin Roth <martinroth@google.com>
diff --git a/scripts/image_signing/sign_psp_verstagebl_fw.sh b/scripts/image_signing/sign_psp_verstagebl_fw.sh
new file mode 100755
index 0000000..9d7fd87
--- /dev/null
+++ b/scripts/image_signing/sign_psp_verstagebl_fw.sh
@@ -0,0 +1,162 @@
+#!/bin/bash
+# Copyright 2020 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.
+
+# Abort on error.
+set -e -o pipefail
+
+# Determine script directory.
+SCRIPT_DIR=$(dirname "$0")
+
+# Load common constants and variables.
+. "${SCRIPT_DIR}/common.sh"
+
+usage() {
+  cat <<EOF
+Usage: ${PROG} <input_firmware> <key_dir> <output_firmware>
+
+Signs <input_firmware> with keys in <key_dir>. Outputs signed firmware to
+<output_firmware>.  The <input_firmware> and <output_firmware> paths should not
+be the same.
+
+For detail, reference the AMD documentation titled "OEM PSP VERSTAGE
+BL FW Signing Key Pair Generation and Certificate Request Process"
+http://dr/corp/drive/folders/1ySJyDgbH73W1lqrhxMvM9UYl5TtJt_mw
+
+EOF
+
+  if [[ $# -ne 0 ]]; then
+    echo "$*" >&2
+    exit 1
+  else
+    exit 0
+  fi
+}
+
+# Check the arguments to make sure we have the correct number.
+if [[ $# -lt 3 ]]; then
+  usage "Error: Too few arguments"
+fi
+if [[ $# -gt 3 ]]; then
+  usage "Error: Too many arguments"
+fi
+
+read_byte() {
+  local position="$1"
+  local file="$2"
+
+  dd if="${file}" bs=1 count=1 skip="$((16#${position}))" status=none |
+    hexdump -e '/1 "%X"'
+}
+
+write_byte() {
+  local position="$1"
+  local value="$2"
+  local file="$3"
+
+  printf "\x${value}" |
+    dd of="${file}" bs=1 count=1 seek="${position}" conv=notrunc status=none
+}
+
+read_dword_le() {
+  local position
+  position=$(printf -- "%d" "$1")
+  local file="$2"
+  read_byte "${position}" "${file}"
+  read_byte $((position + 1)) "${file}"
+  read_byte $((position + 2)) "${file}"
+  read_byte $((position + 3))
+}
+
+write_dword_le() {
+  local position
+  position=$(printf -- "%d" "$1")
+  local value
+  value=$(printf -- "%08x" "$2")
+  local file="$3"
+
+  write_byte "${position}" "${value:6:2}" "$file"
+  write_byte $((position + 1)) "${value:4:2}" "$file"
+  write_byte $((position + 2)) "${value:2:2}" "$file"
+  write_byte $((position + 3)) "${value:0:2}" "$file"
+}
+
+filesize() {
+  local file="$1"
+  stat -c %s -- "${file}"
+}
+
+copy_key_id() {
+  local input_file="$1"
+  local input_offset
+  input_offset=$(printf -- "%d" "$2")
+  local output_file="$3"
+  local output_offset
+  output_offset=$(printf -- "%d" "$4")
+
+  local id_size=16
+
+  dd if="${input_file}" skip="${input_offset}" \
+    of="${output_file}" seek="${output_offset}" \
+    bs=1 count="${id_size}" conv=notrunc status=none
+}
+
+KEYNAME=psp_verstagebl_fw_signing
+
+main() {
+  local input_firmware="$1"
+  local key_dir="$2"
+  local output_firmware="$3"
+
+  if [[ "${input_firmware}" == "${output_firmware}" ]]; then
+    usage "Error: input and output files must not be the same"
+  fi
+
+  local amd_key="${key_dir}/${KEYNAME}.stkn"
+  local hashtype
+  local sig_size
+  local temp_sig
+  local temp_fw
+  local fw_size
+  local image_size
+
+  temp_sig=$(make_temp_file)
+  temp_fw=$(make_temp_file)
+
+  # TODO: Differentiate sizes for Picasso vs later chips
+  hashtype="-sha256"
+  sig_size=256
+
+  fw_size="$(($(filesize "${input_firmware}")))"
+  fw_minus_header_size="$((fw_size - 256))"
+  image_size="$((fw_size + sig_size))"
+
+  cp "${input_firmware}" "${temp_fw}"
+
+  # Refer to Appendix D in the AMD BIOS Signing Key Pair and Certification
+  # Process document for what needs to be changed in the psp_verstage header.
+  write_dword_le "0x14" "${fw_minus_header_size}" "${temp_fw}"
+  write_dword_le "0x30" "1" "${temp_fw}"
+  write_dword_le "0x6c" "${image_size}" "${temp_fw}"
+
+  # TODO: Need the PSP verstage signing token from AMD to verify.
+  copy_key_id "${amd_key}" "0x04" "${temp_fw}" "0x38"
+
+  local cmd=(
+    openssl dgst
+    "${hashtype}"
+    -sign "${key_dir}/${KEYNAME}.pem"
+    -sigopt rsa_padding_mode:pss
+    -sigopt rsa_pss_saltlen:-1
+    -out "${temp_sig}"
+  )
+
+  "${cmd[@]}" "${temp_fw}"
+
+  cat "${temp_fw}" "${temp_sig}" >"${output_firmware}"
+
+  echo "Complete"
+}
+
+main "$@"