dpkg-sig-0.13.1+nmu2/ 0000755 0000000 0000000 00000000000 13026063420 011040 5 ustar dpkg-sig-0.13.1+nmu2/TODO 0000644 0000000 0000000 00000001776 10034063347 011547 0 ustar * Understand the way debsign works and verify its signatures.
* What happens with expired keys?
* Get about 1000 DDs to test the thing and report bugs.
* Create patches for katie, the buildds and dpkg to sign and verify
signatures everytime a package is touched.
* We need a way to check if the signature is done by a DD ... errr ...
Reworded: To check if the package is signed with a DD's gpg key (ATM
we don't see the difference between someone who rebuilt the package
with his h4x0r3d sk111z signing as "builder" and a DD who's supposed
to do so). Perhaps something with debian-keyring, gpg
--no-default-keyring --keyring, but that won't work with NMs. Do we
need a wanna-be-dd-keyring? Perhaps one with all keys of people
with a package in the archive. Oh, and for non-Debian sources we
would need a --accept-people-not-associated-with-debian switch.
*sigh*
We have to discuss this at least with the debian keyring manager,
and perhaps some more DDs (#debian-devel? debian-devel@l.d.o?)
dpkg-sig-0.13.1+nmu2/copyright 0000644 0000000 0000000 00000002051 12345252645 013005 0 ustar This package was written by Andreas Barth und Marc Brockschmidt. It is
Copyright (C) 2003, 2004 by them.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
Upstream web site used to be .
See /usr/share/common-licenses/GPL for the full list of conditions.
It is politly asked (but not legally required) that changes of this code are
forwarded to the author, and that the upstream web site is mentioned.
dpkg-sig-0.13.1+nmu2/debian/ 0000755 0000000 0000000 00000000000 13026063420 012262 5 ustar dpkg-sig-0.13.1+nmu2/debian/changelog 0000644 0000000 0000000 00000027720 13026063420 014144 0 ustar dpkg-sig (0.13.1+nmu4) unstable; urgency=medium
* Non-maintainer upload
* Exit non-zero upon unsigned .deb. Patch by Paul Harvey.
Closes: #783605
-- Christoph Biedl Tue, 20 Dec 2016 00:02:40 +0100
dpkg-sig (0.13.1+nmu3) unstable; urgency=medium
* Non-maintainer upload
* Bump debhelper compat level. Closes: #817437
-- Christoph Biedl Sun, 18 Dec 2016 12:41:15 +0100
dpkg-sig (0.13.1+nmu2) unstable; urgency=medium
* Non-maintainer upload.
* Handle trailing slashes in ar member names in deb archives created with
GNU ar. (Closes: #356509)
* Add support for control.tar, control.tar.xz, data.tar, data.tar.xz,
data.tar.lzma and data.tar.bz2. (Closes: #703437)
Based on a patch by Christoph Berg .
* Use correct get_deb_parts() function name instead of undefined
get_deb_part(). (Closes: #635232)
* Remove dead website URL from package description in debian/control and
dpkg-sig(1) man page. Change dpkg-sig and debian/copyright to mention
the URL used to be the website. (Closes: #422175)
* Add build-arch and build-indep targets in debian/rules.
* Fix typo in man page for “overridden”.
-- Guillem Jover Tue, 10 Jun 2014 19:53:53 +0200
dpkg-sig (0.13.1+nmu1) unstable; urgency=low
* Non-maintainer upload.
* Fix "FTBFS with perl 5.18: POD errors":
fix POD by adding missing '=back'.
(Closes: #723867)
* debian/control: replace Build-Depends-Indep with Build-Depends. Both
debhelper and perl are needed during clean (lintian error).
-- gregor herrmann Fri, 25 Oct 2013 20:07:08 +0200
dpkg-sig (0.13.1) unstable; urgency=low
* Non-Maintainer Upload by Gunnar Wolf
* Updated dependency on libconfigfile-perl to libconfig-file-perl,
updated the invocation of ConfigFile to Config::File, to avoid the
warning for the deprecated call (Closes: #387016)
-- Gunnar Wolf Mon, 20 Nov 2006 09:10:47 -0600
dpkg-sig (0.13) unstable; urgency=low
* HE
- dpkg-sig:
+ Fix -k option so that the maintainer name is still retrieved from the
gpg key. Patch from Julian Gilbey , thanks. (Closes:
#352727)
+ Remove --debug option (but leave code in so that manual code changes
can reactivate the debug stuff). (Closes: #352723)
- dpkg-sig.pod:
+ Update whole manpage, based on patch from Julian Gilbey
. Thanks! (Closes: #352730)
- examples/README:
+ Replace a left-over debsigs-ng.sample/md5sums.asc by digests.asc.
Thanks for the note, Julian. (Closes: #342473)
- debian/control:
+ Updated Standards-Version to 3.6.2
+ Make me Maintainer, aba Co-Maint (mostly to get dpkg-sig on my QA
overview page without co-maintained packages).
- Make package lintian clean (includes overrides for empty files, they
are empty for a reason).
-- Marc 'HE' Brockschmidt Fri, 24 Feb 2006 01:05:53 +0100
dpkg-sig (0.12) unstable; urgency=low
* HE
- dpkg-sig:
+ [1-9A-F] describes possible hex digits not as well as [0-9A-F] (Yes,
i'm a brainless idiot *sigh*). This should fix the Signer field for
people using a 0x\S+0\S+ key id.
+ If passphrase caching enabled, we now check the passphrase at the
beginning (and prompt again if something isn't ok)
+ Properly quote the $key and $maintainer arguments to gpg. (Closes:
#308049)
+ Let ssh choose the username for a host if it wasn't specified in the
URL, this allows the ssh config to do it's job. Thanks for the
report, Marc. (Closes: #331122)
+ Handle ssh errors a *wee* *little* bit better. Almost no improvement,
but enough to thank Marc for the report. (Closes: #331123)
+ Add missing chomps all over the place.
+ Replace '*changes' in a exec(grep) because that's crap and we know
it (the .changes, not the crap).
+ Use another exit code when trying to verify and finding a bad
signature. BAD SIG! GO TO YOUR ROOM! (Closes: #280559)
+ Check if an unknown key was used to create a signature when verifying
a .deb. Output UNKNOWNSIG for those and exit with exitcode 3.
+ Don't use /usr/bin/perl -W, but /usr/bin/perl -w, which doesn't output
stupid warnings.
+ die gracefully if a file couldn't be found (and don't end the show
with a exit 0).
-- Marc 'HE' Brockschmidt Tue, 8 Feb 2005 20:57:21 +0100
dpkg-sig (0.11) unstable; urgency=low
* HE
- dpkg-sig:
+ Change order of return values of get_md5sums.
+ Renamed get_md5sums to get_deb_digests.
+ Added get_deb_parts to allow faster listing of sigs.
+ Use md5sum(1) instead of Digest::MD5
+ Splitted the verify_deb into one sub per signature version,
this should allow to add new versions more easily.
+ Implemented new signature format suggested by weasel (thanks for
that!). We now sign sha1sums, md5sums and the size of every
part in the deb archive. The new format also transports more
meta-information (Signer, Date and Role). (Closes: #276557)
+ Restructured dpkg-sig a bit to shorten the things done in main::
+ Added a lot of documentation as POD.
+ Added --remote-ssh-port|-o as cli option to allow people to
specify the remote sshd port. (Closes: #271454)
- debian/rules:
+ Generate dpkg-sig.7 from the POD documentation in dpkg-sig.
-- Marc 'HE' Brockschmidt Fri, 15 Oct 2004 17:07:16 +0200
dpkg-sig (0.10) unstable; urgency=high
* HE
- urgency=high is IMHO needed, as #268376 would be a serious problems
for developers using stable.
- dpkg-sig:
+ Really really really work without ConfigFile in client mode. (Closes:
#268376)
+ Don't include the damn CVS dirs in the source. (Closes: #263106)
-- Marc 'HE' Brockschmidt Fri, 27 Aug 2004 17:01:04 +0200
dpkg-sig (0.9) unstable; urgency=low
* HE:
- dpkg-sig:
+ Move the use statement for ConfigFile in a way that we don't need
it in --client mode. Useful if you want to install the thing in
your home on a remote machine.
+ Add --help to give a brief help statement. (Closes: #257262)
+ Use value from Changed-By as default key when signing.
-- Marc 'HE' Brockschmidt Fri, 2 Jul 2004 23:30:24 +0200
dpkg-sig (0.8) unstable; urgency=low
* HE:
- debian/control:
+ Update the Uploaders field, i'm a DD now!
+ Depend on perl, not perl-base.
- debian/rules:
+ Fix a dh_md5sum problem, it excludes all files with DEBIAN in their
path (and we have such files as examples)
- dpkg-sig:
+ Fixed the "Signed deb *changes" output to print out the signed deb,
not the changes file it was referenced from.
+ Be a bit more verbose when signing .dscs and .changes.
+ Verify deb before signing it. [This lead also to a change on the
return value of get_md5sums internally]
-- Marc 'HE' Brockschmidt Thu, 11 Mar 2004 18:24:45 +0100
dpkg-sig (0.7) unstable; urgency=low
* HE:
- dpkg-sig:
+ Config file handling: Strip enclosing "s.
+ Die if gpg fails to sign. (Closes: #236183)
+ Rename get_md5_sums to get_md5sums.
+ Don't die when parsing a deb and reading a newline where we
actually expected an ar header (can happen if people change
stuff with vi). (Closes: #236185)
+ Cache md5sums in get_md5sums.
+ Don't ask for a passphrase if both -p/DPKGSIG_CACHE_PASS and
-f are used (use the passphrase from the file specified with -f
in that case)
+ Don't use die() if not needed for the weird stuff in eval{}.
Created the cute _die() function to do that.
+ Added a "--remote-dpkg-sig" (also available as "-r") switch to
allow users to specify where the dpkg-sig executable is. This
is useful if you're not able to get the remote admin to install
dpkg-sig.
+ Rearranged the main routine to drop duplicated code
+ Aliased add_file_to_ar_archive to add_sig_to_deb
+ add_sig_to_deb now starts a new ar archive if the file it should
write to hasn't existed before.
+ New switches --get-hashes, --sign-hashes and --write-signature
(also available as -h, -d and -w) The first one creates an
archiv of hashes of a deb/changes, the second signs it
(wherever you want) and the third one adds the signatures to
the deb(s and corrects the changes file).
+ Make standard output more verbose.
+ Notice when people try dpkg-sig --sign foo --sign-changes *deb
(--sign-changes uses an optional argument). Assume that this
wasn't meant, choose yes for --sign-changes and process the files
as other cli arguments.
- dpkg-sig.1:
+ Document the new --remote-dpkg-sig stuff.
+ Document the new --get-hashes, --sign-hashes and --write-signature
options.
+ Converted to POD, now available as dpkg-sig.pod
- dpkg-sig.pod:
+ Added (converted from dpkg-sig.1)
- debian/control:
+ Build-Depend on perl, we need pod2man to create the manpage.
- debian/rules:
+ Create manpage from dpkg-sig.pod
-- Marc 'HE' Brockschmidt Thu, 11 Mar 2004 14:04:35 +0100
dpkg-sig (0.6) unstable; urgency=high
* he:
- dpkg-sig:
+ Fixed bug with cached passphrases leading to invalid signatures.
We don't use GnuPG anymore (we now talk to GPG directly).
+ Added a "--gpgoptions" (also available as "-g") to allow users to
give gpg arbitrary options.
+ Don't use only -r to check if a .dsc file is readable. Replaced
with file_readable, which can handle a ssh://HOST:FILE path.
- debian/control: Remove the libgnupg-perl suggestion.
- dpkg-sig.1:
+ We don't need the GnuPG perl module to read the passphrase from a file.
+ We don't need the GnuPG to use the cached passphrase.
+ Document the new "--gpgoptions" stuff.
-- Marc 'HE' Brockschmidt Mon, 1 Mar 2004 19:08:40 +0100
dpkg-sig (0.5) unstable; urgency=low
* he:
- Added new switch "--passphrase-file" (also available as "-f"). Allows
signers to store their gpg passphrase in a file.
- Now signs *changes and *dsc without the help of debsign. This is very
useful for people signing many debs, as it uses the cached passphrase
or the file with the passphrase.
- Added example of the signing process, with a sample package and all
temp files. Have fun.
- debian/{control,rules}: Changed to install the examples. Now uses
debhelper version 4.
* aba:
- added the new options to the man page, and added an usage example.
-- Andreas Barth Sun, 29 Feb 2004 16:41:09 +0100
dpkg-sig (0.4) unstable; urgency=high
* Fixed the caching of the gpg passphrase.
* Added support to (re)sign changes files with debsign.
* Fixed a bug in the remote signing code (content of changes files deleted)
* Added support for a --debug switch, leading to a log of the communication
between master and client in the remote /tmp/dpkg-sig.log. Use with care.
-- Marc Brockschmidt Tue, 17 Feb 2004 00:36:23 +0100
dpkg-sig (0.3) unstable; urgency=low
* Marc 'HE' Brockschmidt is now Co-Maintainer (and sprinkled some
perl-magic on it)
* Remote signing now possible.
* Change the signature format to V3.
* Fix error with devscripts containing @. Closes: #229545
-- Andreas Barth Sun, 1 Feb 2004 22:18:38 +0100
dpkg-sig (0.2) unstable; urgency=low
* Create temporary directory only once
* Can now sign also changes-files.
-- Andreas Barth Wed, 14 Jan 2004 21:53:08 +0100
dpkg-sig (0.1) unstable; urgency=low
* Initial release. Closes: #223311
-- Andreas Barth Sun, 14 Dec 2003 22:36:49 +0100
dpkg-sig-0.13.1+nmu2/debian/compat 0000644 0000000 0000000 00000000003 13026063420 013461 0 ustar 10
dpkg-sig-0.13.1+nmu2/debian/control 0000644 0000000 0000000 00000001133 13026063420 013663 0 ustar Source: dpkg-sig
Section: devel
Priority: optional
Uploaders: Andreas Barth
Maintainer: Marc 'HE' Brockschmidt
Build-Depends: debhelper (>= 10~), perl
Standards-Version: 3.6.2
Package: dpkg-sig
Architecture: all
Depends: perl, gnupg, libdigest-md5-perl, libconfig-file-perl
Suggests: ssh, libterm-readkey-perl
Description: create and verify signatures on .deb-files
dpkg-sig is a low-level tool for creation and verification of
signature on Debian binary packages (.deb-files).
.
The created signed packages are strict compatible with dpkg and the
apt-utils.
dpkg-sig-0.13.1+nmu2/debian/dpkg-sig.examples 0000644 0000000 0000000 00000000013 10020337237 015522 0 ustar examples/*
dpkg-sig-0.13.1+nmu2/debian/lintian.overrides 0000644 0000000 0000000 00000000273 12345623342 015656 0 ustar dpkg-sig: zero-byte-file-in-doc-directory usr/share/doc/dpkg-sig/examples/sample/debian/tmp/tmp/test
dpkg-sig: zero-byte-file-in-doc-directory usr/share/doc/dpkg-sig/examples/sample/test
dpkg-sig-0.13.1+nmu2/debian/rules 0000755 0000000 0000000 00000002335 12345623372 013360 0 ustar #!/usr/bin/make -f
build-arch:
build-indep:
build:
clean:
dh_testdir
dh_testroot
dh_clean
binary-arch: build-arch
binary-indep: build-indep
dh_testdir
dh_testroot
dh_clean
mkdir -p debian/dpkg-sig/usr/share/man/man1
mkdir -p debian/dpkg-sig/usr/share/man/man7
mkdir -p debian/dpkg-sig/usr/share/doc/dpkg-sig
mkdir -p debian/dpkg-sig/usr/share/lintian/overrides
mkdir -p debian/dpkg-sig/usr/bin
cp dpkg-sig debian/dpkg-sig/usr/bin
pod2man --section=1 --release="Debian Project" --center="Debian GNU/Linux manual" dpkg-sig.pod debian/dpkg-sig/usr/share/man/man1/dpkg-sig.1
pod2man --section=7 --release="Debian Project" --center="Debian GNU/Linux manual" dpkg-sig debian/dpkg-sig/usr/share/man/man7/dpkg-sig.7
cp copyright debian/changelog debian/dpkg-sig/usr/share/doc/dpkg-sig
cp debian/lintian.overrides debian/dpkg-sig/usr/share/lintian/overrides/dpkg-sig
dh_installexamples
dh_compress
dh_gencontrol
dh_md5sums
#dh_md5sums excludes everything with DEBIAN in its path...
cd debian/dpkg-sig && \
md5sum >> DEBIAN/md5sums \
usr/share/doc/dpkg-sig/examples/sample/debian/tmp/DEBIAN/control \
usr/share/doc/dpkg-sig/examples/sample/debian/tmp/DEBIAN/md5sums
dh_fixperms
dh_builddeb
binary: binary-indep
dpkg-sig-0.13.1+nmu2/dpkg-sig 0000755 0000000 0000000 00000156524 13026063420 012510 0 ustar #!/usr/bin/perl -w
#
# dpkg-sig signs deb-files in a standard way
#
# (c) Andreas Barth 2003
# (c) Marc Brockschmidt 2004
#
# 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
#
# Upstream web site used to be .
=pod
=head1 NAME
B - Debian package archive (.deb) signature generation and verification tool
=head1 DESCRIPTION
This is the description of the source code, trying to help people to understand
how B works.
=head1 SYNOPSIS
=cut
use strict;
use Getopt::Long;
use Data::Dumper;
use IPC::Open2;
use IPC::Open3;
use File::Temp qw(tempdir);
use File::Copy qw(move);
use File::Basename qw(dirname basename);
$| = 1;
#Global variables (used for configuration and/or command line stuff)
my ($sign, $list, $verify, $verify_role, $verify_exact, $client, $cache_pass,
$pass_file, $key, $maintainer, $maintainer_pr, $verbose, %config, $tempdir,
%part_cache, $check_v2_sig, $check_v3_sig, $batch, $gpgoptions,
$passphrase, $remote_dpkg_sig, %ssh_connections, $sign_changes,
$get_hashes, $sign_hashes, $write_signature, $help, $DEBUG,
$verify_pattern, $remote_ssh_port);
my @configfiles = qw(/etc/devscripts.conf ~/.devscripts);
my $DPKG_SIG_VERSION = 0.13;
&process_cli_options();
#If wanted, print only help and exit:
if ($help) { &help; exit; }
#In client mode, we wait for commands and STDIN, we don't need the rest:
if ($client) {
print "Welcome. This is dpkg-sig in client mode. Protocol version 6\n";
&read_cmds();
exit;
}
#Only load Config::File if we're not in the client mode:
eval { require Config::File; import Config::File qw(read_config_file); };
_die($@) if $@;
$tempdir = tempdir("debsigs-ng.XXXXXX", CLEANUP => 1, TMPDIR => 1);
&load_config(@configfiles);
$remote_dpkg_sig ||= "dpkg-sig";
my @files = @ARGV;
if ($sign_hashes || $write_signature) {
for (@files) {
unless (/\.dpkg-sig-hashes$/) {
die _die("$_: Make sure all files were generated by dpkg-sig --get-hashes file\n");
}
}
for my $file (@files) {
if ($sign_hashes) {
print "Processing $file...\n";
sign_hashes($file);
print "Signed hashes in $file...\n";
} else {
print "Processing $file...\n";
my @done = write_signature($file);
print "Added signature to $_\n" for (@done);
}
}
exit;
}
if (grep { ! /(?:deb|changes)$/ } @files) {
die _die("We can only work on debs and changes files.");
}
if ($sign) {
if (length($sign) > 9) {
die _die("The signing name '$sign' is too long.");
} elsif ($sign !~ /^[a-z]+$/) {
die _die("The signing name '$sign' is not valid. Please use only letters.");
}
}
if ($verify_role) {
$verify_pattern = "^_gpg".$verify_role."[0-9A-Z]?\$";
} elsif ($verify_exact) {
$verify_pattern = "^_gpg$verify_exact";
} else {
$verify_pattern = "^_gpg.+";
}
#The main loop:
for my $exp (@files) {
my @globbed_files = glob_exp($exp);
die _die("Cannot find $exp: no such file") if (! @globbed_files);
for my $file (@globbed_files) {
if ($file =~ /\.deb$/) { #Yay! That's easy!
print "Processing $file...\n";
if ($sign) {
sign_deb($sign, $file);
print "Signed deb $file\n" if ! $batch;
} elsif ($verify || $verify_role || $verify_exact) {
my @verify_output = verify_deb($file, $verify_pattern);
print @verify_output;
exit 2 if grep { /^BADSIG/ } @verify_output;
exit 3 if grep { /^UNKNOWNSIG/ } @verify_output;
exit 4 if grep { /^NOSIG/ } @verify_output;
} elsif ($list) {
for (get_deb_parts($file)) {
print "$1\n" if ($_->[0] =~ /_gpg(.+)/);
}
} elsif ($get_hashes) {
write_deb_info($get_hashes, $file);
unlink "$file.dpkg-sig-hashes";
add_part_to_ar_archive ("$file.dpkg-sig-hashes", "deb\n$get_hashes\n$file ".get_file_md5sum($file)."\n" , "control");
add_part_to_ar_archive ("$file.dpkg-sig-hashes", _read_file("$tempdir/digests"), "deb0");
}
} else {
print "--- Processing changes file $file:\n";
my $changes_signed = 0;
my (%new_debs, $sums_control_data, @deb_md5sums, $maintainer_from_changes);
#Get default from *changes:
unless ($maintainer || $key) {
$maintainer_from_changes = 1;
chomp($maintainer = `grep ^Changed-By: $file | cut -d " " -f 2-`);
$maintainer = quotemeta($maintainer);
}
if ($get_hashes) {
unlink "$file.dpkg-sig-hashes";
$sums_control_data = "changes $file\n$get_hashes\n";
}
for my $deb (get_debs_from_changes($file, \$changes_signed)) {
print "Processing $deb...\n";
if ($sign) {
my $r = sign_deb($sign, $deb);
$new_debs{$r->[2]} = $r;
print "Signed deb $deb\n" if ! $batch;
} elsif ($verify || $verify_role || $verify_exact) {
my @verify_output = verify_deb($deb, $verify_pattern);
print @verify_output;
exit 2 if grep { /^BADSIG/ } @verify_output;
exit 3 if grep { /^UNKNOWNSIG/ } @verify_output;
exit 4 if grep { /^NOSIG/ } @verify_output;
} elsif ($list) {
for (get_deb_parts($deb)) {
print "$1\n" if ($_->[0] =~ /_gpg(.+)/);
}
} elsif ($get_hashes) {
$sums_control_data .= $deb." ".get_file_md5sum($deb)."\n";
write_deb_info($get_hashes, $deb);
push @deb_md5sums, _read_file("$tempdir/digests");
}
}
if ($sign) {
correct_changes_file($file, \%new_debs);
sign_control_files($file) if ($sign_changes ne "no" && ! ($sign_changes eq "auto" && ! $changes_signed));
} elsif ($get_hashes) {
add_part_to_ar_archive ("$file.dpkg-sig-hashes", $sums_control_data , "control");
for (my $i=0; $i<@deb_md5sums; $i++) {
add_part_to_ar_archive ("$file.dpkg-sig-hashes", $deb_md5sums[$i], "deb$i");
}
}
undef $maintainer if ($maintainer_from_changes);
}
}
}
#Clean our ssh connections:
for (values %ssh_connections) {
my ($pid, $readerfh, $writerfh) = @$_;
print $writerfh "quit\n";
sleep 1;
kill $pid;
}
exit;
=pod
=head2 I<\@file_info> = sign_deb (I<$signing_role>, I<$file>)
Does everything needed to add a signature to I<$file>:
=over 4
=item * Verifies existing signatures
=item * Creates the meta-data that is actually signed
=item * Calls gpg to sign the meta-data.
=item * Adds the signature to I<$file>
=back
Returns a reference to an array containing the new md5sum, the new size
and the name of the signed deb.
=cut
sub sign_deb {
my ($sig_name, $file) = @_;
#Check the existing signatures:
my @verify = verify_deb($file, "^_gpg.+");
if (grep { /^BADSIG/ } @verify) {
print STDERR "Can't sign $file, some signatures are invalid:\n".(join "", grep { /^BADSIG/ } @verify)."\n";
exit 2;
}
#This also chooses the right sig name:
$sig_name = write_deb_info($sig_name, $file);
sign_file ("$tempdir/digests", "$tempdir/digests.asc", "no_detach");
#Read sig:
my $sig = _read_file ($tempdir."/digests.asc");
return add_sig_to_deb($file, $sig, $sig_name);
}
=pod
=head2 I<$signature_name> = write_deb_info (I<$signing_role>, I<$file>)
Creates a digests.asc file with the meta-data of I<$file> in dpkg-sig's tempdir:
=over 4
=item * Gets the needed information from I<$file>
=item * Chooses the name of the signature
=item * Writes a file in a RFC822-like format containing the meta-data
=back
Returns the name that should be used to add the file to the deb.
=cut
sub write_deb_info {
my ($sig_name, $deb) = @_;
#Get digests:
my $digests = get_deb_digests($deb);
#Get name for our new signature part of the archive
$sig_name = get_sig_name($sig_name, $digests, $deb);
#Create digests file
unlink ($tempdir."/digests.asc");
my $signer_name = $key || $maintainer;
if ($signer_name =~ /^(0x)?[0-9A-F]{8}$/i) {
my $uidline = (grep /^uid:/, qx/gpg --list-keys --with-colons --fixed-list-mode $signer_name/)[0];
$signer_name = (split /:/, $uidline)[9] if defined $uidline;
chomp($signer_name);
}
my @data;
push @data, "Version: 4\n";
push @data, "Signer: $signer_name\n";
push @data, "Date: " . localtime() . "\n";
push @data, "Role: $1\n" if $sig_name =~ /^_gpg(\S+?)[A-Z0-9]?$/;
push @data, "Files: \n";
for my $part_info (@$digests) {
push @data, "\t" . join (" ", reverse @$part_info) . "\n";
}
_write_file("$tempdir/digests", @data);
return $sig_name
}
=pod
=head2 sign_hashes (I<$file>)
Signs a .dpkg-sig-hashes I<$file> containing the digests of a deb/changes file:
=over 4
=item * Checks the .dpkg-sig-hashes file to see if it really was created by us
=item * Creates a new archive, containing the old control file
=item * Signs the digests and adds the clearsigned data to the the new archive
=item * Substitutes the old file by the new, signed one.
=back
=cut
sub sign_hashes {
my ($file) = @_;
unlink ($tempdir."/digests");
unlink ($tempdir."/digests.asc");
unlink ($tempdir."/hashes.signed");
#We don't need the control data, we just want to check if this is real
#dpkg-sig generated hashes archiv:
my $control = get_archive_part($file, "control");
if ($control !~ /^(deb|changes)/) {
die _die("$file seems not to be a dpkg-sig hash archive");
}
add_part_to_ar_archive($tempdir."/hashes.signed", $control, "control");
#Now sign all hashes:
my $num = 0;
for (get_deb_parts($file)) {
my $part_name = $_->[0];
if ($part_name !~ /^(deb\d+|control)$/) {
print STDERR "W: $file contains $part_name, which shouldn't happen in dpkg-sig hash archive\n";
} elsif ($part_name =~ /^deb\d+/) {
my $data = get_archive_part($file, $part_name);
if ($data =~ /-----BEGIN PGP SIGNATURE-----/) {
die _die("$file seems to be already signed!\n");
}
_write_file($tempdir."/digests", $data);
sign_file("$tempdir/digests", "$tempdir/digests.asc", "no_detach");
my $s_data = _read_file($tempdir."/digests.asc");
add_part_to_ar_archive($tempdir."/hashes.signed", $s_data, "deb".$num++);
}
}
move($tempdir."/hashes.signed", $file);
}
=pod
=head2 I<@changed_files> = write_signature (I<$file>)
Adds the signatures from a signed .dpkg-sig-hashes I<$file> to the signed debs:
=over 4
=item * Checks the .dpkg-sig-hashes file to see if it really was created by us
=item * Tries to find out where we find the debs that have sigs in the .dpkg-sig-hashes
=item * Checks if the debs were changed since they were signed
=item * Adds signatures from the .dpkg-sig-hashes file to the debs
=item * If needed, it corrects the changes file to reflect the new sizes/md5sums of the debs
=back
Returns the pathes of the debs that were changed.
=cut
sub write_signature {
my ($file) = @_;
my @done;
unlink ($tempdir."/digests");
unlink ($tempdir."/digests.asc");
unlink ($tempdir."/hashes.signed");
#Get control data:
my @control = split (/\n/, get_archive_part($file, "control"));
if ($control[0] !~ /^(deb|changes)/) {
die _die("$file seems not to be a dpkg-sig hash archive");
}
chomp(my $sig_name = $control[1]);
my ($num, %new_debs) = (0);
for (get_ar_parts($file)) {
my $part_name = $_->[0];
if ($part_name !~ /^(deb\d+|control)$/) {
print STDERR "W: $file contains $part_name, which shouldn't happen in dpkg-sig hash archive\n";
} elsif ($part_name =~ /^deb\d+/) {
my $sig = get_archive_part($file, $part_name);
if ($sig !~ /-----BEGIN PGP SIGNATURE-----/) {
die _die("$file seems to be unsigned!\n");
}
#deb$num is the detached sig for the deb named in control line $num + 1
#Get the name and the md5sum:
my ($name, $md5sum) = split / /, $control[$num + 2];
my $path;
#Try to find the deb in this dir:
if (file_readable(basename($name)) && get_file_md5sum(basename($name)) eq $md5sum) {
$path = basename($name);
#Now try the path in the hashes file:
} elsif (file_readable($name) && get_file_md5sum($name) eq $md5sum) {
$path = $name;
#Wrong md5sum
} elsif (! (get_file_md5sum(basename($name)) eq $md5sum || get_file_md5sum($name) eq $md5sum)) {
die _die("The md5sum for $name is wrong. Please use an archive of signed hashes of the version of the file existing now.");
#We don't find the damn file!
} else {
die _die("Can't find $name. Please start dpkg-sig either in the dir with the debs to sign or in the dir where you got the hashes.");
}
push @done, $path;
$sig_name = get_sig_name($sig_name, [get_deb_parts($path)], $path);
my $r = add_sig_to_deb($path, $sig, $sig_name);
$new_debs{$r->[2]} = $r;
$num++;
}
}
if ($control[0] =~ /^changes (.+)$/) {
if (file_readable(basename($1))) {
correct_changes_file(basename($1), \%new_debs);
print "Corrected changes file ".basename($1)."\n";
} elsif (file_readable($1)) {
correct_changes_file($1, \%new_debs);
print "Corrected changes file $1\n";
} else {
print STDERR "Can't find changes file $1, so won't correct it.\n";
}
}
return @done;
}
=pod
=head2 I<@output> = verify_deb (I<$deb>, I<$verify_pattern>)
Verifies all signatures in I<$deb> with names matching I<$verify_pattern>:
=over 4
=item * Gets the digests of all parts of I<$deb>.
=item * Skips all signatures that don't match I<$verify_pattern>.
=item * Writes the signatures to $tempdir/digests.asc.
=item * Calls a function to check if $tempdir/digests.asc is valid in the v4 format, then tries v3 and v2.
=back
Returns its output. This is needed to achieve a "silent" verification when signing a deb.
=cut
sub verify_deb {
my ($deb, $verify_pattern) = @_;
my @return;
#Get MD5 sums:
my $digests = get_deb_digests($deb);
my $found_sigs;
for (my $n=0;$n<@$digests;$n++) {
my ($part_name, $size, $sha1sum, $md5sum) = @{@$digests[$n]};
next if $part_name !~ /$verify_pattern/;
unlink ($tempdir."/digests.asc");
unlink ($tempdir."/digests");
my $sig = get_archive_part($deb, $part_name);
_write_file($tempdir."/digests.asc", $sig);
my ($status, @info);
if ($sig =~ /BEGIN PGP SIGNED MESSAGE/) {
$status = verify_deb_sig_v4($part_name, $n, $digests, \@info, \@return);
$found_sigs = 1;
}
if ($check_v3_sig && (!$status || $status eq "BAD")) {
$status = verify_deb_sig_v3($part_name, $n, $digests, \@info, \@return);
$found_sigs = 1;
}
if ($check_v2_sig && (!$status || $status eq "BAD")) {
$status = verify_deb_sig_v2($part_name, $n, $digests, \@info, \@return);
$found_sigs = 1;
}
if ($status && $status eq "GOOD") {
push @return, "GOODSIG $part_name $info[0] $info[2]\n";
} elsif ($status && $status eq "UNKNOWN" && (! $batch || $batch >= 2)) {
push @return, "UNKNOWNSIG $part_name $info[0]\n";
} else {
push @return, "BADSIG $part_name\n"
}
}
if (!$found_sigs) {
push @return, "NOSIG\n"
}
return @return;
}
=pod
=head2 I<$verification_status> = verify_deb_sig_v4 (I<$part_name>, I<$part_number>, I<\@digests>, I<\@info>, I<\@return>)
Verifies if $tempdir/digests is a valid (version 4) signature for the deb described with I<\@digests>:
=over 4
=item * Calls gpg to verify the OpenPGP signature in $tempdir/digests.asc itself.
=item * Parses the signature to get the digests that were actually signed
=item * Compare the digests of the deb and those extracted from the signature to see if the deb was changed.
=item * Check that the name in the ar archive matches the "Role" field in the signature.
=item * DON'T check the Signer- and Date-Fiels.
=item * Check that at least the digests for control.tar.gz, data.tar.gz and debian-binary were signed.
=back
Returns if the the signature is good, by an unknown key, or bad.
=cut
sub verify_deb_sig_v4 {
my ($part_name, $part_number, $digests, $info, $return) = @_;
#Check signature:
my @cmdline = qw(gpg --openpgp --decrypt --no-auto-check-trustdb --batch
--no-tty --status-fd 1 2>&1);
push @cmdline, "--output", "$tempdir/digests", "$tempdir/digests.asc";
my $res=qx/@cmdline/;
@$info = split(/ /, $1 ) if $res =~ /^\[GNUPG:\] VALIDSIG (.*)$/m;
if ($res =~ /^\[GNUPG:\] NO_PUBKEY \S{8}(\S{8})/m) {
$info->[0] = $1;
return "UNKNOWN";
}
return "FORCE_BAD" unless $res =~ /^\[GNUPG:\] GOOD/m;
#Now find out if the deb contains the data that was signed:
open (FH, "<", "$tempdir/digests") || die "Can't open $tempdir/digests: $!";
my (%data, $field_name);
while () {
if (/^(\S+):\s*(.*)$/) {
$field_name = lc($1);
$data{$field_name} = $2 || "";
} elsif (/^\s+(.+)$/ && $field_name) {
$data{$field_name} .= ($data{$field_name} ? "\n" : "") . $1;
}
}
close FH;
if ($data{version} > 4) {
push @$return, "$part_name: v$data{version} signature, dpkg-sig is too old to check it.\n";
return "FORCE_BAD";
}
my %seen_files;
for my $file_info (split /\n/, $data{files}) {
my ($md5sum, $sha1sum, $size, $name) = split /\s+/, $file_info;
$seen_files{$name} = 1;
my $checked_something=0;
for my $member_info (@$digests) {
if ($member_info->[0] eq $name) {
$checked_something = 1;
if ($member_info->[1] ne $size) {
push @$return, "$part_name: ${name}'s size differs from signed size.\n" if $verbose;
return "FORCE_BAD";
} elsif ($member_info->[2] ne $sha1sum) {
push @$return, "$part_name: ${name}'s sha1sum differs from signed size.\n" if $verbose;
return "FORCE_BAD";
} elsif ($member_info->[3] ne $md5sum) {
push @$return, "$part_name: ${name}'s md5sum differs from signed size.\n" if $verbose;
return "FORCE_BAD";
}
}
}
unless ($checked_something) {
push @$return, "$part_name: ${name} signed, but not in the deb.\n" if $verbose;
return "FORCE_BAD";
}
}
$part_name =~ /^_gpg(\S+?)[A-Z0-9]?$/;
if ($data{role} ne $1) {
push @$return, "$part_name: signature name and signed role differ.\n" if $verbose;
return "FORCE_BAD";
}
return "FORCE_BAD" unless ($seen_files{'debian-binary'} &&
($seen_files{'control.tar'} || $seen_files{'control.tar.gz'} || $seen_files{'control.tar.xz'}) &&
($seen_files{'data.tar'} || $seen_files{'data.tar.gz'} || $seen_files{'data.tar.xz'} || $seen_files{'data.tar.bz2'} || $seen_files{'data.tar.lzma'}));
return "GOOD";
}
=pod
=head2 I<$verification_status> = verify_deb_sig_v3 (I<$part_name>, I<$part_number>, I<\@digests>, I<\@info>, I<\@return>)
Verifies if $tempdir/digests is a valid (version 3) signature for the deb described with I<\@digests>:
=over 4
=item * Creates a file in $tempdir/digests that contains the signing role and the digests from the current deb.
=item * Calls gpg to verify that the detached OpenPGP signature in $tempdir/digests.asc is valid for $tempdir/digests.
=back
Returns if the the signature is good, by an unknown key, or bad.
=cut
sub verify_deb_sig_v3 {
my ($part_name, $part_number, $digests, $info, $return) = @_;
my @cmdline = qw(gpg --openpgp --verify --no-auto-check-trustdb --batch
--no-tty --status-fd 1 2>&1);
push @cmdline, "$tempdir/digests.asc", "$tempdir/digests";
push @$return, "$part_name: Invalid v4 sig ... Trying v3\n" if $verbose;
$part_name =~ s/^_gpg(\S+?)[A-Z0-9]?$/$1/;
open (FH, ">", $tempdir."/digests") || die _die("Couldn't open $tempdir/digests: $!");
print FH $part_name, "\n";
print FH join "\n", map { $_->[3] . " " . $_->[0] } @$digests[0..$part_number-1];
print FH "\n";
close FH;
my $res=qx/@cmdline/;
@$info = split(/ /, $1 ) if $res =~ /^\[GNUPG:\] VALIDSIG (.*)$/m;
if ($res =~ /^\[GNUPG:\] NO_PUBKEY \S{8}(\S{8})/m) {
$info->[0] = $1;
return "UNKNOWN";
}
return "BAD" unless $res =~ /^\[GNUPG:\] GOOD/m;
return "GOOD";
}
=pod
=head2 I<$verification_status> = verify_deb_sig_v2 (I<$part_name>, I<$part_number>, I<\@digests>, I<\@info>, I<\@return>)
Verifies if $tempdir/digests is a valid (version 2) signature for the deb described with I<\@digests>:
=over 4
=item * Creates a file in $tempdir/digests that contains the digests from the current deb.
=item * Calls gpg to verify that the detached OpenPGP signature in $tempdir/digests.asc is valid for $tempdir/digests.
=back
Returns if the the signature is good, by an unknown key, or bad.
=cut
sub verify_deb_sig_v2 {
my ($part_name, $part_number, $digests, $info, $return) = @_;
my @cmdline = qw(gpg --openpgp --verify --no-auto-check-trustdb --batch
--no-tty --status-fd 1 2>&1);
push @cmdline, "$tempdir/digests.asc", "$tempdir/digests";
push @$return, "$part_name: Invalid v3 sig ... Trying v2\n" if $verbose;
open (FH, ">", $tempdir."/digests") || die _die("Couldn't open $tempdir/digests: $!");
print FH join "\n", map { $_->[3] . " " . $_->[0] } @$digests[0..$part_number-1];
print FH "\n";
close FH;
my $res= qx/@cmdline/;
@$info = split(/ /, $1 ) if $res =~ /^\[GNUPG:\] VALIDSIG (.*)$/m;
if ($res =~ /^\[GNUPG:\] NO_PUBKEY \S{8}(\S{8})/m) {
$info->[0] = $1;
return "UNKNOWN";
}
return "BAD" unless $res =~ /^\[GNUPG:\] GOOD/m;
return "GOOD";
}
=pod
=head2 I<$sig_name> = get_sig_name (I<$sig_name>, I<\@parts>, I<$deb>)
Tries to find a filename for the signature. Receives the role and constructs
a name not already present in I<$deb>.
Returns the final name or dies if it wasn't possible to construct a name.
=cut
sub get_sig_name {
my ($sig_name, $parts, $deb) = @_;
$sig_name = "_gpg".$sig_name;
if (grep { $_->[0] eq $sig_name } @$parts) {
my $changed = 0;
for my $ext (0..9, "A" .. "Z") {
if (! grep { $_->[0] eq $sig_name.$ext} @$parts) {
$sig_name .= $ext;
++$changed;
last;
}
}
die _die("$deb: Couldn't get a name for the signature part") if ! $changed;
}
return $sig_name;
}
=pod
=head2 correct_changes_file (I<$changes>, I<\%new_deb_info>)
Receives a path to a changes file I<$changes> and a hash reference
I<\%new_deb_info> containing new sizes and md5sums of debs in that changes
file. It'll parse the changes file, replace the old values by the new ones.
If the file is signed, the signature will be stripped (as it would be
invalid anyway).
=cut
sub correct_changes_file {
my ($changes, $new_deb_info) = @_;
if ($changes =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($changes);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
print $writerfh "correct_changes_file $file\n";
my ($response, $t);
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
if ($response =~ /^300 /) {
for (keys %$new_deb_info) {
print $writerfh join (" ", @{$new_deb_info->{$_}}), "\n";
}
print $writerfh ".\n";
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
if ($response !~ /^200 /) {
die _die("remote dpkg-sig on $host returned \"$response\"");
}
} else {
die _die("remote dpkg-sig on $host seems to be weird. Can't parse \"$response\"");
}
} else {
my ($new_changes, $in_files) = ('', 0);
open (CHANGES, "+<", $changes) || die _die("$changes: Can't open file: $!");
while () {
if (/^-----BEGIN PGP SIGNED MESSAGE-----$/) { while () { last if /^\s*$/ }; next }
if ($in_files) {
chomp;
last if ! s/^ //;
my ($md5sum, $size, $section, $priority, $file_name) = split / /, $_;
if ($new_deb_info->{$file_name}) {
$md5sum = $new_deb_info->{$file_name}->[0];
$size = $new_deb_info->{$file_name}->[1];
chomp($md5sum);
}
$new_changes .= " " . join (" ", ($md5sum, $size, $section, $priority, $file_name)). "\n";
} else {
$new_changes .= $_;
}
$in_files = "yes" if /^Files:/;
}
seek(CHANGES, 0, 0) || die _die("$changes: Can't rewind file: $!");
truncate(CHANGES, 0) || die _die("$changes: Can't truncate file: $!");
print CHANGES $new_changes;
close CHANGES;
}
}
=pod
=head2 I<\@new_file_info> = add_part_to_ar_archive (I<$file>, I<$new_data>, I<$new_name>)
=head2 I<\@new_file_info> = add_sig_to_deb (I<$file>, I<$new_data>, I<$new_name>)
Adds I<$new_data> to I<$file> as new ar archiv part, using $new_name as
filename. If I<$file> doesn't exist, a new ar archive is created. Returns
the new md5sum and size of I<$file>.
=cut
sub add_part_to_ar_archive { return add_sig_to_deb(@_); }
sub add_sig_to_deb {
my ($deb, $sig, $sig_name) = @_;
my ($new_md5sum, $new_file_size);
if ($deb =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($deb);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
print $writerfh "add_sig_to_deb $sig_name $file\n";
my ($response, $t);
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
if ($response =~ /^300 /) {
for (split /\n/, $sig) {
s/^\./../g;
print $writerfh $_, "\n";
}
print $writerfh ".\n";
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
if ($response !~ /^200 /) {
die _die("remote dpkg-sig on $host returned \"$response\"");
} else {
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
($new_md5sum, $new_file_size) = split (/ /, $response);
}
} else {
die _die("remote dpkg-sig on $host seems to be weird. Can't parse \"$response\"");
}
} else {
die _die("$deb: Arch member name $sig_name too long!") if (length($sig_name) > 14);
my $new_part = sprintf("%-16s%-12s%-6s%-6s%-8s%-10s`\n%s",
$sig_name, time, 0, 0, 100644, length($sig), $sig . (length($sig)%2 ? "\n":""));
if (!stat($deb)) {
open (DEB, ">", (glob $deb)[0]) || die _die("Couldn't open ".(glob $deb)[0].": $!");
print DEB "!\n";
} else {
open (DEB, ">>", (glob $deb)[0]) || die _die("Couldn't open ".(glob $deb)[0].": $!");
}
print DEB $new_part || die _die("Couldn write to $deb: $!");
close DEB;
$new_md5sum = get_file_md5sum($deb);
$new_file_size = (stat($deb))[7];
}
return [$new_md5sum, $new_file_size, basename($deb)];
}
=pod
=head2 I<@parts> = get_ar_parts (I<$file>)
=head2 I<@parts> = get_deb_parts (I<$file>)
Parses I<$file> as ar archive and returns all filenames included in the archive.
=cut
sub get_ar_parts { get_deb_parts(@_) }
sub get_deb_parts {
my ($deb) = shift;
my @parts;
if ($deb =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($deb);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
print $writerfh "get_deb_parts $file\n";
my $response = <$readerfh>;
chomp($response);
if ($response !~ /^200 /) {
die _die("remote dpkg-sig on $host returned \"$response\"");
} else {
while (<$readerfh>) {
last if (/^\.$/);
s/^\.\././;
chomp;
push @parts, [$_];
}
}
} else {
open(DEB, "<", (glob $deb)[0]) || die _die("Couldn't open $deb: $!");
if (read(DEB, $_, 8) != 8) {
die _die("Couldn't open $deb: ar format b0rken [Couldn't read first 8 bytes]");
} elsif ($_ ne "!\n") {
die _die("Couldn't open $deb: ar format b0rken");
}
do {
my $line = ;
if ($line =~ /\S/) { #This should help with additional newlines
#debian-binary 1075243548 0 0 100644 4 `
my $name = substr($line, 0, 16);
$name =~ s{/?\s*$}{}g;
my $length = substr($line, 48, 10);
$length =~ s/\s*//g;
next if (!$name && $length && $length =~ /^\d+\s*$/);
seek (DEB, $length, 1) or die _die("Couldn't read $name in $deb: File too short!");
if ($length % 2) {
seek (DEB, 1, 1) or die _die("Couldn't read $name in $deb: File too short!");
}
push @parts, [$name];
}
} while (!eof(DEB));
close DEB;
}
return @parts;
}
=pod
=head2 I<@debs> = get_debs_from_changes (I<$file>, I<\$changes_signed>)
Parses I<$file> as Debian .changes file and returns all listed debs. The dirname
of I<$file> is prepended to the debs, which means that the returned URIs should
exist.
If I<$file> is signed, I<$changes_signed> is set to "yes".
=cut
sub get_debs_from_changes {
my ($changes, $changes_signed) = @_;
my $changes_path = dirname($changes);
my @debs;
if ($changes =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($changes);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
print $writerfh "get_debs_from_changes $file\n";
my $response = <$readerfh>;
chomp($response);
if ($response !~ /^200 /) {
die _die("remote dpkg-sig on $host returned \"$response\"");
} else {
$$changes_signed = "yes" if $response =~ /^200 ok debs in signed/;
while (<$readerfh>) {
last if (/^\.$/);
s/^\.\././;
chomp;
if (defined ($user)) {
push @debs, "ssh://$user\@$host:$_";
} else {
push @debs, "ssh://$host:$_";
}
}
}
} else {
open (CHANGES, "<", $changes) || die _die("$changes: Can't open file: $!");
while () {
$$changes_signed = "yes" if /-----BEGIN PGP SIGNED MESSAGE-----/;
last if /^Files:/
}
while () {
chomp;
if (/^ [^ ]+ \d+ [^ ]+ [^ ]+ (.+)$/) {
push @debs, $changes_path."/".$1 if $1 =~ /^(.+\.deb)$/;
} elsif (/^\s*$/) {
last;
} else {
print STDERR "$changes corrupted\n";
}
}
close CHANGES;
}
return @debs;
}
=pod
=head2 I<\@digests> = get_deb_digests (I<$deb>)
Parses I<$deb> and returns the meta-data of the included files. The read
data is piped to md5sums and sha1sums, which create the respective
digests. The digests, the filename and the size are put in an anymous
array looking like this: [B<$name>, B<$size>, B<$sha1sum>, B<$md5sum>].
One of these arrays is pushed to I<@digests> for every file in I<$deb>.
=cut
sub get_deb_digests {
my $deb = shift;
my @digests;
if ($deb =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($deb);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
print $writerfh "get_deb_digests $file\n";
my $response = <$readerfh>;
chomp($response);
if ($response !~ /^200 /) {
die _die("remote dpkg-sig on $host returned \"$response\"");
} else {
while (<$readerfh>) {
last if (/^\.$/);
s/^\.\././;
chomp;
my ($name, $size, $sha1sum, $md5sum) = split / /, $_;
push @digests, [$name, $size, $sha1sum, $md5sum];
}
}
} else {
open(DEB, "<", (glob $deb)[0]) || die _die("Couldn't open $deb: $!");
if (read(DEB, $_, 8) != 8) {
die _die("Couldn't open $deb: ar format b0rken [Couldn't read first 8 bytes]");
} elsif ($_ ne "!\n") {
die _die("Couldn't open $deb: ar format b0rken");
}
do {
my $line = ;
if ($line =~ /\S/) { #This should help with additional newlines
my ($name, $size, $md5sum, $sha1sum);
#debian-binary 1075243548 0 0 100644 4 `
$name = substr($line, 0, 16);
$name =~ s{/?\s*$}{}g;
my $length = substr($line, 48, 10);
$length =~ s/\s*//g;
next if (!$name && $length && $length =~ /^\d+\s*$/);
$size = $length;
my ($part, $read_length, $md5sum_input, $md5sum_output, $sha1sum_input, $sha1sum_output);
open2($md5sum_output, $md5sum_input, qq{md5sum});
if (-x "/usr/bin/sha1sum") {
open2($sha1sum_output, $sha1sum_input, qq{sha1sum});
} elsif (-x "/usr/bin/gpg") { #We need this for woody *sigh*:
open2($sha1sum_output, $sha1sum_input, qq{gpg --print-md sha1 | tr 'A-Z' 'a-z' | sed 's/ //g'});
} else {
die _die("Can't compute sha1sum, please install sha1sum or gpg");
}
do {
$read_length = ($length > 4096) ? 4096 : $length;
$length -= $read_length;
if (read (DEB, $part, $read_length) != $read_length) {
die _die("Couldn't read $name in $deb: File too short!");
}
if ($read_length % 2 && read (DEB, $_, 1) != 1) {
die _die("Couldn't read $name in $deb: File too short!");
}
print $md5sum_input $part;
print $sha1sum_input $part;
} while ($length > 0);
close $md5sum_input; close $sha1sum_input;
($md5sum = <$md5sum_output>) =~ s/[\s\n\r-]//g;
($sha1sum = <$sha1sum_output>) =~ s/[\s\n\r-]//g;
push @digests, [$name, $size, $sha1sum, $md5sum];
}
} while (!eof(DEB));
close DEB;
}
return \@digests;
}
=pod
=head2 I<$md5sum> = get_file_md5sum (I<$file>)
Returns the md5sum for I<$file>.
=cut
sub get_file_md5sum {
my $file = shift;
my $md5sum;
if ($file =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($file);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
if ($prot_version < 5) {
die _die("remote dpkg-sig on $host is too old and can't return the needed md5sum of a file.");
}
print $writerfh "get_file_md5sum $file\n";
my ($response, $t);
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
if ($response =~ /^200 ok md5sum is (\S+)/) {
$md5sum = $1;
} else {
die _die("remote dpkg-sig on $host returned \"$response\"");
}
} else {
chomp ($md5sum = `md5sum $file | cut -d " " -f 1`);
}
return $md5sum;
}
=pod
=head2 I<$part_data> = get_archive_part (I<$archive>, I<$part_name>)
Returns the content of I<$part_name> in the ar archive I<$archive>.
=cut
sub get_archive_part {
my ($deb, $part_name) = @_;
my $part = '';
if ($deb =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($deb);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
print $writerfh "get_archive_part $part_name $file\n";
my $response = <$readerfh>;
if ($response !~ /^200 /) {
die _die("remote dpkg-sig on $host returned \"$response\"");
} else {
while (<$readerfh>) {
last if (/^\.$/);
s/^\.\././;
chomp;
$part .= "$_\n";
}
}
} else {
open(DEB, "<", $deb) || die _die("Couldn't open $deb: $!");
if (read(DEB, $_, 8) != 8) {
die _die("Couldn't open $deb: ar format b0rken [Couldn't read first 8 bytes]");
} elsif ($_ ne "!\n") {
die _die("Couldn't open $deb: ar format b0rken");
}
while (!eof(DEB)) {
my $line = ;
#debian-binary 1075243548 0 0 100644 4 `
my $name = substr($line, 0, 16);
$name =~ s{/?\s*$}{}g;
my $length = substr($line, 48, 10);
next if (!$name && $length && $length =~ /^\d+\s*$/);
my $tmp_part;
if (read (DEB, $tmp_part, $length) != $length) {
die _die("Couldn't read $name in $deb: File too short!");
}
if ($length % 2 && read (DEB, $_, 1) != 1) {
die _die("Couldn't read $name in $deb: File too short!");
}
if ($name eq $part_name) {
$part = $tmp_part;
last;
}
}
close DEB;
}
return $part;
}
=pod
=head2 I<@file_data> = read_control_file (I<$file>)
Returns the content of I<$file> as array with one line per element.
=cut
sub read_control_file {
my $file = shift;
my @file_data;
die _die("This only returns debian control files (ending with .changes or dsc)") if $file !~ /\.(?:dsc|changes)$/;
if ($file =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($file);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
if ($prot_version < 3) {
die _die("remote dpkg-sig on $host is too old and can't return the needed control file data.");
}
print $writerfh "read_control_file $file\n";
my $response = <$readerfh>;
chomp($response);
if ($response !~ /^200 /) {
die _die("remote dpkg-sig on $host returned \"$response\"");
} else {
while (<$readerfh>) {
last if (/^\.$/);
s/^\.\././;
push @file_data, $_;
}
}
} else {
open (FH, $file) or die _die("Can't open $file: $!");
@file_data = ;
close FH;
}
return @file_data;
}
=pod
=head2 I<@file_info> = write_control_file (I<$file>, I<\@data>)
Writes contents of I<\@data> to I<$file>. Returns new md5sum and size
of I<$file>.
=cut
sub write_control_file {
my ($file, $data) = @_;
my ($response, $t, $new_md5sum, $new_file_size);
die _die("This only writes debian control files (ending with .changes or dsc)") if $file !~ /\.(?:dsc|changes)$/;
if ($file =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($file);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
if ($prot_version < 3) {
die _die("remote dpkg-sig on $host is too old and can't return the needed control file data.");
}
print $writerfh "write_control_file $file\n";
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
if ($response =~ /^300 /) {
print $writerfh @$data;
print $writerfh ".\n";
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
if ($response =~ /^200 .+New md5sum, size: ([^ ]+) (\d+)/) {
$new_md5sum = $1;
$new_file_size = $2;
} else {
die _die("remote dpkg-sig on $host returned \"$response\"");
}
} else {
die _die("remote dpkg-sig on $host seems to be weird. Can't parse \"$response\"");
}
} else {
_write_file($file, @$data);
chomp ($new_md5sum = `md5sum $file | cut -d " " -f 1`);
$new_file_size = (stat($file))[7];
}
return ($new_md5sum, $new_file_size);
}
=pod
=head2 I<@files> = glob_exp (I<$exp>)
Returns the result of globbing I<$exp> as array.
=cut
sub glob_exp {
my $exp = shift;
my @files;
if ($exp =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($exp);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
print $writerfh "glob_exp $file\n";
my $response = <$readerfh>;
if ($response !~ /^200 /) {
die _die("remote dpkg-sig on $host returned \"$response\"");
} else {
while (<$readerfh>) {
last if (/^\.$/);
s/^\.\././;
chomp;
if (defined ($user)) {
push @files, "ssh://$user\@$host:$_";
} else {
push @files, "ssh://$host:$_";
}
}
}
} else {
push @files, glob($exp);
}
return @files;
}
=pod
=head2 I<$file_readable> = file_readable (I<$file>)
Returns a true value if I<$file> is readable.
=cut
sub file_readable {
my $file = shift;
if ($file =~ m!^ssh://!) {
my ($user, $host, $file) = split_ssh_uri($file);
my ($readerfh, $writerfh, $prot_version) = get_ssh_connection($user, $host);
if ($prot_version < 4) {
print "W: remote dpkg-sig on $host is too old and can't return the needed data. .dsc not signed";
return 0;
}
print $writerfh "file_readable $file\n";
my ($response, $t);
$response = '';
do { read($readerfh, $t, 1); $response .= $t } while ($t ne "\n");
chomp($response);
if ($response =~ /^200 /) {
return 1;
} elsif ($response =~ /^400 /) {
return 0;
} else {
die _die("remote dpkg-sig on $host returned \"$response\"");
}
} else {
return -r $file;
}
}
=pod
=head2 I<@ssh_uri_parts> = split_ssh_uri (I<$uri>)
Splits an ssh URI $uri into a B<$user>, B<$host> and B<$path> part.
=cut
sub split_ssh_uri {
my ($uri) = @_;
my ($user, $host, $path);
#ssh://$USER@$HOST:$PATH
if ($uri =~ m!^ssh://(?:([^@\s]+)@)?(\S+):(.+)!) {
($user, $host, $path) = ($1, $2, $3);
$user ||= undef;
die _die("$uri: Please specify at least a host to connect to.") if !$host;
die _die("$uri: Please specify a path on the remote host.") if !$path;
} else {
die _die("$uri is no ssh uri!");
}
return ($user, $host, $path);
}
=pod
=head2 I<@ssh_connection_info> = get_ssh_connection (I<$user>, I<$host>)
Opens a ssh connection to I<$host> as user I<$user>, directly calling
B. It checks if the remote B is compatible to the
current version and returns the B<$pid>, the Read-Filehandle B<$readerfh>
and the Write-Filehandle B<$writerfh>.
=cut
sub get_ssh_connection {
my ($user, $host) = @_;
my $connection_id = (defined ($user))?"$user\@$host":$host;
$remote_ssh_port ||= "";
$remote_ssh_port =~ s/^\s*(\d+)\s*$/-p $&/;
if (! $ssh_connections{$connection_id} ) {
my ($readerfh, $writerfh);
die _die("No ssh installed, we need it to connect to the remote host.") if (not `which ssh`);
my $pid = open2($readerfh, $writerfh, qq{ssh $remote_ssh_port $connection_id '$remote_dpkg_sig --client $DEBUG 2>/dev/null || echo "No dpkg-sig available"' 2>&1});
my $response = <$readerfh>;
if ($response && $response !~ /protocol version/i) {
if ($response && $response =~ /No dpkg-sig available/) {
die _die("No $remote_dpkg_sig on remote host installed.");
} else {
if ($response) {
die _die("ssh returned $response");
} else {
die _die("Some problem with the ssh connection $connection_id occured");
}
}
}
if ($response !~ /protocol version (\d+)$/i || $1 < 6) {
die _die("dpkg-sig on $host is too old (we need protocol version 6)");
}
$ssh_connections{$connection_id} = [$pid, $readerfh, $writerfh, $1];
}
return (@{$ssh_connections{$connection_id}}[1,2,3]);
}
=pod
=head2 sign_control_files (I<$changes_file>)
This works like debsign:
=over 4
=item Checks if a .dsc exists.
=item If the .dsc should be signed, it tries to do so..
=item Writes the new .dsc with the new signature.
=item Reads I<$changes_file> and puts in the new size/md5sum of the .dsc.
=item Signs I<$changes_file> and write the signed copy back.
=back
=cut
sub sign_control_files {
my $file = shift;
my $sign_dsc = $sign_changes =~ /full$/ ? 1 : 0;
my ($dsc, $new_dsc_md5sum, $new_dsc_size);
$dsc = "$1.dsc" if ($file =~ /^(.+)_[^ _]+.changes/ && file_readable("$1.dsc"));
#Clean the tempdir:
unlink ($tempdir."/dsc.unsigned");
unlink ($tempdir."/dsc.signed");
unlink ($tempdir."/changes.unsigned");
unlink ($tempdir."/changes.signed");
if ($sign_dsc && $dsc) {
open (DSC, ">", $tempdir."/dsc.unsigned") || die _die("Can't open $tempdir/dsc.unsigned: $!");
my @data = read_control_file($dsc);
for (my $i=0;$i<@data;$i++) {
if ($data[$i] =~ /^-----BEGIN PGP SIGNED MESSAGE-----$/) {
if ($sign_changes eq "force_full") {
$sign_dsc = 1;
} elsif (! $batch) {
print "The .dsc file is already signed.\nWould you like to use the current signature? [Yn] ";
chomp(my $answer = lc());
$sign_dsc = 0 unless ($answer eq "n" || $answer eq "no");
} else {
$sign_dsc = 0;
}
while(defined $data[$i]) { last if $data[$i++] =~ /^\s*$/ }
} elsif ($data[$i] =~ /^\s*$/) {
last;
}
print DSC $data[$i];
}
print DSC "\n";
close DSC;
if ($sign_dsc) {
#Sign it:
sign_file($tempdir."/dsc.unsigned",$tempdir."/dsc.signed", "no_detach") if $sign_dsc;
#Read and write them to the fitting location:
open (DSC, $tempdir."/dsc.signed") || die _die("Can't open $tempdir/dsc.signed: $!");
@data = ;
close DSC;
($new_dsc_md5sum, $new_dsc_size) = write_control_file($dsc, \@data);
print "Signed .dsc $dsc\n" unless $batch;
}
}
#Now the changes file:
open (CHANGES, ">", $tempdir."/changes.unsigned") || die _die("Can't open $tempdir/changes.unsigned: $!");
my $basename_dsc = basename($dsc) if $dsc;
for (read_control_file($file), "\n") {
#If we've changed the .dsc file, we have to use the new values in the .changes:
if ($basename_dsc && $new_dsc_md5sum && $new_dsc_size && $_ =~ /\Q$basename_dsc\E$/) {
s/^ [^ ]+ \d+ (.+)$/ $new_dsc_md5sum $new_dsc_size $1/;
}
print CHANGES $_;
}
close CHANGES;
sign_file($tempdir."/changes.unsigned",$tempdir."/changes.signed", "no_detach");
my @data;
open (CHANGES, $tempdir."/changes.signed") || die _die("Can't open $tempdir/changes.signed: $!");
@data = ;
close CHANGES;
write_control_file($file, \@data);
print "Signed .changes $file\n" unless $batch;
}
=pod
=head2 sign_file (I<$in_file>, I<$out_file>, I<$no_detach>)
Signs I<$in_file> with gpg and puts the detached signature in I<$out_file>.
If I<$no_detach> is true, I<$out_file> is a clearsigned copy of I<$in_file>.
=cut
sub sign_file {
my ($in_file, $out_file, $no_detach) = @_;
my @cmdline = ("gpg", "--openpgp", "--armor", "--output", $out_file);
if ($no_detach) {
push @cmdline, "--clearsign";
} else {
push @cmdline, "--detach-sign";
}
if ($key) {
push (@cmdline, "--default-key", "'$key'");
print "Default key: $key\n" if $verbose;
} elsif ($maintainer) {
push (@cmdline, "--default-key", "'$maintainer'");
}
if ($pass_file) {
push (@cmdline, "--no-tty", "--batch", "--passphrase-fd", "42", "42<$pass_file");
print "Using passphrase from $pass_file\n" if $verbose;
} elsif ($passphrase) {
push (@cmdline, "--no-tty", "--batch", "--passphrase-fd", "0");
print "Using cached passphrase\n" if $verbose;
}
push (@cmdline, $gpgoptions) if $gpgoptions;
print "Signing $in_file with key ".($key || "of $maintainer")."\n" if $verbose;
push (@cmdline, $in_file, "2>&1");
open (GPG, "| ".join " ", @cmdline) || die _die("Signing failed: $!");
print GPG $passphrase, "\n" if $passphrase;
close GPG;
die _die("Signing failed. Error code: $?") if $?;
}
sub read_cmds {
$DEBUG && (open (LOG, ">", "/tmp/dpkg-sig.log") || die _die("Couldn't open log: $!"));
$DEBUG && select LOG; $|=1;
$DEBUG && select STDOUT;
sub send { print STDOUT @_; $DEBUG && print LOG "Sent: ", @_; }
sub read { $_ = ; $DEBUG && print LOG "Received: ", $_; return $_ } ;
while ($_ = &read()) {
chomp;
if (/^get_deb_digests (.+)$/) {
my $r = eval { get_deb_digests ($1) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send ("500 error: $@\n");
} else {
&send("200 ok digests for $1 follow\n");
&send(join (" ", @$_), "\n") for @$r;
&send(".\n");
}
} elsif (/^get_deb_parts (.+)$/) {
my @r = eval { get_deb_parts ($1) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send ("500 error: $@\n");
} else {
&send("200 ok parts of $1 follow\n");
&send($_->[0] . "\n") for @r;
&send(".\n");
}
} elsif (/^get_archive_part ([^ ]+) (.+)$/) {
my $r = eval { get_archive_part ($2, $1) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: $@\n");
} else {
&send("200 ok part $1 of $2 follows\n");
for (split (/\n/, $r)) {
s/^\./../;
&send("$_\n");
}
&send(".\n");
}
} elsif (/^read_control_file (.+)$/) {
my @r = eval { read_control_file ($1) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: $@\n");
} else {
&send("200 ok file $1 follows\n");
for (@r) {
s/^\./../;
&send("$_");
}
&send(".\n");
}
} elsif (/^get_debs_from_changes (.+)$/) {
my $changes_signed = 0;
my @r = eval { get_debs_from_changes ($1, \$changes_signed) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: $@\n");
} else {
if ($changes_signed) {
&send("200 ok debs in signed $1 follow\n");
} else {
&send("200 ok debs in $1 follow\n");
}
for (@r) {
s/^\./../;
&send("$_\n");
}
&send(".\n");
}
} elsif (/^glob_exp (.+)$/) {
my @r = eval { glob_exp ($1) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: $@\n");
} else {
&send("200 ok files matching \"$1\" follow\n");
for (@r) {
s/^\./../;
&send("$_\n");
}
&send(".\n");
}
} elsif (/^file_readable (.+)$/) {
my $r = eval { file_readable ($1) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: $@\n");
} else {
if ($r) {
&send("200 ok file readable\n");
} else {
&send("400 not ok file not readable\n");
}
}
} elsif (/^get_file_md5sum (.+)$/) {
my $r = eval { get_file_md5sum ($1) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: $@\n");
} else {
&send("200 ok md5sum is $r\n");
}
} elsif (/^add_sig_to_deb ([^ ]+) (.+)$/) {
my ($sig_name, $deb, $sig) = ($1, $2, '');
&send("300 ok waiting for data\n");
while ($_ = &read()) {
last if (/^\.$/);
s/^\.\././;
$sig .= $_;
}
my $r = eval { add_sig_to_deb ($deb, $sig, $sig_name) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: ");
&send($@, "\n");
} else {
&send("200 ok added sig to $deb. New data follows\n");
&send(join (" ", @$r), "\n");
}
} elsif (/^correct_changes_file (.+)$/) {
my ($changes, $new_changes_data) = ($1, {});
&send("300 ok waiting for data\n");
while ($_ = &read()) {
last if (/^\.$/);
s/^\.\././;
chomp;
my ($md5sum, $size, $name) = split (/ /, $_, 3);
$new_changes_data->{$name} = [$md5sum, $size, $name];
}
my $r = eval { correct_changes_file ($changes, $new_changes_data) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: ");
&send($@, "\n");
} else {
&send("200 ok $changes corrected\n");
}
} elsif (/^write_control_file (.+)$/) {
my ($file, @data) = ($1, ());
&send("300 ok waiting for data\n");
while ($_ = &read()) {
last if (/^\.$/);
s/^\.\././;
push @data, $_;
}
my @r = eval { write_control_file ($file, \@data) };
if ($@) {
chomp($@); $@ =~ s/\n/\t/g;
&send("500 error: ");
&send($@, "\n");
} else {
&send("200 ok $file written. New md5sum, size: $r[0] $r[1]\n");
}
} elsif (/^quit\s*$/) {
&send("200 ok Bye!\n");
exit;
} else {
&send("501 unknown command ".(split / /, $_)[0]."\n");
}
}
$DEBUG && close LOG;
}
sub process_cli_options {
exit 1 unless GetOptions("sign|s=s" => \$sign,
"list|l|t" => \$list,
"verify|check|c" => \$verify,
"verify-role=s" => \$verify_role,
"verify-exact=s" => \$verify_exact,
"get-hashes=s" => \$get_hashes,
"sign-hashes" => \$sign_hashes,
"write-signature" => \$write_signature,
"client" => \$client,
"help" => \$help,
#Options:
"default-key|k=s" => \$key,
"cache-passphrase|p" => \$cache_pass,
"passphrase-file|f=s" => \$pass_file,
"m=s" => \$maintainer,
"e=s" => \$maintainer_pr,
"verbose|v+" => \$verbose,
"also-v2-sig" => \$check_v2_sig,
"also-v3-sig" => \$check_v2_sig,
"sign-changes|a:s" => \$sign_changes,
"batch:i" => \$batch,
"gpg-options|g=s" => \$gpgoptions,
"remote-dpkg-sig|r=s" => \$remote_dpkg_sig,
"remote-ssh-port|o=i" => \$remote_ssh_port,
);
$check_v2_sig = ($check_v2_sig && $check_v2_sig eq "false"?0:"yes");
$check_v3_sig = ($check_v3_sig && $check_v3_sig eq "false"?0:"yes");
die _die('Please use only one of --sign, --list, --verify[-role|-exact], --get-hashes, --write-signature, --help and --client!')
if (! !$sign + ! !$list + ! !$verify + ! !$verify_role + ! !$verify_exact + ! !$client + ! !$get_hashes + ! !$sign_hashes + ! !$write_signature + ! ! $help> 1);
$maintainer_pr && ($maintainer = $maintainer_pr);
if (!$sign && !$list && !$verify && !$verify_role && !$verify_exact &&
!$client && !$get_hashes && !$sign_hashes && !$write_signature &&
!$help) {
if (@ARGV) {
$verify = 1;
print "I: No action requested, verifying files.\n";
} else {
$help = 1;
}
}
}
sub load_config {
my @configfiles = @_;
for my $configfile (@configfiles) {
$configfile = (glob($configfile))[0];
if ($configfile && -r $configfile) {
%config = %{read_config_file($configfile) || {}};
}
}
($maintainer = ($config{'DEBSIGN_MAINT'} || "")) =~ s/^"(.+)"$/$1/ if ! $maintainer;
($key = ($config{'DPKGSIG_KEYID'} || $config{'DEBSIGN_KEYID'} || "")) =~ s/^"(.+)"$/$1/ if ! $key;
($cache_pass = ($config{'DPKGSIG_CACHE_PASS'} || "")) =~ s/^"(.+)"$/$1/ if ! $cache_pass;
($sign_changes=($config{'DPKGSIG_SIGN_CHANGES'} ||""))=~ s/^"(.+)"$/$1/ if ! $sign_changes;
if (! $sign_changes) {
$sign_changes = "auto";
} elsif (! grep {$sign_changes eq $_} qw(no auto yes full force_full)) {
if ($sign_changes =~ /(?:deb|changes)$/) {
push @files, $sign_changes;
$sign_changes = "yes";
} else {
print "W: Unrecognized argument to --sign-changes, using \"auto\": $sign_changes\n";
$sign_changes = "auto";
}
}
if ($sign && $cache_pass && ! $pass_file) {
eval { require Term::ReadKey; };
if ($@) {
print STDERR "Couldn't load Term::ReadKey. Please install. Passphrase caching disabled.\n";
} else {
my $passphrase_valid = 0;
while (! $passphrase_valid) {
print "The passphrase for ".($key || "your default key").": ";
Term::ReadKey::ReadMode("noecho");
chomp($passphrase = Term::ReadKey::ReadLine(0));
Term::ReadKey::ReadMode("restore");
print "\n";
#Try to use the key:
open (TMP, ">", $tempdir . '/tmp-file') or die "Can't open $tempdir/tmp-file: $!";
print TMP "Foobar";
close TMP;
my $error;
eval {
my @sign_cmd = ("gpg", "--clearsign");
push @sign_cmd, ("--default-key", $key) if $key;
push @sign_cmd, ("--no-tty", "--batch", "--passphrase-fd", "0");
push @sign_cmd, $gpgoptions if $gpgoptions;
push @sign_cmd, "$tempdir/tmp-file";
my ($write_handle, $read_handle);
open3 ($write_handle, $read_handle, undef, @sign_cmd) || die _die("Signing failed: $!");
print $write_handle $passphrase, "\n";
close $write_handle;
$error = join "", <$read_handle>;
close $read_handle;
};
if ($error && $error =~ /^gpg:.+bad passphrase\n/) {
$passphrase_valid = 0;
print STDERR "Wrong passphrase for " . (($key)?"key $key":"default key") . "!\n";
} else {
$passphrase_valid = 1;
}
}
}
}
}
sub help {
print < Sign files
-c,--verify Verify signatures on files
-l,--list List signatures on files
--get-hashes Get hashes file for files
--sign-hashes Sign hashes file
--write-hashes Write sigs from signed hashes file
Options:
-m,-e Specify maintainer name to use when signing
-k Specify keyid to use when signing
-v,--verbose Makes dpkg-sig more verbose
--also-v2-sig Verify sigs from dpkg-sig 0.2 and earlier
--also-v3-sig Verify sigs from dpkg-sig 0.3-0.10
-a,--sign-changes
Tells whether also sign the changes and dsc-files. The default is auto.
-g,--gpgoptions DANGEROUS: Specify custom gpg options.
-p,--cache-passphrase INSECURE: Caches gpg passphrase in dpkg-sig
-f,--passphrase-file INSECURE: Let gpg use passphrase from
EOH
}
sub _die {
chomp(my $msg = shift || "No error msg given! This is a bug, hurt the author!");
my $i = 0;
while ($_ = (caller($i++))[3]) {
if ($_ && $_ eq "(eval)") {
return $msg;
}
}
my $code = shift || 1;
my $line = (caller)[2];
print STDERR "E: $msg\n";
exit $code;
}
sub _read_file {
my $file = shift;
my $content;
open (FH, $file) or die _die "Can't open $file: $!";
$content = join "", ;
close FH;
return $content;
}
sub _write_file {
my $file = shift;
my @content = @_;
open (FH, ">", $file) or die _die "Can't open $file for writing: $!";
print FH @content;
close FH;
}
=pod
=head1 AUTHOR
B and this manpage were written by Andreas Barth und Marc
Brockschmidt. They are Copyright (C) 2003, 2004 by them and released
under the GNU General Public Licence version 2 or later; there is NO
WARRANTY. See F and
F for details.
=cut
# vim:set shiftwidth=4:
# vim:set tabstop=4:
# vim:set noet:
# vim:set shiftround:
dpkg-sig-0.13.1+nmu2/dpkg-sig.pod 0000644 0000000 0000000 00000023560 12345254673 013276 0 ustar =pod
=head1 NAME
B - Debian package archive (.deb) signature generation and verification tool
=head1 SYNOPSIS
B B<[options]> B<--sign> I I<[archive|changes]>+
B B<[options]> B<--verify> I<[archive]>+
B B<[options]> B<--verify-role> I I<[archive]>+
B B<[options]> B<--verify-exact> I I<[archive]>+
B B<[options]> B<--list> I<[archive]>+
B B<[options]> B<--get-hashes> I I<[archive|changes]>+
B B<[options]> B<--sign-hashes> I<[hashes-archive]>+
B B<[options]> B<--write-signature> I<[hashes-archive]>+
=head1 DESCRIPTION
B creates and verifies signatures on Debian archives (.deb-files).
Use higher-level tools to install and remove packages from your system,
and to verify a signature as acceptable for your system.
A usage example can be found at the end of this man page.
=head1 ACTION OPTIONS
=over 4
=item B<--sign>, B<-s> I
Signs a standard-conforming Debian archive. I gives the name of the
signature (usually 'builder' for the builder of the .deb). The
signature is made using your default key, unless specified via any
explicit or implicit option (see below).
If one or more .changes-files are given, the md5sums inside the
.changes file(s) are also updated.
If a .changes file was gpg-signed, the signature is removed when
updating the md5sums.
=item B<--verify>, B<-c>; B<--verify-role>; B<--verify-exact>
Verifies a signature on the given archive file. B<--verify> and B<-c> just
check all signatures; B<--verify-role> verifies all signatures with a given
role, and B<--verify-exact> wants the exact name of the archive member
(without the leading _gpg). However, both commands also accept perl regular
expressions as the name.
All verify variants output (in turn for each signature) either a line
consisting of GOODSIG, role, gpg-fingerprint and signature time (in
seconds since 1970-1-1 0:00:00 UTC), or BADSIG.
Starting from version 0.12, B returns 2 if a bad signature
was found when trying to verify. If an unknown key was used to
sign a .deb, B returns 3.
=item B<--list>, B<-l>, B<-t>
Lists all names inside the deb that look like a signature.
=item B<--get-hashes>, B<--sign-hashes>, B<--write-signature>
B<--get-hashes> creates an B(1) archive containing a control file
part and files with the digests of all the .debs specified on the
command-line or named in the .changes file(s) specified on the
command-line.
After that, you can transfer this (small) file to another machine, for
example an offline system containing your gpg keys. (Yep, that's paranoid!)
B<--sign-hashes> then signs this file containing the digests (in fact,
it replaces the digests parts with their signatures).
Now transfer the signed file back to the machine where you created the
hashes and use B<--write-signature> to add the signatures from the archive
to the deb.
=back
=head1 OPTIONS
=over 4
=item B<-m> I
Specify the maintainer name to be used for signing.
=item B<-e> I
Same as B<-m> but takes precedence.
=item B<-k> I
Specify the key ID to be used for signing; overrides any B<-e> or B<-m>
option.
=item B<--verbose>
Get some more details.
=item B<--batch=1>
Gurantees that the non-verbose output will not change. Use this if you want
to parse the output.
=item B<--also-v3-sig>
The signature format changed between version 0.10 and 0.11. If you want to
verify old signatures too, try this switch.
=item B<--also-v2-sig>
The signature format changed between version 0.2 and 0.3. If you want to
verify old signatures too, try this switch.
=item B<--cache-passphrase>, B<-p>
Caches the gpg-passphrase inside B. This needs the suggested
package C.
Be warned: Doing this is insecure, B doesn't protect the
memory it uses to store the passphrase.
=item B<--sign-changes>, B<-a> [ no | auto | yes | full | force_full ]
Tells whether also sign the .changes and .dsc-files. The default is
I, which means that the .changes-file is re-signed if it was
signed before.
The other values are I (don't sign .changes, and remove an existing
signature), I (always add a signature to .changes), I (always
add a signature to .changes, and also sign the .dsc-file if there was
no previous signature; otherwise ask) and I (always add a
signature to both the .changes and .dsc files).
=item B<--remote-dpkg-sig>, B<-r> I
Use this if you want to specify where B can find the
B executable on the remote machine.
This is useful if you're not able/allowed to install B as a .deb.
To do that, copy the script to something like F<~/bin/dpkg-sig> on the remote
system. After that, you can call your local B with something like the
following to use the remote signing/verifying features:
C
=item B<--remote-ssh-port>, B<-o> I
Port of the B on the remote host. Default value is 22.
=back
=head1 MORE OPTIONS
These options should normally not be used, but are here for completeness.
Be warned: Use them only if you really know what you are doing.
=over 4
=item B<--gpgoptions>, B<-g> I
Use this to pass arbitrary options to B(1) whenever a file is
signed. As this can lead to broken signatures, test your changes
carefully.
=item B<--passphrase-file>, B<-f> I
Tells gpg to use the passphrase in I to sign.
Be warned: Doing this is insecure, DON'T use this feature.
However, in some cases (e.g. automatic signing on a buildd) this could be
useful, and is still better than using a gpg-key without passphrase. You
can gain at least some security by putting this file on a ramdisk, but it
would be better to use B(1).
=back
=head1 CONFIGURATION VARIABLES
The two configuration files F and
F<~/.devscripts> are sourced in that order to set configuration
variables. Command line options can be used to override configuration
file settings. Environment variable settings are ignored for this
purpose. The currently recognised variables are:
=over 4
=item B
This is the B<-m> option.
=item B, B
This is the B<-k> option, and B has most precedence.
=item B
This is the B<--sign-changes> option. Valid values are I, I,
I, I and I.
=item B
This is the B<--cache-passphrase> option. Set this to a true value
to enable it.
=back
=head1 SIGNATURE FORMAT
The signatures created by B are added in a strict
standard-conforming way to the .deb archive file. The signature itself
is made on a file formatted like a Debian control file. The fields of
this file are: Version, specifying a B file version number;
Signer, giving the name of the signer; Date and Role, and finally
Files, which gives the digests of the prior contents of the .deb
archive file. Note that this includes any prior signatures made by
B. Thus it is possible to verify any signature by hand with
just B(1), B(1), B(1) and B(1). Signing a
list of digests has the advantage that it is possible to perform remote
signatures without transferring the whole archive file. This does
require one to trust the remote machine, though!
=head1 REMOTE SIGNING
B can sign remote files using B(1) without transferring
the whole file to the local machine, or the key to the remote
machine. Simply specify the file with
C, and have B installed
on the remote machine. (See also the B<--remote-dpkg-sig> option
above.)
Remote signing supports the usual filename globbing.
Remote signing has been tested, but is at the moment considered a more
experimental feature.
=head1 BUGS, TODO
B should be able to also verify signatures made by older
code. This may be added in a later version.
B assumes that any given archive is strictly standard-compatible.
This is valid for archives created by B - but if you're not sure
about a archive, verify this yourself, or live with the risk of a bad
signature.
More documentation about the signature format should be added.
Deal better with expired etc. keys and signatures.
Better inclusion into the other tools like B.
And of course: Still missing is testing, testing and testing B.
=head1 USAGE EXAMPLE
A typical use is to sign packages before a (maintainer-)upload. This can
be done by running B and afterwards calling
C.
If you want to do all signing with B you could run
C and afterwards call
C.
If you do this, there is no need to call B any more, as
B does all the signing for you.
If you don't want to type in your passphrase multiple times, then you could
add the option B<--cache-passphrase>.
The options B<--sign-changes> and B<--cache-passphrase> could be
replaced with setting the variables B respectivly
B (set the later one set to a true value) in
F<~/.devscripts>.
The key-id is automatically set from F and
F<~/.devscripts>, but could be overridden via the B<-m>, B<-e> or B<-k>
command line options (see above).
=head1 SEE ALSO
B(5), B(1), B(8), F
=head1 AUTHOR
B and this manpage were written by Andreas Barth and Marc
Brockschmidt. They are Copyright (C) 2003-2006 by them and released
under the GNU General Public Licence version 2 or later; there is NO
WARRANTY. See F and
F for details. Some parts of this
manpage are taken from debsign.
=cut
dpkg-sig-0.13.1+nmu2/examples/ 0000755 0000000 0000000 00000000000 10377602746 012676 5 ustar dpkg-sig-0.13.1+nmu2/examples/README 0000644 0000000 0000000 00000002736 10377442452 013562 0 ustar This dir contains a sample package, the dpkg-sig tempdir (named
debsigs-ng.sample) and all generated files.
What happened:
sample$ dpkg-buildpackage -rfakeroot -uc -us
[...]
sample$ cd ..
examples$ dpkg-sig --sign-changes full --sign builder dpkg-sig-example_0.1_i386.changes
[...]
The used dpkg-sig version was slightly modified to make the temporary
files available.
dpkg-sig did the following things:
1) Parse the .changes to get all binaries that need to be signed.
2) Get the md5sums, sha1sums, sizes and names of all members of the
deb (which is an ar archive)
3) Write this information + some meta-data (Date, Role, Signer) in
a RFC822-compliant format to debsigs-ng.sample/digests.
4) Clearsign debsigs-ng.sample/digests, the signed version is in
debsigs-ng.sample/digests.asc.
5) debsigs-ng.sample/digests.asc is added to the deb (as new ar member)
with an unique name reflecting the signing role.
6) The new md5sum and size of the deb are put in the .changes file.
As this invalidates an existing gpg signature, it is stripped.
[This is an optional feature of dpkg-sig:
7) The .dsc is signed (an unsigned copy is in debsigs-ng/dsc, the
clearsigned copy is in debsigs-ng/dsc.asc and then moved to the
original location)
8) The new .dsc size and md5sum are put in the .changes file.
9) The new .changes is signed (an unsigned copy is in debsigs-ng/changes,
the clearsigned copy is in debsigs-ng/changes.asc and then moved
to the original location)
]
dpkg-sig-0.13.1+nmu2/examples/debsigs-ng.sample/ 0000755 0000000 0000000 00000000000 10377602746 016200 5 ustar dpkg-sig-0.13.1+nmu2/examples/debsigs-ng.sample/changes.signed 0000644 0000000 0000000 00000001566 10134511572 020776 0 ustar -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Format: 1.7
Date: Sat, 28 Feb 2004 20:51:00 +0100
Source: dpkg-sig-example
Binary: dpkg-sig-example
Architecture: source all
Version: 0.1
Distribution: unstable
Urgency: low
Maintainer: Andreas Barth
Changed-By: Marc 'HE' Brockschmidt
Description:
dpkg-sig-example - sample package
Changes:
dpkg-sig-example (0.1) unstable; urgency=low
.
* Foo.
Files:
34a85c5305f88a78b3e7d6339c4121b1 565 devel optional dpkg-sig-example_0.1.dsc
a7beeef85a612c4cb3cf7e1e26f64739 951 devel optional dpkg-sig-example_0.1.tar.gz
16b320195066f99fd82ea7c6da550484 1386 devel optional dpkg-sig-example_0.1_all.deb
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iEYEARECAAYFAkFykPEACgkQmO5zOp3h7rEZEQCfbyaaDgOLBfFKnR3qhApDaQL1
sqMAn2ixLMp+47vuv/bOHoMa+7JDpoCs
=6vBZ
-----END PGP SIGNATURE-----
dpkg-sig-0.13.1+nmu2/examples/debsigs-ng.sample/changes.unsigned 0000644 0000000 0000000 00000001202 10134511572 021324 0 ustar Format: 1.7
Date: Sat, 28 Feb 2004 20:51:00 +0100
Source: dpkg-sig-example
Binary: dpkg-sig-example
Architecture: source all
Version: 0.1
Distribution: unstable
Urgency: low
Maintainer: Andreas Barth
Changed-By: Marc 'HE' Brockschmidt
Description:
dpkg-sig-example - sample package
Changes:
dpkg-sig-example (0.1) unstable; urgency=low
.
* Foo.
Files:
34a85c5305f88a78b3e7d6339c4121b1 565 devel optional dpkg-sig-example_0.1.dsc
a7beeef85a612c4cb3cf7e1e26f64739 951 devel optional dpkg-sig-example_0.1.tar.gz
16b320195066f99fd82ea7c6da550484 1386 devel optional dpkg-sig-example_0.1_all.deb
dpkg-sig-0.13.1+nmu2/examples/debsigs-ng.sample/digests 0000644 0000000 0000000 00000000603 10134511572 017547 0 ustar Version: 4
Signer: Marc 'HE' Brockschmidt
Date: Sun Oct 17 17:34:05 2004
Role: builder
Files:
3cf918272ffa5de195752d73f3da3e5e 7959c969e092f2a5a8604e2287807ac5b1b384ad 4 debian-binary
79bb73dbb522dc1a2dd1b9c2ec89fc79 26d29d15aad5c0e051d07571e28da2bc0009707e 366 control.tar.gz
e1a6e48c95a760170029ef7872cec994 e02ed99e5c4fd847bde12b4c2c30dd814b26ec27 136 data.tar.gz
dpkg-sig-0.13.1+nmu2/examples/debsigs-ng.sample/digests.asc 0000644 0000000 0000000 00000001167 10134511572 020322 0 ustar -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Version: 4
Signer: Marc 'HE' Brockschmidt
Date: Sun Oct 17 17:34:05 2004
Role: builder
Files:
3cf918272ffa5de195752d73f3da3e5e 7959c969e092f2a5a8604e2287807ac5b1b384ad 4 debian-binary
79bb73dbb522dc1a2dd1b9c2ec89fc79 26d29d15aad5c0e051d07571e28da2bc0009707e 366 control.tar.gz
e1a6e48c95a760170029ef7872cec994 e02ed99e5c4fd847bde12b4c2c30dd814b26ec27 136 data.tar.gz
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iEYEARECAAYFAkFykO0ACgkQmO5zOp3h7rEW7gCgg7jKhJKn/xh+39jR8omgU3FV
uucAoI7NX+t5QCyjKWh8ron+IAFvN2+a
=j0nX
-----END PGP SIGNATURE-----
dpkg-sig-0.13.1+nmu2/examples/debsigs-ng.sample/dsc.signed 0000644 0000000 0000000 00000001065 10134511572 020131 0 ustar -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Format: 1.0
Source: dpkg-sig-example
Version: 0.1
Binary: dpkg-sig-example
Maintainer: Andreas Barth
Architecture: all
Standards-Version: 3.6.1.0
Build-Depends-Indep: debhelper
Uploaders: Marc Brockschmidt
Files:
a7beeef85a612c4cb3cf7e1e26f64739 951 dpkg-sig-example_0.1.tar.gz
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iEYEARECAAYFAkFykPAACgkQmO5zOp3h7rFa6ACghdIZg5GDNTmm795IJQ0KSCb7
ks4An1Cb72wbx5RHZdLgNLeBy6mYz2C3
=Waai
-----END PGP SIGNATURE-----
dpkg-sig-0.13.1+nmu2/examples/debsigs-ng.sample/dsc.unsigned 0000644 0000000 0000000 00000000501 10134511572 020466 0 ustar Format: 1.0
Source: dpkg-sig-example
Version: 0.1
Binary: dpkg-sig-example
Maintainer: Andreas Barth
Architecture: all
Standards-Version: 3.6.1.0
Build-Depends-Indep: debhelper
Uploaders: Marc Brockschmidt
Files:
a7beeef85a612c4cb3cf7e1e26f64739 951 dpkg-sig-example_0.1.tar.gz
dpkg-sig-0.13.1+nmu2/examples/dpkg-sig-example_0.1.dsc 0000644 0000000 0000000 00000001065 10134511572 017072 0 ustar -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Format: 1.0
Source: dpkg-sig-example
Version: 0.1
Binary: dpkg-sig-example
Maintainer: Andreas Barth
Architecture: all
Standards-Version: 3.6.1.0
Build-Depends-Indep: debhelper
Uploaders: Marc Brockschmidt
Files:
a7beeef85a612c4cb3cf7e1e26f64739 951 dpkg-sig-example_0.1.tar.gz
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iEYEARECAAYFAkFykPAACgkQmO5zOp3h7rFa6ACghdIZg5GDNTmm795IJQ0KSCb7
ks4An1Cb72wbx5RHZdLgNLeBy6mYz2C3
=Waai
-----END PGP SIGNATURE-----
dpkg-sig-0.13.1+nmu2/examples/dpkg-sig-example_0.1.tar.gz 0000644 0000000 0000000 00000001667 10134511572 017536 0 ustar rAߓ6z+Ӈi-M3%oqCw4qGcw#~i)XQYYWJx#CV.DFZZ{f`a6YFVv.B?B[ײoЪ$!<ҵGgLlr+rJ~1!eJcOp|L ?+٪0d3#dmk{^JH%u
γb6v*'u8pƔ)[ZWK yT\tv[{4J19kE;uuΛa%ʰ:gV4tw)!YaJalZeYUs3%'= måT풯_}Pv1:K|jEmنsAȺS^JHVqV$/%̅9ҁ}oc/5SpޔDOd4]o7r5еFqBW_nCՅcW;gn?Ev~c2GAAAAAAAAdE6 P dpkg-sig-0.13.1+nmu2/examples/dpkg-sig-example_0.1_all.deb 0000644 0000000 0000000 00000002552 10134511572 017705 0 ustar !
debian-binary 1098027154 0 0 100644 4 `
2.0
control.tar.gz 1098027154 0 0 100644 366 `
AO0)`AŃ{0֥-~zD=YӭkxoԮ{H*L$\1'X=Q❋?t*UX?A3dB?R2/i9LsΧ\fCW0Y'5X#%_I?{],uefTvjl50z5=kgSLwy1
yfnWMn6)Ӷ}3~FF>tUb\}UWƄnuE>bF
_>C(nCu8)^ p> ś ( data.tar.gz 1098027154 0 0 100644 136 `
1 @Q "88K4M[J
UpE8DJLEVս`]w8ٻ~
6Ls[Ş|jR ` ( _gpgbuilder 1098027247 0 0 100644 631 `
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Version: 4
Signer: Marc 'HE' Brockschmidt
Date: Sun Oct 17 17:34:05 2004
Role: builder
Files:
3cf918272ffa5de195752d73f3da3e5e 7959c969e092f2a5a8604e2287807ac5b1b384ad 4 debian-binary
79bb73dbb522dc1a2dd1b9c2ec89fc79 26d29d15aad5c0e051d07571e28da2bc0009707e 366 control.tar.gz
e1a6e48c95a760170029ef7872cec994 e02ed99e5c4fd847bde12b4c2c30dd814b26ec27 136 data.tar.gz
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iEYEARECAAYFAkFykO0ACgkQmO5zOp3h7rEW7gCgg7jKhJKn/xh+39jR8omgU3FV
uucAoI7NX+t5QCyjKWh8ron+IAFvN2+a
=j0nX
-----END PGP SIGNATURE-----
dpkg-sig-0.13.1+nmu2/examples/dpkg-sig-example_0.1_i386.changes 0000644 0000000 0000000 00000001566 10134511572 020510 0 ustar -----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Format: 1.7
Date: Sat, 28 Feb 2004 20:51:00 +0100
Source: dpkg-sig-example
Binary: dpkg-sig-example
Architecture: source all
Version: 0.1
Distribution: unstable
Urgency: low
Maintainer: Andreas Barth
Changed-By: Marc 'HE' Brockschmidt
Description:
dpkg-sig-example - sample package
Changes:
dpkg-sig-example (0.1) unstable; urgency=low
.
* Foo.
Files:
34a85c5305f88a78b3e7d6339c4121b1 565 devel optional dpkg-sig-example_0.1.dsc
a7beeef85a612c4cb3cf7e1e26f64739 951 devel optional dpkg-sig-example_0.1.tar.gz
16b320195066f99fd82ea7c6da550484 1386 devel optional dpkg-sig-example_0.1_all.deb
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.5 (GNU/Linux)
iEYEARECAAYFAkFykPEACgkQmO5zOp3h7rEZEQCfbyaaDgOLBfFKnR3qhApDaQL1
sqMAn2ixLMp+47vuv/bOHoMa+7JDpoCs
=6vBZ
-----END PGP SIGNATURE-----
dpkg-sig-0.13.1+nmu2/examples/sample/ 0000755 0000000 0000000 00000000000 10377602746 014157 5 ustar dpkg-sig-0.13.1+nmu2/examples/sample/debian/ 0000755 0000000 0000000 00000000000 10377602746 015401 5 ustar dpkg-sig-0.13.1+nmu2/examples/sample/debian/changelog 0000644 0000000 0000000 00000000204 10020337070 017223 0 ustar dpkg-sig-example (0.1) unstable; urgency=low
* Foo.
-- Marc 'HE' Brockschmidt Sat, 28 Feb 2004 20:51:00 +0100
dpkg-sig-0.13.1+nmu2/examples/sample/debian/control 0000644 0000000 0000000 00000000514 10020337070 016760 0 ustar Source: dpkg-sig-example
Section: devel
Priority: optional
Maintainer: Andreas Barth
Uploaders: Marc Brockschmidt
Build-Depends-Indep: debhelper
Standards-Version: 3.6.1.0
Package: dpkg-sig-example
Architecture: all
Description: sample package
This is a example to show how dpkg-sig works.
dpkg-sig-0.13.1+nmu2/examples/sample/debian/files 0000644 0000000 0000000 00000000054 10020337070 016401 0 ustar dpkg-sig-example_0.1_all.deb devel optional
dpkg-sig-0.13.1+nmu2/examples/sample/debian/rules 0000755 0000000 0000000 00000000420 10020337070 016431 0 ustar #!/usr/bin/make -f
build:
clean:
dh_testdir
dh_testroot
dh_clean
binary-arch:
binary-indep:
dh_testdir
dh_testroot
dh_clean
mkdir -p debian/tmp/tmp
cp test debian/tmp/tmp
dh_compress
dh_gencontrol
dh_md5sums
dh_fixperms
dh_builddeb
binary: binary-indep
dpkg-sig-0.13.1+nmu2/examples/sample/debian/tmp/ 0000755 0000000 0000000 00000000000 10377602747 016202 5 ustar dpkg-sig-0.13.1+nmu2/examples/sample/debian/tmp/DEBIAN/ 0000755 0000000 0000000 00000000000 10377602746 017123 5 ustar dpkg-sig-0.13.1+nmu2/examples/sample/debian/tmp/DEBIAN/control 0000644 0000000 0000000 00000000351 10020337070 020501 0 ustar Package: dpkg-sig-example
Version: 0.1
Section: devel
Priority: optional
Architecture: all
Installed-Size: 12
Maintainer: Andreas Barth
Description: sample package
This is a example to show how dpkg-sig works.
dpkg-sig-0.13.1+nmu2/examples/sample/debian/tmp/DEBIAN/md5sums 0000644 0000000 0000000 00000000053 10020337070 020415 0 ustar d41d8cd98f00b204e9800998ecf8427e tmp/test
dpkg-sig-0.13.1+nmu2/examples/sample/debian/tmp/tmp/ 0000755 0000000 0000000 00000000000 10377602747 017002 5 ustar dpkg-sig-0.13.1+nmu2/examples/sample/debian/tmp/tmp/test 0000644 0000000 0000000 00000000000 10020337070 017645 0 ustar dpkg-sig-0.13.1+nmu2/examples/sample/test 0000644 0000000 0000000 00000000000 10020337070 015023 0 ustar