github.com/decred/dcrlnd@v0.7.6/scripts/verify-install.sh (about) 1 #!/bin/bash 2 3 REPO=lightningnetwork 4 PROJECT=lnd 5 6 RELEASE_URL=https://github.com/$REPO/$PROJECT/releases 7 API_URL=https://api.github.com/repos/$REPO/$PROJECT/releases 8 MANIFEST_SELECTOR=". | select(.name | test(\"manifest-v.*(\\\\.txt)$\")) | .name" 9 SIGNATURE_SELECTOR=". | select(.name | test(\"manifest-.*(\\\\.sig)$\")) | .name" 10 HEADER_JSON="Accept: application/json" 11 HEADER_GH_JSON="Accept: application/vnd.github.v3+json" 12 13 # All keys that can sign lnd releases. The key must be downloadable/importable 14 # from the URL given after the space. 15 KEYS=() 16 KEYS+=("F4FC70F07310028424EFC20A8E4256593F177720 https://keybase.io/guggero/pgp_keys.asc") 17 KEYS+=("15E7ECF257098A4EF91655EB4CA7FE54A6213C91 https://keybase.io/carlakirkcohen/pgp_keys.asc") 18 KEYS+=("9C8D61868A7C492003B2744EE7D737B67FA592C7 https://keybase.io/bitconner/pgp_keys.asc") 19 KEYS+=("E4D85299674B2D31FAA1892E372CBD7633C61696 https://keybase.io/roasbeef/pgp_keys.asc") 20 KEYS+=("729E9D9D92C75A5FBFEEE057B5DD717BEF7CA5B1 https://keybase.io/wpaulino/pgp_keys.asc") 21 KEYS+=("7E81EF6B9989A9CC93884803118759E83439A9B1 https://keybase.io/eugene_/pgp_keys.asc") 22 KEYS+=("7AB3D7F5911708842796513415BAADA29DA20D26 https://keybase.io/halseth/pgp_keys.asc") 23 24 function check_command() { 25 echo -n "Checking if $1 is installed... " 26 if ! command -v "$1"; then 27 echo "ERROR: $1 is not installed or not in PATH!" 28 exit 1 29 fi 30 } 31 32 # By default we're picking up lnd and lncli from the system $PATH. 33 LND_BIN=$(which lnd) 34 LNCLI_BIN=$(which lncli) 35 36 # If exactly two parameters are specified, we expect the first one to be lnd and 37 # the second one to be lncli. 38 if [[ $# -eq 2 ]]; then 39 LND_BIN=$(realpath $1) 40 LNCLI_BIN=$(realpath $2) 41 42 # Make sure both files actually exist. 43 if [[ ! -f $LND_BIN ]]; then 44 echo "ERROR: $LND_BIN not found!" 45 exit 1 46 fi 47 if [[ ! -f $LNCLI_BIN ]]; then 48 echo "ERROR: $LNCLI_BIN not found!" 49 exit 1 50 fi 51 elif [[ $# -eq 0 ]]; then 52 # Make sure both binaries can be found and are executable. 53 check_command lnd 54 check_command lncli 55 else 56 echo "ERROR: invalid number of parameters!" 57 echo "Usage: verify-install.sh [lnd-binary lncli-binary]" 58 exit 1 59 fi 60 61 check_command curl 62 check_command jq 63 check_command gpg 64 65 LND_VERSION=$($LND_BIN --version | cut -d'=' -f2) 66 LNCLI_VERSION=$($LNCLI_BIN --version | cut -d'=' -f2) 67 68 # Make this script compatible with both linux and *nix. 69 SHA_CMD="sha256sum" 70 if ! command -v "$SHA_CMD"; then 71 if command -v "shasum"; then 72 SHA_CMD="shasum -a 256" 73 else 74 echo "ERROR: no SHA256 sum binary installed!" 75 exit 1 76 fi 77 fi 78 LND_SUM=$($SHA_CMD $LND_BIN | cut -d' ' -f1) 79 LNCLI_SUM=$($SHA_CMD $LNCLI_BIN | cut -d' ' -f1) 80 81 echo "Detected lnd $LND_BIN version $LND_VERSION with SHA256 sum $LND_SUM" 82 echo "Detected lncli $LNCLI_BIN version $LNCLI_VERSION with SHA256 sum $LNCLI_SUM" 83 84 # Make sure lnd and lncli are installed with the same version and is an actual 85 # version string. 86 if [[ "$LNCLI_VERSION" != "$LND_VERSION" ]]; then 87 echo "ERROR: Version $LNCLI_VERSION of lncli does not match $LND_VERSION of lnd!" 88 exit 1 89 fi 90 version_regex="^v[[:digit:]]+\.[[:digit:]]+\.[[:digit:]]" 91 if [[ ! "$LND_VERSION" =~ $version_regex ]]; then 92 echo "ERROR: Invalid version of lnd detected: $LND_VERSION" 93 exit 1 94 fi 95 96 # Make sure the hash was actually calculated by looking at its length. 97 if [[ ${#LND_SUM} -ne 64 ]]; then 98 echo "ERROR: Invalid hash for lnd: $LND_SUM!" 99 exit 1 100 fi 101 if [[ ${#LNCLI_SUM} -ne 64 ]]; then 102 echo "ERROR: Invalid hash for lncli: $LNCLI_SUM!" 103 exit 1 104 fi 105 106 # If we're inside the docker image, there should be a shasums.txt file in the 107 # root directory. If that's the case, we first want to make sure we still have 108 # the same hash as we did when building the image. 109 if [[ -f /shasums.txt ]]; then 110 if ! grep -q "$LND_SUM" /shasums.txt; then 111 echo "ERROR: Hash $LND_SUM for lnd not found in /shasums.txt: " 112 cat /shasums.txt 113 exit 1 114 fi 115 if ! grep -q "$LNCLI_SUM" /shasums.txt; then 116 echo "ERROR: Hash $LNCLI_SUM for lnd not found in /shasums.txt: " 117 cat /shasums.txt 118 exit 1 119 fi 120 fi 121 122 # Import all the signing keys. 123 for key in "${KEYS[@]}"; do 124 KEY_ID=$(echo $key | cut -d' ' -f1) 125 IMPORT_URL=$(echo $key | cut -d' ' -f2) 126 echo "Downloading and importing key $KEY_ID from $IMPORT_URL" 127 curl -L -s $IMPORT_URL | gpg --import 128 129 # Make sure we actually imported the correct key. 130 if ! gpg --list-key "$KEY_ID"; then 131 echo "ERROR: Imported key from $IMPORT_URL doesn't match ID $KEY_ID." 132 fi 133 done 134 135 echo "" 136 137 # Download the JSON of the release itself. That'll contain the release ID we need for the next call. 138 RELEASE_JSON=$(curl -L -s -H "$HEADER_JSON" "$RELEASE_URL/$LND_VERSION") 139 140 TAG_NAME=$(echo $RELEASE_JSON | jq -r '.tag_name') 141 RELEASE_ID=$(echo $RELEASE_JSON | jq -r '.id') 142 echo "Release $TAG_NAME found with ID $RELEASE_ID" 143 144 # Now download the asset list and filter by the manifest and the signatures. 145 ASSETS=$(curl -L -s -H "$HEADER_GH_JSON" "$API_URL/$RELEASE_ID" | jq -c '.assets[]') 146 MANIFEST=$(echo $ASSETS | jq -r "$MANIFEST_SELECTOR") 147 SIGNATURES=$(echo $ASSETS | jq -r "$SIGNATURE_SELECTOR") 148 149 # Download the main "manifest-*.txt" and all "manifest-*.sig" files containing 150 # the detached signatures. 151 TEMP_DIR=$(mktemp -d /tmp/lnd-sig-verification-XXXXXX) 152 echo "Downloading $MANIFEST" 153 curl -L -s -o "$TEMP_DIR/$MANIFEST" "$RELEASE_URL/download/$LND_VERSION/$MANIFEST" 154 155 for signature in $SIGNATURES; do 156 echo "Downloading $signature" 157 curl -L -s -o "$TEMP_DIR/$signature" "$RELEASE_URL/download/$LND_VERSION/$signature" 158 done 159 160 echo "" 161 cd $TEMP_DIR || exit 1 162 163 # Before we even look at the content of the manifest, we first want to make sure 164 # the signatures actually sign that exact manifest. 165 NUM_CHECKS=0 166 for signature in $SIGNATURES; do 167 echo "Verifying $signature" 168 if gpg --verify "$signature" "$MANIFEST" 2>&1 | grep -q "Good signature"; then 169 echo "Signature for $signature appears valid: " 170 gpg --verify "$signature" "$MANIFEST" 2>&1 | grep "using" 171 elif gpg --verify "$signature" 2>&1 | grep -q "No public key"; then 172 echo "Unable to verify signature $signature, no key available, skipping" 173 continue 174 else 175 echo "ERROR: Did not get valid signature for $MANIFEST in $signature!" 176 echo " The developer signature $signature disagrees on the expected" 177 echo " release binaries in $MANIFEST. The release may have been faulty or" 178 echo " was backdoored." 179 exit 1 180 fi 181 182 echo "Verified $signature against $MANIFEST" 183 ((NUM_CHECKS=NUM_CHECKS+1)) 184 done 185 186 # We want at least five signatures (out of seven public keys) that sign the 187 # hashes of the binaries we have installed. If we arrive here without exiting, 188 # it means no signature manifests were uploaded (yet) with the correct naming 189 # pattern. 190 MIN_REQUIRED_SIGNATURES=5 191 if [[ $NUM_CHECKS -lt $MIN_REQUIRED_SIGNATURES ]]; then 192 echo "ERROR: Not enough valid signatures found!" 193 echo " Valid signatures found: $NUM_CHECKS" 194 echo " Valid signatures required: $MIN_REQUIRED_SIGNATURES" 195 echo 196 echo " Make sure the release $LND_VERSION contains the required " 197 echo " number of signatures on the manifest, or wait until more " 198 echo " signatures have been added to the release." 199 exit 1 200 fi 201 202 # Then make sure that the hash of the installed binaries can be found in the 203 # manifest that we now have verified the signatures for. 204 if ! grep -q "^$LND_SUM" "$MANIFEST"; then 205 echo "ERROR: Hash $LND_SUM for lnd not found in $MANIFEST: " 206 cat "$MANIFEST" 207 echo " The expected release binaries have been verified with the developer " 208 echo " signatures. Your binary's hash does not match the expected release " 209 echo " binary hashes. Make sure you're using an official binary." 210 exit 1 211 fi 212 213 if ! grep -q "^$LNCLI_SUM" "$MANIFEST"; then 214 echo "ERROR: Hash $LNCLI_SUM for lncli not found in $MANIFEST: " 215 cat "$MANIFEST" 216 echo " The expected release binaries have been verified with the developer " 217 echo " signatures. Your binary's hash does not match the expected release " 218 echo " binary hashes. Make sure you're using an official binary." 219 exit 1 220 fi 221 222 echo "" 223 echo "SUCCESS! Verified lnd and lncli against $MANIFEST signed by $NUM_CHECKS developers."