File Coverage

blib/lib/Mail/GPG.pm
Criterion Covered Total %
statement 595 647 91.9
branch 167 254 65.7
condition 54 87 62.0
subroutine 49 62 79.0
pod 16 43 37.2
total 881 1093 80.6


line stmt bran cond sub pod time code
1             package Mail::GPG;
2              
3             $VERSION = "1.0.13";
4              
5 6     6   801 use strict;
  6         22  
  6         158  
6 6     6   29 use Carp;
  6         15  
  6         547  
7 6     6   475 use IO::Handle;
  6         5125  
  6         232  
8 6     6   3146 use Data::Dumper ();
  6         31569  
  6         152  
9 6     6   2809 use GnuPG::Interface;
  6         1644788  
  6         214  
10 6     6   633 use MIME::Parser;
  6         85516  
  6         209  
11 6     6   2294 use Mail::GPG::Result;
  6         14  
  6         169  
12 6     6   30 use Mail::Address;
  6         53  
  6         134  
13 6     6   26 use File::Temp;
  6         10  
  6         495  
14 6     6   30 use List::MoreUtils ();
  6         37  
  6         90  
15              
16 6     6   2822 use EV;
  6         11402  
  6         145  
17 6     6   4642 use AnyEvent;
  6         25768  
  6         184  
18              
19             #-- control debug output on i/o multiplexing
20 6     6   30 use constant IODEBUG => 0;
  6         17  
  6         36037  
21              
22 51     51 0 214 sub get_default_key_id { shift->{default_key_id} }
23 81     81 0 295 sub get_default_passphrase { shift->{default_passphrase} }
24 107     107 0 593 sub get_debug { shift->{debug} }
25 0     0 0 0 sub get_debug_dir { shift->{debug_dir} }
26 184     184 0 640 sub get_gnupg_hash_init { shift->{gnupg_hash_init} }
27 201     201 0 7282 sub get_digest { shift->{digest} }
28 30     30 0 115 sub get_default_key_encrypt { shift->{default_key_encrypt} }
29 368     368 0 4448 sub get_gpg_call { shift->{gpg_call} }
30 81     81 0 222 sub get_no_strict_7bit_encoding { shift->{no_strict_7bit_encoding} }
31 103     103 0 468 sub get_use_long_key_ids { shift->{use_long_key_ids} }
32              
33 0     0 0 0 sub set_default_key_id { shift->{default_key_id} = $_[1] }
34 0     0 0 0 sub set_default_passphrase { shift->{default_passphrase} = $_[1] }
35 0     0 0 0 sub set_debug { shift->{debug} = $_[1] }
36 0     0 0 0 sub set_debug_dir { shift->{debug_dir} = $_[1] }
37 0     0 0 0 sub set_gnupg_hash_init { shift->{gnupg_hash_init} = $_[1] }
38 0     0 0 0 sub set_digest { shift->{digest} = $_[1] }
39 0     0 0 0 sub set_default_key_encrypt { shift->{default_key_encrypt} = $_[1] }
40 0     0 0 0 sub set_gpg_call { shift->{gpg_call} = $_[1] }
41 0     0 0 0 sub set_no_strict_7bit_encoding { shift->{no_strict_7bit_encoding}=$_[1]}
42 0     0 0 0 sub set_use_long_key_ids { shift->{use_long_key_ids} = $_[1] }
43              
44             sub new {
45 62     62 1 244 my $class = shift;
46 62         1136 my %par = @_;
47             my ($default_key_id, $default_passphrase, $debug, $debug_dir) =
48 62         268 @par{'default_key_id','default_passphrase','debug','debug_dir'};
49             my ($gnupg_hash_init, $digest, $gpg_call, $default_key_encrypt) =
50 62         152 @par{'gnupg_hash_init','digest','gpg_call','default_key_encrypt'};
51             my ($no_strict_7bit_encoding, $use_long_key_ids) =
52 62         151 @par{'no_strict_7bit_encoding','use_long_key_ids'};
53              
54 62   33     2737 $debug_dir ||= $ENV{DUMPDIR} || File::Spec->tmpdir . '/mail-gpg-test';
      33        
55 62   50     178 $gnupg_hash_init ||= {};
56 62   50     382 $digest ||= "RIPEMD160";
57 62   50     340 $gpg_call ||= "gpg";
58 62   50     436 $no_strict_7bit_encoding ||= 0;
59 62   100     259 $use_long_key_ids ||= 0;
60              
61 62         1133 my $self = bless {
62             default_key_id => $default_key_id,
63             default_passphrase => $default_passphrase,
64             debug => $debug,
65             debug_dir => $debug_dir,
66             gnupg_hash_init => $gnupg_hash_init,
67             digest => $digest,
68             default_key_encrypt => $default_key_encrypt,
69             gpg_call => $gpg_call,
70             no_strict_7bit_encoding => $no_strict_7bit_encoding,
71             use_long_key_ids => $use_long_key_ids,
72             }, $class;
73              
74 62         337 return $self;
75             }
76              
77             sub new_gpg_interface {
78 184     184 0 463 my $self = shift;
79 184         515 my %par = @_;
80 184         473 my ($options, $passphrase) = @par{'options','passphrase'};
81              
82 184         6876 my $gpg = GnuPG::Interface->new;
83              
84 184 100       46510 $gpg->passphrase($passphrase) if defined $passphrase;
85 184 50       3995 $gpg->call( $self->get_gpg_call ) if $self->get_gpg_call ne '';
86              
87 184         4119 my $gnupg_hash_init = $self->get_gnupg_hash_init;
88              
89 184 100       518 if ($options) {
90 55         1194 $gpg->options->hash_init( %{$options}, %{$gnupg_hash_init} );
  55         22943  
  55         230  
91             }
92             else {
93 129         3622 $gpg->options->hash_init( %{$gnupg_hash_init} );
  129         63430  
94             }
95              
96 184         34384 $gpg->options->push_extra_args( '--digest', $self->get_digest );
97 184         21783 $gpg->options->meta_interactive(0);
98              
99 184         6414 return $gpg;
100             }
101              
102             sub save_debug_file {
103 0     0 0 0 my $self = shift;
104 0         0 my %par = @_;
105 0         0 my ($name, $data, $data_fh ) = @par{'name','data','data_fh' };
106              
107 0         0 $name = $self->get_debug_dir . "/mgpg-" . $name;
108              
109 0 0       0 open( DBG, ">$name" ) or die "can't write $name";
110 0 0       0 if ($data_fh) {
    0          
111 0         0 seek $data_fh, 0, 0;
112 0         0 print DBG $_ while <$data_fh>;
113             }
114             elsif ( ref $data ) {
115 0         0 print DBG $$data;
116             }
117             else {
118 0         0 print DBG $data;
119             }
120 0         0 close DBG;
121              
122 0         0 1;
123             }
124              
125             sub check_7bit_encoding_of_all_parts {
126 73     73 0 412 my $self = shift;
127 73         264 my %par = @_;
128 73         176 my ($entity) = $par{'entity'};
129              
130             #-- skip if no strict encoding check should be applied
131 73 50       252 return 1 if $self->get_no_strict_7bit_encoding;
132              
133             #-- first the primary entity
134 73         196 my $encoding = $entity->head->get("content-transfer-encoding");
135 73 50 66     3753 die "Content transfer encoding '$encoding' is not 7bit safe"
136             unless not defined $encoding
137             or $encoding =~ /^(quoted-printable|base64|7bit)\s*$/i;
138              
139             #-- now all parts
140 73 100       261 return 1 if not $entity->parts;
141              
142             #-- recursively
143 17         191 my $parts = $entity->parts;
144 17         167 for ( my $i = 0; $i < $parts; ++$i ) {
145 34         208 $self->check_7bit_encoding_of_all_parts( entity => $entity->parts($i),
146             );
147             }
148              
149 17         153 return 1;
150             }
151              
152             sub check_encryption {
153 60     60 0 112 my $self = shift;
154 60         372 my %par = @_;
155             my ($entity, $encrypted_text_sref) =
156 60         178 @par{'entity','encrypted_text_sref'};
157              
158 60         94 my $is_armor;
159 60 100       438 if ( $entity->effective_type =~ m!multipart/encrypted!i ) {
    50          
160              
161             #-- is this a valid RFC 3156 multipart/encrypted entity?
162 44 50       12046 die "Entity must have two parts"
163             if $entity->parts != 2;
164 44 50       490 die "Entity is not OpenPGP encrypted"
165             unless $entity->parts(0)->effective_type
166             =~ m!application/pgp-encrypted!i;
167 44         4950 $$encrypted_text_sref = $entity->parts(1)->body_as_string;
168              
169             }
170             elsif ( $entity->bodyhandle ) {
171              
172             #-- probably an ASCII armor encrypted entity
173             #-- (we need the *decoded* data here - hopefully the
174             #-- MIME::Parser had decode_body(1) set).
175 16         3458 $$encrypted_text_sref = $entity->bodyhandle->as_string;
176 16 50       362 die "Entity is not OpenPGP encrypted"
177             unless $$encrypted_text_sref =~ /^-----BEGIN PGP MESSAGE-----/m;
178 16         36 $is_armor = 1;
179             }
180             else {
181 0         0 die "Entity is not multipart/encrypted and has no body";
182             }
183              
184 60         20947 return $is_armor;
185             }
186              
187             sub perform_multiplexed_gpg_io {
188 137     137 0 1179 my $self = shift;
189 137         4122 my %par = @_;
190             my ($data_fh, $data_canonify, $stdin_fh, $stderr_fh) =
191 137         537 @par{'data_fh','data_canonify','stdin_fh','stderr_fh'};
192             my ($stdout_fh, $status_fh, $stderr_sref, $stdout_sref) =
193 137         508 @par{'stdout_fh','status_fh','stderr_sref','stdout_sref'};
194             my ($status_sref) =
195 137         301 $par{'status_sref'};
196              
197             #-- Debug stuff
198 137         606 IODEBUG && print "anyevent\n";
199 137         916 my $nl = "\n";
200 137         282 my $r = 0;
201 137         174 my $w = 0;
202              
203             #-- I/O buffer size
204 137         544 my $bsize = 8192;
205              
206             #-- perl < 5.6 compatibility: seek() and read() work
207             #-- on native GLOB filehandle only, so dertmine type
208             #-- of filehandle here
209 137         1364 my $data_fh_glob = ref $data_fh eq 'GLOB';
210              
211             #-- rewind the data filehandle
212 137 50       399 if ($data_fh_glob) {
213 137         3723 seek $data_fh, 0, 0;
214             }
215             else {
216 0         0 $data_fh->seek( 0, 0 );
217             }
218              
219             #-- Watchers for various handles
220 137         805 my ($data_watcher, $stdin_watcher, $stderr_watcher,
221             $stdout_watcher, $status_watcher);
222              
223             #-- Buffer for data reading and stdin writing
224 137         581 my $data_buffer = "";
225              
226             #-- Mainloop condvar
227 137         7396 my $done = AnyEvent->condvar;
228              
229 137         10924 IODEBUG && print "dw $nl";
230              
231             #-- watch for incoming data
232             $data_watcher = AnyEvent->io (
233             fh => $data_fh,
234             poll => "r",
235             cb => sub {
236 12063     12063   147508 IODEBUG && print "d";
237              
238 12063         99990 my $rc = sysread($data_fh, my $buffer, $bsize);
239              
240 12063         16911 IODEBUG && ( $r += $rc );
241 12063         10635 IODEBUG && print "($rc->$r) $nl";
242              
243             #-- on eof stop watcher and close filehandle
244 12063 100       18190 if ( !$rc ) {
245 137         155 IODEBUG && print "de $nl";
246 137         177 $data_watcher = undef;
247 137         30799 close $data_fh;
248 137         1910 return;
249             }
250              
251 11926 100       19926 if ( $data_canonify ) {
252             #-- canonify it if requested
253 11918         278178 $buffer =~ s/\x0A/\x0D\x0A/g;
254 11918         44020 $buffer =~ s/\x0D\x0D\x0A/\x0D\x0A/g;
255             }
256              
257 11926         161813 $data_buffer .= $buffer;
258              
259             #-- start stdin watcher if there is no watcher yet
260 11926 100       43896 if ( not $stdin_watcher ) {
261 137         182 IODEBUG && print "iw $nl";
262              
263             $stdin_watcher = AnyEvent->io (
264             fh => $stdin_fh,
265             poll => 'w',
266             cb => sub {
267 12120         150782 IODEBUG && print "i";
268              
269 12120         196742 my $written = syswrite($stdin_fh, $data_buffer, $bsize);
270              
271 12120         20720 $w += $written;
272 12120         12364 IODEBUG && print "($written->$w) $nl";
273              
274             #-- if we couldn't write anything, stop watcher
275 12120 50       19206 if ( not defined $written ) {
276 0         0 $stdin_watcher = undef;
277 0         0 IODEBUG && print "ie $nl";
278 0         0 return;
279             }
280              
281             #-- cut off i/o buffer
282 12120 50       1225299 $data_buffer = substr($data_buffer, $written) if $written;
283              
284             #-- on empty buffer there is no need to watch
285             #-- for writing into the stdin handle
286 12120 100       27045 $stdin_watcher = undef if $data_buffer eq "";
287              
288 12120 100       21748 IODEBUG && print "is $nl" unless $stdin_watcher;
289              
290             #-- if read and write watchers are off, we
291             #-- are done with feeding and close stdin
292             #-- filehandle to signal that to gpg
293 12120 100 66     60651 if ( not $stdin_watcher and not $data_watcher ) {
294 137         216 IODEBUG && print "ic $nl";
295 137         2643 close $stdin_fh;
296             }
297             },
298 137         1724 );
299             }
300             }
301 137         6525 );
302              
303 137         6985 IODEBUG && print "ew $nl";
304              
305             #-- grab stderr
306             $stderr_watcher = AnyEvent->io (
307             fh => $stderr_fh,
308             poll => 'r',
309             cb => sub {
310 250     250   218742 IODEBUG && print "e";
311              
312             my $rc = sysread(
313             $stderr_fh,
314 250         388 ${$stderr_sref},
315             $bsize,
316 250         455 length(${$stderr_sref})
  250         2577  
317             );
318              
319 250         573 IODEBUG && print "($rc) $nl";
320              
321 250 100       1807 $stderr_watcher = undef unless $rc;
322             },
323 137         3341 );
324              
325             #-- grab stdout and stop loop on eof
326             $stdout_watcher = AnyEvent->io (
327             fh => $stdout_fh,
328             poll => 'r',
329             cb => sub {
330 12182     12182   1611666 IODEBUG && print "o";
331              
332             my $rc = sysread(
333             $stdout_fh,
334 12182         14912 ${$stdout_sref},
335             $bsize,
336 12182         15889 length(${$stdout_sref})
  12182         250215  
337             );
338              
339 12182         22246 IODEBUG && print "($rc) $nl";
340              
341             #-- if gpg stdout is eof we're done
342 12182 100       46786 if ( not $rc ) {
343 137         255 $stdout_watcher = undef;
344 137         1481 $done->send;
345             }
346             },
347 137         3816 );
348              
349             #-- grab status if requested
350 137 100       1462 if ( $status_fh ) {
351 52         89 IODEBUG && print "sw $nl";
352              
353             $status_watcher = AnyEvent->io (
354             fh => $status_fh,
355             poll => 'r',
356             cb => sub {
357 283     283   507521 IODEBUG && print "s";
358              
359             my $rc = sysread(
360             $status_fh,
361 283         434 ${$status_sref},
362             $bsize,
363 283         553 length(${$status_sref})
  283         3198  
364             );
365              
366 283         555 IODEBUG && print "($rc) $nl";
367              
368 283 100       1737 $status_watcher = undef unless $rc;
369             },
370 52         400 );
371             }
372              
373 137         555 IODEBUG && print "loop $nl";
374              
375             #-- enter mainloop until eof of gpg stdout
376 137         2328 $done->recv;
377              
378 137         1608 1;
379             }
380              
381             #-- Addresses bug: https://rt.cpan.org/Public/Bug/Display.html?id=103828 (here)
382             #-- Possibly also: https://rt.cpan.org/Public/Bug/Display.html?id=81082 (here)
383             # and https://rt.cpan.org/Public/Bug/Display.html?id=80500 (in Makefile.PL)
384              
385             sub _parse_key_list {
386 59     59   12530 my $self = shift;
387 59         486 my ($output_stdout, %par) = @_;
388             my ($coerce, $debug, $verbose) =
389 59         211 @par{'coerce','debug','verbose'};
390              
391             #-- grab key ID's and emails from output (backward compatible to gpg 1.x)
392             #
393             # Example:
394             # search request: "--list-keys --with-colons 6C187D0F196ED9E3"
395             # format : see /usr/share/doc/packages/gpg2/DETAILS
396             #
397             #--OLD sample: gpg (GnuPG) 1.4.11
398             # tru:t:1:1431088683:0:3:1:5
399             # pub:-:1024:17:062F00DAE20F5035:2004-02-10:::-:Jörn Reder Mail\x3a\x3aGPG Test Key ::scaESCA:
400             # sub:-:1024:16:6C187D0F196ED9E3:2004-02-10::::::e:
401             #
402             # expected output: (062F00DAE20F5035, 'Jörn Reder Mail::GPG Test Key ')
403             #
404             #--NEW sample: gpg (GnuPG) 2.0.22
405             # tru:t:1:1429473192:0:3:1:5
406             # pub:-:1024:17:062F00DAE20F5035:1076425915:::-:::scaESCA:
407             # uid:-::::1076425915::588869ADE077B8FB05788A99565AEED15AED8231::Jörn Reder Mail\x3a\x3aGPG Test Key :
408             # sub:-:1024:16:6C187D0F196ED9E3:1076425917::::::e:
409             #
410             # expected output: (062F00DAE20F5035, 'Jörn Reder Mail::GPG Test Key ',
411             # 6C187D0F196ED9E3, 'Jörn Reder Mail::GPG Test Key ')
412             #
413             # PERLBOTIX<ätt>cpan.org / May, 2015
414              
415 59         180 my @result;
416              
417             #-- needed for utf8 handling
418 59 50       560 require Encode if $] >= 5.008;
419              
420 59         401 $output_stdout .= "\nFLUSH\n"; #-- we add this token to trigger flushing of the last record
421              
422             #-- these values are valid per "paragraph" (from pub: to pub:)
423 59         302 my @ids; #-- list of potential IDs (pub, sub)
424             my @emails; #-- list of potential email adresses (uid)
425 59         200 my $gpg2_mode = 0; #-- auto-detect OLD/NEW format: true if NEW (gpg2) format
426              
427             #-- parse output line by line
428             #-- OLD-format (gpg 1.x): simulate old behaviour
429             #-- NEW-format (gpg 2.x): create all combinations of valid key-IDs and emails; return (pub) key-ID first,
430             # so the result stays backward compatible
431              
432 59         877 while ( $output_stdout =~ m!^((\w+):?.*?)[\r\n]+!mg ) {
433              
434 274         1086 my ($line, $tag) = ($1, $2);
435 274         1108 my @fields = split /:/, $line, -1;
436              
437 274 50       464 warn("\nFields: ", join(", ", map { "($_)" } @fields)) if $debug;
  0         0  
438              
439             #-- skip entries that are expired or otherwise invalid
440 274 100 100     1962 if ( ( $fields[1] and $fields[1] =~ /^([eird])$/ )
      66        
      66        
441             or ( $fields[11] and $fields[11] =~ /([D])/ )
442             ) { #-- cannot use key (invalid/expired/revoked/[dD]isabled)
443 48 50 33     114 carp "Skipping key invalidated by '$1'-flag: ($line)" if $verbose or $debug;
444 48         332 next;
445             }
446              
447             #-- a further 'pub' marks a new paragraph or the end of the current paragraph
448             #-- a 'FLUSH' marks the end of the the whole text
449 226 100 100     1421 if ( $tag eq 'pub' or $tag eq 'FLUSH' ) {
    100 100        
    100 66        
      66        
      66        
450              
451             #-- flush intermediate or final results
452 110 100 66     842 if ( @ids and @emails ) {
    50 33        
453              
454 51         471 @emails = List::MoreUtils::uniq @emails; #-- uniq preserves order
455              
456 51         183 for ( @emails ) {
457             #-- $key_mail is quoted C-style (e.g. \x3a is a colon)
458 55         564 s/\\x(..)/chr(hex($1))/eg;
  86         429  
459              
460             #-- tell Perl that this variable is utf8 encoded
461             #-- (if Perl version is 5.8.0 or greater)
462 55 50       195 eval { $_ = Encode::decode("utf-8", $_, Encode::FB_CROAK) }
  55         596  
463             if $] >= 5.008;
464             }
465              
466 51         6033 @ids = List::MoreUtils::uniq @ids;
467 51 100       388 if ( !$self->get_use_long_key_ids ) {
468 29         142 $_ = substr($_,-8) for ( @ids );
469             }
470              
471             #-- finally, fill result array with all combinations of key-ids and emails (legacy), found in the previous paragraph
472 51         215 for my $id ( @ids ) {
473              
474 63 100       135 if ( $coerce ) {
475 14         32 push @result, $id, [ @emails ]; #-- "modern" interface
476             }
477             else {
478 49         74 for my $m ( @emails ) {
479 53         260 push @result, ($id, $m); #-- legacy
480             }
481             }
482             }
483              
484             } elsif ( @ids or @emails ) {
485 0         0 carp "Incomplete key data - key is probably invalid? (@ids) x (@emails)!";
486             }
487              
488 110         248 @ids = ();
489 110         141 @emails = ();
490 110 50 66     407 last if defined $fields[1] and $fields[1] eq 'FLUSH';
491              
492              
493             #-- parse 'new' format (pub:..; next: uid:..., uid:..., sub:... )
494 110 100 100     888 if ( not defined $fields[9] or $fields[9] =~ /^\s*$/ ) {
    50          
495 71         88 $gpg2_mode = 1;
496 71         284 push @ids, $fields[4];
497             }
498             #-- parse 'old' format (pub:)
499             elsif ( $fields[9] =~ /<[^>]+>/ ) {
500 39         86 $gpg2_mode = 0;
501 39         77 push @ids, $fields[4];
502 39         291 push @emails, $fields[9];
503             }
504             else {
505 0         0 die "Cannot parse: ($line)";
506             }
507              
508             } #-- 'pub' & 'FLUSH' handled obove
509              
510             #-- handle 'sub' entries / extract key-id
511             elsif ( $tag eq 'sub' and $gpg2_mode and $fields[4]) {
512 12         72 push @ids, $fields[4];
513             }
514              
515             #-- handle 'uid' entries / extract email
516             elsif ( $tag eq 'uid' and $gpg2_mode and $fields[9] =~ /<[^>]+>/ ) {
517 16         109 push @emails, $fields[9];
518             }
519              
520             #-- ignore anything else
521             else {
522 88 50       698 warn "Ignoring line [gpg2_mode=$gpg2_mode] -- '$line'" if $debug;
523             }
524              
525             } #-- loop over output_stdout
526              
527 59 50       116 warn Data::Dumper->Dump( [ \@result], [qw(RESULT_AS_REF)] ) if $debug;
528              
529 59         365 return @result;
530             }
531              
532              
533             sub query_keyring {
534 35     35 1 145 my $self = shift;
535 35         287 my %par = @_;
536 35         153 my ($search, $debug) = @par{'search','debug'};
537              
538             #-- ignore any PIPE signals, in case of gpg exited
539             #-- early before we fed our data into it.
540 35         796 local $SIG{PIPE} = 'IGNORE';
541              
542             #-- we parse gpg's output and rely on english
543 35         522 local $ENV{LC_ALL} = "C";
544              
545             #-- get a GnuPG::Interface
546 35         234 my $gpg = $self->new_gpg_interface;
547              
548             #-- initialize Handles
549 35         680 my $stdout = IO::Handle->new;
550 35         1817 my $stderr = IO::Handle->new;
551 35         1607 my $handles = GnuPG::Handles->new(
552             stdout => $stdout,
553             stderr => $stderr,
554             );
555              
556             #-- execute gpg --list-public-keys
557 35         25777 my $pid = $gpg->wrap_call(
558             handles => $handles,
559             commands => [ "--list-keys", "--with-colons" ],
560             command_args => [$search],
561             );
562              
563             #-- fetch gpg's STDERR
564 35         120233 my $output_stderr;
565 35         466302 $output_stderr .= $_ while <$stderr>;
566 35         734 close $stderr;
567              
568             #-- fetch gpg's STDOUT
569 35         127 my $output_stdout;
570 35         927 $output_stdout .= $_ while <$stdout>;
571 35         327 close $stdout;
572              
573             #-- wait on gpg exit
574 35         506 waitpid $pid, 0;
575              
576 35 50       238 if ( $debug ) {
577 0         0 warn "LIST_KEYS(CMD) -- --list-keys --with-colons $search\n";
578 0         0 warn "LIST_KEYS(STDERR) -- search for ($search):\n$output_stderr\n";
579 0         0 warn "LIST_KEYS(STDOUT) -- search for ($search):\n$output_stdout\n";
580             }
581              
582 35         505 my @result = $self->_parse_key_list( $output_stdout , %par);
583              
584             #-- return result: undef if nothing found, first key-id if
585             #-- a scalar is requested, all entries suitable for a hash
586             #-- slurp if an array is requested
587              
588             # Compatibility note: The first id is always the id of the 'pub' entry, even for a subkey-hit.
589             # gpgv2: The result should not be used to initialise a hash, since some emails will be clobbered.
590             # We need another interface here. Curently Mail::GPG uses only the first entry...
591 35 50       136 return if not @result;
592 35 100       930 return $result[0] if not wantarray;
593 30         3208 return @result;
594             }
595              
596             sub build_rfc3156_multipart_entity {
597 39     39 0 87 my $self = shift;
598 39         257 my %par = @_;
599 39         135 my ($entity, $method) = @par{'entity','method'};
600              
601             #-- check, if content-transfer-encoding follows the
602             #-- RFC 3156 requirement of being 7bit safe
603 39         341 $self->check_7bit_encoding_of_all_parts( entity => $entity );
604              
605             #-- build entity for signed/encrypted version; first make
606             #-- a copy of the given entity (deep copy of body
607             #-- files isn't necessary, body data isn't modified
608             #-- here).
609 39         374 my $rfc_entity = $entity->dup;
610              
611             #-- determine the part, which is to be signed/encrypted
612 39         18012 my ( $work_part, $multipart );
613 39 100       126 if ( $rfc_entity->parts > 1 ) {
614              
615             #-- the entity is multipart, so we need to build
616             #-- a new version of it with all parts, but without
617             #-- the rfc822 mail headers of the original entity
618             #-- (according RFC 3156 the signed/encrypted parts
619             #-- need MIME content headers only)
620 17         162 $work_part = MIME::Entity->build( Type => "multipart/mixed" );
621 17         14806 $work_part->add_part($_) for $rfc_entity->parts;
622 17         496 $rfc_entity->parts( [] );
623 17         184 $multipart = 1;
624             }
625             else {
626              
627             #-- the entity is single part, so just make it
628             #-- multipart and take the first (and only) part
629 22         325 $rfc_entity->make_multipart;
630 22         32826 $work_part = $rfc_entity->parts(0);
631 22         178 $multipart = 0;
632             }
633              
634             #-- configure headers and add first part to the entity
635 39 100       131 if ( $method eq 'sign' ) {
636              
637             #-- set correct MIME OpenPGP header für multipart/signed
638 17         72 $rfc_entity->head->mime_attr( "Content-Type", "multipart/signed" );
639 17         3926 $rfc_entity->head->mime_attr( "Content-Type.protocol",
640             "application/pgp-signature" );
641 17         5354 $rfc_entity->head->mime_attr( "Content-Type.micalg",
642             "pgp-" . lc( $self->get_digest ) );
643              
644             #-- add content part as first part
645 17 100       5301 $rfc_entity->add_part($work_part) if $multipart;
646             }
647             else {
648              
649             #-- set correct MIME OpenPGP header für multipart/encrypted
650 22         56 $rfc_entity->head->mime_attr( "Content-Type", "multipart/encrypted" );
651 22         5277 $rfc_entity->head->mime_attr( "Content-Type.protocol",
652             "application/pgp-encrypted" );
653              
654             #-- remove all parts
655 22         6635 $rfc_entity->parts( [] );
656              
657             #-- and add OpenPGP version part as first part
658 22         222 $rfc_entity->attach(
659             Type => "application/pgp-encrypted",
660             Disposition => "inline",
661             Data => ["Version: 1\n"],
662             Encoding => "7bit",
663             );
664             }
665              
666             #-- return the newly created entitiy and the part to work on
667 39         22902 return ( $rfc_entity, $work_part );
668             }
669              
670             sub mime_sign {
671 17     17 1 4584 my $self = shift;
672 17         110 my %par = @_;
673             my ($key_id, $passphrase, $entity) =
674 17         70 @par{'key_id','passphrase','entity'};
675              
676             #-- ignore any PIPE signals, in case of gpg exited
677             #-- early before we fed our data into it.
678 17         335 local $SIG{PIPE} = 'IGNORE';
679              
680             #-- we parse gpg's output and rely on english
681 17         181 local $ENV{LC_ALL} = "C";
682              
683             #-- get default key ID and passphrase, if not given
684 17 50       206 $key_id = $self->get_default_key_id if not defined $key_id;
685 17 50       163 $passphrase = $self->get_default_passphrase if not defined $passphrase;
686              
687             #-- check parameters
688 17 50       64 die "No key_id set" if $key_id eq '';
689 17 50       48 die "No passphrase set" if not defined $passphrase;
690              
691             #-- build entity for signed version
692             #-- (only the 2nd part with the signature data
693             #-- needs to be added later)
694 17         176 my ( $signed_entity, $sign_part ) = $self->build_rfc3156_multipart_entity(
695             entity => $entity,
696             method => "sign",
697             );
698              
699             #-- get a GnuPG::Interface
700 17         252 my $gpg = $self->new_gpg_interface(
701             options => {
702             armor => 1,
703             default_key => $key_id,
704             },
705             passphrase => $passphrase,
706             );
707              
708             #-- initialize handles
709 17         277 my $stdin = IO::Handle->new;
710 17         748 my $stdout = IO::Handle->new;
711 17         285 my $stderr = IO::Handle->new;
712 17         692 my $handles = GnuPG::Handles->new(
713             stdin => $stdin,
714             stdout => $stdout,
715             stderr => $stderr,
716             );
717              
718             #-- execute gpg for signing
719 17         11298 my $pid = $gpg->detach_sign( handles => $handles );
720              
721             #-- put encoded entity data into temporary file
722             #-- (faster than in-memory operation)
723 17         68832 my ( $data_fh, $data_file ) = File::Temp::tempfile();
724 17         11803 unlink $data_file;
725 17         436 $sign_part->print($data_fh);
726              
727             #-- perform I/O (multiplexed to prevent blocking)
728 17         48346 my ( $output_stdout, $output_stderr ) = ("", "");
729 17         508 $self->perform_multiplexed_gpg_io(
730             data_fh => $data_fh,
731             data_canonify => 1,
732             stdin_fh => $stdin,
733             stderr_fh => $stderr,
734             stdout_fh => $stdout,
735             stderr_sref => \$output_stderr,
736             stdout_sref => \$output_stdout,
737             );
738              
739             #-- close reader filehandles (stdin was closed
740             #-- by perform_multiplexed_gpg_io())
741 17         312 close $stdout;
742 17         181 close $stderr;
743              
744             #-- fetch zombie
745 17         305 waitpid $pid, 0;
746 17 50       261 die $output_stderr if $?;
747              
748             #-- attach OpenPGP signature as second part
749 17         258 $signed_entity->attach(
750             Type => "application/pgp-signature",
751             Disposition => "inline",
752             Data => [$output_stdout],
753             Encoding => "7bit",
754             );
755              
756             #-- debugging: create file with signed data
757 17 50       22123 if ( $self->get_debug ) {
758 0         0 $self->save_debug_file(
759             name => "mime-sign-data.txt",
760             data_fh => $data_fh,
761             );
762 0         0 $self->save_debug_file(
763             name => "mime-sign-entity.txt",
764             data => \$signed_entity->as_string,
765             );
766             }
767              
768             #-- close temporary data filehandle
769 17         56 close $data_fh;
770              
771             #-- return signed entity
772 17         1924 return $signed_entity;
773             }
774              
775             sub mime_encrypt {
776 8     8 1 22 my $self = shift;
777 8         34 my %par = @_;
778 8         30 my ($entity, $recipients) = @par{'entity','recipients'};
779              
780             #-- call mime_sign_encrypt() with no_sign option
781 8         31 return $self->mime_sign_encrypt(
782             entity => $entity,
783             recipients => $recipients,
784             _no_sign => 1,
785             );
786             }
787              
788             sub mime_sign_encrypt {
789 22     22 1 58 my $self = shift;
790 22         116 my %par = @_;
791             my ($key_id, $passphrase, $entity, $recipients, $_no_sign) =
792 22         86 @par{'key_id','passphrase','entity','recipients','_no_sign'};
793              
794             #-- ignore any PIPE signals, in case of gpg exited
795             #-- early before we fed our data into it.
796 22         363 local $SIG{PIPE} = 'IGNORE';
797              
798             #-- we parse gpg's output and rely on english
799 22         151 local $ENV{LC_ALL} = "C";
800              
801             #-- get default key ID and passphrase, if not given
802 22 50       185 $key_id = $self->get_default_key_id if not defined $key_id;
803 22 50       94 $passphrase = $self->get_default_passphrase if not defined $passphrase;
804              
805             #-- check parameters
806 22 50 66     170 die "No key_id set" if not $_no_sign and $key_id eq '';
807 22 50 66     92 die "No passphrase set" if not $_no_sign and not defined $passphrase;
808              
809             #-- build entity for encrypted version
810             #-- (only the 2nd part with the encrypted data
811             #-- needs to be added later)
812 22         197 my ( $encrypted_entity, $encrypt_part )
813             = $self->build_rfc3156_multipart_entity(
814             entity => $entity,
815             method => "encrypt",
816             );
817              
818             #-- get a GnuPG::Interface
819 22         365 my $gpg = $self->new_gpg_interface(
820             options => {
821             armor => 1,
822             default_key => $key_id,
823             },
824             passphrase => $passphrase,
825             );
826              
827             #-- add recipients, but first extract the mail-adress
828             #-- part, otherwise gpg couldn't find keys for adresses
829             #-- with quoted printable encodings in the name part-
830 22         227 $recipients = $self->extract_mail_address( recipients => $recipients, );
831 22         50 $gpg->options->push_recipients($_) for @{$recipients};
  22         428  
832              
833             #-- add default key to recipients if requested
834 22 50 33     2370 $gpg->options->push_recipients( $self->get_default_key_id )
835             if $self->get_default_key_encrypt
836             and $self->get_default_key_id;
837              
838             #-- initialize handles
839 22         138 my $stdin = IO::Handle->new;
840 22         512 my $stdout = IO::Handle->new;
841 22         357 my $stderr = IO::Handle->new;
842 22         966 my $handles = GnuPG::Handles->new(
843             stdin => $stdin,
844             stdout => $stdout,
845             stderr => $stderr,
846             );
847              
848             #-- execute gpg for encryption
849 22         10095 my $pid;
850 22 100       75 if ($_no_sign) {
851 8         34 $pid = $gpg->encrypt( handles => $handles );
852             }
853             else {
854 14         56 $pid = $gpg->sign_and_encrypt( handles => $handles );
855             }
856              
857             #-- put encoded entity data into temporary file
858             #-- (faster than in-memory operation)
859 22         96288 my ( $data_fh, $data_file ) = File::Temp::tempfile();
860 22         16045 unlink $data_file;
861 22         507 $encrypt_part->print($data_fh);
862              
863             #-- perform I/O (multiplexed to prevent blocking)
864 22         16108552 my ( $output_stdout, $output_stderr ) = ("", "");
865 22         484 $self->perform_multiplexed_gpg_io(
866             data_fh => $data_fh,
867             data_canonify => 1,
868             stdin_fh => $stdin,
869             stderr_fh => $stderr,
870             stdout_fh => $stdout,
871             stderr_sref => \$output_stderr,
872             stdout_sref => \$output_stdout,
873             );
874              
875             #-- close reader filehandles (stdin was closed
876             #-- by perform_multiplexed_gpg_io())
877 22         352 close $stdout;
878 22         256 close $stderr;
879              
880             #-- fetch zombie
881 22         371 waitpid $pid, 0;
882 22 50       304 die $output_stderr if $?;
883              
884             #-- attach second part with the encrytped text
885 22         419 $encrypted_entity->attach(
886             Type => "application/octet-stream",
887             Disposition => "inline",
888             Data => [$output_stdout],
889             Encoding => "7bit",
890             );
891              
892             #-- debugging: create file with encrypted data
893 22 50       29077 if ( $self->get_debug ) {
894 0         0 $self->save_debug_file(
895             name => "mime-enc-data.txt",
896             data_fh => $data_fh,
897             );
898 0         0 $self->save_debug_file(
899             name => "mime-enc-entity.txt",
900             data => \$encrypted_entity->as_string,
901             );
902             }
903              
904             #-- close temporary data filehandle
905 22         109 close $data_fh;
906              
907             #-- return encrytped entity
908 22         2815 return $encrypted_entity;
909             }
910              
911             sub armor_sign {
912 8     8 1 20 my $self = shift;
913 8         76 my %par = @_;
914             my ($key_id, $passphrase, $entity) =
915 8         31 @par{'key_id','passphrase','entity'};
916              
917             #-- ignore any PIPE signals, in case of gpg exited
918             #-- early before we fed our data into it.
919 8         135 local $SIG{PIPE} = 'IGNORE';
920              
921             #-- we parse gpg's output and rely on english
922 8         101 local $ENV{LC_ALL} = "C";
923              
924             #-- get default key ID and passphrase, if not given
925 8 50       86 $key_id = $self->get_default_key_id if not defined $key_id;
926 8 50       58 $passphrase = $self->get_default_passphrase if not defined $passphrase;
927              
928             #-- check parameters
929 8 50       18 die "No key_id set" if $key_id eq '';
930 8 50       19 die "No passphrase set" if not defined $passphrase;
931 8 50       21 die "Entity has no body" if not $entity->bodyhandle;
932              
933             #-- check, if body content-transfer-encoding is 7bit safe
934 8 50       82 if ( not $self->get_no_strict_7bit_encoding ) {
935 8         21 my $encoding = $entity->head->get("content-transfer-encoding");
936 8 50       559 die "Content transfer encoding '$encoding' is not 7bit safe"
937             unless $encoding =~ /^(quoted-printable|base64|7bit)\s*$/i;
938             }
939              
940             #-- get a GnuPG::Interface, with ASCII armor enabled
941 8         167 my $gpg = $self->new_gpg_interface(
942             options => {
943             armor => 1,
944             default_key => $key_id,
945             },
946             passphrase => $passphrase,
947             );
948              
949             #-- initialize handles
950 8         157 my $stdin = IO::Handle->new;
951 8         342 my $stdout = IO::Handle->new;
952 8         129 my $stderr = IO::Handle->new;
953 8         360 my $handles = GnuPG::Handles->new(
954             stdin => $stdin,
955             stdout => $stdout,
956             stderr => $stderr,
957             );
958              
959             #-- execute gpg for signing
960 8         3494 my $pid = $gpg->clearsign( handles => $handles );
961              
962             #-- put encoded entity data into temporary file
963             #-- (faster than in-memory operation)
964 8         30818 my ( $data_fh, $data_file ) = File::Temp::tempfile();
965 8         5734 unlink $data_file;
966 8         233 $entity->print($data_fh);
967              
968             #-- perform I/O (multiplexed to prevent blocking)
969 8         20630 my ( $output_stdout, $output_stderr ) = ("", "");
970 8         205 $self->perform_multiplexed_gpg_io(
971             data_fh => $data_fh,
972             data_canonify => 1,
973             stdin_fh => $stdin,
974             stderr_fh => $stderr,
975             stdout_fh => $stdout,
976             stderr_sref => \$output_stderr,
977             stdout_sref => \$output_stdout,
978             );
979              
980             #-- close reader filehandles (stdin was closed
981             #-- by perform_multiplexed_gpg_io())
982 8         151 close $stdout;
983 8         104 close $stderr;
984              
985             #-- fetch zombie
986 8         123 waitpid $pid, 0;
987 8 50       115 die $output_stderr if $?;
988              
989             #-- build entity for encrypted version
990 8         158 my $signed_entity = MIME::Entity->build( Data => [$output_stdout], );
991              
992             #-- copy all header fields from original entity
993 8         11401 foreach my $tag ( $entity->head->tags ) {
994 56         5329 my @values = $entity->head->get($tag);
995 56         1868 for ( my $i = 0; $i < @values; ++$i ) {
996 56         104 $signed_entity->head->replace( $tag, $values[$i], $i );
997             }
998             }
999              
1000             #-- debugging: create file with signed data
1001 8 50       925 if ( $self->get_debug ) {
1002 0         0 $self->save_debug_file(
1003             name => "armor-sign-data.txt",
1004             data => \$entity->bodyhandle->as_string,
1005             );
1006 0         0 $self->save_debug_file(
1007             name => "armor-sign-entity.txt",
1008             data => \$signed_entity->as_string,
1009             );
1010             }
1011              
1012             #-- return the signed entity
1013 8         881 return $signed_entity;
1014             }
1015              
1016             sub armor_encrypt {
1017 4     4 1 10 my $self = shift;
1018 4         19 my %par = @_;
1019 4         14 my ($entity, $recipients) = @par{'entity','recipients'};
1020              
1021             #-- call armor_sign_encrypt() with no_sign option
1022 4         15 return $self->armor_sign_encrypt(
1023             entity => $entity,
1024             recipients => $recipients,
1025             _no_sign => 1,
1026             );
1027             }
1028              
1029             sub armor_sign_encrypt {
1030 8     8 1 15 my $self = shift;
1031 8         33 my %par = @_;
1032             my ($key_id, $passphrase, $entity, $recipients, $_no_sign) =
1033 8         26 @par{'key_id','passphrase','entity','recipients','_no_sign'};
1034              
1035             #-- ignore any PIPE signals, in case of gpg exited
1036             #-- early before we fed our data into it.
1037 8         127 local $SIG{PIPE} = 'IGNORE';
1038              
1039             #-- we parse gpg's output and rely on english
1040 8         76 local $ENV{LC_ALL} = "C";
1041              
1042             #-- get default key ID and passphrase, if not given
1043 8 100       22 if ( not $_no_sign ) {
1044 4 50       40 $key_id = $self->get_default_key_id if not defined $key_id;
1045 4 50       13 $passphrase = $self->get_default_passphrase
1046             if not defined $passphrase;
1047              
1048             #-- check parameters
1049 4 50       12 die "No key_id set" if $key_id eq '';
1050 4 50       8 die "No passphrase set" if not defined $passphrase;
1051             }
1052              
1053             #-- check parameters
1054 8 50       23 die "Entity has no body" if not $entity->bodyhandle;
1055              
1056             #-- get a GnuPG::Interface, with ASCII armor enabled
1057 8         166 my $gpg = $self->new_gpg_interface(
1058             options => {
1059             armor => 1,
1060             default_key => $key_id,
1061             },
1062             passphrase => $passphrase,
1063             );
1064              
1065             #-- add recipients, but first extract the mail-adress
1066             #-- part, otherwise gpg couldn't find keys for adresses
1067             #-- with quoted printable encodings in the name part-
1068 8         80 $recipients = $self->extract_mail_address( recipients => $recipients, );
1069 8         15 $gpg->options->push_recipients($_) for @{$recipients};
  8         176  
1070              
1071             #-- add default key to recipients if requested
1072 8 50 33     823 $gpg->options->push_recipients( $self->get_default_key_id )
1073             if $self->get_default_key_encrypt
1074             and $self->get_default_key_id;
1075              
1076             #-- initialize handles
1077 8         85 my $stdin = IO::Handle->new;
1078 8         202 my $stdout = IO::Handle->new;
1079 8         113 my $stderr = IO::Handle->new;
1080 8         337 my $handles = GnuPG::Handles->new(
1081             stdin => $stdin,
1082             stdout => $stdout,
1083             stderr => $stderr,
1084             );
1085              
1086             #-- execute gpg for encryption
1087 8         3353 my $pid;
1088 8 100       22 if ($_no_sign) {
1089 4         76 $pid = $gpg->encrypt( handles => $handles );
1090             }
1091             else {
1092 4         15 $pid = $gpg->sign_and_encrypt( handles => $handles );
1093             }
1094              
1095             #-- put encoded entity data into temporary file
1096             #-- (faster than in-memory operation)
1097 8         30343 my ( $data_fh, $data_file ) = File::Temp::tempfile();
1098 8         6175 unlink $data_file;
1099 8         198 $entity->print($data_fh);
1100              
1101             #-- perform I/O (multiplexed to prevent blocking)
1102 8         22024 my ( $output_stdout, $output_stderr ) = ("", "");
1103 8         162 $self->perform_multiplexed_gpg_io(
1104             data_fh => $data_fh,
1105             data_canonify => 0,
1106             stdin_fh => $stdin,
1107             stderr_fh => $stderr,
1108             stdout_fh => $stdout,
1109             stderr_sref => \$output_stderr,
1110             stdout_sref => \$output_stdout,
1111             );
1112              
1113             #-- close reader filehandles (stdin was closed
1114             #-- by perform_multiplexed_gpg_io())
1115 8         133 close $stdout;
1116 8         118 close $stderr;
1117              
1118             #-- fetch zombie
1119 8         147 waitpid $pid, 0;
1120 8 50       63 die $output_stderr if $?;
1121              
1122             #-- build entity for encrypted version
1123 8         226 my $encrypted_entity = MIME::Entity->build(
1124             Type => "text/plain",
1125             Encoding => "7bit",
1126             Data => [$output_stdout],
1127             );
1128              
1129             #-- copy header fields from original entity
1130 8         9559 foreach my $tag ( $entity->head->tags ) {
1131 56 100       3198 next if $tag =~ /^content/i;
1132 32         77 my @values = $entity->head->get($tag);
1133 32         1052 for ( my $i = 0; $i < @values; ++$i ) {
1134 32         58 $encrypted_entity->head->replace( $tag, $values[$i], $i );
1135             }
1136             }
1137              
1138             #-- debugging: create file with signed data
1139 8 50       598 if ( $self->get_debug ) {
1140 0         0 $self->save_debug_file(
1141             name => "armor-enc-data.txt",
1142             data => \$entity->bodyhandle->as_string,
1143             );
1144 0         0 $self->save_debug_file(
1145             name => "armor-enc-entity.txt",
1146             data => \$encrypted_entity->as_string,
1147             );
1148             }
1149              
1150             #-- return the signed entity
1151 8         848 return $encrypted_entity;
1152             }
1153              
1154             sub decrypt {
1155 30     30 1 91 my $self = shift;
1156 30         184 my %par = @_;
1157 30         213 my ($entity, $passphrase) = @par{'entity','passphrase'};
1158              
1159             #-- ignore any PIPE signals, in case of gpg exited
1160             #-- early before we fed our data into it.
1161 30         497 local $SIG{PIPE} = 'IGNORE';
1162              
1163             #-- we parse gpg's output and rely on english
1164 30         316 local $ENV{LC_ALL} = "C";
1165              
1166             #-- get default passphrase, if not given
1167 30 50       328 $passphrase = $self->get_default_passphrase if not defined $passphrase;
1168              
1169             #-- check if the entity is encrypted at all
1170             #-- (dies if not)
1171 30         61 my $encrypted_text;
1172 30         271 my $is_armor = $self->check_encryption(
1173             entity => $entity,
1174             encrypted_text_sref => \$encrypted_text,
1175             );
1176              
1177             #-- get a GnuPG::Interface
1178 30         205 my $gpg = $self->new_gpg_interface( passphrase => $passphrase, );
1179              
1180             #-- initialize handles
1181 30         263 my $stdin = IO::Handle->new;
1182 30         882 my $stdout = IO::Handle->new;
1183 30         542 my $stderr = IO::Handle->new;
1184 30         575 my $status = IO::Handle->new;
1185              
1186 30         1492 my $handles = GnuPG::Handles->new(
1187             stdin => $stdin,
1188             stdout => $stdout,
1189             stderr => $stderr,
1190             status => $status,
1191             );
1192              
1193             #-- start gpg for decryption
1194 30         15201 my $pid = $gpg->decrypt( handles => $handles );
1195              
1196             #-- put encoded entity data into temporary file
1197             #-- (faster than in-memory operation)
1198 30         136584 my ( $data_fh, $data_file ) = File::Temp::tempfile();
1199 30         21942 unlink $data_file;
1200 30         1256 print $data_fh $encrypted_text;
1201              
1202             #-- perform I/O (multiplexed to prevent blocking)
1203 30         510 my ( $output_stdout, $output_stderr, $output_status ) = ( "", "", "" );
1204              
1205 30         813 $self->perform_multiplexed_gpg_io(
1206             data_fh => $data_fh,
1207             data_canonify => 1,
1208             stdin_fh => $stdin,
1209             stderr_fh => $stderr,
1210             stdout_fh => $stdout,
1211             status_fh => $status,
1212             stderr_sref => \$output_stderr,
1213             stdout_sref => \$output_stdout,
1214             status_sref => \$output_status,
1215             );
1216              
1217             #-- close reader filehandles (stdin was closed
1218             #-- by perform_multiplexed_gpg_io())
1219 30         450 close $stdout;
1220 30         293 close $stderr;
1221              
1222             #-- fetch zombie
1223 30         474 waitpid $pid, 0;
1224 30         279 my $rc = $? >> 8;
1225              
1226             #-- don't die here for return values != 0, because
1227             #-- this also happens for encrypted+signed mails,
1228             #-- where the public key is missing for verification
1229             #-- and that's not intended here.
1230              
1231             #-- parse decrypted text
1232 30         854 my $parser = new MIME::Parser;
1233 30         10191 $parser->output_to_core(1);
1234              
1235             # for armor message (which usually contain no MIME entity)
1236             # and if the first line seems to be no header, add an empty
1237             # line at the top, otherwise the first line of a text message
1238             # will be removed by the parser.
1239 30 50 66     679 if ( $is_armor and $output_stdout !~ /^[\w-]+:/ ) {
1240 0         0 $output_stdout = "\n" . $output_stdout;
1241             }
1242              
1243 30         287 my $dec_entity = $parser->parse_data( $output_stdout );
1244              
1245             #-- Add headers from original entity
1246 30 50       764101 if ( $dec_entity->head->as_string eq '' ) {
1247 0         0 $dec_entity->head( $entity->head->dup );
1248             }
1249             else {
1250              
1251             #-- copy header fields from original entity
1252 30         1775 foreach my $tag ( $entity->head->tags ) {
1253 166 100       12951 next if $tag =~ /^content/i;
1254 120         314 my @values = $entity->head->get($tag);
1255 120         4524 for ( my $i = 0; $i < @values; ++$i ) {
1256 120         287 $dec_entity->head->replace( $tag, $values[$i], $i );
1257             }
1258             }
1259             }
1260              
1261             #-- debugging: create file with encrypted data
1262 30 50       2667 if ( $self->get_debug ) {
1263 0         0 $self->save_debug_file(
1264             name => "dec-data.txt",
1265             data => $dec_entity->as_string,
1266             );
1267             }
1268              
1269             #-- fetch information from gpg's stderr output
1270             #-- and construct a Mail::GPG::Result object from it
1271 30         749 my $result = Mail::GPG::Result->new(
1272             mail_gpg => $self,
1273             gpg_stdout => \$output_stdout,
1274             gpg_stderr => \$output_stderr,
1275             gpg_status => \$output_status,
1276             gpg_rc => $rc,
1277             );
1278              
1279             #-- return decrypted entity and result object
1280 30 50       80 return $dec_entity if not wantarray;
1281 30         3496 return ( $dec_entity, $result );
1282             }
1283              
1284             sub verify {
1285 24     24 1 57 my $self = shift;
1286 24         98 my %par = @_;
1287 24         79 my ($entity) = $par{'entity'};
1288              
1289             #-- ignore any PIPE signals, in case of gpg exited
1290             #-- early before we fed our data into it.
1291 24         406 local $SIG{PIPE} = 'IGNORE';
1292              
1293             #-- we parse gpg's output and rely on english
1294 24         154 local $ENV{LC_ALL} = "C";
1295              
1296             #-- check if the entity is signed
1297 24         51 my ( $signed_text, $signature_text );
1298              
1299 24 100       90 if ( $entity->effective_type =~ m!multipart/signed!i ) {
    50          
1300              
1301             #-- is this a valid RFC 3156 multipart/signed entity?
1302 16 50       2899 die "Entity must have two parts"
1303             if $entity->parts != 2;
1304 16 50       159 die "Entity is not OpenPGP signed"
1305             unless $entity->parts(1)->effective_type
1306             =~ m!application/pgp-signature!i;
1307              
1308             #-- hopefully the $entity was parsed with
1309             #-- decode_bodies(0), otherwise this would
1310             #-- return decoded data, but the signature
1311             #-- is calculated on the *encoded* version.
1312 16         1702 $signed_text = $entity->parts(0)->as_string;
1313 16         10560 $signature_text = $entity->parts(1)->body_as_string;
1314              
1315             }
1316             elsif ( $entity->bodyhandle ) {
1317              
1318             #-- probably an ASCII armor signed entity
1319             #-- in that case we need the *decoded* data
1320 8         1161 $signed_text = $entity->bodyhandle->as_string;
1321 8 100       203 die "Entity is not OpenPGP signed"
1322             unless $signed_text =~ /^-----BEGIN PGP SIGNED MESSAGE-----/m;
1323             }
1324             else {
1325 0         0 die "Entity is not multipart/signed and has no body";
1326             }
1327              
1328             #-- get a GnuPG::Interface
1329 22         4506 my $gpg = $self->new_gpg_interface;
1330              
1331             #-- initialize handles
1332 22         113 my $stdin = IO::Handle->new;
1333 22         403 my $stdout = IO::Handle->new;
1334 22         306 my $stderr = IO::Handle->new;
1335 22         290 my $status = IO::Handle->new;
1336              
1337 22         935 my $handles = GnuPG::Handles->new(
1338             stdin => $stdin,
1339             stdout => $stdout,
1340             stderr => $stderr,
1341             status => $status,
1342             );
1343              
1344             #-- distinguish between ascii amor embedded signature
1345             #-- and detached signature (RFC 3156)
1346 22         11741 my ( $pid, $sign_file, $sign_fh );
1347 22 100       57 if ($signature_text) {
1348              
1349             #-- signature is detached, save it to a temp file
1350 16         47 ( $sign_fh, $sign_file ) = File::Temp::tempfile();
1351 16         4043 print $sign_fh $signature_text;
1352 16         354 close $sign_fh;
1353              
1354             #-- pass signature filename to gpg
1355 16         178 $pid = $gpg->verify(
1356             handles => $handles,
1357             command_args => [ $sign_file, "-" ],
1358             );
1359              
1360             }
1361             else {
1362              
1363             #-- ASCII armor message with embedded signature
1364 6         24 $pid = $gpg->verify( handles => $handles, );
1365             }
1366              
1367             #-- put encoded entity data into temporary file
1368             #-- (faster than in-memory operation)
1369 22         80729 my ( $data_fh, $data_file ) = File::Temp::tempfile();
1370 22         14436 unlink $data_file;
1371 22         483 print $data_fh $signed_text;
1372              
1373             #-- perform I/O (multiplexed to prevent blocking)
1374 22         265 my ( $output_stdout, $output_stderr, $output_status ) = ( "", "", "" );
1375 22         583 $self->perform_multiplexed_gpg_io(
1376             data_fh => $data_fh,
1377             data_canonify => 1,
1378             stdin_fh => $stdin,
1379             stderr_fh => $stderr,
1380             stdout_fh => $stdout,
1381             status_fh => $status,
1382             stderr_sref => \$output_stderr,
1383             stdout_sref => \$output_stdout,
1384             status_sref => \$output_status,
1385             );
1386              
1387             #-- close reader filehandles (stdin was closed
1388             #-- by perform_multiplexed_gpg_io())
1389 22         408 close $stdout;
1390 22         216 close $stderr;
1391              
1392             #-- fetch zombie
1393 22         352 waitpid $pid, 0;
1394 22         204 my $rc = $? >> 8;
1395              
1396             #-- remove detached signature file
1397 22 100       803 unlink $sign_file if defined $sign_file;
1398              
1399             #-- debugging: create file with verified data
1400 22 50       298 if ( $self->get_debug ) {
1401 0         0 $self->save_debug_file(
1402             name => "verify-data.txt",
1403             data => \$signed_text,
1404             );
1405             }
1406              
1407             #-- construct a Mail::GPG::Result object from
1408             #-- gpg's stderr output
1409 22         510 my $result = Mail::GPG::Result->new(
1410             mail_gpg => $self,
1411             gpg_stdout => \$output_stdout,
1412             gpg_stderr => \$output_stderr,
1413             gpg_status => \$output_status,
1414             gpg_rc => $rc,
1415             );
1416              
1417             #-- return result object
1418 22         2734 return $result;
1419             }
1420              
1421             sub is_encrypted {
1422 30     30 1 81 my $self = shift;
1423 30         100 my %par = @_;
1424 30         69 my ($entity) = $par{'entity'};
1425              
1426 30 100       182 if ( $entity->effective_type =~ m!multipart/encrypted!i ) {
    50          
1427              
1428             #-- is this a valid RFC 3156 multipart/encrypted entity?
1429 22 50       3598 return 0 if $entity->parts != 2;
1430 22 50       323 return 0
1431             unless $entity->parts(0)->effective_type
1432             =~ m!application/pgp-encrypted!i;
1433              
1434             }
1435             elsif ( $entity->bodyhandle ) {
1436              
1437             #-- probably an ASCII armor encrypted entity
1438             #-- check the decoded body for a PGP message
1439 8 50       990 return 0
1440             unless $entity->bodyhandle->as_string
1441             =~ /^-----BEGIN PGP MESSAGE-----/m;
1442             }
1443             else {
1444 0         0 return 0;
1445             }
1446              
1447 30         2832 return 1;
1448             }
1449              
1450             sub is_signed {
1451 34     34 1 86 my $self = shift;
1452 34         99 my %par = @_;
1453 34         74 my ($entity) = $par{'entity'};
1454              
1455 34 100       118 if ( $entity->effective_type =~ m!multipart/signed!i ) {
    50          
1456              
1457             #-- is this a valid RFC 3156 multipart/signed entity?
1458 24 50       4294 return 0 if $entity->parts != 2;
1459 24 50       232 return 0
1460             unless $entity->parts(1)->effective_type
1461             =~ m!application/pgp-signature!i;
1462              
1463             }
1464             elsif ( $entity->bodyhandle ) {
1465              
1466             #-- probably an ASCII armor signed entity,
1467             #-- check the decoded body for a PGP message
1468 10 50       1433 return 0
1469             unless $entity->bodyhandle->as_string
1470             =~ /^-----BEGIN PGP SIGNED MESSAGE-----/m;
1471             }
1472             else {
1473 0         0 return 0;
1474             }
1475              
1476 34         2777 return 1;
1477             }
1478              
1479             sub is_signed_quick {
1480 20     20 1 60 my $self = shift;
1481 20         52 my %par = @_;
1482 20         47 my ($mail_fh, $mail_sref) = @par{'mail_fh', 'mail_sref'};
1483              
1484 20 50 50     128 croak "Specify mail_fh xor mail_sref"
1485             unless $mail_fh xor $mail_sref;
1486              
1487 20 100       68 if ( defined $mail_fh ) {
    50          
1488              
1489             #-- rewind filehandle
1490 10         230 seek( $mail_fh, 0, 0 );
1491              
1492             #-- read filehandle and do rough checks
1493 10         29 local ($_);
1494 10         17 my $is_signed = 0;
1495 10         139 while (<$mail_fh>) {
1496 82 100       187 if (m!application/pgp-signature!i) {
1497 8         17 $is_signed = 1;
1498 8         15 last;
1499             }
1500 74 100       162 if (/^-----BEGIN PGP SIGNED MESSAGE-----/) {
1501 2         7 $is_signed = 1;
1502 2         5 last;
1503             }
1504             }
1505              
1506             #-- rewind filehandle again
1507 10         107 seek( $mail_fh, 0, 0 );
1508              
1509             #-- return sign status
1510 10         56 return $is_signed;
1511              
1512             }
1513             elsif ( defined $mail_sref ) {
1514              
1515             #-- looks like a RFC 3156 multipart/signed entity?
1516 10 100       100 return 1 if $$mail_sref =~ m!application/pgp-signature!i;
1517              
1518             #-- or ASCII armor signed?
1519 2 50       30 return 1 if $$mail_sref =~ m!^-----BEGIN PGP SIGNED MESSAGE-----!m;
1520              
1521             #-- not signed at all
1522 0         0 return 0,;
1523             }
1524              
1525 0         0 return 1;
1526             }
1527              
1528             sub get_decrypt_key {
1529 30     30 1 45 my $self = shift;
1530 30         99 my %par = @_;
1531 30         72 my ($entity) = $par{'entity'};
1532              
1533             #-- ignore any PIPE signals, in case of gpg exited
1534             #-- early before we fed our data into it.
1535 30         518 local $SIG{PIPE} = 'IGNORE';
1536              
1537             #-- we parse gpg's output and rely on english
1538 30         320 local $ENV{LC_ALL} = "C";
1539              
1540             #-- check if the entity is encrypted at all
1541             #-- (dies if not)
1542 30         65 my $encrypted_text;
1543 30         114 my $is_armor = $self->check_encryption(
1544             entity => $entity,
1545             encrypted_text_sref => \$encrypted_text,
1546             );
1547              
1548             #-- get a GnuPG::Interface
1549 30         92 my $gpg = $self->new_gpg_interface;
1550              
1551             #-- initialize handles
1552 30         144 my $stdin = IO::Handle->new;
1553 30         582 my $stdout = IO::Handle->new;
1554 30         415 my $stderr = IO::Handle->new;
1555 30         1273 my $handles = GnuPG::Handles->new(
1556             stdin => $stdin,
1557             stdout => $stdout,
1558             stderr => $stderr,
1559             );
1560              
1561             #-- start gpg for decryption
1562 30         14222 my $pid = $gpg->wrap_call(
1563             handles => $handles,
1564             commands =>
1565             [ "--decrypt", "--batch", "--list-only", "--status-fd", "1" ],
1566             );
1567              
1568             #-- put encoded entity data into temporary file
1569             #-- (faster than in-memory operation)
1570 30         111524 my ( $data_fh, $data_file ) = File::Temp::tempfile();
1571 30         21276 unlink $data_file;
1572 30         1904 print $data_fh $encrypted_text;
1573              
1574             #-- perform I/O (multiplexed to prevent blocking)
1575 30         485 my ( $output_stdout, $output_stderr ) = ( "", "" );
1576 30         640 $self->perform_multiplexed_gpg_io(
1577             data_fh => $data_fh,
1578             data_canonify => 1,
1579             stdin_fh => $stdin,
1580             stderr_fh => $stderr,
1581             stdout_fh => $stdout,
1582             stderr_sref => \$output_stderr,
1583             stdout_sref => \$output_stdout,
1584             );
1585              
1586             #-- close reader filehandles (stdin was closed
1587             #-- by perform_multiplexed_gpg_io())
1588 30         419 close $stdout;
1589 30         354 close $stderr;
1590              
1591             #-- fetch zombie
1592 30         411 waitpid $pid, 0;
1593 30         332 my $rc = $? >> 8;
1594              
1595             #-- grep ENC_TO and NO_SECKEY items
1596 30         72 my ( @enc_to_keys, %no_sec_keys, $line );
1597 30         995 while ( $output_stdout =~ /^(.*)$/mg ) {
1598 90         280 $line = $1;
1599 90 100       615 push @enc_to_keys, $1 if $line =~ /ENC_TO\s+([^\s]+)/;
1600 90 50       356 $no_sec_keys{$1} = 1 if $line =~ /NO_SECKEY\s+([^\s]+)/;
1601             }
1602              
1603             #-- find first key we have the secret portion of
1604 30         72 my $key_id;
1605 30         163 foreach my $k (@enc_to_keys) {
1606 30 50       135 if ( not exists $no_sec_keys{$k} ) {
1607 30         53 $key_id = $k;
1608 30         60 last;
1609             }
1610             }
1611              
1612             #-- get mail address of this key
1613 30         99 my $key_mail;
1614 30         311 ( $key_id, $key_mail ) = $self->query_keyring( search => $key_id );
1615              
1616 30 50       232 return $key_id if not wantarray;
1617 30         2358 return ( $key_id, $key_mail );
1618             }
1619              
1620             sub extract_mail_address {
1621 30     30 0 76 my $self = shift;
1622 30         96 my %par = @_;
1623 30         66 my ($recipients) = $par{'recipients'};
1624              
1625 30         53 my @recipients;
1626              
1627             my $address;
1628 30         45 foreach my $r ( @{$recipients} ) {
  30         159  
1629 30         640 ($address) = Mail::Address->parse($r);
1630 30 50       8972 push @recipients, $address
1631             ? $address->address
1632             : $r;
1633             }
1634 30         511 return \@recipients;
1635             }
1636              
1637             sub parse {
1638 54     54 1 114 my $thing = shift;
1639 54         372 my %par = @_;
1640 54         175 my ($mail_fh, $mail_sref) = @par{'mail_fh','mail_sref'};
1641              
1642 54 50 25     496 croak "Specify mail_fh xor mail_sref"
1643             unless $mail_fh xor $mail_sref;
1644              
1645 54         461 require MIME::Parser;
1646 54         157 my ( $parser, $entity );
1647              
1648             #-- First parse without body decoding, which is correct
1649             #-- for MIME messages
1650 54         1211 $parser = MIME::Parser->new;
1651 54         16457 $parser->output_to_core(1);
1652 54         1054 $parser->decode_bodies(0);
1653 54 50       642 $entity = $mail_fh
1654             ? $parser->parse($mail_fh)
1655             : $parser->parse_data($$mail_sref);
1656              
1657             #-- Ok, if this is a MIME message
1658 54 100 100     369408 return $entity
1659             if $entity->effective_type eq 'multipart/signed'
1660             or $entity->effective_type eq 'multipart/encrypted';
1661              
1662             #-- Now with body decoding, which is MIME::Parser's default
1663             #-- and correct for OpenPGP armor message. Probably this
1664             #-- isn't an OpenPGP message at all. But also in that case
1665             #-- it's the best to return a decoded entity, as MIME::Parser
1666             #-- usually does.
1667 16 50       3835 seek( $mail_fh, 0, 0 ) if $mail_fh;
1668 16         104 $parser->decode_bodies(1);
1669 16 50       128 $entity = $mail_fh
1670             ? $parser->parse($mail_fh)
1671             : $parser->parse_data($$mail_sref);
1672              
1673 16         32275 return $entity;
1674             }
1675              
1676             sub get_key_trust {
1677 12     12 1 23 my $self = shift;
1678 12         97 my %par = @_;
1679 12         63 my ($key_id) = $par{'key_id'};
1680              
1681             # Suppress warnings about unknown record type 'tru'
1682             # in GnuPG::Interface
1683 12     0   224 local $SIG{__WARN__} = sub {1};
  0         0  
1684              
1685 12         112 my $gpg = $self->new_gpg_interface;
1686 12         97 my @keys = $gpg->get_public_keys($key_id);
1687              
1688 12 50       689993 croak "Request for key ID '$key_id' got multiple result"
1689             if @keys > 1;
1690              
1691 12 50       57 return "" unless $keys[0];
1692 12         255 return $keys[0]->owner_trust;
1693             }
1694              
1695             1;
1696              
1697             __END__