From 4c8bf9c28d2e6094c46d379f0248a96ed3ca13b6 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Mon, 27 Sep 2021 11:03:03 +0200 Subject: [PATCH] scripts: extract functions As a preparation to make the script easier to understand, we extract some of the sub tasks into functions. --- scripts/verify-install.sh | 217 +++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 108 deletions(-) diff --git a/scripts/verify-install.sh b/scripts/verify-install.sh index c7c0a9b71..2dd03443b 100755 --- a/scripts/verify-install.sh +++ b/scripts/verify-install.sh @@ -9,6 +9,7 @@ MANIFEST_SELECTOR=". | select(.name | test(\"manifest-v.*(\\\\.txt)$\")) | .name SIGNATURE_SELECTOR=". | select(.name | test(\"manifest-.*(\\\\.sig)$\")) | .name" HEADER_JSON="Accept: application/json" HEADER_GH_JSON="Accept: application/vnd.github.v3+json" +MIN_REQUIRED_SIGNATURES=5 # All keys that can sign lnd releases. The key must be downloadable/importable # from the URL given after the space. @@ -22,6 +23,8 @@ KEYS+=("7E81EF6B9989A9CC93884803118759E83439A9B1 https://keybase.io/eugene_/pgp_ KEYS+=("7AB3D7F5911708842796513415BAADA29DA20D26 https://keybase.io/halseth/pgp_keys.asc") KEYS+=("E97A1AB6C77A1D2B72F50A6F90E00CCB1C74C611 https://keybase.io/arshbot/pgp_keys.asc") +TEMP_DIR=$(mktemp -d /tmp/lnd-sig-verification-XXXXXX) + function check_command() { echo -n "Checking if $1 is installed... " if ! command -v "$1"; then @@ -30,6 +33,107 @@ function check_command() { fi } +function import_keys() { + for key in "${KEYS[@]}"; do + KEY_ID=$(echo $key | cut -d' ' -f1) + IMPORT_URL=$(echo $key | cut -d' ' -f2) + echo "Downloading and importing key $KEY_ID from $IMPORT_URL" + curl -L -s $IMPORT_URL | gpg --import + + # Make sure we actually imported the correct key. + if ! gpg --list-key "$KEY_ID"; then + echo "ERROR: Imported key from $IMPORT_URL doesn't match ID $KEY_ID." + fi + done +} + +function verify_signatures() { + # Download the JSON of the release itself. That'll contain the release ID we + # need for the next call. + RELEASE_JSON=$(curl -L -s -H "$HEADER_JSON" "$RELEASE_URL/$LND_VERSION") + + TAG_NAME=$(echo $RELEASE_JSON | jq -r '.tag_name') + RELEASE_ID=$(echo $RELEASE_JSON | jq -r '.id') + echo "Release $TAG_NAME found with ID $RELEASE_ID" + + # Now download the asset list and filter by the manifest and the signatures. + ASSETS=$(curl -L -s -H "$HEADER_GH_JSON" "$API_URL/$RELEASE_ID" | jq -c '.assets[]') + MANIFEST=$(echo $ASSETS | jq -r "$MANIFEST_SELECTOR") + SIGNATURES=$(echo $ASSETS | jq -r "$SIGNATURE_SELECTOR") + + # Download the main "manifest-*.txt" and all "manifest-*.sig" files containing + # the detached signatures. + echo "Downloading $MANIFEST" + curl -L -s -o "$TEMP_DIR/$MANIFEST" "$RELEASE_URL/download/$LND_VERSION/$MANIFEST" + + for signature in $SIGNATURES; do + echo "Downloading $signature" + curl -L -s -o "$TEMP_DIR/$signature" "$RELEASE_URL/download/$LND_VERSION/$signature" + done + + echo "" + + # Before we even look at the content of the manifest, we first want to make + # sure the signatures actually sign that exact manifest. + NUM_CHECKS=0 + for signature in $SIGNATURES; do + echo "Verifying $signature" + if gpg --verify "$TEMP_DIR/$signature" "$TEMP_DIR/$MANIFEST" 2>&1 | grep -q "Good signature"; then + echo "Signature for $signature appears valid: " + gpg --verify "$TEMP_DIR/$signature" "$TEMP_DIR/$MANIFEST" 2>&1 | grep "using" + elif gpg --verify "$TEMP_DIR/$signature" 2>&1 | grep -q "No public key"; then + echo "Unable to verify signature $signature, no key available, skipping" + continue + else + echo "ERROR: Did not get valid signature for $MANIFEST in $signature!" + echo " The developer signature $signature disagrees on the expected" + echo " release binaries in $MANIFEST. The release may have been faulty or" + echo " was backdoored." + exit 1 + fi + + echo "Verified $signature against $MANIFEST" + ((NUM_CHECKS=NUM_CHECKS+1)) + done + + # We want at least five signatures (out of seven public keys) that sign the + # hashes of the binaries we have installed. If we arrive here without exiting, + # it means no signature manifests were uploaded (yet) with the correct naming + # pattern. + if [[ $NUM_CHECKS -lt $MIN_REQUIRED_SIGNATURES ]]; then + echo "ERROR: Not enough valid signatures found!" + echo " Valid signatures found: $NUM_CHECKS" + echo " Valid signatures required: $MIN_REQUIRED_SIGNATURES" + echo + echo " Make sure the release $LND_VERSION contains the required " + echo " number of signatures on the manifest, or wait until more " + echo " signatures have been added to the release." + exit 1 + fi +} + +function check_hash() { + # If we're inside the docker image, there should be a shasums.txt file in the + # root directory. If that's the case, we first want to make sure we still have + # the same hash as we did when building the image. + if [[ -f /shasums.txt ]]; then + if ! grep -q "$1" /shasums.txt; then + echo "ERROR: Hash $1 for $2 not found in /shasums.txt: " + cat /shasums.txt + exit 1 + fi + fi + + if ! grep -q "^$1" "$TEMP_DIR/$MANIFEST"; then + echo "ERROR: Hash $1 for $2 not found in $MANIFEST: " + cat "$TEMP_DIR/$MANIFEST" + echo " The expected release binaries have been verified with the developer " + echo " signatures. Your binary's hash does not match the expected release " + echo " binary hashes. Make sure you're using an official binary." + exit 1 + fi +} + # By default we're picking up lnd and lncli from the system $PATH. LND_BIN=$(which lnd) LNCLI_BIN=$(which lncli) @@ -104,121 +208,18 @@ if [[ ${#LNCLI_SUM} -ne 64 ]]; then exit 1 fi -# If we're inside the docker image, there should be a shasums.txt file in the -# root directory. If that's the case, we first want to make sure we still have -# the same hash as we did when building the image. -if [[ -f /shasums.txt ]]; then - if ! grep -q "$LND_SUM" /shasums.txt; then - echo "ERROR: Hash $LND_SUM for lnd not found in /shasums.txt: " - cat /shasums.txt - exit 1 - fi - if ! grep -q "$LNCLI_SUM" /shasums.txt; then - echo "ERROR: Hash $LNCLI_SUM for lnd not found in /shasums.txt: " - cat /shasums.txt - exit 1 - fi -fi - # Import all the signing keys. -for key in "${KEYS[@]}"; do - KEY_ID=$(echo $key | cut -d' ' -f1) - IMPORT_URL=$(echo $key | cut -d' ' -f2) - echo "Downloading and importing key $KEY_ID from $IMPORT_URL" - curl -L -s $IMPORT_URL | gpg --import - - # Make sure we actually imported the correct key. - if ! gpg --list-key "$KEY_ID"; then - echo "ERROR: Imported key from $IMPORT_URL doesn't match ID $KEY_ID." - fi -done +import_keys echo "" -# Download the JSON of the release itself. That'll contain the release ID we need for the next call. -RELEASE_JSON=$(curl -L -s -H "$HEADER_JSON" "$RELEASE_URL/$LND_VERSION") - -TAG_NAME=$(echo $RELEASE_JSON | jq -r '.tag_name') -RELEASE_ID=$(echo $RELEASE_JSON | jq -r '.id') -echo "Release $TAG_NAME found with ID $RELEASE_ID" - -# Now download the asset list and filter by the manifest and the signatures. -ASSETS=$(curl -L -s -H "$HEADER_GH_JSON" "$API_URL/$RELEASE_ID" | jq -c '.assets[]') -MANIFEST=$(echo $ASSETS | jq -r "$MANIFEST_SELECTOR") -SIGNATURES=$(echo $ASSETS | jq -r "$SIGNATURE_SELECTOR") - -# Download the main "manifest-*.txt" and all "manifest-*.sig" files containing -# the detached signatures. -TEMP_DIR=$(mktemp -d /tmp/lnd-sig-verification-XXXXXX) -echo "Downloading $MANIFEST" -curl -L -s -o "$TEMP_DIR/$MANIFEST" "$RELEASE_URL/download/$LND_VERSION/$MANIFEST" - -for signature in $SIGNATURES; do - echo "Downloading $signature" - curl -L -s -o "$TEMP_DIR/$signature" "$RELEASE_URL/download/$LND_VERSION/$signature" -done - -echo "" -cd $TEMP_DIR || exit 1 - -# Before we even look at the content of the manifest, we first want to make sure -# the signatures actually sign that exact manifest. -NUM_CHECKS=0 -for signature in $SIGNATURES; do - echo "Verifying $signature" - if gpg --verify "$signature" "$MANIFEST" 2>&1 | grep -q "Good signature"; then - echo "Signature for $signature appears valid: " - gpg --verify "$signature" "$MANIFEST" 2>&1 | grep "using" - elif gpg --verify "$signature" 2>&1 | grep -q "No public key"; then - echo "Unable to verify signature $signature, no key available, skipping" - continue - else - echo "ERROR: Did not get valid signature for $MANIFEST in $signature!" - echo " The developer signature $signature disagrees on the expected" - echo " release binaries in $MANIFEST. The release may have been faulty or" - echo " was backdoored." - exit 1 - fi - - echo "Verified $signature against $MANIFEST" - ((NUM_CHECKS=NUM_CHECKS+1)) -done - -# We want at least five signatures (out of seven public keys) that sign the -# hashes of the binaries we have installed. If we arrive here without exiting, -# it means no signature manifests were uploaded (yet) with the correct naming -# pattern. -MIN_REQUIRED_SIGNATURES=5 -if [[ $NUM_CHECKS -lt $MIN_REQUIRED_SIGNATURES ]]; then - echo "ERROR: Not enough valid signatures found!" - echo " Valid signatures found: $NUM_CHECKS" - echo " Valid signatures required: $MIN_REQUIRED_SIGNATURES" - echo - echo " Make sure the release $LND_VERSION contains the required " - echo " number of signatures on the manifest, or wait until more " - echo " signatures have been added to the release." - exit 1 -fi +# Verify and count the signatures. +verify_signatures # Then make sure that the hash of the installed binaries can be found in the # manifest that we now have verified the signatures for. -if ! grep -q "^$LND_SUM" "$MANIFEST"; then - echo "ERROR: Hash $LND_SUM for lnd not found in $MANIFEST: " - cat "$MANIFEST" - echo " The expected release binaries have been verified with the developer " - echo " signatures. Your binary's hash does not match the expected release " - echo " binary hashes. Make sure you're using an official binary." - exit 1 -fi - -if ! grep -q "^$LNCLI_SUM" "$MANIFEST"; then - echo "ERROR: Hash $LNCLI_SUM for lncli not found in $MANIFEST: " - cat "$MANIFEST" - echo " The expected release binaries have been verified with the developer " - echo " signatures. Your binary's hash does not match the expected release " - echo " binary hashes. Make sure you're using an official binary." - exit 1 -fi +check_hash "$LND_SUM" "lnd" +check_hash "$LNCLI_SUM" "lncli" echo "" echo "SUCCESS! Verified lnd and lncli against $MANIFEST signed by $NUM_CHECKS developers."