~ubuntu-branches/ubuntu/trusty/libmodule-signature-perl/trusty-updates

« back to all changes in this revision

Viewing changes to lib/Module/Signature.pm

  • Committer: Bazaar Package Importer
  • Author(s): Chip Salzenberg
  • Date: 2003-10-05 21:45:16 UTC
  • Revision ID: james.westby@ubuntu.com-20031005214516-93q02srkdovy5lor
Tags: upstream-0.35
ImportĀ upstreamĀ versionĀ 0.35

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# $File: //member/autrijus/Module-Signature/lib/Module/Signature.pm $ 
 
2
# $Revision: #24 $ $Change: 7734 $ $DateTime: 2003/08/27 06:48:25 $
 
3
 
 
4
package Module::Signature;
 
5
$Module::Signature::VERSION = '0.35';
 
6
 
 
7
use strict;
 
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); 
 
11
 
 
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;
 
20
 
 
21
use ExtUtils::Manifest ();
 
22
use Exporter;
 
23
 
 
24
@EXPORT_OK      = (qw(sign verify),
 
25
                   qw($SIGNATURE $KeyServer $Cipher $Preamble),
 
26
                   grep /^[A-Z_]+_[A-Z_]+$/, keys %Module::Signature::);
 
27
@ISA            = 'Exporter';
 
28
 
 
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';
 
33
$Cipher         = 'SHA1';
 
34
$Preamble       = << ".";
 
35
This file contains message digests of all files listed in MANIFEST,
 
36
signed via the Module::Signature module, version $VERSION.
 
37
 
 
38
To verify the content in this distribution, first make sure you have
 
39
Module::Signature installed, then type:
 
40
 
 
41
    % cpansign -v
 
42
 
 
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.
 
47
 
 
48
.
 
49
 
 
50
$AutoKeyRetrieve    = 1;
 
51
$CanKeyRetrieve     = undef;
 
52
 
 
53
=head1 NAME
 
54
 
 
55
Module::Signature - Module signature file manipulation
 
56
 
 
57
=head1 VERSION
 
58
 
 
59
This document describes version 0.35 of B<Module::Signature>,
 
60
released August 27, 2003.
 
61
 
 
62
=head1 SYNOPSIS
 
63
 
 
64
As a shell command:
 
65
 
 
66
    % cpansign              # verify an existing SIGNATURE, or
 
67
                              make a new one if none exists 
 
68
 
 
69
    % cpansign sign         # make signature; overwrites existing one
 
70
    % cpansign -s           # same thing
 
71
 
 
72
    % cpansign verify       # verify a signature
 
73
    % cpansign -v           # same thing
 
74
    % cpansign -v --skip    # ignore files in MANIFEST.SKIP
 
75
 
 
76
    % cpansign help         # display this documentation
 
77
    % cpansign -h           # same thing
 
78
 
 
79
In programs:
 
80
 
 
81
    use Module::Signature qw(sign verify SIGNATURE_OK);
 
82
    sign();
 
83
    sign(overwrite => 1);       # overwrites without asking
 
84
 
 
85
    # see the CONSTANTS section below
 
86
    (verify() == SIGNATURE_OK) or die "failed!";
 
87
 
 
88
=head1 DESCRIPTION
 
89
 
 
90
B<Module::Signature> adds cryptographic authentications to CPAN
 
91
distributions, via the special SIGNATURE file.
 
92
 
 
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
 
96
tampered with.
 
97
 
 
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>:
 
101
 
 
102
    #!/usr/bin/perl
 
103
    use strict;
 
104
    print "1..1\n";
 
105
 
 
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";
 
110
    }
 
111
    elsif (!eval { require Socket; Socket::inet_aton('pgp.mit.edu') }) {
 
112
        print "ok 1 # skip ",
 
113
              "Cannot connect to the keyserver\n";
 
114
    }
 
115
    else {
 
116
        (Module::Signature::verify() == Module::Signature::SIGNATURE_OK())
 
117
            or print "not ";
 
118
        print "ok 1 # Valid signature\n";
 
119
    }
 
120
 
 
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.
 
124
 
 
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.
 
128
 
 
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>.
 
131
 
 
132
=head1 VARIABLES
 
133
 
 
134
No package variables are exported by default.
 
135
 
 
136
=over 4
 
137
 
 
138
=item $Verbose
 
139
 
 
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.
 
143
 
 
144
=item $SIGNATURE
 
145
 
 
146
The filename for a distribution's signature file.  Defaults to
 
147
C<SIGNATURE>.
 
148
 
 
149
=item $KeyServer
 
150
 
 
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.
 
155
 
 
156
=item $KeyServerPort
 
157
 
 
158
The OpenPGP key server port, defaults to C<11371>.
 
159
 
 
160
=item $AutoKeyRetrieve
 
161
 
 
162
Whether to automatically fetch unknown keys from the key server.
 
163
Defaults to C<1>.
 
164
 
 
165
=item $Cipher
 
166
 
 
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.
 
170
 
 
171
Module::Signature version 0.09 and above will use the cipher
 
172
specified in the SIGNATURE file's first entry to validate its
 
173
integrity.
 
174
 
 
175
=item $Preamble
 
176
 
 
177
The explanatory text written to newly generated SIGNATURE files
 
178
before the actual entries.
 
179
 
 
180
=back
 
181
 
 
182
=head1 ENVIRONMENT
 
183
 
 
184
Module::Signature honors these environment variables:
 
185
 
 
186
=over 4
 
187
 
 
188
=item MODULE_SIGNATURE_VERBOSE
 
189
 
 
190
Works like $Verbose.
 
191
 
 
192
=item MODULE_SIGNATURE_KEYSERVER
 
193
 
 
194
Works like $KeyServer.
 
195
 
 
196
=item MODULE_SIGNATURE_KEYSERVERPORT
 
197
 
 
198
Works like $KeyServerPort.
 
199
 
 
200
=back
 
201
 
 
202
=head1 CONSTANTS
 
203
 
 
204
These constants are not exported by default.
 
205
 
 
206
=over 4
 
207
 
 
208
=item CANNOT_VERIFY (C<0E0>)
 
209
 
 
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.
 
213
 
 
214
=item SIGNATURE_OK (C<0>)
 
215
 
 
216
Signature successfully verified.
 
217
 
 
218
=item SIGNATURE_MISSING (C<-1>)
 
219
 
 
220
The F<SIGNATURE> file does not exist.
 
221
 
 
222
=item SIGNATURE_MALFORMED (C<-2>)
 
223
 
 
224
The signature file does not contains a valid OpenPGP message.
 
225
 
 
226
=item SIGNATURE_BAD (C<-3>)
 
227
 
 
228
Invalid signature detected -- it might have been tampered.
 
229
 
 
230
=item SIGNATURE_MISMATCH (C<-4>)
 
231
 
 
232
The signature is valid, but files in the distribution have changed
 
233
since its creation.
 
234
 
 
235
=item MANIFEST_MISMATCH (C<-5>)
 
236
 
 
237
There are extra files in the current directory not specified by
 
238
the MANIFEST file.
 
239
 
 
240
=item CIPHER_UNKNOWN (C<-6>)
 
241
 
 
242
The cipher used by the signature file is not recognized by the
 
243
C<Digest> module.
 
244
 
 
245
=back
 
246
 
 
247
=head1 NOTES
 
248
 
 
249
(The following section is lifted from Iain Truskett's B<Test::Signature>
 
250
module, under the Perl license.  Thanks, Iain!)
 
251
 
 
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.
 
257
 
 
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
 
260
below.
 
261
 
 
262
If you're using C<ExtUtils::MakeMaker>, you should have, at least:
 
263
 
 
264
    ^Makefile$
 
265
    ^blib/
 
266
    ^pm_to_blib$
 
267
 
 
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.
 
271
 
 
272
If you are using C<Module::Build>, you should have two extra entries:
 
273
 
 
274
    ^Build$
 
275
    ^_build/
 
276
 
 
277
If you don't have the correct entries, C<Module::Signature> will
 
278
complain that you have:
 
279
 
 
280
    ==> MISMATCHED content between MANIFEST and distribution files! <==
 
281
 
 
282
You should note this during normal development testing anyway.
 
283
 
 
284
=cut
 
285
 
 
286
sub verify {
 
287
    my %args = ( skip => 1, @_ );
 
288
    my $rv;
 
289
 
 
290
    (-r $SIGNATURE) or do {
 
291
        warn "==> MISSING Signature file! <==\n";
 
292
        return SIGNATURE_MISSING;
 
293
    };
 
294
 
 
295
    (my $sigtext = _read_sigfile($SIGNATURE)) or do {
 
296
        warn "==> MALFORMED Signature file! <==\n";
 
297
        return SIGNATURE_MALFORMED;
 
298
    };
 
299
 
 
300
    (my ($cipher) = ($sigtext =~ /^(\w+) /)) or do {
 
301
        warn "==> MALFORMED Signature file! <==\n";
 
302
        return SIGNATURE_MALFORMED;
 
303
    };
 
304
 
 
305
    (defined(my $plaintext = _mkdigest($cipher))) or do {
 
306
        warn "==> UNKNOWN Cipher format! <==\n";
 
307
        return CIPHER_UNKNOWN;
 
308
    };
 
309
 
 
310
    $rv = _verify($SIGNATURE, $sigtext, $plaintext);
 
311
 
 
312
    if ($rv == SIGNATURE_OK) {
 
313
        my ($mani, $file) = _fullcheck($args{skip});
 
314
 
 
315
        if (@{$mani} or @{$file}) {
 
316
            warn "==> MISMATCHED content between MANIFEST and distribution files! <==\n";
 
317
            return MANIFEST_MISMATCH;
 
318
        }
 
319
        else {
 
320
            warn "==> Signature verified OK! <==\n" if $Verbose;
 
321
        }
 
322
    }
 
323
    elsif ($rv == SIGNATURE_BAD) {
 
324
        warn "==> BAD/TAMPERED signature detected! <==\n";
 
325
    }
 
326
    elsif ($rv == SIGNATURE_MISMATCH) {
 
327
        warn "==> MISMATCHED content between SIGNATURE and distribution files! <==\n";
 
328
    }
 
329
 
 
330
    return $rv;
 
331
}
 
332
 
 
333
sub _verify {
 
334
    my $signature = shift || $SIGNATURE;
 
335
    my $sigtext   = shift || '';
 
336
    my $plaintext = shift || '';
 
337
 
 
338
    local $SIGNATURE = $signature if $signature ne $SIGNATURE;
 
339
 
 
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;
 
346
        }
 
347
        $AutoKeyRetrieve = $CanKeyRetrieve;
 
348
    }
 
349
 
 
350
    if (`gpg --version` =~ /GnuPG.*?(\S+)$/m) {
 
351
        return _verify_gpg($sigtext, $plaintext, $1);
 
352
    }
 
353
    elsif (eval {require Crypt::OpenPGP; 1}) {
 
354
        return _verify_crypt_openpgp($sigtext, $plaintext);
 
355
    }
 
356
    else {
 
357
        warn "Cannot use GnuPG or Crypt::OpenPGP, please install either one first!\n";
 
358
        return _compare($sigtext, $plaintext, CANNOT_VERIFY);
 
359
    }
 
360
}
 
361
 
 
362
sub _fullcheck {
 
363
    my $skip = shift;
 
364
    my @extra;
 
365
 
 
366
    local $^W;
 
367
    local $ExtUtils::Manifest::Quiet = 1;
 
368
 
 
369
    my($mani, $file);
 
370
    if( _legacy_extutils() ) {
 
371
        my $_maniskip = &ExtUtils::Manifest::_maniskip;
 
372
 
 
373
        local *ExtUtils::Manifest::_maniskip = sub { sub {
 
374
            return unless $skip;
 
375
            my $ok = $_maniskip->(@_);
 
376
            if ($ok ||= (!-e 'MANIFEST.SKIP' and _default_skip(@_))) {
 
377
                print "Skipping $_\n" for @_;
 
378
                push @extra, @_;
 
379
            }
 
380
            return $ok;
 
381
        } };
 
382
 
 
383
        ($mani, $file) = ExtUtils::Manifest::fullcheck();
 
384
    }
 
385
    else {
 
386
        ($mani, $file) = ExtUtils::Manifest::fullcheck();
 
387
    }
 
388
 
 
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;
 
393
    }
 
394
 
 
395
    @{$mani} = grep {$_ ne 'SIGNATURE'} @{$mani};
 
396
 
 
397
    warn "Not in MANIFEST: $_\n" for @{$file};
 
398
    warn "No such file: $_\n" for @{$mani};
 
399
 
 
400
    return ($mani, $file);
 
401
}
 
402
 
 
403
sub _legacy_extutils {
 
404
    # ExtUtils::Manifest older than 1.41 does not handle default skips well.
 
405
    return (ExtUtils::Manifest->VERSION < 1.41);
 
406
}
 
407
 
 
408
sub _default_skip {
 
409
    local $_ = shift;
 
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 /^\.#/;
 
415
}
 
416
 
 
417
sub _verify_gpg {
 
418
    my ($sigtext, $plaintext, $version) = @_;
 
419
 
 
420
    local $SIGNATURE = Win32::GetShortPathName($SIGNATURE)
 
421
        if defined &Win32::GetShortPathName and $SIGNATURE =~ /[^-\w.:~\\\/]/;
 
422
 
 
423
    my @quiet = $Verbose ? () : qw(-q --logger-fd=1);
 
424
    my @cmd = (
 
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"
 
429
                : ()
 
430
        ) : ()), $SIGNATURE
 
431
    );
 
432
 
 
433
    my $output = '';
 
434
    if( $Verbose ) {
 
435
        system @cmd;
 
436
    }
 
437
    else {
 
438
        my $cmd = join ' ', @cmd;
 
439
        $output = `$cmd`;
 
440
    }
 
441
 
 
442
    if( $? ) {
 
443
        print STDERR $output;
 
444
    }
 
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";
 
448
    }
 
449
 
 
450
    return SIGNATURE_BAD if ($? and $AutoKeyRetrieve);
 
451
    return _compare($sigtext, $plaintext, (!$?) ? SIGNATURE_OK : CANNOT_VERIFY);
 
452
}
 
453
 
 
454
sub _verify_crypt_openpgp {
 
455
    my ($sigtext, $plaintext) = @_;
 
456
 
 
457
    require Crypt::OpenPGP;
 
458
    my $pgp = Crypt::OpenPGP->new(
 
459
        ($KeyServer) ? ( KeyServer => $KeyServer, AutoKeyRetrieve => $AutoKeyRetrieve ) : (),
 
460
    );
 
461
    my $rv = $pgp->handle( Filename => $SIGNATURE )
 
462
        or die $pgp->errstr;
 
463
 
 
464
    return SIGNATURE_BAD if (!$rv->{Validity} and $AutoKeyRetrieve);
 
465
 
 
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;
 
470
    }
 
471
    else {
 
472
        warn "Cannot verify signature; public key not found\n";
 
473
    }
 
474
 
 
475
    return _compare($sigtext, $plaintext, $rv->{Validity} ? SIGNATURE_OK : CANNOT_VERIFY);
 
476
}
 
477
 
 
478
sub _read_sigfile {
 
479
    my $sigfile = shift;
 
480
    my $signature = '';
 
481
    my $well_formed;
 
482
 
 
483
    local *D;
 
484
    open D, $sigfile or die "Could not open $sigfile: $!";
 
485
    while (<D>) {
 
486
        next if (1 .. /^-----BEGIN PGP SIGNED MESSAGE-----/);
 
487
        last if /^-----BEGIN PGP SIGNATURE/;
 
488
 
 
489
        $signature .= $_;
 
490
    }
 
491
 
 
492
    return ((split(/\n+/, $signature, 2))[1]);
 
493
}
 
494
 
 
495
sub _compare {
 
496
    my ($str1, $str2, $ok) = @_;
 
497
 
 
498
    # normalize all linebreaks
 
499
    $str1 =~ s/[^\S ]+/\n/; $str2 =~ s/[^\S ]+/\n/;
 
500
 
 
501
    return $ok if $str1 eq $str2;
 
502
 
 
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" } );
 
507
    }
 
508
    else {
 
509
        local (*D, *S);
 
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);
 
512
        while (<S>) {
 
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;
 
517
        }
 
518
        print D <S>;
 
519
        close D;
 
520
    }
 
521
 
 
522
    return SIGNATURE_MISMATCH;
 
523
}
 
524
 
 
525
sub sign {
 
526
    my %args = ( skip => 1, @_ );
 
527
    my $overwrite = $args{overwrite};
 
528
    my $plaintext = _mkdigest();
 
529
 
 
530
    my ($mani, $file) = _fullcheck($args{skip});
 
531
 
 
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";
 
535
    }
 
536
 
 
537
    if (!$overwrite and -e $SIGNATURE and -t STDIN) {
 
538
        local $/ = "\n";
 
539
        print "$SIGNATURE already exists; overwrite [y/N]? ";
 
540
        return unless <STDIN> =~ /[Yy]/;
 
541
    }
 
542
 
 
543
    if (`gpg --version` =~ /GnuPG.*?(\S+)$/m) {
 
544
        _sign_gpg($SIGNATURE, $plaintext, $1);
 
545
    }
 
546
    elsif (eval {require Crypt::OpenPGP; 1}) {
 
547
        _sign_crypt_openpgp($SIGNATURE, $plaintext);
 
548
    }
 
549
    else {
 
550
        die "Cannot use GnuPG or Crypt::OpenPGP, please install either one first!";
 
551
    }
 
552
 
 
553
    warn "==> SIGNATURE file created successfully. <==\n";
 
554
}
 
555
 
 
556
sub _sign_gpg {
 
557
    my ($sigfile, $plaintext) = @_;
 
558
 
 
559
    die "Could not write to $sigfile"
 
560
        if -e $sigfile and (-d $sigfile or not -w $sigfile);
 
561
 
 
562
    local *D;
 
563
    open D, "| gpg --clearsign >> $sigfile.tmp" or die "Could not call gpg: $!";
 
564
    print D $plaintext;
 
565
    close D;
 
566
 
 
567
    (-e "$sigfile.tmp" and -s "$sigfile.tmp") or do {
 
568
        unlink "$sigfile.tmp";
 
569
        die "Cannot find $sigfile.tmp, signing aborted.\n";
 
570
    };
 
571
 
 
572
    open D, "$sigfile.tmp" or die "Cannot open $sigfile.tmp: $!";
 
573
 
 
574
    open S, ">$sigfile" or do {
 
575
        unlink "$sigfile.tmp";
 
576
        die "Could not write to $sigfile: $!";
 
577
    };
 
578
 
 
579
    print S $Preamble;
 
580
    print S <D>;
 
581
 
 
582
    close S;
 
583
    close D;
 
584
 
 
585
    unlink("$sigfile.tmp");
 
586
    return 1;
 
587
}
 
588
 
 
589
sub _sign_crypt_openpgp {
 
590
    my ($sigfile, $plaintext) = @_;
 
591
 
 
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);
 
599
 
 
600
    my $cert = $kb->signing_key;
 
601
    my $uid = $cert->uid($kb->primary_uid);
 
602
    warn "Debug: acquiring signature from $uid\n" if $Debug;
 
603
 
 
604
    my $signature = $pgp->sign(
 
605
        Data       => $plaintext,
 
606
        Detach     => 0,
 
607
        Clearsign  => 1,
 
608
        Armour     => 1,
 
609
        Key        => $cert,
 
610
        PassphraseCallback => \&Crypt::OpenPGP::_default_passphrase_cb,
 
611
    ) or die $pgp->errstr;
 
612
 
 
613
 
 
614
    local *D;
 
615
    open D, ">$sigfile" or die "Could not write to $sigfile: $!";
 
616
    print D $Preamble;
 
617
    print D $signature;
 
618
    close D;
 
619
 
 
620
    return 1;
 
621
}
 
622
 
 
623
sub _mkdigest {
 
624
    my $digest = _mkdigest_files(undef, @_) or return;
 
625
    my $plaintext = '';
 
626
 
 
627
    foreach my $file (sort keys %$digest) {
 
628
        next if $file eq $SIGNATURE;
 
629
        $plaintext .= "@{$digest->{$file}} $file\n";
 
630
    }
 
631
 
 
632
    return $plaintext;
 
633
}
 
634
 
 
635
sub _mkdigest_files {
 
636
    my $p = shift;
 
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);
 
641
    my(%digest) = ();
 
642
    my $obj = eval { Digest->new($algorithm) } || eval {
 
643
        require "Digest/$algorithm.pm"; "Digest::$algorithm"->new
 
644
    } or do {
 
645
        warn("Unknown cipher: $algorithm\n"); return;
 
646
    };
 
647
 
 
648
    foreach my $file (sort keys %$read){
 
649
        warn "Debug: collecting digest from $file\n" if $Debug;
 
650
        if ($dosnames){
 
651
            $file = lc $file;
 
652
            $file =~ s=(\.(\w|-)+)=substr ($1,0,4)=ge;
 
653
            $file =~ s=((\w|-)+)=substr ($1,0,8)=ge;
 
654
        }
 
655
        unless ( exists $found->{$file} ) {
 
656
            warn "No such file: $file\n" if $Verbose;
 
657
        }
 
658
        else {
 
659
            local *F;
 
660
            open F, $file or die "Cannot open $file for reading: $!";
 
661
            binmode(F) if -B $file;
 
662
            $obj->addfile(*F);
 
663
            $digest{$file} = [$algorithm, $obj->hexdigest];
 
664
            $obj->reset;
 
665
        }
 
666
    }
 
667
 
 
668
    return \%digest;
 
669
}
 
670
 
 
671
1;
 
672
 
 
673
__END__
 
674
 
 
675
=head1 SEE ALSO
 
676
 
 
677
L<ExtUtils::Manifest>, L<Crypt::OpenPGP>, L<Test::Signature>
 
678
 
 
679
=head1 AUTHORS
 
680
 
 
681
Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>
 
682
 
 
683
=head1 COPYRIGHT
 
684
 
 
685
Copyright 2002, 2003 by Autrijus Tang E<lt>autrijus@autrijus.orgE<gt>.
 
686
 
 
687
Parts of the documentation are copyrighted by Iain Truskett, 2002.
 
688
 
 
689
This program is free software; you can redistribute it and/or 
 
690
modify it under the same terms as Perl itself.
 
691
 
 
692
See L<http://www.perl.com/perl/misc/Artistic.html>
 
693
 
 
694
=cut