1#!/usr/bin/env bash 2# Copyright (c) 2016-2019 The Bitcoin Core developers 3# Distributed under the MIT software license, see the accompanying 4# file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 6### This script attempts to download the signature file SHA256SUMS.asc from 7### bitcoincore.org and bitcoin.org and compares them. 8### It first checks if the signature passes, and then downloads the files specified in 9### the file, and checks if the hashes of these files match those that are specified 10### in the signature file. 11### The script returns 0 if everything passes the checks. It returns 1 if either the 12### signature check or the hash check doesn't pass. If an error occurs the return value is 2 13 14export LC_ALL=C 15function clean_up { 16 for file in "$@" 17 do 18 rm "$file" 2> /dev/null 19 done 20} 21 22WORKINGDIR="/tmp/bitcoin_verify_binaries" 23TMPFILE="hashes.tmp" 24 25SIGNATUREFILENAME="SHA256SUMS.asc" 26RCSUBDIR="test" 27HOST1="https://bitcoincore.org" 28HOST2="https://bitcoin.org" 29BASEDIR="/bin/" 30VERSIONPREFIX="bitcoin-core-" 31RCVERSIONSTRING="rc" 32 33if [ ! -d "$WORKINGDIR" ]; then 34 mkdir "$WORKINGDIR" 35fi 36 37cd "$WORKINGDIR" || exit 1 38 39#test if a version number has been passed as an argument 40if [ -n "$1" ]; then 41 #let's also check if the version number includes the prefix 'bitcoin-', 42 # and add this prefix if it doesn't 43 if [[ $1 == "$VERSIONPREFIX"* ]]; then 44 VERSION="$1" 45 else 46 VERSION="$VERSIONPREFIX$1" 47 fi 48 49 STRIPPEDLAST="${VERSION%-*}" 50 51 #now let's see if the version string contains "rc" or a platform name (e.g. "osx") 52 if [[ "$STRIPPEDLAST-" == "$VERSIONPREFIX" ]]; then 53 BASEDIR="$BASEDIR$VERSION/" 54 else 55 # let's examine the last part to see if it's rc and/or platform name 56 STRIPPEDNEXTTOLAST="${STRIPPEDLAST%-*}" 57 if [[ "$STRIPPEDNEXTTOLAST-" == "$VERSIONPREFIX" ]]; then 58 59 LASTSUFFIX="${VERSION##*-}" 60 VERSION="$STRIPPEDLAST" 61 62 if [[ $LASTSUFFIX == *"$RCVERSIONSTRING"* ]]; then 63 RCVERSION="$LASTSUFFIX" 64 else 65 PLATFORM="$LASTSUFFIX" 66 fi 67 68 else 69 RCVERSION="${STRIPPEDLAST##*-}" 70 PLATFORM="${VERSION##*-}" 71 72 VERSION="$STRIPPEDNEXTTOLAST" 73 fi 74 75 BASEDIR="$BASEDIR$VERSION/" 76 if [[ $RCVERSION == *"$RCVERSIONSTRING"* ]]; then 77 BASEDIR="$BASEDIR$RCSUBDIR.$RCVERSION/" 78 fi 79 fi 80else 81 echo "Error: need to specify a version on the command line" 82 exit 2 83fi 84 85if ! WGETOUT=$(wget -N "$HOST1$BASEDIR$SIGNATUREFILENAME" 2>&1); then 86 echo "Error: couldn't fetch signature file. Have you specified the version number in the following format?" 87 # shellcheck disable=SC1087 88 echo "[$VERSIONPREFIX]<version>-[$RCVERSIONSTRING[0-9]] (example: ${VERSIONPREFIX}0.10.4-${RCVERSIONSTRING}1)" 89 echo "wget output:" 90 # shellcheck disable=SC2001 91 echo "$WGETOUT"|sed 's/^/\t/g' 92 exit 2 93fi 94 95if ! WGETOUT=$(wget -N -O "$SIGNATUREFILENAME.2" "$HOST2$BASEDIR$SIGNATUREFILENAME" 2>&1); then 96 echo "bitcoin.org failed to provide signature file, but bitcoincore.org did?" 97 echo "wget output:" 98 # shellcheck disable=SC2001 99 echo "$WGETOUT"|sed 's/^/\t/g' 100 clean_up $SIGNATUREFILENAME 101 exit 3 102fi 103 104SIGFILEDIFFS="$(diff $SIGNATUREFILENAME $SIGNATUREFILENAME.2)" 105if [ "$SIGFILEDIFFS" != "" ]; then 106 echo "bitcoin.org and bitcoincore.org signature files were not equal?" 107 clean_up $SIGNATUREFILENAME $SIGNATUREFILENAME.2 108 exit 4 109fi 110 111#then we check it 112GPGOUT=$(gpg --yes --decrypt --output "$TMPFILE" "$SIGNATUREFILENAME" 2>&1) 113 114#return value 0: good signature 115#return value 1: bad signature 116#return value 2: gpg error 117 118RET="$?" 119if [ $RET -ne 0 ]; then 120 if [ $RET -eq 1 ]; then 121 #and notify the user if it's bad 122 echo "Bad signature." 123 elif [ $RET -eq 2 ]; then 124 #or if a gpg error has occurred 125 echo "gpg error. Do you have the Bitcoin Core binary release signing key installed?" 126 fi 127 128 echo "gpg output:" 129 # shellcheck disable=SC2001 130 echo "$GPGOUT"|sed 's/^/\t/g' 131 clean_up $SIGNATUREFILENAME $SIGNATUREFILENAME.2 $TMPFILE 132 exit "$RET" 133fi 134 135if [ -n "$PLATFORM" ]; then 136 grep $PLATFORM $TMPFILE > "$TMPFILE-plat" 137 TMPFILESIZE=$(stat -c%s "$TMPFILE-plat") 138 if [ $TMPFILESIZE -eq 0 ]; then 139 echo "error: no files matched the platform specified" && exit 3 140 fi 141 mv "$TMPFILE-plat" $TMPFILE 142fi 143 144#here we extract the filenames from the signature file 145FILES=$(awk '{print $2}' "$TMPFILE") 146 147#and download these one by one 148for file in $FILES 149do 150 echo "Downloading $file" 151 wget --quiet -N "$HOST1$BASEDIR$file" 152done 153 154#check hashes 155DIFF=$(diff <(sha256sum $FILES) "$TMPFILE") 156 157if [ $? -eq 1 ]; then 158 echo "Hashes don't match." 159 echo "Offending files:" 160 echo "$DIFF"|grep "^<"|awk '{print "\t"$3}' 161 exit 1 162elif [ $? -gt 1 ]; then 163 echo "Error executing 'diff'" 164 exit 2 165fi 166 167if [ -n "$2" ]; then 168 echo "Clean up the binaries" 169 clean_up $FILES $SIGNATUREFILENAME $SIGNATUREFILENAME.2 $TMPFILE 170else 171 echo "Keep the binaries in $WORKINGDIR" 172 clean_up $TMPFILE 173fi 174 175echo -e "Verified hashes of \n$FILES" 176 177exit 0 178