1
# $File: //member/autrijus/Module-Signature/lib/Module/Signature.pm $
2
# $Revision: #24 $ $Change: 7734 $ $DateTime: 2003/08/27 06:48:25 $
4
package Module::Signature;
5
$Module::Signature::VERSION = '0.35';
8
use vars qw($VERSION $SIGNATURE @ISA @EXPORT_OK);
9
use vars qw($Preamble $Cipher $Debug $Verbose);
10
use vars qw($KeyServer $KeyServerPort $AutoKeyRetrieve $CanKeyRetrieve);
12
use constant CANNOT_VERIFY => "0E0";
13
use constant SIGNATURE_OK => 0;
14
use constant SIGNATURE_MISSING => -1;
15
use constant SIGNATURE_MALFORMED => -2;
16
use constant SIGNATURE_BAD => -3;
17
use constant SIGNATURE_MISMATCH => -4;
18
use constant MANIFEST_MISMATCH => -5;
19
use constant CIPHER_UNKNOWN => -6;
21
use ExtUtils::Manifest ();
24
@EXPORT_OK = (qw(sign verify),
25
qw($SIGNATURE $KeyServer $Cipher $Preamble),
26
grep /^[A-Z_]+_[A-Z_]+$/, keys %Module::Signature::);
29
$SIGNATURE = 'SIGNATURE';
30
$Verbose = $ENV{MODULE_SIGNATURE_VERBOSE} || 0;
31
$KeyServer = $ENV{MODULE_SIGNATURE_KEYSERVER} || 'pgp.mit.edu';
32
$KeyServerPort = $ENV{MODULE_SIGNATURE_KEYSERVERPORT} || '11371';
35
This file contains message digests of all files listed in MANIFEST,
36
signed via the Module::Signature module, version $VERSION.
38
To verify the content in this distribution, first make sure you have
39
Module::Signature installed, then type:
43
It would check each file's integrity, as well as the signature's
44
validity. If "==> Signature verified OK! <==" is not displayed,
45
the distribution may already have been compromised, and you should
46
not run its Makefile.PL or Build.PL.
51
$CanKeyRetrieve = undef;
55
Module::Signature - Module signature file manipulation
59
This document describes version 0.35 of B<Module::Signature>,
60
released August 27, 2003.
66
% cpansign # verify an existing SIGNATURE, or
67
make a new one if none exists
69
% cpansign sign # make signature; overwrites existing one
70
% cpansign -s # same thing
72
% cpansign verify # verify a signature
73
% cpansign -v # same thing
74
% cpansign -v --skip # ignore files in MANIFEST.SKIP
76
% cpansign help # display this documentation
77
% cpansign -h # same thing
81
use Module::Signature qw(sign verify SIGNATURE_OK);
83
sign(overwrite => 1); # overwrites without asking
85
# see the CONSTANTS section below
86
(verify() == SIGNATURE_OK) or die "failed!";
90
B<Module::Signature> adds cryptographic authentications to CPAN
91
distributions, via the special SIGNATURE file.
93
If you are a module user, all you have to do is to remember running
94
C<cpansign -v> (or just C<cpansign>) before issuing C<perl Makefile.PL>
95
or C<perl Build.PL>; that will ensure the distribution has not been
98
For module authors, you'd want to add the F<SIGNATURE> file to your
99
F<MANIFEST>, then type C<cpansign -s> before making a distribution.
100
You may also want to consider adding this code as F<t/0-signature.t>:
106
if (!eval { require Module::Signature; 1 }) {
107
print "ok 1 # skip ",
108
"Next time around, consider install Module::Signature, ",
109
"# so you can verify the integrity of this distribution.\n";
111
elsif (!eval { require Socket; Socket::inet_aton('pgp.mit.edu') }) {
112
print "ok 1 # skip ",
113
"Cannot connect to the keyserver\n";
116
(Module::Signature::verify() == Module::Signature::SIGNATURE_OK())
118
print "ok 1 # Valid signature\n";
121
If you are already using B<Test::More> for testing, a more
122
straightforward version of F<t/0-signature.t> can be found in the
123
B<Module::Signature> distribution.
125
Also, if you prefer a more full-fledged testing package, and are
126
willing to inflict the dependency of B<Module::Build> on your users,
127
Iain Truskett's B<Test::Signature> might be a better choice.
129
Please also see L</NOTES> about F<MANIFEST.SKIP> issues, especially if
130
you are using B<Module::Build> or writing your own F<MANIFEST.SKIP>.
134
No package variables are exported by default.
140
If true, Module::Signature will give information during processing including
141
gpg output. If false, Module::Signature will be as quiet as possible as
142
long as everything is working ok. Defaults to false.
146
The filename for a distribution's signature file. Defaults to
151
The OpenPGP key server for fetching the author's public key
152
(currently only implemented on C<gpg>, not C<Crypt::OpenPGP>).
153
May be set to a false value to prevent this module from
154
fetching public keys.
158
The OpenPGP key server port, defaults to C<11371>.
160
=item $AutoKeyRetrieve
162
Whether to automatically fetch unknown keys from the key server.
167
The default cipher used by the C<Digest> module to make signature
168
files. Defaults to C<SHA1>, but may be changed to other ciphers
169
if the SHA1 cipher is undesirable for the user.
171
Module::Signature version 0.09 and above will use the cipher
172
specified in the SIGNATURE file's first entry to validate its
177
The explanatory text written to newly generated SIGNATURE files
178
before the actual entries.
184
Module::Signature honors these environment variables:
188
=item MODULE_SIGNATURE_VERBOSE
192
=item MODULE_SIGNATURE_KEYSERVER
194
Works like $KeyServer.
196
=item MODULE_SIGNATURE_KEYSERVERPORT
198
Works like $KeyServerPort.
204
These constants are not exported by default.
208
=item CANNOT_VERIFY (C<0E0>)
210
Cannot verify the OpenPGP signature, maybe due to lack of network
211
connection to the key server, or neither of gnupg nor Crypt::OpenPGP
212
exists on the system.
214
=item SIGNATURE_OK (C<0>)
216
Signature successfully verified.
218
=item SIGNATURE_MISSING (C<-1>)
220
The F<SIGNATURE> file does not exist.
222
=item SIGNATURE_MALFORMED (C<-2>)
224
The signature file does not contains a valid OpenPGP message.
226
=item SIGNATURE_BAD (C<-3>)
228
Invalid signature detected -- it might have been tampered.
230
=item SIGNATURE_MISMATCH (C<-4>)
232
The signature is valid, but files in the distribution have changed
235
=item MANIFEST_MISMATCH (C<-5>)
237
There are extra files in the current directory not specified by
240
=item CIPHER_UNKNOWN (C<-6>)
242
The cipher used by the signature file is not recognized by the
249
(The following section is lifted from Iain Truskett's B<Test::Signature>
250
module, under the Perl license. Thanks, Iain!)
252
It is B<imperative> that your F<MANIFEST> and F<MANIFEST.SKIP> files be
253
accurate and complete. If you are using C<ExtUtils::MakeMaker> and you
254
do not have a F<MANIFEST.SKIP> file, then don't worry about the rest of
255
this. If you do have a F<MANIFEST.SKIP> file, or you use
256
C<Module::Build>, you must read this.
258
Since the test is run at C<make test> time, the distribution has been
259
made. Thus your F<MANIFEST.SKIP> file should have the entries listed
262
If you're using C<ExtUtils::MakeMaker>, you should have, at least:
268
These entries are part of the default set provided by
269
C<ExtUtils::Manifest>, which is ignored if you provide your own
270
F<MANIFEST.SKIP> file.
272
If you are using C<Module::Build>, you should have two extra entries:
277
If you don't have the correct entries, C<Module::Signature> will
278
complain that you have:
280
==> MISMATCHED content between MANIFEST and distribution files! <==
282
You should note this during normal development testing anyway.
287
my %args = ( skip => 1, @_ );
290
(-r $SIGNATURE) or do {
291
warn "==> MISSING Signature file! <==\n";
292
return SIGNATURE_MISSING;
295
(my $sigtext = _read_sigfile($SIGNATURE)) or do {
296
warn "==> MALFORMED Signature file! <==\n";
297
return SIGNATURE_MALFORMED;
300
(my ($cipher) = ($sigtext =~ /^(\w+) /)) or do {
301
warn "==> MALFORMED Signature file! <==\n";
302
return SIGNATURE_MALFORMED;
305
(defined(my $plaintext = _mkdigest($cipher))) or do {
306
warn "==> UNKNOWN Cipher format! <==\n";
307
return CIPHER_UNKNOWN;
310
$rv = _verify($SIGNATURE, $sigtext, $plaintext);
312
if ($rv == SIGNATURE_OK) {
313
my ($mani, $file) = _fullcheck($args{skip});
315
if (@{$mani} or @{$file}) {
316
warn "==> MISMATCHED content between MANIFEST and distribution files! <==\n";
317
return MANIFEST_MISMATCH;
320
warn "==> Signature verified OK! <==\n" if $Verbose;
323
elsif ($rv == SIGNATURE_BAD) {
324
warn "==> BAD/TAMPERED signature detected! <==\n";
326
elsif ($rv == SIGNATURE_MISMATCH) {
327
warn "==> MISMATCHED content between SIGNATURE and distribution files! <==\n";
334
my $signature = shift || $SIGNATURE;
335
my $sigtext = shift || '';
336
my $plaintext = shift || '';
338
local $SIGNATURE = $signature if $signature ne $SIGNATURE;
340
if ($AutoKeyRetrieve and !$CanKeyRetrieve) {
341
if (!defined $CanKeyRetrieve) {
342
require IO::Socket::INET;
343
my $sock = IO::Socket::INET->new("$KeyServer:$KeyServerPort");
344
$CanKeyRetrieve = ($sock ? 1 : 0);
345
$sock->shutdown(2) if $sock;
347
$AutoKeyRetrieve = $CanKeyRetrieve;
350
if (`gpg --version` =~ /GnuPG.*?(\S+)$/m) {
351
return _verify_gpg($sigtext, $plaintext, $1);
353
elsif (eval {require Crypt::OpenPGP; 1}) {
354
return _verify_crypt_openpgp($sigtext, $plaintext);
357
warn "Cannot use GnuPG or Crypt::OpenPGP, please install either one first!\n";
358
return _compare($sigtext, $plaintext, CANNOT_VERIFY);
367
local $ExtUtils::Manifest::Quiet = 1;
370
if( _legacy_extutils() ) {
371
my $_maniskip = &ExtUtils::Manifest::_maniskip;
373
local *ExtUtils::Manifest::_maniskip = sub { sub {
375
my $ok = $_maniskip->(@_);
376
if ($ok ||= (!-e 'MANIFEST.SKIP' and _default_skip(@_))) {
377
print "Skipping $_\n" for @_;
383
($mani, $file) = ExtUtils::Manifest::fullcheck();
386
($mani, $file) = ExtUtils::Manifest::fullcheck();
389
foreach my $makefile ('Makefile', 'Build') {
390
warn "==> SKIPPED CHECKING '$_'!" .
391
(-e "$_.PL" && " (run $_.PL to ensure its integrity)") .
392
" <===\n" for grep $_ eq $makefile, @extra;
395
@{$mani} = grep {$_ ne 'SIGNATURE'} @{$mani};
397
warn "Not in MANIFEST: $_\n" for @{$file};
398
warn "No such file: $_\n" for @{$mani};
400
return ($mani, $file);
403
sub _legacy_extutils {
404
# ExtUtils::Manifest older than 1.41 does not handle default skips well.
405
return (ExtUtils::Manifest->VERSION < 1.41);
410
return 1 if /\bRCS\b/ or /\bCVS\b/ or /\B\.svn\b/ or /,v$/
411
or /^MANIFEST\.bak/ or /^Makefile$/ or /^blib\//
412
or /^MakeMaker-\d/ or /^pm_to_blib$/
413
or /^_build\// or /^Build$/
414
or /~$/ or /\.old$/ or /\#$/ or /^\.#/;
418
my ($sigtext, $plaintext, $version) = @_;
420
local $SIGNATURE = Win32::GetShortPathName($SIGNATURE)
421
if defined &Win32::GetShortPathName and $SIGNATURE =~ /[^-\w.:~\\\/]/;
423
my @quiet = $Verbose ? () : qw(-q --logger-fd=1);
425
qw(gpg --verify --batch --no-tty), @quiet, ($KeyServer ? (
426
"--keyserver=hkp://$KeyServer:$KeyServerPort",
427
($AutoKeyRetrieve and $version ge "1.0.7")
428
? "--keyserver-options=auto-key-retrieve"
438
my $cmd = join ' ', @cmd;
443
print STDERR $output;
445
elsif ($output =~ /((?: +[\dA-F]{4}){10,})/) {
446
warn "WARNING: This key is not certified with a trusted signature!\n";
447
warn "Primary key fingerprint:$1\n";
450
return SIGNATURE_BAD if ($? and $AutoKeyRetrieve);
451
return _compare($sigtext, $plaintext, (!$?) ? SIGNATURE_OK : CANNOT_VERIFY);
454
sub _verify_crypt_openpgp {
455
my ($sigtext, $plaintext) = @_;
457
require Crypt::OpenPGP;
458
my $pgp = Crypt::OpenPGP->new(
459
($KeyServer) ? ( KeyServer => $KeyServer, AutoKeyRetrieve => $AutoKeyRetrieve ) : (),
461
my $rv = $pgp->handle( Filename => $SIGNATURE )
464
return SIGNATURE_BAD if (!$rv->{Validity} and $AutoKeyRetrieve);
466
if ($rv->{Validity}) {
467
warn "Signature made ", scalar localtime($rv->{Signature}->timestamp),
468
" using key ID ", substr(uc(unpack("H*", $rv->{Signature}->key_id)), -8), "\n",
469
"Good signature from \"$rv->{Validity}\"\n" if $Verbose;
472
warn "Cannot verify signature; public key not found\n";
475
return _compare($sigtext, $plaintext, $rv->{Validity} ? SIGNATURE_OK : CANNOT_VERIFY);
484
open D, $sigfile or die "Could not open $sigfile: $!";
486
next if (1 .. /^-----BEGIN PGP SIGNED MESSAGE-----/);
487
last if /^-----BEGIN PGP SIGNATURE/;
492
return ((split(/\n+/, $signature, 2))[1]);
496
my ($str1, $str2, $ok) = @_;
498
# normalize all linebreaks
499
$str1 =~ s/[^\S ]+/\n/; $str2 =~ s/[^\S ]+/\n/;
501
return $ok if $str1 eq $str2;
503
if (eval { require Text::Diff; 1 }) {
504
warn "--- $SIGNATURE ".localtime((stat($SIGNATURE))[9])."\n";
505
warn "+++ (current) ".localtime()."\n";
506
warn Text::Diff::diff( \$str1, \$str2, { STYLE => "Unified" } );
510
open S, $SIGNATURE or die "Could not open $SIGNATURE: $!";
511
open D, "| diff -u $SIGNATURE -" or (warn "Could not call diff: $!", return SIGNATURE_MISMATCH);
513
print D $_ if (1 .. /^-----BEGIN PGP SIGNED MESSAGE-----/);
514
print D if (/^Hash: / .. /^$/);
515
next if (1 .. /^-----BEGIN PGP SIGNATURE/);
516
print D $str2, "-----BEGIN PGP SIGNATURE-----\n", $_ and last;
522
return SIGNATURE_MISMATCH;
526
my %args = ( skip => 1, @_ );
527
my $overwrite = $args{overwrite};
528
my $plaintext = _mkdigest();
530
my ($mani, $file) = _fullcheck($args{skip});
532
if (@{$mani} or @{$file}) {
533
warn "==> MISMATCHED content between MANIFEST and the distribution! <==\n";
534
warn "==> Please correct your MANIFEST file and/or delete extra files. <==\n";
537
if (!$overwrite and -e $SIGNATURE and -t STDIN) {
539
print "$SIGNATURE already exists; overwrite [y/N]? ";
540
return unless <STDIN> =~ /[Yy]/;
543
if (`gpg --version` =~ /GnuPG.*?(\S+)$/m) {
544
_sign_gpg($SIGNATURE, $plaintext, $1);
546
elsif (eval {require Crypt::OpenPGP; 1}) {
547
_sign_crypt_openpgp($SIGNATURE, $plaintext);
550
die "Cannot use GnuPG or Crypt::OpenPGP, please install either one first!";
553
warn "==> SIGNATURE file created successfully. <==\n";
557
my ($sigfile, $plaintext) = @_;
559
die "Could not write to $sigfile"
560
if -e $sigfile and (-d $sigfile or not -w $sigfile);
563
open D, "| gpg --clearsign >> $sigfile.tmp" or die "Could not call gpg: $!";
567
(-e "$sigfile.tmp" and -s "$sigfile.tmp") or do {
568
unlink "$sigfile.tmp";
569
die "Cannot find $sigfile.tmp, signing aborted.\n";
572
open D, "$sigfile.tmp" or die "Cannot open $sigfile.tmp: $!";
574
open S, ">$sigfile" or do {
575
unlink "$sigfile.tmp";
576
die "Could not write to $sigfile: $!";
585
unlink("$sigfile.tmp");
589
sub _sign_crypt_openpgp {
590
my ($sigfile, $plaintext) = @_;
592
require Crypt::OpenPGP;
593
my $pgp = Crypt::OpenPGP->new;
594
my $ring = Crypt::OpenPGP::KeyRing->new(
595
Filename => $pgp->{cfg}->get('SecRing')
596
) or die $pgp->error(Crypt::OpenPGP::KeyRing->errstr);
597
my $kb = $ring->find_keyblock_by_index(-1)
598
or die $pgp->error("Can't find last keyblock: " . $ring->errstr);
600
my $cert = $kb->signing_key;
601
my $uid = $cert->uid($kb->primary_uid);
602
warn "Debug: acquiring signature from $uid\n" if $Debug;
604
my $signature = $pgp->sign(
610
PassphraseCallback => \&Crypt::OpenPGP::_default_passphrase_cb,
611
) or die $pgp->errstr;
615
open D, ">$sigfile" or die "Could not write to $sigfile: $!";
624
my $digest = _mkdigest_files(undef, @_) or return;
627
foreach my $file (sort keys %$digest) {
628
next if $file eq $SIGNATURE;
629
$plaintext .= "@{$digest->{$file}} $file\n";
635
sub _mkdigest_files {
637
my $algorithm = shift || $Cipher;
638
my $dosnames = (defined(&Dos::UseLFN) && Dos::UseLFN()==0);
639
my $read = ExtUtils::Manifest::maniread() || {};
640
my $found = ExtUtils::Manifest::manifind($p);
642
my $obj = eval { Digest->new($algorithm) } || eval {
643
require "Digest/$algorithm.pm"; "Digest::$algorithm"->new
645
warn("Unknown cipher: $algorithm\n"); return;
648
foreach my $file (sort keys %$read){
649
warn "Debug: collecting digest from $file\n" if $Debug;
652
$file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
653
$file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
655
unless ( exists $found->{$file} ) {
656
warn "No such file: $file\n" if $Verbose;
660
open F, $file or die "Cannot open $file for reading: $!";
661
binmode(F) if -B $file;
663
$digest{$file} = [$algorithm, $obj->hexdigest];
677
L<ExtUtils::Manifest>, L<Crypt::OpenPGP>, L<Test::Signature>
681
Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>
685
Copyright 2002, 2003 by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>.
687
Parts of the documentation are copyrighted by Iain Truskett, 2002.
689
This program is free software; you can redistribute it and/or
690
modify it under the same terms as Perl itself.
692
See L<http://www.perl.com/perl/misc/Artistic.html>