#!/usr/bin/perl # vim:expandtab:ai:tabstop=4:textwidth=78:softtabstop=4:shiftwidth=4 use strict; use warnings; use Getopt::Long; # Version: 2.1 # Date: 2001.01.07 # Revised: 2004.04.06 # Revised: 2008.01.17 # Revised: 2009.01.24 # Author: V. Alex Brennen # http://www.cryptnet.net/people/vab/ # Author: Gerfried Fuchs # http://alfie.ist.org/alfie/ # Author: Phil Dibowitz # http://www.phildev.net/ # License: Public Domain # Description: # This script was written as part of the gpg keysigning # party howto. It generates a checklist for individuals # participating in a keysigning party. The keysigning # howto lives at: # http://www.cryptnet.net/fdp/crypto/gpg-party.html # Changelog: # 2008.01.17 phil@ipom.com: # - Refactored entire script into subroutines # - Added sorting of users # - Added a modeline and make all of the spacing consistent # - Converted to conform to K&R style guidelines # - Fixed lines > 80 chars # - Switched '-w' to 'use warnings;' # 2009.01.24 phil@ipom.com: # - HTML cleanup # - Move option parsing to Getopt::Long # - Add ability to have extra columns # - Add help/usage # - Since our usage tells people to redirect STDOUT, make sure all # errors/usage/help is printed to STDERR # - Some more code style cleanups # sub print_html_header($) { my $extra_fields = shift; print "\nPGP Keysigning Party Keys\n"; print "\n\n"; print "\n" . " \n \n \n" . " \n \n \n" . " \n"; foreach my $field (@$extra_fields) { print " \n"; } print "\n"; } sub get_fingerprints($) { my $keyring = shift; my $cmd = 'gpg --fingerprint --no-default-keyring --no-options' . " --with-colons --keyring $keyring | egrep " . '\'^(pub|fpr):\''; my @fps = `$cmd`; return \@fps; } sub parse_fingerprints($) { my $fps = shift; my $key_metadata = {}; while (my $line = shift(@{$fps})) { if($line =~ /^pub/) { my ($pub, $comptrust, $size, $type, $longid, $date, undef, undef, $settrust, $owner, undef, undef, $flags, undef) = split(/:/, $line); my $id = substr($longid, 8); my ($fpr, undef, undef, undef, undef, undef, undef, undef, undef, $fingerprint) = split(/:/, shift(@{$fps})); if ($type eq '17') { $type = 'DSA'; } elsif ($type eq '20') { $type = 'El Gamal'; } elsif ($type eq '1') { $type = 'RSA'; } if (length($fingerprint) == 40) { for my $i qw(36 32 28 24 20 16 12 8 4) { if ($i != 20) { substr($fingerprint, $i, 0, ' '); } if ($i == 20) { substr($fingerprint, $i, 0, "\n"); } } } elsif (length($fingerprint) == 32) { for my $i qw(30 28 26 24 22 20 18 16 14 12 10 8 6 4 2) { if ($i != 16) { substr($fingerprint, $i, 0, ' '); } if ($i == 16) { substr($fingerprint, $i, 0, "\n"); } } } $owner =~ s/&/&/; $owner =~ s//>\;/; push (@{$key_metadata->{$owner}}, { 'id' => $id, 'owner' => $owner, 'fingerprint' => $fingerprint, 'size' => $size, 'type' => $type, }); } } return $key_metadata; } sub print_table_body($$) { my ($metadata, $num_fields) = @_; # Loop to create extra-fields HTML only once my $extra_fields_html = ''; for (my $i = 0; $i < $num_fields; $i++) { $extra_fields_html .= " \n"; } foreach my $user (sort(keys(%{$metadata}))) { foreach my $key (@{$metadata->{$user}}) { print "\n" . " \n" . " \n" . " \n" . " \n" . " \n" . " \n" . " \n" . $extra_fields_html . "\n"; } } } sub print_html_footer() { print "
Key IDOwnerFingerprintSizeTypeKey Info Matches?Owner ID Matches?$field
 
$key->{'id'}
$key->{'owner'}
$key->{'fingerprint'}
$key->{'size'}$key->{'type'}  
\n\n"; } sub help() { print STDERR < > out-file.html should be the gpg keyring file with the public keys for all party participants. Options: -e, --extra-fields A comma-separated list of extra colums to have. This is useful if a subset of the participants want to do something extra such as S/MIME for CA Cert verification. -h, --help Print this help message and exit. EOF } my $opts = {}; GetOptions($opts, 'extra-fields|e=s', 'help|h' ) || die("Bad options"); if (exists($opts->{'help'})) { help(); exit(0); } my $extra_fields = []; if (exists($opts->{'extra-fields'})) { @$extra_fields = split(',', $opts->{'extra-fields'}); } my $keyring = shift; unless($keyring) { help(); exit(1); } my $fps = get_fingerprints($keyring); my $metadata = parse_fingerprints($fps); print_html_header($extra_fields); print_table_body($metadata, scalar(@$extra_fields)); print_html_footer();