blob: 9d7fd87fdb68ad22956e6e7dcf9fe7fadb4452ed [file] [log] [blame]
#!/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 "$@"