#================================================================= # imp_gpg.pm - Imprints support for gnuGPG # # A set of routines to handle calls to the gnuPG package. #================================================================= package imp_gpg; use strict; use vars qw($GPG_BINARY @GPG_ARGS @ISA @EXPORT); @ISA = qw(Exporter); @EXPORT = qw(impgpg_set_binary impgpg_binary_exists impgpg_set_args impgpg_parse_detsig impgpg_build_sigfile impgpg_print_sigfile impgpg_verify_signature impgpg_verify_signature_using_sigfile impgpg_install_pubkey); $GPG_BINARY = "/usr/bin/gpg"; @GPG_ARGS = (); #----------------------------------------------------------------- # Set the name of the gpg binary. The $bin parameter should # include the full path and file name. #----------------------------------------------------------------- sub impgpg_set_binary { my ($bin) = @_; $GPG_BINARY = $bin; print STDERR "Binary set to [$bin]\n"; } #----------------------------------------------------------------- # Return 1 if the binary ($GPG_BINARY) exists and is executable, # else return 0; #----------------------------------------------------------------- sub impgpg_binary_exists { my $rc; if (-x $GPG_BINARY) { $rc = 1; } else { $rc = 0; } } #----------------------------------------------------------------- # Set the standard arguments used by subsequent impgpg functions. # These are arguments that appear on the gpg command line. #----------------------------------------------------------------- sub impgpg_set_args { @GPG_ARGS = @_; } #----------------------------------------------------------------- # Parse an ASCII-armored detached sig file and return a return # code, the version string, signature, and CRC. Returns a non-zero # return code (first returned value) on failure. #----------------------------------------------------------------- sub impgpg_parse_detsig { my ($sigfile) = @_; my $version; my $sig, my $crc; my $rc = 0; my $state = ""; open (INF, "< $sigfile"); # Run through a simple state machine to break file into # pieces. while () { chop; # Start state if ($state eq "") { if (index ($_, "BEGIN PGP SIGNATURE", 0) >= 0) { $state = "VERSION"; } else { last; } } elsif ($state eq "VERSION") { if (substr ($_, 0, 9) eq "Version: ") { $state = "BLANKLINE"; $version = substr ($_, 9, 255); } } elsif ($state eq "BLANKLINE") { if ($_ eq "") { $state = "READSIG"; } } elsif ($state eq "READSIG") { $sig .= $_; if (substr ($_, length($_) - 1, 1) eq "=") { $state = "READCRC"; } } elsif ($state eq "READCRC") { $crc = $_; $state = "READEND"; } elsif ($state eq "READEND") { if (index ($_, "END PGP SIGNATURE", 0) >= 0) { $state = "DONE"; } } } close INF; if ($state ne "DONE") { $rc = 1; } return ($rc, $version, $sig, $crc); } #----------------------------------------------------------------- # Given the pieces of an ASCII-armored gnuGPG signature, construct # and return the text of a signature file. #----------------------------------------------------------------- sub impgpg_build_sigfile { my ($ver, $sig, $crc) = @_; my $data = "-----BEGIN PGP SIGNATURE-----\n" . "Version: $ver\n" . "Comment: For info see http://www.gnupg.org\n" . "\n"; while (length ($sig) > 64) { my $chunk = substr ($sig, 0, 64); $sig = substr ($sig, 64, 1024); $data .= "$chunk\n"; } if (length ($sig) > 0) { $data .= "$sig\n"; } $data .= "$crc\n" . "-----END PGP SIGNATURE-----\n"; return $data; } #----------------------------------------------------------------- # Given a file name and the pieces of an ASCII-armored gnuPGP # signature, construct the detached signature text and write to # the specified file. #----------------------------------------------------------------- sub impgpg_print_sigfile { my ($outfile, $ver, $sig, $crc) = @_; my $data = impgpg_build_sigfile ($ver, $sig, $crc); unless (open (OUTF, "> $outfile")) { return 1; } print OUTF $data; unless (close (OUTF)) { return 1; } return 0; # success } #----------------------------------------------------------------- # Verify the gnuGPG signature of a file. #----------------------------------------------------------------- sub impgpg_verify_signature { my ($infile, $ver, $sig, $crc) = @_; # "Reconstitute" a facsimile of the original # detached signature file from its pieces. my $data = impgpg_build_sigfile ($ver, $sig, $crc); # verify the file my $rc = system ("echo -en \"$data\" " . "| $GPG_BINARY @GPG_ARGS --verify - $infile 2> /dev/null"); return $rc; } #----------------------------------------------------------------- # Verify the file $infile, using the signature file $sigfile. #----------------------------------------------------------------- sub impgpg_verify_signature_using_sigfile { my ($infile, $sigfile) = @_; my $rc; $rc = system ($GPG_BINARY, @GPG_ARGS, "--verify", $sigfile, $infile); return $rc; } #----------------------------------------------------------------- # Install public key. #----------------------------------------------------------------- sub impgpg_install_pubkey { my ($key_filename) = @_; my $rc; $rc = system ($GPG_BINARY, @GPG_ARGS, "--import", $key_filename); return $rc; } 1;