aboutsummaryrefslogtreecommitdiff
path: root/contrib/verifybinaries/verify.sh
blob: e0266bf08afb64401212a8f553a386a456e81adb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#!/bin/bash
# Copyright (c) 2016 The Bitcoin Core developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.

###   This script attempts to download the signature file SHA256SUMS.asc from
###   bitcoincore.org and bitcoin.org and compares them.
###   It first checks if the signature passes, and then downloads the files specified in
###   the file, and checks if the hashes of these files match those that are specified
###   in the signature file.
###   The script returns 0 if everything passes the checks. It returns 1 if either the
###   signature check or the hash check doesn't pass. If an error occurs the return value is 2

function clean_up {
   for file in $*
   do
      rm "$file" 2> /dev/null
   done
}

WORKINGDIR="/tmp/bitcoin_verify_binaries"
TMPFILE="hashes.tmp"

SIGNATUREFILENAME="SHA256SUMS.asc"
RCSUBDIR="test"
HOST1="https://bitcoincore.org"
HOST2="https://bitcoin.org"
BASEDIR="/bin/"
VERSIONPREFIX="bitcoin-core-"
RCVERSIONSTRING="rc"

if [ ! -d "$WORKINGDIR" ]; then
   mkdir "$WORKINGDIR"
fi

cd "$WORKINGDIR" || exit 1

#test if a version number has been passed as an argument
if [ -n "$1" ]; then
   #let's also check if the version number includes the prefix 'bitcoin-',
   #  and add this prefix if it doesn't
   if [[ $1 == "$VERSIONPREFIX"* ]]; then
      VERSION="$1"
   else
      VERSION="$VERSIONPREFIX$1"
   fi

   STRIPPEDLAST="${VERSION%-*}"

   #now let's see if the version string contains "rc" or a platform name (e.g. "osx")
   if [[ "$STRIPPEDLAST-" == "$VERSIONPREFIX" ]]; then
      BASEDIR="$BASEDIR$VERSION/"
   else
      # let's examine the last part to see if it's rc and/or platform name
      STRIPPEDNEXTTOLAST="${STRIPPEDLAST%-*}"
      if [[ "$STRIPPEDNEXTTOLAST-" == "$VERSIONPREFIX" ]]; then

         LASTSUFFIX="${VERSION##*-}"
         VERSION="$STRIPPEDLAST"

         if [[ $LASTSUFFIX == *"$RCVERSIONSTRING"* ]]; then
            RCVERSION="$LASTSUFFIX"
         else
            PLATFORM="$LASTSUFFIX"
         fi

      else
         RCVERSION="${STRIPPEDLAST##*-}"
         PLATFORM="${VERSION##*-}"

         VERSION="$STRIPPEDNEXTTOLAST"
      fi

      BASEDIR="$BASEDIR$VERSION/"
      if [[ $RCVERSION == *"$RCVERSIONSTRING"* ]]; then
         BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSION/"
      fi
   fi
else
   echo "Error: need to specify a version on the command line"
   exit 2
fi

#first we fetch the file containing the signature
WGETOUT=$(wget -N "$HOST1$BASEDIR$SIGNATUREFILENAME" 2>&1)

#and then see if wget completed successfully
if [ $? -ne 0 ]; then
   echo "Error: couldn't fetch signature file. Have you specified the version number in the following format?"
   echo "[$VERSIONPREFIX]<version>-[$RCVERSIONSTRING[0-9]] (example: ${VERSIONPREFIX}0.10.4-${RCVERSIONSTRING}1)"
   echo "wget output:"
   echo "$WGETOUT"|sed 's/^/\t/g'
   exit 2
fi

WGETOUT=$(wget -N -O "$SIGNATUREFILENAME.2" "$HOST2$BASEDIR$SIGNATUREFILENAME" 2>&1)
if [ $? -ne 0 ]; then
   echo "bitcoin.org failed to provide signature file, but bitcoincore.org did?"
   echo "wget output:"
   echo "$WGETOUT"|sed 's/^/\t/g'
   clean_up $SIGNATUREFILENAME
   exit 3
fi

SIGFILEDIFFS="$(diff $SIGNATUREFILENAME $SIGNATUREFILENAME.2)"
if [ "$SIGFILEDIFFS" != "" ]; then
   echo "bitcoin.org and bitcoincore.org signature files were not equal?"
   clean_up $SIGNATUREFILENAME $SIGNATUREFILENAME.2
   exit 4
fi

#then we check it
GPGOUT=$(gpg --yes --decrypt --output "$TMPFILE" "$SIGNATUREFILENAME" 2>&1)

#return value 0: good signature
#return value 1: bad signature
#return value 2: gpg error

RET="$?"
if [ $RET -ne 0 ]; then
   if [ $RET -eq 1 ]; then
      #and notify the user if it's bad
      echo "Bad signature."
   elif [ $RET -eq 2 ]; then
      #or if a gpg error has occurred
      echo "gpg error. Do you have the Bitcoin Core binary release signing key installed?"
   fi

   echo "gpg output:"
   echo "$GPGOUT"|sed 's/^/\t/g'
   clean_up $SIGNATUREFILENAME $SIGNATUREFILENAME.2 $TMPFILE
   exit "$RET"
fi

if [ -n "$PLATFORM" ]; then
   grep $PLATFORM $TMPFILE > "$TMPFILE-plat"
   TMPFILESIZE=$(stat -c%s "$TMPFILE-plat")
   if [ $TMPFILESIZE -eq 0 ]; then
      echo "error: no files matched the platform specified" && exit 3
   fi
   mv "$TMPFILE-plat" $TMPFILE
fi

#here we extract the filenames from the signature file
FILES=$(awk '{print $2}' "$TMPFILE")

#and download these one by one
for file in $FILES
do
   echo "Downloading $file"
   wget --quiet -N "$HOST1$BASEDIR$file"
done

#check hashes
DIFF=$(diff <(sha256sum $FILES) "$TMPFILE")

if [ $? -eq 1 ]; then
   echo "Hashes don't match."
   echo "Offending files:"
   echo "$DIFF"|grep "^<"|awk '{print "\t"$3}'
   exit 1
elif [ $? -gt 1 ]; then
   echo "Error executing 'diff'"
   exit 2
fi

if [ -n "$2" ]; then
   echo "Clean up the binaries"
   clean_up $FILES $SIGNATUREFILENAME $SIGNATUREFILENAME.2 $TMPFILE
else
   echo "Keep the binaries in $WORKINGDIR"
   clean_up $TMPFILE
fi

echo -e "Verified hashes of \n$FILES"

exit 0