diff --git a/.sig/manifest.8E47A1EC35A1551D.asc b/.sig/manifest.8E47A1EC35A1551D.asc index 95afe86..92a855e 100644 --- a/.sig/manifest.8E47A1EC35A1551D.asc +++ b/.sig/manifest.8E47A1EC35A1551D.asc @@ -1,16 +1,16 @@ -----BEGIN PGP SIGNATURE----- -iQIzBAABCgAdFiEEZ1U/vaRrtxq9LgsLjkeh7DWhVR0FAl+ydC8ACgkQjkeh7DWh -VR09Lg/9F+xu75alg8aXBSw2JJXf90OrZukVi54FoIMoziYbQLPazu8TqvcS9x4M -5Z9Aw1GJlkNXd02zqLNO41twLAmbfBUjm+FUa3oB6MkyIijjgLk913XjUmy+ZHw1 -kvPihdiNFefzQsWAmw+Qvt+S9sXLQ4h/CIc86/Skb61ivoY5V1VR2zIZfUIg4na1 -rO3mSWCzO0H7EOCb+ahB716Oal4Byw7AsbQjSIt25Nlqq4l5j7AQnDKHo/tiLNS8 -RNeU5mIjQ3kPOWtSXGYYuxS0VjVap33ZAGsHx6g2NrrO3wbb2BoGsBAHGsFlUetd -wq8pbLkA+9HXTvIwR+2llKp0i+2uhPWiD+/SNKVWIqrRWr6ySWDjXHjut5cP74zo -lEE4qBweT4PuW9YmEIvQaKHUKeTvP/sWYinKizVtM3jmbcFfTAWqdMeCc+V0kZhb -p56s9VyZKHG7FGMueXcRsFV8QnESOFZ6BlybRFUFJt6pgFcGUa9QVLHDudn+hsJI -dhiCs5LKxFYoAKEXzJTafMqnnuwRGVrDCbBn6tL9wzBn0MerYD4YEmegglnEtNpX -nbo/+15VXsiU90hoXJGDsVOdCEJRyrANL98NhAci3+2IKQQQY6VgFX0TJqKrJFFc -qNNV+5VQbcJcceSwZUg/dUCYkTmhvW6Vn9vB7R8AX0r+KT4ByWM= -=R1GH +iQIzBAABCgAdFiEEZ1U/vaRrtxq9LgsLjkeh7DWhVR0FAl+zF58ACgkQjkeh7DWh +VR2DbQ//fLBe5OUcrT7O4TWguYPOYmQJSNM7NWG2tNS4roiJFaJUPhx0djnEIhqI +4Ui8FJfXyowHYDyxbtzL165bl2LcjUVlp2+xyTZxZwqh/TGVSqSy0tioepiWiTO3 +f/aVki7j7TkGwi/fPb1t7WpwbGlMxgXDGFsYYZ8+MWi7XQEg72bl+dOHUy8EsDBd +jZKfWuc6NcpUwip814WAQBTWQbRrNdyTPTn/jJ974Ba75trEY9RMbMbaDw80Aw98 +KoRSo6zDu/xT9UBoxWfRO+aMahtYqKNO+F8PmXFxXGI0Gi3iwciv82H5h3KH52Cx +LHAeUApApI5xD0A7s/UfOei48ed34XiSymbJG6ppIwaEsXNIgbe3qhdx4YvGQ9X0 +euvRGxRGbOZjCPalqQfu4Z7CWywTPdX2q/usyPe7u+D8SzD0ICdhBk0A86qi4J84 +/1cWHmtotssN9tNNLGGoGKmDkxawqElQWeHTlNvxzFzW5CI9KyYPD5cxaFtr+jsY +yc2Av6PDnKOLH3HFUo03eoeq9p7ov5NGQswDFxdlTEDcbpaPZDcYiV+Z5zJPMJOs +ve2otw9WcximzSs9mryNgLEFSlRTG31oNzLI5E92oHS3pkYRNgW0Wr1SpzetRk+6 +JhCp7f3C2dwUx3/TxeNX/F5j/vQvYrbS0Km83a7CzgEIvfrJEYs= +=8zXb -----END PGP SIGNATURE----- diff --git a/.sig/manifest.txt b/.sig/manifest.txt index 4490a47..9c9914c 100644 --- a/.sig/manifest.txt +++ b/.sig/manifest.txt @@ -1,3 +1,3 @@ 64263feac7b00952e9ec3b6c1fd11316faa58ff673c6bd085fac9f6f8d8389f6 .gitignore -3725c292d31a893395e3316046a2ac9264410f62e0a3bf0ae774cff6234d8533 README.md -b470a31ed13fb1177a0ffae1872f3e24f9aa8292090f4d838ad2a4bc639f8404 sig +c5649b242a88aec7617c627b75d3d6c6057123fdd9f1ebd8fee1d7001a827da0 README.md +bbe6f757d0f17cd0eab5b4cafbd7351e2cd403a7386ac47a2a894115b6f29683 sig diff --git a/README.md b/README.md index df0585f..c62b9fb 100644 --- a/README.md +++ b/README.md @@ -124,3 +124,37 @@ sig verify --threshold 2 --group myteam --method git ``` sig add ``` + +## Frequently Asked Questions + +### Why Bash? + +Because it is easy to quickly verify at any time, has wide OS compatibility andthe majority of the needed operations are calling other programs already on +your system like gpg and openssl. + +If this were in another language it would be harder to audit on the fly, would +require the user to have a specific language toolchain installed, and it would +still mostly just be a bunch of shell executions to call system binaries +anyway. + +### Why PGP? + +In spite of many popular claims to the contrary, PGP is still the most well +supported protocol for distribution, verification, and signing for keys held +by individual humans. It is also the only protocoal with wide HSM support +allowing you to keep keys out of system memory and requier physical approval +for each operation. E.G a trezor, ledger, or yubikey. + +Popular alternatives like signify or straight openssl have poor support for +these workflows. + +Admittedly the GnuPG codebase itself is a buggy dated mess, but PGP as a spec +is still Pretty Good for many use cases. A recent modern rewrite by a number +of former GnuPG team members is near complete and set to give PGP a long and +stable future. + +See: https://sequoia-pgp.org/ + +The only promising alternative to GnuPG for software signing that has hsm +support and the very attractive feature of expiring signatures is [The Update Framework](https://theupdateframework.io) which may be supported as an alternate +method in the future if m-of-n multisig is ever implemented. diff --git a/sig b/sig index a2abdcb..1a68565 100755 --- a/sig +++ b/sig @@ -36,7 +36,7 @@ die_pkg() { *) die "Error: Your operating system is not supported" ;; esac echo "Error: ${package} ${version}+ does not appear to be installed." >&2 - [ ! -z "$install_cmd" ] && printf "Try: \`${install_cmd}\`" >&2 + [ ! -z "$install_cmd" ] && echo "Try: \`${install_cmd}\`" >&2 exit 1 } @@ -60,9 +60,8 @@ check_version(){ ### Check if required binaries are installed at appropriate versions check_tools(){ - if [ -z "${BASH_VERSINFO}" ] \ - || [ -z "${BASH_VERSINFO[0]}" ] \ - || [ ${BASH_VERSINFO[0]} -lt ${MIN_BASH_VERSION} ]; then + if [ -z "${BASH_VERSINFO[0]}" ] \ + || [ "${BASH_VERSINFO[0]}" -lt "${MIN_BASH_VERSION}" ]; then die_pkg "bash" "${MIN_BASH_VERSION}" fi for cmd in "$@"; do @@ -84,19 +83,6 @@ check_tools(){ done } -### Handle different implementations of mktemp across platforms -get_temp(){ - echo "$( - mktemp \ - --quiet \ - --directory \ - -t "$(basename "$0").XXXXXX" 2>/dev/null - || mktemp \ - --quiet \ - --directory - )" -} - ### Get files that will be added to the manifest for signing ### Use git if available, else fall back to find get_files(){ @@ -120,6 +106,13 @@ get_signer(){ | head -n1 } +get_group_config(){ + local group=${1?} + gpg --with-colons --list-config group \ + | grep -i "^cfg:group:${group}:" \ + || die "Error: group \"${group}\" not found in ~/.gnupg/gpg.conf" +} + ### Verify a file has 0-N unique valid detached signatures ### Optionally verify all signatures belong to keys in gpg alias group verify_detached() { @@ -133,13 +126,6 @@ verify_detached() { local fingerprint local signer - if [ ! -z "$group" ]; then - group_config="$( \ - gpg --with-colons --list-config group \ - | grep -i "^cfg:group:${group}:" \ - )" || die "Error: group \"${group}\" not found in ~/.gnupg/gpg.conf" - fi - for sig_filename in "${filename%.*}".*.asc; do gpg --verify "${sig_filename}" "${filename}" >/dev/null 2>&1 || { echo "Invalid signature: ${sig_filename}"; @@ -155,9 +141,11 @@ verify_detached() { [[ "${seen_fingerprints}" == *"${fingerprint}"* ]] \ && die "Duplicate signature: ${sig_filename}"; - [ ! -z "$group_config" ] \ - && [[ "${group_config}" != *"${fingerprint}"* ]] \ + if [ ! -z "$group" ]; then + group_config=$(get_group_config "${group}") + [[ "${group_config}" != *"${fingerprint}"* ]] \ && die "Signature not in group \"${group}\": ${sig_filename}"; + fi echo "Verified detached signature by \"${signer}\"" @@ -175,10 +163,10 @@ verify_git(){ [ $# -eq 2 ] || die "Usage: verify_git " local threshold="${1}" local group="${2}" - local sig_count=0 + local group_config="" local seen_fingerprints="" + local sig_count=0 local depth=0 - #TODO: implement group validation while [[ $depth != "$(git rev-list --count HEAD)" ]]; do ref=HEAD~${depth} @@ -189,6 +177,12 @@ verify_git(){ git verify-commit HEAD~${depth} >/dev/null 2>&1\ || die "Unsigned commit: ${commit}" + if [ ! -z "$group" ]; then + group_config=$(get_group_config "${group}") + [[ "${group_config}" != *"${fingerprint}"* ]] \ + && die "Git signing key not in group \"${group}\": ${fingerprint}"; + fi + [[ "${seen_fingerprints}" != *"${fingerprint}"* ]] \ && seen_fingerprints="${seen_fingerprints} ${fingerprint}" \ && ((sig_count=sig_count+1)) \ @@ -208,7 +202,7 @@ verify_git(){ cmd_manifest() { mkdir -p ".${PROGRAM}" - printf "$(get_files | xargs openssl sha256 -r)" \ + printf "%s" "$(get_files | xargs openssl sha256 -r)" \ | sed -e 's/ \*/ /g' -e 's/ \.\// /g' \ | LC_ALL=C sort -k2 \ > ".${PROGRAM}/manifest.txt" @@ -225,7 +219,7 @@ cmd_verify() { --) shift; break ;; esac done - if ( [ -z "$method" ] || [ "$method" == "git" ] ); then + if [ -z "$method" ] || [ "$method" == "git" ]; then if [ "$method" == "git" ]; then command -v git >/dev/null 2>&1 \ || die "Error: method 'git' specified and git is not installed" @@ -235,23 +229,24 @@ cmd_verify() { && verify_git "${threshold}" "${group}" fi - if ( [ -z "$method" ] || [ "$method" == "detached" ] ); then - ( [ -d ".${PROGRAM}" ] && ls .${PROGRAM}/*.asc >/dev/null 2>&1 ) \ + if [ -z "$method" ] || [ "$method" == "detached" ]; then + ( [ -d ".${PROGRAM}" ] && ls ."${PROGRAM}"/*.asc >/dev/null 2>&1 ) \ || die "Error: No signatures" cmd_manifest - verify_detached "${threshold}" "${group}" .${PROGRAM}/manifest.txt + verify_detached "${threshold}" "${group}" ."${PROGRAM}"/manifest.txt fi } cmd_add(){ + local fingerprint cmd_manifest - gpg --armor --detach-sig .${PROGRAM}/manifest.txt - local fingerprint=$( \ - gpg --list-packets .${PROGRAM}/manifest.txt.asc \ + gpg --armor --detach-sig ."${PROGRAM}"/manifest.txt >/dev/null 2>&1 + fingerprint=$( \ + gpg --list-packets ."${PROGRAM}"/manifest.txt.asc \ | grep "issuer key ID" \ | sed 's/.*\([A-Z0-9]\{16\}\).*/\1/g' \ ) - mv .${PROGRAM}/manifest.{"txt.asc","${fingerprint}.asc"} + mv ."${PROGRAM}"/manifest.{"txt.asc","${fingerprint}.asc"} } cmd_version() {