mirror of
https://github.com/raspberrypi/rpi-eeprom.git
synced 2026-01-20 12:53:34 +08:00
181 lines
5.1 KiB
Bash
Executable File
181 lines
5.1 KiB
Bash
Executable File
#!/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
|
|
set -u
|
|
|
|
OPENSSL=${OPENSSL:-openssl}
|
|
KEY=""
|
|
SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH:-""}
|
|
HSM_WRAPPER=""
|
|
|
|
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 a bootloader EEPROM image
|
|
for secure-boot because the signed data is the 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
|
|
-H The name of the HSM wrapper script to invoke - default ""
|
|
|
|
RSA signing:
|
|
If a private key in PEM format or a PKCS#11 URI 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 2048-bit 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
|
|
|
|
# Generate RSA signature for the EEPROM config file and delegate
|
|
# the signing process to a HSM wrapper script instead of using the private key directly.
|
|
rpi-eeprom-digest -H hsm-wrapper -i bootconf.txt -o bootconf.sig
|
|
|
|
# Similarly, but specifying the key with a PKCS#11 URI
|
|
# (Deprecated - use HSM wrapper instead)
|
|
rpi-eeprom-digest -k pkcs11:token=deadbeef;object=bl-key;type=private;pin-value=1234 -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
|
|
if [ -n "${SOURCE_DATE_EPOCH}" ] ; then
|
|
echo "ts: ${SOURCE_DATE_EPOCH}" >> "${OUTPUT}"
|
|
else
|
|
echo "ts: $(date -u +%s)" >> "${OUTPUT}"
|
|
fi
|
|
|
|
if [ -n "${HSM_WRAPPER}" ]; then
|
|
echo "rsa2048: $("${HSM_WRAPPER}" -a rsa2048-sha256 "${IMAGE}")" >> "${OUTPUT}"
|
|
elif [ -n "${KEY}" ]; then
|
|
"${OPENSSL}" dgst ${ENGINE_OPTS} -sign "${KEY}" -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 ${ENGINE_OPTS} -verify "${KEY}" -signature "${TMP_DIR}/sig.bin" "${IMAGE}" || die "${IMAGE} not verified"
|
|
}
|
|
|
|
OUTPUT=""
|
|
VERIFY=0
|
|
while getopts i:H:k:ho:v: option; do
|
|
case "${option}" in
|
|
i) IMAGE="${OPTARG}"
|
|
;;
|
|
k) KEY="${OPTARG}"
|
|
;;
|
|
H) HSM_WRAPPER="${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"
|
|
[ "${VERIFY}" != 1 ] || [ -n "${KEY}" ] || die "Option -v also requires passing public key via -k"
|
|
|
|
if [ -n "${KEY}" ] ; then
|
|
if [ -f "${KEY}" ] ; then
|
|
ENGINE_OPTS=
|
|
elif echo "${KEY}" | grep -q "^pkcs11:" ; then
|
|
ENGINE_OPTS="-engine pkcs11 -keyform engine"
|
|
else
|
|
die "RSA key \"${KEY}\" not found"
|
|
fi
|
|
fi
|
|
|
|
if [ "${VERIFY}" = 1 ]; then
|
|
verifySig "${SIGNATURE}"
|
|
else
|
|
[ -n "${OUTPUT}" ] || usage
|
|
writeSig
|
|
fi
|
|
|