#!/usr/bin/env perl # git-verify-commit-by-fp -- verify that a commit was signed by a particular key # Copyright (C) 2019 Sean Whitton # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . use strict; use warnings; use 5.016; die "usage: git verify-commit-by-fp FINGERPRINT COMMIT" unless @ARGV == 2; my $fp = shift; my $commit = shift; my ($newsig, $goodsig, $validsig) = (0, 0, 0); foreach (`git verify-commit --raw $commit 2>&1`) { # Given doc/DETAILS in the gnupg source and "5.5.1 Automated # signature checking" in the gnupg manual, especially the fact # that if GOODSIG is emitted in a NEWSIG block there will not also # be any EXPSIG etc., what we require is this sequence: # # NEWSIG (ignore trailing) # any non-NEWSIG lines # GOODSIG (ignore trailing) # any non-NEWSIG lines # 'VALIDSIG .* $fp' or 'VALIDSIG $fp .*' # # We don't check for any TRUST_* line because we are pinning to a # specific fingerprint. if (/^\[GNUPG:\] NEWSIG/) { $newsig = 1; $goodsig = $validsig = 0; } elsif ($newsig && /^\[GNUPG:\] GOODSIG/) { $goodsig = 1; } elsif ($newsig && $goodsig # primary key fingerprint && (/^\[GNUPG:\] VALIDSIG .* $fp$/ # (possibly) subkey fingerprint || /^\[GNUPG:\] VALIDSIG $fp /)) { $validsig = 1; last; } } exit !$validsig;