add git tag signing, optional automatic pushing, and hybrid commit/tag threshold/group verification

This commit is contained in:
Lance Vick 2020-12-03 02:24:18 -08:00
parent 685c93d4b4
commit efe88005e9
Signed by: lrvick
GPG Key ID: 8E47A1EC35A1551D
1 changed files with 77 additions and 28 deletions

97
sig
View File

@ -266,8 +266,8 @@ verify_detached() {
} }
} }
### Verify all commits in git repo have valid signatures ### Verify head commit is signed
### Optionally verify a minimum number of valid unique signatures ### Optionally verify unique signed git tags to meet a threshold
### Optionally verify all signatures belong to keys in gpg alias group ### Optionally verify all signatures belong to keys in gpg alias group
verify_git(){ verify_git(){
[ $# -eq 2 ] || die "Usage: verify_git <threshold> <group>" [ $# -eq 2 ] || die "Usage: verify_git <threshold> <group>"
@ -275,39 +275,45 @@ verify_git(){
local -r group="${2}" local -r group="${2}"
local seen_fps="" sig_count=0 depth=0 ref commit fp uid local seen_fps="" sig_count=0 depth=0 ref commit fp uid
while [[ $depth != "$(git rev-list --count HEAD)" ]]; do git verify-commit HEAD >/dev/null 2>&1 \
ref=HEAD~${depth} || die "HEAD commit not signed"
commit=$(git log --format="%H" "$ref" -n1)
fp=$(git log --format="%GP" "$ref" -n1 ) fp=$(git log --format="%GP" HEAD -n1 )
seen_fps="${fp}"
sig_count=1
uid=$( get_uid "${fp}" ) uid=$( get_uid "${fp}" )
echo "Verified signed git commit by \"${uid}\""
git verify-commit HEAD~${depth} >/dev/null 2>&1 || { for tag in $(git tag --points-at HEAD); do
echo "Unsigned commit: ${commit}"; git tag --verify "$tag" >/dev/null 2>&1 && {
return 1; fp=$( \
} git verify-tag --raw extra-sig 2>&1 \
| grep VALIDSIG \
| sed 's/.*VALIDSIG \([A-Z0-9]\+\).*/\1/g' \
)
uid=$( get_uid "${fp}" )
seen_fps="${seen_fps} ${fp}"
if [[ "${seen_fps}" != *"${fp}"* ]]; then if [[ "${seen_fps}" != *"${fp}"* ]]; then
seen_fps="${seen_fps} ${fp}" seen_fps="${seen_fps} ${fp}"
echo "Verified signed git tag by \"${uid}\""
((sig_count=sig_count+1)) ((sig_count=sig_count+1))
echo "Verified git signature at depth ${depth} by \"${uid}\""
fi fi
if [ ! -z "$group" ]; then
group_check_fp "${fp}" "${group}" || {
echo "Git signing key not in group \"${group}\": ${fp}";
return 1;
} }
fi
[[ "${sig_count}" -ge "${threshold}" ]] && break;
((depth=depth+1))
done done
[[ "${sig_count}" -ge "${threshold}" ]] || { [[ "${sig_count}" -ge "${threshold}" ]] || {
echo "Minimum git signatures not found: ${sig_count}/${threshold}"; echo "Minimum git signatures not found: ${sig_count}/${threshold}";
return 1; return 1;
} }
if [ ! -z "$group" ]; then
for fp in "${seen_fps}"; do
group_check_fp "${fp}" "${group}" || {
echo "Git signing key not in group \"${group}\": ${fp}";
return 1;
}
done
fi
} }
get_temp(){ get_temp(){
@ -449,7 +455,7 @@ cmd_fetch() {
done done
} }
cmd_add(){ sign_detached(){
cmd_manifest cmd_manifest
gpg --armor --detach-sig ."${PROGRAM}"/manifest.txt >/dev/null 2>&1 gpg --armor --detach-sig ."${PROGRAM}"/manifest.txt >/dev/null 2>&1
local -r fp=$( \ local -r fp=$( \
@ -460,6 +466,49 @@ cmd_add(){
mv ."${PROGRAM}"/manifest.{"txt.asc","${fp}.asc"} mv ."${PROGRAM}"/manifest.{"txt.asc","${fp}.asc"}
} }
sign_tag(){
[ -d '.git' ] \
|| die "Not a git repository"
command -v git >/dev/null \
|| die "Git not installed"
git config --get user.signingKey >/dev/null \
|| die "Git user.signingKey not set"
local -r push="${1}"
local -r short_hash=$(git rev-parse --short HEAD)
local -r signing_fp=$( \
git config --get user.signingKey \
| sed 's/.*\([A-Z0-9]\{16\}\).*/\1/g' \
)
local -r name="sig-${short_hash}-${signing_fp}"
git tag -fsm "$name" "$name"
[[ $push -eq 1 ]] && git push --tags
}
cmd_add(){
local opts method="default" push=0
local -r args="$@"
opts="$(getopt -o m:p:: -l method:push:: -n "$PROGRAM" -- "$@")"
eval set -- "$opts"
while true; do case $1 in
-m|--method) method="$2"; shift 2 ;;
-p|--push) push="1"; shift 2 ;;
--) shift; break ;;
esac done
case $method in
default)
if [ -d '.git' ]; then
sign_tag "$push"
else
sign_detached
fi
;;
detached) sign_detached ;;
git) sign_tag "$push" ;;
*) cmd_help ;;
--) shift; break ;;
esac
}
cmd_version() { cmd_version() {
cat <<-_EOF cat <<-_EOF
========================================== ==========================================
@ -476,7 +525,7 @@ cmd_usage() {
cmd_version cmd_version
cat <<-_EOF cat <<-_EOF
Usage: Usage:
$PROGRAM add $PROGRAM add [-m,--method=<git|detached>] [-p,--push]
Add signature to manifest for this directory Add signature to manifest for this directory
$PROGRAM verify [-g,--group=<group>] [-t,--threshold=<N>] [-m,--method=<git|detached> ] [d,--diff=<branch>] $PROGRAM verify [-g,--group=<group>] [-t,--threshold=<N>] [-m,--method=<git|detached> ] [d,--diff=<branch>]
Verify m-of-n signatures by given group are present for directory. Verify m-of-n signatures by given group are present for directory.