aboutsummaryrefslogtreecommitdiff
path: root/contrib/verify-commits
diff options
context:
space:
mode:
authorLuke Dashjr <luke-jr+git@utopios.org>2016-08-09 05:45:50 +0000
committerLuke Dashjr <luke-jr+git@utopios.org>2016-08-09 05:45:50 +0000
commitdf634908ba758232413c50e8f1f7a80d546d777b (patch)
tree92cccae378b192f5f70986d2167209cbfd24ae08 /contrib/verify-commits
parente98e3dde6a976a2c8f266ee963d6931fd4b37262 (diff)
parente4382fbef56a0e04b0ed834e8b3a3a16f81db149 (diff)
Merge tag 'branch-0.13' into bugfix_gitdir
Diffstat (limited to 'contrib/verify-commits')
-rw-r--r--contrib/verify-commits/README.md26
-rw-r--r--contrib/verify-commits/allow-revsig-commits0
-rwxr-xr-xcontrib/verify-commits/gpg.sh33
-rwxr-xr-xcontrib/verify-commits/pre-push-hook.sh16
-rw-r--r--contrib/verify-commits/trusted-git-root1
-rw-r--r--contrib/verify-commits/trusted-keys4
-rwxr-xr-xcontrib/verify-commits/verify-commits.sh58
7 files changed, 138 insertions, 0 deletions
diff --git a/contrib/verify-commits/README.md b/contrib/verify-commits/README.md
new file mode 100644
index 0000000000..e9e3f65da2
--- /dev/null
+++ b/contrib/verify-commits/README.md
@@ -0,0 +1,26 @@
+Tooling for verification of PGP signed commits
+----------------------------------------------
+
+This is an incomplete work in progress, but currently includes a pre-push hook
+script (`pre-push-hook.sh`) for maintainers to ensure that their own commits
+are PGP signed (nearly always merge commits), as well as a script to verify
+commits against a trusted keys list.
+
+
+Using verify-commits.sh safely
+------------------------------
+
+Remember that you can't use an untrusted script to verify itself. This means
+that checking out code, then running `verify-commits.sh` against `HEAD` is
+_not_ safe, because the version of `verify-commits.sh` that you just ran could
+be backdoored. Instead, you need to use a trusted version of verify-commits
+prior to checkout to make sure you're checking out only code signed by trusted
+keys:
+
+ git fetch origin && \
+ ./contrib/verify-commits/verify-commits.sh origin/master && \
+ git checkout origin/master
+
+Note that the above isn't a good UI/UX yet, and needs significant improvements
+to make it more convenient and reduce the chance of errors; pull-reqs
+improving this process would be much appreciated.
diff --git a/contrib/verify-commits/allow-revsig-commits b/contrib/verify-commits/allow-revsig-commits
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/contrib/verify-commits/allow-revsig-commits
diff --git a/contrib/verify-commits/gpg.sh b/contrib/verify-commits/gpg.sh
new file mode 100755
index 0000000000..375d711725
--- /dev/null
+++ b/contrib/verify-commits/gpg.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+INPUT=$(cat /dev/stdin)
+VALID=false
+REVSIG=false
+IFS='
+'
+for LINE in $(echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null); do
+ case "$LINE" in
+ "[GNUPG:] VALIDSIG "*)
+ while read KEY; do
+ case "$LINE" in "[GNUPG:] VALIDSIG $KEY "*) VALID=true;; esac
+ done < ./contrib/verify-commits/trusted-keys
+ ;;
+ "[GNUPG:] REVKEYSIG "*)
+ [ "$BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG" != 1 ] && exit 1
+ while read KEY; do
+ case "$LINE" in "[GNUPG:] REVKEYSIG ${KEY#????????????????????????} "*)
+ REVSIG=true
+ GOODREVSIG="[GNUPG:] GOODSIG ${KEY#????????????????????????} "
+ esac
+ done < ./contrib/verify-commits/trusted-keys
+ ;;
+ esac
+done
+if ! $VALID; then
+ exit 1
+fi
+if $VALID && $REVSIG; then
+ echo "$INPUT" | gpg --trust-model always "$@" | grep "\[GNUPG:\] \(NEWSIG\|SIG_ID\|VALIDSIG\)" 2>/dev/null
+ echo "$GOODREVSIG"
+else
+ echo "$INPUT" | gpg --trust-model always "$@" 2>/dev/null
+fi
diff --git a/contrib/verify-commits/pre-push-hook.sh b/contrib/verify-commits/pre-push-hook.sh
new file mode 100755
index 0000000000..c57222818a
--- /dev/null
+++ b/contrib/verify-commits/pre-push-hook.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+if ! [[ "$2" =~ ^(git@)?(www.)?github.com(:|/)bitcoin/bitcoin(.git)?$ ]]; then
+ exit 0
+fi
+
+while read LINE; do
+ set -- A $LINE
+ if [ "$4" != "refs/heads/master" ]; then
+ continue
+ fi
+ if ! ./contrib/verify-commits/verify-commits.sh $3 > /dev/null 2>&1; then
+ echo "ERROR: A commit is not signed, can't push"
+ ./contrib/verify-commits/verify-commits.sh
+ exit 1
+ fi
+done < /dev/stdin
diff --git a/contrib/verify-commits/trusted-git-root b/contrib/verify-commits/trusted-git-root
new file mode 100644
index 0000000000..c60f8ab695
--- /dev/null
+++ b/contrib/verify-commits/trusted-git-root
@@ -0,0 +1 @@
+82bcf405f6db1d55b684a1f63a4aabad376cdad7
diff --git a/contrib/verify-commits/trusted-keys b/contrib/verify-commits/trusted-keys
new file mode 100644
index 0000000000..75242c2a97
--- /dev/null
+++ b/contrib/verify-commits/trusted-keys
@@ -0,0 +1,4 @@
+71A3B16735405025D447E8F274810B012346C9A6
+3F1888C6DCA92A6499C4911FDBA1A67379A1A931
+32EE5C4C3FA15CCADB46ABE529D4BCB6416F53EC
+FE09B823E6D83A3BC7983EAA2D7F2372E50FE137
diff --git a/contrib/verify-commits/verify-commits.sh b/contrib/verify-commits/verify-commits.sh
new file mode 100755
index 0000000000..5219331e2e
--- /dev/null
+++ b/contrib/verify-commits/verify-commits.sh
@@ -0,0 +1,58 @@
+#!/bin/sh
+# Not technically POSIX-compliant due to use of "local", but almost every
+# shell anyone uses today supports it, so its probably fine
+
+DIR=$(dirname "$0")
+[ "/${DIR#/}" != "$DIR" ] && DIR=$(dirname "$(pwd)/$0")
+
+VERIFIED_ROOT=$(cat "${DIR}/trusted-git-root")
+REVSIG_ALLOWED=$(cat "${DIR}/allow-revsig-commits")
+
+HAVE_FAILED=false
+IS_SIGNED () {
+ if [ $1 = $VERIFIED_ROOT ]; then
+ return 0;
+ fi
+ if [ "${REVSIG_ALLOWED#*$1}" != "$REVSIG_ALLOWED" ]; then
+ export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=1
+ else
+ export BITCOIN_VERIFY_COMMITS_ALLOW_REVSIG=0
+ fi
+ if ! git -c "gpg.program=${DIR}/gpg.sh" verify-commit $1 > /dev/null 2>&1; then
+ return 1;
+ fi
+ local PARENTS
+ PARENTS=$(git show -s --format=format:%P $1)
+ for PARENT in $PARENTS; do
+ if IS_SIGNED $PARENT > /dev/null; then
+ return 0;
+ fi
+ done
+ if ! "$HAVE_FAILED"; then
+ echo "No parent of $1 was signed with a trusted key!" > /dev/stderr
+ echo "Parents are:" > /dev/stderr
+ for PARENT in $PARENTS; do
+ git show -s $PARENT > /dev/stderr
+ done
+ HAVE_FAILED=true
+ fi
+ return 1;
+}
+
+if [ x"$1" = "x" ]; then
+ TEST_COMMIT="HEAD"
+else
+ TEST_COMMIT="$1"
+fi
+
+IS_SIGNED "$TEST_COMMIT"
+RES=$?
+if [ "$RES" = 1 ]; then
+ if ! "$HAVE_FAILED"; then
+ echo "$TEST_COMMIT was not signed with a trusted key!"
+ fi
+else
+ echo "There is a valid path from $TEST_COMMIT to $VERIFIED_ROOT where all commits are signed!"
+fi
+
+exit $RES