group support for git sigs

This commit is contained in:
Lance Vick 2020-11-16 16:22:24 -08:00
parent b53757b062
commit a56a9c477e
Signed by: lrvick
GPG Key ID: 8E47A1EC35A1551D
4 changed files with 81 additions and 52 deletions

View File

@ -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-----

View File

@ -1,3 +1,3 @@
64263feac7b00952e9ec3b6c1fd11316faa58ff673c6bd085fac9f6f8d8389f6 .gitignore
3725c292d31a893395e3316046a2ac9264410f62e0a3bf0ae774cff6234d8533 README.md
b470a31ed13fb1177a0ffae1872f3e24f9aa8292090f4d838ad2a4bc639f8404 sig
c5649b242a88aec7617c627b75d3d6c6057123fdd9f1ebd8fee1d7001a827da0 README.md
bbe6f757d0f17cd0eab5b4cafbd7351e2cd403a7386ac47a2a894115b6f29683 sig

View File

@ -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.

69
sig
View File

@ -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 <threshold> <group>"
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() {