Last active
November 8, 2023 12:58
-
-
Save jow-/446448dc2b681a7c63de20d31fea0bd5 to your computer and use it in GitHub Desktop.
Script to perform a verified firmware download.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Script to perform verified file downloads. | |
# Exit codes: | |
# 0 - File downloaded successfully and verified | |
# 1 - Failed to download requested file | |
# 2 - Failed to download sha256sums file | |
# 3 - Failed to download sha256sums.gpg file | |
# 4 - GnuPG is available but fails to verify the signature (missing pubkey, file integrity error, ...) | |
# 5 - The checksums do not match | |
# 6 - Unable to copy the requested file to its final destination | |
# 254 - The script got interrupted by a signal | |
# 255 - A suitable download or checksum utility is missing | |
[ -n "$1" ] || { | |
echo "Usage: $0 <url>" >&2 | |
exit 1 | |
} | |
finish() { | |
[ -e "/tmp/verify.$$" ] && { | |
echo "Cleaning up." | |
rm -r "/tmp/verify.$$" | |
} | |
exit $1 | |
} | |
trap "finish 254" INT TERM | |
destdir="$(pwd)" | |
image_url="$1" | |
image_file="${image_url##*/}" | |
sha256_url="${image_url%/*}/sha256sums" | |
gpgsig_url="${image_url%/*}/sha256sums.gpg" | |
keyserver_url="hkp://pool.sks-keyservers.net" | |
# Find a suitable download utility | |
if which curl >/dev/null; then | |
download() { curl --progress-bar -o "$1" "$2"; } | |
elif which wget >/dev/null; then | |
download() { wget -O "$1" "$2"; } | |
elif which fetch >/dev/null; then | |
download() { fetch -o "$1" "$2"; } | |
else | |
echo "No suitable download utility found, cannot download files!" >&2 | |
finish 255 | |
fi | |
# Find a suitable checksum utility | |
if which sha256sum >/dev/null; then | |
checksum() { sha256sum -c --ignore-missing "sha256sums"; } | |
elif which shasum >/dev/null; then | |
checksum() { | |
local sum="$(shasum -a 256 "$image_file")"; | |
grep -xF "${sum%% *} *$image_file" "sha256sums"; | |
} | |
else | |
echo "No SHA256 checksum executable installed, cannot verify checksums!" >&2 | |
finish 255 | |
fi | |
# Check for gpg availability | |
if which gpg >/dev/null; then | |
runpgp() { gpg "$@"; } | |
else | |
runpgp() { | |
echo "WARNING: No GnuPG installed, cannot verify digital signature!" >&2 | |
return 0 | |
} | |
fi | |
mkdir -p "/tmp/verify.$$" | |
cd "/tmp/verify.$$" | |
echo "" | |
echo "1) Downloading image file" | |
echo "=========================" | |
download "$image_file" "$image_url" || { | |
echo "Failed to download image file!" >&2 | |
finish 1 | |
} | |
echo "" | |
echo "2) Downloading checksum file" | |
echo "============================" | |
download "sha256sums" "$sha256_url" || { | |
echo "Failed to download checksum file!" >&2 | |
finish 2 | |
} | |
echo "" | |
echo "3) Downloading the GPG signature" | |
echo "================================" | |
download "sha256sums.gpg" "$gpgsig_url" || { | |
echo "Failed to download GPG signature!" >&2 | |
finish 3 | |
} | |
echo "" | |
echo "4) Verifying GPG signature" | |
echo "==========================" | |
missing_key=$(runpgp --status-fd 1 --with-fingerprint --verify \ | |
"sha256sums.gpg" "sha256sums" 2>/dev/null | sed -ne 's!^.* NO_PUBKEY !!p') | |
if [ -n "$missing_key" ]; then | |
echo "The signature was signed by a public key with the id $missing_key" >&2 | |
echo "which is not present on this system." >&2 | |
echo "" >&2 | |
echo "Provide a public keyserver url below or press enter to accept the" >&2 | |
echo "default suggestion. Hit Ctrl-C to abort the operation." >&2 | |
echo "" >&2 | |
while true; do | |
printf "Keyserver to use? [$keyserver_url] > " | |
read url; case "${url:-$keyserver_url}" in | |
hkp://*) | |
gpg --keyserver "${url:-$keyserver_url}" --recv-keys "$missing_key" || { | |
echo "Failed to download public key." >&2 | |
finish 7 | |
} | |
break | |
;; | |
*) | |
echo "Expecting a key server url in the form 'hkp://hostname'." >&2 | |
;; | |
esac | |
done | |
fi | |
runpgp --with-fingerprint --verify "sha256sums.gpg" "sha256sums" || { | |
echo "Failed to verify checksum file with GPG signature!" >&2 | |
finish 4 | |
} | |
echo "" | |
echo "5) Verifying SHA256 checksum" | |
echo "============================" | |
checksum || { | |
echo "Checksums do not match!" >&2 | |
finish 5 | |
} | |
cp "$image_file" "$destdir/$image_file" || { | |
echo "Failed to write '$destdir/$image_file'" >&2 | |
finish 6 | |
} | |
echo "" | |
echo "Verficiation done!" | |
echo "==================" | |
echo "Firmware image placed in '$destdir/$image_file'." | |
echo "" | |
finish 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment