#!/bin/sh

# Helper script to generate .sig files for use with the Raspberry Pi bootloader.

# This has been implemented in a separate script in order to have avoid having
# a hard dependency on OpenSSL.

set -e

OPENSSL=${OPENSSL:-openssl}

die() {
   echo "$@" >&2
   exit 1
}

TMP_DIR=""
cleanup() {
   if [ -d "${TMP_DIR}" ]; then
      rm -rf "${TMP_DIR}"
   fi
}

checkDependencies() {
   if ! command -v sha256sum > /dev/null; then
      die "sha256sum not found. Try installing the coreutilities package."
   fi

   if [ -n "${KEY}" ] || [ "${VERIFY}" = 1 ]; then
       if ! command -v openssl > /dev/null; then
          die "openssl not found. Try installing the openssl package."
       fi

       if ! command -v xxd > /dev/null; then
          die "xxd not found. Try installing the xxd package."
       fi
   fi
}

usage() {
cat <<EOF
rpi-eeprom-digest [-k RSA_KEY] -i IMAGE -o OUTPUT

Tool to generate .sig files containing the SHA256 digest and optional
RSA signature. Typically this tool is used by rpi-eeprom-update to
generate a hash to guard against file-system corruption for EEPROM updates
OR for signing OS images (boot.img) for secure-boot.

This tool CANNOT be used directly to sign an bootloader EEPROM image
for secure-boot because the signed data is bootloader configuration file
rather than the entire flash image.
To create signed bootloader images please see
https://github.com/raspberrypi/usbboot/tree/master/secure-boot-recovery/README.md


Options:
   -i The source image e.g. boot.img
   -o The name of the digest/signature file.
   -k Optional RSA private key.

RSA signing
If a private key in PEM format is supplied then the RSA signature of the
sha256 digest is included in the .sig file. Currently, the bootloader only
supports sha256 digests signed with a 2048bit RSA key.
The bootloader only verifies RSA signatures in signed boot mode
and only for the EEPROM config file and the signed image.

Examples:

# Generate the normal sha256 hash to guard against file-system corruption
rpi-eeprom-digest -i pieeprom.bin -o pieeprom.sig
rpi-eeprom-digest -i vl805.bin -o vl805.sig

# Generate a signed OS ramdisk image for secure-boot
rpi-eeprom-digest -k private.pem -i boot.img -o boot.sig

# Generate RSA signature for the EEPROM config file
# As used by update-pieeprom.sh in usbboot/secure-boot-recovery
rpi-eeprom-digest -k private.pem -i bootconf.txt  -o bootconf.sig

# To verify the signature of an existing .sig file using the public key.
# N.B The key file must be the PUBLIC key in PEM format.
rpi-eeprom-digest -k public.pem -i boot.bin -v boot.sig

EOF
exit 0
}

writeSig() {
   TMP_DIR=$(mktemp -d)
   SIG_TMP="${TMP_DIR}/tmp.sig"
   sha256sum "${IMAGE}" | awk '{print $1}' > "${OUTPUT}"

   # Include the update-timestamp
   echo "ts: $(date -u +%s)" >> "${OUTPUT}"

   if [ -n "${KEY}" ]; then
      [ -f "${KEY}" ] || die "RSA private \"${KEY}\" not found"
      "${OPENSSL}" dgst -sign "${KEY}" -keyform PEM -sha256 -out "${SIG_TMP}" "${IMAGE}"
      echo "rsa2048: $(xxd -c 4096 -p < "${SIG_TMP}")" >> "${OUTPUT}"
   fi
}

verifySig() {
   TMP_DIR=$(mktemp -d)
   sig_file="${1}"
   [ -f "${sig_file}" ] || die "Signature file ${sig_file} not found"
   sig_hex="$(grep rsa2048 "${sig_file}" | cut -f 2 -d ' ')"
   [ -n "${sig_hex}" ] || die "No RSA signature in ${sig_file}"

   echo ${sig_hex} | xxd -c 4096 -p -r > "${TMP_DIR}/sig.bin"
   "${OPENSSL}" dgst -verify "${KEY}" -signature "${TMP_DIR}/sig.bin" "${IMAGE}" || die "${IMAGE} not verified"
}

OUTPUT=""
VERIFY=0
while getopts i:k:ho:v: option; do
   case "${option}" in
   i) IMAGE="${OPTARG}"
      ;;
   k) KEY="${OPTARG}"
      ;;
   o) OUTPUT="${OPTARG}"
      ;;
   v) SIGNATURE="${OPTARG}"
      VERIFY=1
      ;;
   h) usage
      ;;
   *) echo "Unknown argument \"${option}\""
      usage
      ;;
   esac
done

trap cleanup EXIT
checkDependencies

[ -n "${IMAGE}" ] || usage
[ -f "${IMAGE}" ] || die "Source image \"${IMAGE}\" not found"
if [ "${VERIFY}" = 1 ]; then
   verifySig "${SIGNATURE}"
else
   [ -n "${OUTPUT}" ] || usage
   writeSig
fi

