#!/usr/bin/perl -w # debsigs: Package signing/verification system # Copyright (C) 2000 Progeny Linux Systems, Inc. # Copyright (C) 2009 Peter Pentchev # # 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 2 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, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #$CVSVERSION = '$Progeny: debsigs,v 1.14 2001/12/16 07:12:25 branden Exp $'; #$VERSION = "$CVSVERSION+2002.09.19"; use strict; use Debian::debsigs::arf; use Debian::debsigs::debsigsmain; use Debian::debsigs::forktools ':all'; use Debian::debsigs::gpg; use Getopt::Long; use IO::File; use POSIX ":sys_wait_h"; sub cmd_sign($); sub cmd_list($); sub cmd_delete($); sub syntax($); sub version(); Getopt::Long::Configure('no_ignore_case'); my ($delete, $sign, $key, $keyring, $gpgopts, $list, $showhelp, $showversion); my ($verbose, $verify); # Parse the command line; @ARGV will then contain filenames to operate on. my($result) = GetOptions("sign|s=s" => \$sign, "default-key|k=s" => \$key, "secret-keyring|K=s" => \$keyring, "gpgopts|g=s" => \$gpgopts, "help|h" => \$showhelp, "list|l|t" => \$list, "delete=s" => \$delete, "verbose|v+" => \$verbose, "verify|check|c" => \$verify, "version|V" => \$showversion); version() if $showversion; syntax(0) if $showhelp; exit(0) if $showhelp || $showversion; unless (($#ARGV >= 0) && $result) { syntax(1); exit(1); } # Process each file. foreach my $file (@ARGV) { print " *** Processing file $file\n" if (defined($verbose) && $verbose >= 1); if ($sign) { cmd_sign($file); } elsif ($list) { cmd_list($file); } elsif ($delete) { cmd_delete($file); } elsif ($verify) { die "Verify not yet implemented."; } } sub cmd_sign($) { my $file = shift @_; if (length($sign) > 10) { die "Signature type must be 10 characters or less."; } unless (-r $file && -f $file) { die "File $file does not exist, is not a file, or is not readable."; } my $arobj = new Debian::debsigs::arf($file); my ($arfd,$arpid) = $arobj->getfiles("debian-binary", "control.tar.gz", "data.tar.gz"); my $dir = mktempdir(); my $sigfile = new IO::File(">$dir/_gpg$sign") or die "Couldn't open: $!"; # forktools::assertsuccess($arpid, 'ar'); # Why doesn't this work? # my $gpgout = forktools::forkboth($arfd, $sigfile, "/usr/bin/gpg", #"--detach-sign"); my @cmdline = ("gpg", "--openpgp", "--detach-sign"); if ($key) { push (@cmdline, "--default-key", $key); } if ($keyring) { push (@cmdline, "--secret-keyring", $keyring); } if ($verbose) { warn("RUNNING: " . join(" ", @cmdline)); } my ($gpgout, $gpgpid) = forkreader($arfd, @cmdline); my($line); while (defined($line = <$gpgout>)) { print $sigfile $line; } close $sigfile; Debian::debsigs::forktools::assertsuccess($arpid, 'ar', 1); Debian::debsigs::forktools::assertsuccess($gpgpid, "gpg", 1); $arobj->setfile("$dir/_gpg$sign"); system("rm -rf $dir"); $arobj->fixup(); exit(0); } sub cmd_list($) { my $file = shift @_; my $arobj = new Debian::debsigs::arf($file); my @list = $arobj->contents(); print "GPG signatures in $file:\n"; foreach my $sigfile (@list) { if ($sigfile =~ /^_gpg/) { my ($sig) = $sigfile =~ /^_gpg(.+)$/; my ($arfd, $arpid) = $arobj->getfiles($sigfile); my ($gpgkey, $gpgdate) = Debian::debsigs::gpg::getkeyfromfd($arfd); Debian::debsigs::forktools::assertsuccess($arpid, 'ar'); if ($verbose) { my $gpgkeyname = Debian::debsigs::gpg::getkeynamefromid($gpgkey); print "$sig: signed by "; print $gpgkeyname ? $gpgkeyname : $gpgkey; print " on ", scalar(localtime($gpgdate)), "\n"; } else { print "$sig: signed by $gpgkey on ", scalar(localtime($gpgdate)), "\n"; } } } print " *** NO ATTEMPT HAS BEEN MADE TO VERIFY THE LISTED SIGNATURES ***\n"; exit(0); } sub cmd_delete($) { my $file = shift @_; my $arobj = new Debian::debsigs::arf($file); my @list = $arobj->contents(); die "File $file is not readable or does not exist." unless (-f $file); unless(scalar(grep(/^_gpg$delete$/, @list))) { die "File $file does not contain signature type $delete to remove.\n"; } if ($arobj->delete("_gpg$delete")) { die "ar failed: $!\n"; } } sub mktempdir() { mkdir("/tmp/debsigndeb.$$", 0700) or die "couldn't mkdir: $!"; return "/tmp/debsigndeb.$$"; } sub syntax($) { my ($err) = @_; my $s = < B<--list>|B<-l> [B<-v>] file [file...] B B<--sign=type> [B<--default-key=keyID>] [B<-v>] file [file...] B B<--verify>|B<--check>|B<-c> file [file...] B B<--delete=type> file [file...] =head1 DESCRIPTION I is used to manipulate the cryptographic signatures stored inside a .deb file. It is not used to verify those signatures; for that purpose, see debsig-verify(1). =head1 OPTIONS =over 5 =item B<--list> or B<-l> or B<-t> Lists the signatures found in the specified file. =item B<--sign=type> Creates a new signature of the type specified in the given file. The signature will be created using the default key for your GPG keyring. See L below for possible values of the C field. =item B<--default-key=keyID> Uses a key other than the default for signing the package. =item B<--secret-keyring=file> or B<-K file> Uses a keyring other than the default for signing the package. This option is passed along to GPG verbatim; see the discussion in the gpg(1) manpage for information on how to specify the keyring file. =item B<-v> Displays verbose output. =item B<--verify> or B<--check> or B<-c> Invokes debsig-verify to check the validity of the signature on this package. =item B<--delete=type> Deletes the signature of the specified type from the package. =back =head1 SIGNATURE TYPES A Debian package may carry different types of signatures. The most commonly-used ones are: =over 4 =item * C The official signature of the organization which distributes the package, usually the Debian Project or a GNU/Linux distribution derived from it. This signature may be added automatically. =item * C The signature of the maintainer of the Debian package. This signature should be added by the maintainer before uploading the package. =item * C An automatically-added signature renewed periodically to ensure that a package downloaded from an online archive is indeed the latest version distributed by the organization. =back See the F file for more information and rationale for the different signature types. =head1 FUTURE DIRECTIONS It would be nice to have a command-line option to change the command used for signing, instead of hard-coding "gpg". =head1 AUTHOR John Goerzen =head1 SEE ALSO debsig-verify(1), gpg(1) =cut