]>
git.sthu.org Git - pgp-tools.git/blob - gpgsigs/gpgsigs
5 # See the pod documentation at the end of this file for author,
6 # copyright, and licence information.
9 # libintl-perl (Locale::Recode)
10 # OR libtext-iconv-perl (Text::Iconv),
11 # OR the "recode" binary
16 # * use the user's normal keyring to find signatures
17 # * support for multiple user keys
18 # * better charset conversion
21 my $VERSION = qq$Rev$;
35 gpgsigs $VERSION- http://pgp-tools.alioth.debian.org/
36 (c) 2004 Uli Martens <uli\@youam.net>
37 (c) 2004, 2005 Peter Palfrader <peter\@palfrader.org>
38 (c) 2004, 2005 Christoph Berg <cb\@df7cb.de>
44 my ($fd, $error) = @_;
49 Usage: $PROGRAM_NAME [-r] [-t <charset>] <keyid> <keytxt> [<outfile>]
51 keyid is a long or short keyid (e.g. DE7AAF6E94C09C7F or 94C09C7F)
52 separate multiple keyids with ','
53 -r call gpg --recv-keys before proceeding
54 -f <charset> convert <keytxt> from charset
55 -t <charset> convert UIDs to charset in output
61 my ($fromcharset, $charset, $recv_keys);
62 Getopt
::Long
::config
('bundling');
64 '-f=s' => \
$fromcharset,
67 help
=> sub { usage
(*STDOUT
, 0); },
68 version
=> sub { version
(*STDOUT
); exit 0;},
69 ) or usage
(*STDERR
, 1);
73 $fromcharset ||= "ISO-8859-1";
74 $charset ||= $ENV{LC_ALL
} || $ENV{LC_CTYPE
} || $ENV{LANG
} || "ISO-8859-1";
75 $charset = "ISO-8859-1" unless $charset =~ /[\.-]/;
81 my ($text, $from, $to) = @_;
83 if (eval "require Locale::Recode") {
84 my $rt = Locale
::Recode
->new (from
=> $from, to
=> $to);
89 } elsif (eval "require Text::Iconv") {
90 my $it = Text
::Iconv
->new($from, $to);
92 my $result = $it->convert($text);
93 warn ("Could not convert '$text'\n") unless defined $result;
94 return (defined $result) ?
$result : $text
96 my $pid = open3
(\
*WTRFH
, \
*RDRFH
, \
*ERRFH
, 'recode', "utf8..$charset");
100 my $result = <RDRFH
>;
104 warn ("'recode' failed, is it installed?\n") unless defined $result;
105 return (defined $result) ?
$result : $text
111 my $mykey = uc(shift @ARGV);
112 my $keytxt = (shift @ARGV) || usage
(*STDERR
, 1);
113 my $outfile = (shift @ARGV) || '-';
115 my @mykeys = split /,/, $mykey;
116 map { s/^0x//i; } @mykeys;
118 if (!@mykeys || scalar @ARGV) {
121 foreach my $falsekey (grep { $_ !~ /^([0-9A-F]{16,16}|[0-9A-F]{8,8})$/ } @mykeys) {
122 print STDERR
"Invalid keyid $falsekey given\n";
126 -r
$keytxt or die ("$keytxt does not exist\n");
129 # get list of keys in file
131 open (TXT
, $keytxt) or die ("Cannot open $keytxt\n");
133 if ( m/^pub +(?:\d+)[DR]\/([0-9A
-F
]{8}) [0-9]{4}-[0-9]{2}-[0-9]{2} *(.*)/ ) {
140 # get all known signatures
142 print STDERR
"Requesting keys from keyserver\n";
143 system "gpg --recv-keys @keys";
146 print STDERR
"Running --list-sigs, this will take a while ";
147 open SIGS
, "gpg --fixed-list-mode --with-colons --list-sigs @keys 2>/dev/null |"
148 or die "can't get gpg listing";
150 my ($key, $uid, $sigs);
152 if ( m/^pub:(?:.*?:){3,3}([0-9A-F]{16,16}):/ ) {
157 if ( m/^uid:(?:.*?:){8,8}(.*):/s ) {
159 $uid =~ s/\\x([0-9a-f][0-9a-f])/ chr(hex($1)) /gie;
160 $uid = myrecode
($uid, "UTF-8", $charset);
163 if ( m/^sig:(?:.*?:){3,3}([0-9A-F]{8})([0-9A-F]{8}):(?:.*?:){5,5}(.*?):/ ) {
165 if ($class eq '10x') {
167 } elsif ($class eq '11x') {
169 } elsif ($class eq '12x') {
171 } elsif ($class eq '13x') {
176 # Handle the case where one UID was signed multiple times
177 # with different signature classes.
178 my $before = $sigs->{$key}->{$uid}->{$1.$2};
179 if (defined $before) {
180 if ($before eq 'S' || $before eq 's') {
181 $sigs->{$key}->{$uid}->{$1.$2} = $class;
182 } elsif ($class eq 'S' || $class eq 's') {
183 # intentionall left blank
184 } elsif ($before < $class) {
185 $sigs->{$key}->{$uid}->{$1.$2} = $class;
188 $sigs->{$key}->{$uid}->{$1.$2} .= $class;
190 $sigs->{$key}->{$uid}->{$2} = $sigs->{$key}->{$uid}->{$1.$2};
197 next if ( m/^(rev|sub|tru):/ );
198 warn "unknown value: '$_', key: ".(defined $key ?
$key :'none')."\n";
203 for my $k ( keys %{$sigs} ) {
204 if ( $k =~ m/^[0-9A-F]{8}([0-9A-F]{8})$/ ) {
205 $sigs->{$1} = $sigs->{$k};
211 open MD
, "gpg --print-md md5 $keytxt|" or warn "can't get gpg md5\n";
214 open MD
, "gpg --print-md sha1 $keytxt|" or warn "can't get gpg sha1\n";
220 my $metatxt = quotemeta($keytxt);
221 $MD5 =~ s/^$metatxt:\s*//;
222 $SHA1 =~ s/^$metatxt:\s*//;
228 my ($key, $uid) = @_;
229 if (! defined $sigs->{$key}->{$uid}) {
230 warn "uid '$uid' not found on key $key\n";
231 #for (keys %{ $sigs->{$key} }) {
232 # print STDERR "only have $_\n";
234 return '(' . (' ' x
@mykeys) . ')';
237 foreach my $mykey (@mykeys) {
238 $r .= defined $sigs->{$key}->{$uid}->{$mykey} ?
$sigs->{$key}->{$uid}->{$mykey} : ' ';
247 print STDERR
"Annotating $keytxt, writing into $outfile\n";
248 open (TXT
, $keytxt) or die ("Cannot open $keytxt\n");
249 open (WRITE
, '>'.$outfile) or die ("Cannot open $outfile for writing\n");
252 $_ = myrecode
($_, $fromcharset, $charset);
253 if (/^MD5 Checksum:/ && defined $MD5) {
254 s/[_[:xdigit:]][_ [:xdigit:]]+_/$MD5/;
256 if (/^SHA1 Checksum:/ && defined $SHA1) {
257 s/[_[:xdigit:]][_ [:xdigit:]]+_/$SHA1/;
259 if ( m/^pub +(?:\d+)[DR]\/([0-9A
-F
]{8}) [0-9]{4}-[0-9]{2}-[0-9]{2} *(.*)/ ) {
262 #if ($uid) { # in gpg 1.2, the first uid is here
263 # print WRITE print_tag($key, $uid) . " $_";
267 if ( m/^uid +(.*)$/ ) {
269 unless (defined $key) {
270 warn "key is undefined - input text is possibly malformed near line $line\n";
273 die "uid is undefined, key $key" unless defined $uid;
274 die "bad tag from $key | $uid" unless defined (print_tag
($key, $uid));
275 print WRITE print_tag
($key, $uid) . " $_";
281 print WRITE
"Legend:\n";
282 foreach my $i (0 .. @mykeys - 1) {
283 print WRITE
'('. ' 'x
$i . 'S' . ' 'x
(@mykeys-$i-1) . ") signed with $mykeys[$i]\n";
291 B<gpgsigs> - annotate list of GnuPG keys with already done signatures
295 B<gpgsigs> [-r] [-f I<charset>] [-t I<charset>] I<keyid>I<[>B<,>I<keyidI<[>B<,>I<...>I<]>>I<]> F<keytxt> [F<outfile>]
299 B<gpgsigs> was written to assist the user in signing keys during a keysigning
300 party. It takes as input a file containing keys in C<gpg --list-keys> format
301 and prepends every line with a tag indicating if the user has already signed
302 that uid. When the file contains C<MD5 Checksum:> or C<SHA1 Checksum:> lines
303 and placeholders (C<__ __>), the checksum is inserted.
311 Call I<gpg --recv-keys> before creating the output.
315 Convert F<keytxt> from I<charset>. The default is ISO-8859-1.
319 Convert UIDs to I<charset>. The default is derived from LC_ALL, LC_CTYPE, and
320 LANG, and if all these are unset, the default is ISO-8859-1.
324 Use this keyid (8 or 16 byte) for annotation. Multiple keyids can be separated
329 Read input from F<keytxt>.
333 Write output to F<outfile>. Default is stdout.
339 The following key signing parties are using B<gpgsigs>:
341 http://www.palfrader.org/ksp-lt2k4.html
343 http://www.palfrader.org/ksp-lt2k5.html
347 B<GnuPG> is known to change its output format quite often. This version has
348 been tested with gpg 1.2.5 and gpg 1.4.1. YMMV.
354 http://pgp-tools.alioth.debian.org/
356 =head1 AUTHORS AND COPYRIGHT
358 (c) 2004 Uli Martens <uli@youam.net>
360 (c) 2004, 2005 Peter Palfrader <peter@palfrader.org>
362 (c) 2004, 2005 Christoph Berg <cb@df7cb.de>
368 Redistribution and use in source and binary forms, with or without
369 modification, are permitted provided that the following conditions
372 1. Redistributions of source code must retain the above copyright
373 notice, this list of conditions and the following disclaimer.
375 2. Redistributions in binary form must reproduce the above copyright
376 notice, this list of conditions and the following disclaimer in the
377 documentation and/or other materials provided with the distribution.
379 3. The name of the author may not be used to endorse or promote products
380 derived from this software without specific prior written permission.
382 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
383 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
384 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
385 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
386 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
387 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
388 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
389 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
390 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
391 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.