From 99ba2728221cdd62d3c1f235c98125b1b73a33a0 Mon Sep 17 00:00:00 2001 From: Oliver Gugger Date: Fri, 12 Feb 2021 10:52:28 +0100 Subject: [PATCH] docs+scripts: switch to detached signatures Due to a misunderstanding of how the gpg command line options work, we didn't actually create detached signatures because the --clear-sign flag would overwrite that. We update our verification script to now only download the detached signatures and verify them against the main manifest file. We also update the signing instructions. --- .github/workflows/release.yaml | 6 ++-- docs/release.md | 16 +++++----- scripts/verify-install.sh | 57 +++++++++++++++++++--------------- 3 files changed, 42 insertions(+), 37 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 704f406e..0f40d520 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -73,10 +73,10 @@ jobs: curl https://keybase.io/roasbeef/pgp_keys.asc | gpg --import ``` - Once you have the required PGP keys, you can verify the release (assuming `manifest-roasbeef-${{ env.RELEASE_VERSION }}.txt.asc` is in the current directory) with: + Once you have the required PGP keys, you can verify the release (assuming `manifest-roasbeef-${{ env.RELEASE_VERSION }}.sig` and `manifest-${{ env.RELEASE_VERSION }}.txt` are in the current directory) with: ``` - gpg --verify manifest-roasbeef-${{ env.RELEASE_VERSION }}.txt.asc + gpg --verify manifest-roasbeef-${{ env.RELEASE_VERSION }}.sig manifest-${{ env.RELEASE_VERSION }}.txt ``` You should see the following if the verification was successful: @@ -95,7 +95,7 @@ jobs: Assuming you have the opentimestamps client installed locally, the timestamps can be verified with the following commands: ``` - ots verify manifest-roasbeef-${{ env.RELEASE_VERSION }}.txt.asc.ots -f manifest-roasbeef-${{ env.RELEASE_VERSION }}.txt.asc + ots verify manifest-roasbeef-${{ env.RELEASE_VERSION }}.sig.ots -f manifest-roasbeef-${{ env.RELEASE_VERSION }}.sig ``` Alternatively, [the open timestamps website](https://opentimestamps.org/) can be used to verify timestamps if one doesn't have a `bitcoind` instance accessible locally. diff --git a/docs/release.md b/docs/release.md index 8b364fda..42f2b8df 100644 --- a/docs/release.md +++ b/docs/release.md @@ -99,11 +99,11 @@ script in the image that can be called (before starting the container for example): ```shell -$ docker pull lightninglabs/lnd:v0.12.0-beta -$ docker run --rm --entrypoint="" lightninglabs/lnd:v0.12.0-beta /verify-install.sh -$ OK=$? -$ if [ "$OK" -ne "0" ]; then echo "Verification failed!"; exit 1; done -$ docker run lightninglabs/lnd [command-line options] +⛰ docker pull lightninglabs/lnd:v0.12.0-beta +⛰ docker run --rm --entrypoint="" lightninglabs/lnd:v0.12.0-beta /verify-install.sh +⛰ OK=$? +⛰ if [ "$OK" -ne "0" ]; then echo "Verification failed!"; exit 1; done +⛰ docker run lightninglabs/lnd [command-line options] ``` # Signing an Existing Manifest File @@ -121,8 +121,6 @@ signature during signing. Assuming `USERNAME` is your current nick as a developer, then the following command will generate a proper signature: +```shell +⛰ gpg --detach-sig --output manifest-USERNAME-TAG.sig manifest-TAG.txt ``` -gpg --detach-sig --output manifest-USERNAME-TAG.txt.asc --clear-sign manifest-TAG.txt -``` - - diff --git a/scripts/verify-install.sh b/scripts/verify-install.sh index cf5f9ad3..2bdd18c5 100755 --- a/scripts/verify-install.sh +++ b/scripts/verify-install.sh @@ -5,7 +5,8 @@ PROJECT=lnd RELEASE_URL=https://github.com/$REPO/$PROJECT/releases API_URL=https://api.github.com/repos/$REPO/$PROJECT/releases -SIGNATURE_SELECTOR=". | select(.name | test(\"manifest-.*(\\\\.txt\\\\.asc)$\")) | .name" +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" @@ -129,13 +130,17 @@ 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 manifests and signatures. +# 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 all "manifest-*.txt.asc" as those contain both the hashes that were -# signed and the signature itself (=detached sig). +# 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" @@ -144,13 +149,14 @@ 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 - # First make sure the downloaded signature file is valid. echo "Verifying $signature" - if gpg --verify "$signature" 2>&1 | grep -q "Good signature"; then + if gpg --verify "$signature" "$MANIFEST" 2>&1 | grep -q "Good signature"; then echo "Signature for $signature checks out: " - gpg --verify "$signature" 2>&1 | grep "using" + 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 @@ -159,32 +165,33 @@ for signature in $SIGNATURES; do exit 1 fi - echo "" - - # Then make sure that the hash of the installed binaries can be found in the - # signed list of hashes. - if ! grep -q "$LND_SUM" "$signature"; then - echo "ERROR: Hash $LND_SUM for lnd not found in $signature: " - cat "$signature" - exit 1 - fi - - if ! grep -q "$LNCLI_SUM" "$signature"; then - echo "ERROR: Hash $LNCLI_SUM for lncli not found in $signature: " - cat "$signature" - exit 1 - fi - - echo "Verified lnd and lncli hashes against $signature" + echo "Verified $signature against $MANIFEST" ((NUM_CHECKS=NUM_CHECKS+1)) done +# 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" + exit 1 +fi + +if ! grep -q "^$LNCLI_SUM" "$MANIFEST"; then + echo "ERROR: Hash $LNCLI_SUM for lncli not found in $MANIFEST: " + cat "$MANIFEST" + exit 1 +fi + +echo "" +echo "Verified lnd and lncli hashes against $MANIFEST" + # We want at least one signature that signs 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 1 ]]; then echo "ERROR: No valid signatures found!" - echo "Make sure the release $LND_VERSION contains any signed manifests." + echo "Make sure the release $LND_VERSION contains any signatures for the manifest." exit 1 fi