Update file verification / signing documentation.
[web.git] / scripts / download.sh
1 #!/usr/bin/env bash
2 # Script to perform verified file downloads.
3 # Exit codes:
4 # 0 - File downloaded successfully and verified
5 # 1 - Failed to download requested file
6 # 2 - Failed to download sha256sums file
7 # 3 - Failed to download sha256sums.gpg file
8 # 4 - GnuPG is available but fails to verify the signature (missing pubkey, file integrity error, ...)
9 # 5 - The checksums do not match
10 # 6 - Unable to copy the requested file to its final destination
11 # 254 - The script got interrupted by a signal
12 # 255 - A suitable download or checksum utility is missing
13
14 [ -n "$1" ] || {
15 echo "Usage: $0 <url>" >&2
16 exit 1
17 }
18
19 finish() {
20 [ -e "/tmp/verify.$$" ] && {
21 echo "Cleaning up."
22 rm -r "/tmp/verify.$$"
23 }
24 exit $1
25 }
26
27 trap "finish 254" INT TERM
28
29 destdir="$(pwd)"
30 image_url="$1"
31 image_file="${image_url##*/}"
32 sha256_url="${image_url%/*}/sha256sums"
33 gpgsig_url="${image_url%/*}/sha256sums.gpg"
34 keyserver_url="hkp://pool.sks-keyservers.net"
35
36 # Find a suitable download utility
37 if which curl >/dev/null; then
38 download() { curl --progress-bar -o "$1" "$2"; }
39 elif which wget >/dev/null; then
40 download() { wget -O "$1" "$2"; }
41 elif which fetch >/dev/null; then
42 download() { fetch -o "$1" "$2"; }
43 else
44 echo "No suitable download utility found, cannot download files!" >&2
45 finish 255
46 fi
47
48 # Find a suitable checksum utility
49 if which sha256sum >/dev/null; then
50 checksum() { sha256sum -c --ignore-missing "sha256sums"; }
51 elif which shasum >/dev/null; then
52 checksum() {
53 local sum="$(shasum -a 256 "$image_file")";
54 grep -xF "${sum%% *} *$image_file" "sha256sums";
55 }
56 else
57 echo "No SHA256 checksum executable installed, cannot verify checksums!" >&2
58 finish 255
59 fi
60
61 # Check for gpg availability
62 if which gpg >/dev/null; then
63 runpgp() { gpg "$@"; }
64 else
65 runpgp() {
66 echo "WARNING: No GnuPG installed, cannot verify digital signature!" >&2
67 return 0
68 }
69 fi
70
71 mkdir -p "/tmp/verify.$$"
72 cd "/tmp/verify.$$"
73
74 echo ""
75 echo "1) Downloading image file"
76 echo "========================="
77 download "$image_file" "$image_url" || {
78 echo "Failed to download image file!" >&2
79 finish 1
80 }
81
82 echo ""
83 echo "2) Downloading checksum file"
84 echo "============================"
85 download "sha256sums" "$sha256_url" || {
86 echo "Failed to download checksum file!" >&2
87 finish 2
88 }
89
90 echo ""
91 echo "3) Downloading the GPG signature"
92 echo "================================"
93 download "sha256sums.gpg" "$gpgsig_url" || {
94 echo "Failed to download GPG signature!" >&2
95 finish 3
96 }
97
98 echo ""
99 echo "4) Verifying GPG signature"
100 echo "=========================="
101 missing_key=$(runpgp --status-fd 1 --with-fingerprint --verify \
102 "sha256sums.gpg" "sha256sums" 2>/dev/null | sed -ne 's!^.* NO_PUBKEY !!p')
103
104 if [ -n "$missing_key" ]; then
105 echo "The signature was signed by a public key with the id $missing_key" >&2
106 echo "which is not present on this system." >&2
107 echo "" >&2
108
109 echo "Provide a public keyserver url below or press enter to accept the" >&2
110 echo "default suggestion. Hit Ctrl-C to abort the operation." >&2
111 echo "" >&2
112
113 while true; do
114 printf "Keyserver to use? [$keyserver_url] > "
115 read url; case "${url:-$keyserver_url}" in
116 hkp://*)
117 gpg --keyserver "${url:-$keyserver_url}" --recv-keys "$missing_key" || {
118 echo "Failed to download public key." >&2
119 finish 7
120 }
121 break
122 ;;
123 *)
124 echo "Expecting a key server url in the form 'hkp://hostname'." >&2
125 ;;
126 esac
127 done
128 fi
129
130 runpgp --with-fingerprint --verify "sha256sums.gpg" "sha256sums" || {
131 echo "Failed to verify checksum file with GPG signature!" >&2
132 finish 4
133 }
134
135 echo ""
136 echo "5) Verifying SHA256 checksum"
137 echo "============================"
138 checksum || {
139 echo "Checksums do not match!" >&2
140 finish 5
141 }
142
143 cp "$image_file" "$destdir/$image_file" || {
144 echo "Failed to write '$destdir/$image_file'" >&2
145 finish 6
146 }
147
148 echo ""
149 echo "Verification done!"
150 echo "=================="
151 echo "Firmware image placed in '$destdir/$image_file'."
152 echo ""
153
154 finish 0