| line | stmt | bran | path | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  |  | #  Interface.pm | 
| 2 |  |  |  |  |  |  |  | #    - providing an object-oriented approach to interacting with GnuPG | 
| 3 |  |  |  |  |  |  |  | # | 
| 4 |  |  |  |  |  |  |  | #  Copyright (C) 2000 Frank J. Tobin <ftobin@cpan.org> | 
| 5 |  |  |  |  |  |  |  | # | 
| 6 |  |  |  |  |  |  |  | #  This module is free software; you can redistribute it and/or modify it | 
| 7 |  |  |  |  |  |  |  | #  under the same terms as Perl itself. | 
| 8 |  |  |  |  |  |  |  | # | 
| 9 |  |  |  |  |  |  |  | #  This program is distributed in the hope that it will be useful, | 
| 10 |  |  |  |  |  |  |  | #  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
| 11 |  |  |  |  |  |  |  | #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | 
| 12 |  |  |  |  |  |  |  | # | 
| 13 |  |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  |  | package GnuPG::Interface; | 
| 15 | 78 |  |  |  | 78 |  | 4203379 | use Moo; | 
|  | 78 |  |  |  |  |  | 695276 |  | 
|  | 78 |  |  |  |  |  | 404 |  | 
| 16 | 78 |  |  |  | 78 |  | 153030 | use MooX::late; | 
|  | 78 |  |  |  |  |  | 2150840 |  | 
|  | 78 |  |  |  |  |  | 521 |  | 
| 17 |  |  |  |  |  |  |  | with qw(GnuPG::HashInit); | 
| 18 |  |  |  |  |  |  |  |  | 
| 19 | 78 |  |  |  | 78 |  | 14725741 | use English qw( -no_match_vars ); | 
|  | 78 |  |  |  |  |  | 220 |  | 
|  | 78 |  |  |  |  |  | 687 |  | 
| 20 | 78 |  |  |  | 78 |  | 33401 | use Carp; | 
|  | 78 |  |  |  |  |  | 251 |  | 
|  | 78 |  |  |  |  |  | 4837 |  | 
| 21 | 78 |  |  |  | 78 |  | 546 | use Fcntl; | 
|  | 78 |  |  |  |  |  | 174 |  | 
|  | 78 |  |  |  |  |  | 19515 |  | 
| 22 | 78 |  |  |  | 78 |  | 605 | use vars qw( $VERSION ); | 
|  | 78 |  |  |  |  |  | 377 |  | 
|  | 78 |  |  |  |  |  | 4406 |  | 
| 23 | 78 |  |  |  | 78 |  | 5727 | use Fatal qw( open close pipe fcntl ); | 
|  | 78 |  |  |  |  |  | 104721 |  | 
|  | 78 |  |  |  |  |  | 759 |  | 
| 24 | 78 |  |  |  | 78 |  | 166454 | use Class::Struct; | 
|  | 78 |  |  |  |  |  | 14328 |  | 
|  | 78 |  |  |  |  |  | 925 |  | 
| 25 | 78 |  |  |  | 78 |  | 9301 | use IO::Handle; | 
|  | 78 |  |  |  |  |  | 225 |  | 
|  | 78 |  |  |  |  |  | 3645 |  | 
| 26 |  |  |  |  |  |  |  |  | 
| 27 | 78 |  |  |  | 78 |  | 108727 | use Math::BigInt try => 'GMP'; | 
|  | 78 |  |  |  |  |  | 2150660 |  | 
|  | 78 |  |  |  |  |  | 415 |  | 
| 28 | 78 |  |  |  | 78 |  | 1992332 | use GnuPG::Options; | 
|  | 78 |  |  |  |  |  | 1460 |  | 
|  | 78 |  |  |  |  |  | 3390 |  | 
| 29 | 78 |  |  |  | 78 |  | 41860 | use GnuPG::Handles; | 
|  | 78 |  |  |  |  |  | 274 |  | 
|  | 78 |  |  |  |  |  | 3108 |  | 
| 30 | 78 |  |  |  | 78 |  | 625 | use Scalar::Util 'tainted'; | 
|  | 78 |  |  |  |  |  | 175 |  | 
|  | 78 |  |  |  |  |  | 175936 |  | 
| 31 |  |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  |  | $VERSION = '1.03'; | 
| 33 |  |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  |  | has passphrase => ( | 
| 35 |  |  |  |  |  |  |  | isa     => 'Any', | 
| 36 |  |  |  |  |  |  |  | is      => 'rw', | 
| 37 |  |  |  |  |  |  |  | clearer => 'clear_passphrase', | 
| 38 |  |  |  |  |  |  |  | ); | 
| 39 |  |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  |  | has call => ( | 
| 41 |  |  |  |  |  |  |  | isa     => 'Any', | 
| 42 |  |  |  |  |  |  |  | is      => 'rw', | 
| 43 |  |  |  |  |  |  |  | trigger => 1, | 
| 44 |  |  |  |  |  |  |  | clearer => 'clear_call', | 
| 45 |  |  |  |  |  |  |  | ); | 
| 46 |  |  |  |  |  |  |  |  | 
| 47 |  |  |  |  |  |  |  | # NB: GnuPG versions | 
| 48 |  |  |  |  |  |  |  | # | 
| 49 |  |  |  |  |  |  |  | # There are now two supported versions of GnuPG: legacy 1.4 and stable 2.2 | 
| 50 |  |  |  |  |  |  |  | # They are detected and each behave slightly differently. | 
| 51 |  |  |  |  |  |  |  | # | 
| 52 |  |  |  |  |  |  |  | # When using features specific to branches, check that the system's | 
| 53 |  |  |  |  |  |  |  | # version of gpg corresponds to the branch. | 
| 54 |  |  |  |  |  |  |  | # | 
| 55 |  |  |  |  |  |  |  | # legacy: 1.4 | 
| 56 |  |  |  |  |  |  |  | # stable: >= 2.2 | 
| 57 |  |  |  |  |  |  |  | # | 
| 58 |  |  |  |  |  |  |  | # You can find examples of version comparison in the tests. | 
| 59 |  |  |  |  |  |  |  | has version => ( | 
| 60 |  |  |  |  |  |  |  | isa      => 'Str', | 
| 61 |  |  |  |  |  |  |  | is       => 'ro', | 
| 62 |  |  |  |  |  |  |  | reader   => 'version', | 
| 63 |  |  |  |  |  |  |  | writer   => '_set_version', | 
| 64 |  |  |  |  |  |  |  | ); | 
| 65 |  |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  |  | has options => ( | 
| 67 |  |  |  |  |  |  |  | isa        => 'GnuPG::Options', | 
| 68 |  |  |  |  |  |  |  | is         => 'rw', | 
| 69 |  |  |  |  |  |  |  | lazy_build => 1, | 
| 70 |  |  |  |  |  |  |  | ); | 
| 71 |  |  |  |  |  |  |  |  | 
| 72 | 83 |  |  |  | 83 |  | 26938 | sub _build_options { GnuPG::Options->new() } | 
| 73 |  |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  |  | # deprecated! | 
| 75 | 4 |  |  |  | 4 | 0 | 1038 | sub gnupg_call { shift->call(@_); } | 
| 76 |  |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  |  | sub BUILD { | 
| 78 | 91 |  |  |  | 91 | 0 | 420451 | my ( $self, $args ) = @_; | 
| 79 | 91 |  |  |  |  |  | 1691 | $self->hash_init( call => 'gpg', %$args ); | 
| 80 |  |  |  |  |  |  |  | } | 
| 81 |  |  |  |  |  |  |  |  | 
| 82 |  |  |  |  |  |  |  | struct( | 
| 83 |  |  |  |  |  |  |  | fh_setup => { | 
| 84 |  |  |  |  |  |  |  | parent_end       => '$', child_end      => '$', | 
| 85 |  |  |  |  |  |  |  | direct           => '$', is_std         => '$', | 
| 86 |  |  |  |  |  |  |  | parent_is_source => '$', name_shows_dup => '$', | 
| 87 |  |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  |  | ); | 
| 89 |  |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  |  | # Update version if "call" is updated | 
| 91 |  |  |  |  |  |  |  | sub _trigger_call { | 
| 92 | 120 |  |  |  | 120 |  | 47059 | my ( $self, $gpg ) = @_; | 
| 93 | 120 |  |  |  |  |  | 683 | $self->_set_version( $self->_version() ); | 
| 94 |  |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  |  | ################################################################# | 
| 97 |  |  |  |  |  |  |  | # real worker functions | 
| 98 |  |  |  |  |  |  |  |  | 
| 99 |  |  |  |  |  |  |  | # This function does any 'extra' stuff that the user might | 
| 100 |  |  |  |  |  |  |  | # not want to handle himself, such as passing in the passphrase | 
| 101 |  |  |  |  |  |  |  | sub wrap_call( $% ) { | 
| 102 | 241 |  |  |  | 241 | 1 | 32221 | my ( $self, %args ) = @_; | 
| 103 |  |  |  |  |  |  |  |  | 
| 104 |  |  |  |  |  |  |  | my $handles = $args{handles} | 
| 105 | 241 | 50 |  |  |  |  | 2033 | or croak 'error: no handles defined'; | 
| 106 |  |  |  |  |  |  |  |  | 
| 107 | 241 | 100 |  |  |  |  | 7202 | $handles->stdin('<&STDIN')   unless $handles->stdin(); | 
| 108 | 241 | 50 |  |  |  |  | 15992 | $handles->stdout('>&STDOUT') unless $handles->stdout(); | 
| 109 | 241 | 100 |  |  |  |  | 9290 | $handles->stderr('>&STDERR') unless $handles->stderr(); | 
| 110 |  |  |  |  |  |  |  |  | 
| 111 | 241 | 100 |  |  |  |  | 16484 | $self->passphrase("\n") unless $self->passphrase(); | 
| 112 |  |  |  |  |  |  |  |  | 
| 113 | 241 | 100 |  | 66 |  |  | 10191 | my $needs_passphrase_handled | 
| 114 |  |  |  |  |  |  |  | = ( $self->passphrase() =~ m/\S/ and not $handles->passphrase() ) ? 1 : 0; | 
| 115 |  |  |  |  |  |  |  |  | 
| 116 | 241 | 100 |  |  |  |  | 12997 | if ($needs_passphrase_handled) { | 
| 117 | 187 |  |  |  |  |  | 1408 | $handles->passphrase( IO::Handle->new() ); | 
| 118 |  |  |  |  |  |  |  | } | 
| 119 |  |  |  |  |  |  |  |  | 
| 120 | 241 |  |  |  |  |  | 18055 | my $pid = $self->fork_attach_exec(%args); | 
| 121 |  |  |  |  |  |  |  |  | 
| 122 | 186 | 100 |  |  |  |  | 3261 | if ($needs_passphrase_handled) { | 
| 123 | 146 |  |  |  |  |  | 8257 | my $passphrase_handle = $handles->passphrase(); | 
| 124 | 146 |  |  |  |  |  | 8792 | print $passphrase_handle $self->passphrase(); | 
| 125 | 146 |  |  |  |  |  | 10493 | close $passphrase_handle; | 
| 126 |  |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  |  | # We put this in in case the user wants to re-use this object | 
| 128 | 146 |  |  |  |  |  | 7632 | $handles->clear_passphrase(); | 
| 129 |  |  |  |  |  |  |  | } | 
| 130 |  |  |  |  |  |  |  |  | 
| 131 | 186 |  |  |  |  |  | 10001 | return $pid; | 
| 132 |  |  |  |  |  |  |  | } | 
| 133 |  |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  |  | # does does command-line creation, forking, and execcing | 
| 135 |  |  |  |  |  |  |  | # the reasing cli creation is done here is because we should | 
| 136 |  |  |  |  |  |  |  | # fork before finding the fd's for stuff like --status-fd | 
| 137 |  |  |  |  |  |  |  | sub fork_attach_exec( $% ) { | 
| 138 | 241 |  |  |  | 241 | 0 | 1486 | my ( $self, %args ) = @_; | 
| 139 |  |  |  |  |  |  |  |  | 
| 140 | 241 | 50 |  |  |  |  | 1421 | my $handles = $args{handles} or croak 'no GnuPG::Handles passed'; | 
| 141 | 241 |  |  |  |  |  | 702 | my $use_loopback_pinentry = 0; | 
| 142 |  |  |  |  |  |  |  |  | 
| 143 |  |  |  |  |  |  |  | # Don't use loopback pintentry for legacy (1.4) GPG | 
| 144 |  |  |  |  |  |  |  | # | 
| 145 |  |  |  |  |  |  |  | # Check that $version is populated before running cmp_version. If | 
| 146 |  |  |  |  |  |  |  | # we are invoked as part of BUILD to populate $version, then any | 
| 147 |  |  |  |  |  |  |  | # methods that depend on $version will fail. We don't care about | 
| 148 |  |  |  |  |  |  |  | # loopback when we're called just to check gpg version. | 
| 149 | 241 | 50 |  | 100 |  |  | 6401 | $use_loopback_pinentry = 1 | 
|  |  |  |  | 66 |  |  |  |  | 
| 150 |  |  |  |  |  |  |  | if ($handles->passphrase() && $self->version && $self->cmp_version($self->version, '2.2') > 0 ); | 
| 151 |  |  |  |  |  |  |  |  | 
| 152 |  |  |  |  |  |  |  | # deprecation support | 
| 153 | 241 |  |  | 66 |  |  | 3320 | $args{commands} ||= $args{gnupg_commands}; | 
| 154 |  |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  |  | my @commands | 
| 156 | 241 |  |  |  |  |  | 1934 | = ref $args{commands} ? @{ $args{commands} } : ( $args{commands} ) | 
| 157 | 241 | 50 |  |  |  |  | 1612 | or croak "no gnupg commands passed"; | 
|  |  | 50 |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  |  | # deprecation support | 
| 160 | 241 |  |  | 100 |  |  | 2680 | $args{command_args} ||= $args{gnupg_command_args}; | 
| 161 |  |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  |  | my @command_args | 
| 163 |  |  |  |  |  |  |  | = ref $args{command_args} | 
| 164 | 24 |  |  |  |  |  | 191 | ? @{ $args{command_args} } | 
| 165 | 241 | 100 |  | 100 |  |  | 2016 | : ( $args{command_args} || () ); | 
| 166 | 241 | 100 |  | 66 |  |  | 1749 | unshift @command_args, "--" | 
| 167 |  |  |  |  |  |  |  | if @command_args and $command_args[0] ne "--"; | 
| 168 |  |  |  |  |  |  |  |  | 
| 169 | 241 |  |  |  |  |  | 625 | my %fhs; | 
| 170 | 241 |  |  |  |  |  | 959 | foreach my $fh_name ( | 
| 171 |  |  |  |  |  |  |  | qw( stdin stdout stderr status | 
| 172 |  |  |  |  |  |  |  | logger passphrase command | 
| 173 |  |  |  |  |  |  |  | ) | 
| 174 |  |  |  |  |  |  |  | ) { | 
| 175 | 1687 | 100 |  |  |  |  | 55161 | my $fh = $handles->$fh_name() or next; | 
| 176 | 919 |  |  |  |  |  | 26060 | $fhs{$fh_name} = fh_setup->new(); | 
| 177 | 919 |  |  |  |  |  | 71600 | $fhs{$fh_name}->parent_end($fh); | 
| 178 |  |  |  |  |  |  |  | } | 
| 179 |  |  |  |  |  |  |  |  | 
| 180 | 241 |  |  |  |  |  | 4017 | foreach my $fh_name (qw( stdin stdout stderr )) { | 
| 181 | 723 |  |  |  |  |  | 15895 | $fhs{$fh_name}->is_std(1); | 
| 182 |  |  |  |  |  |  |  | } | 
| 183 |  |  |  |  |  |  |  |  | 
| 184 | 241 |  |  |  |  |  | 2401 | foreach my $fh_name (qw( stdin passphrase command )) { | 
| 185 | 723 | 100 |  |  |  |  | 5234 | my $entry = $fhs{$fh_name} or next; | 
| 186 | 433 |  |  |  |  |  | 7259 | $entry->parent_is_source(1); | 
| 187 |  |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  |  | # Below is code derived heavily from | 
| 190 |  |  |  |  |  |  |  | # Marc Horowitz's IPC::Open3, a base Perl module | 
| 191 | 241 |  |  |  |  |  | 1622 | foreach my $fh_name ( keys %fhs ) { | 
| 192 | 919 |  |  |  |  |  | 18839 | my $entry = $fhs{$fh_name}; | 
| 193 |  |  |  |  |  |  |  |  | 
| 194 | 919 |  |  |  |  |  | 14967 | my $parent_end = $entry->parent_end(); | 
| 195 | 919 |  |  |  |  |  | 11331 | my $name_shows_dup = ( $parent_end =~ s/^[<>]&// ); | 
| 196 | 919 |  |  |  |  |  | 16828 | $entry->parent_end($parent_end); | 
| 197 |  |  |  |  |  |  |  |  | 
| 198 | 919 |  |  |  |  |  | 20610 | $entry->name_shows_dup($name_shows_dup); | 
| 199 |  |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  |  | $entry->direct( $name_shows_dup | 
| 201 |  |  |  |  |  |  |  | || $handles->options($fh_name)->{direct} | 
| 202 | 919 |  |  | 100 |  |  | 15287 | || 0 ); | 
| 203 |  |  |  |  |  |  |  | } | 
| 204 |  |  |  |  |  |  |  |  | 
| 205 | 241 |  |  |  |  |  | 7260 | foreach my $fh_name ( keys %fhs ) { | 
| 206 | 919 |  |  |  |  |  | 32839 | $fhs{$fh_name}->child_end( IO::Handle->new() ); | 
| 207 |  |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  |  |  | 
| 209 | 241 |  |  |  |  |  | 12158 | foreach my $fh_name ( keys %fhs ) { | 
| 210 | 919 |  |  |  |  |  | 33335 | my $entry = $fhs{$fh_name}; | 
| 211 | 919 | 100 |  |  |  |  | 18978 | next if $entry->direct(); | 
| 212 |  |  |  |  |  |  |  |  | 
| 213 | 639 |  |  |  |  |  | 6274 | my $reader_end; | 
| 214 |  |  |  |  |  |  |  | my $writer_end; | 
| 215 | 639 | 100 |  |  |  |  | 10988 | if ( $entry->parent_is_source() ) { | 
| 216 | 293 |  |  |  |  |  | 7213 | $reader_end = $entry->child_end(); | 
| 217 | 293 |  |  |  |  |  | 6714 | $writer_end = $entry->parent_end(); | 
| 218 |  |  |  |  |  |  |  | } | 
| 219 |  |  |  |  |  |  |  | else { | 
| 220 | 346 |  |  |  |  |  | 8968 | $reader_end = $entry->parent_end(); | 
| 221 | 346 |  |  |  |  |  | 11989 | $writer_end = $entry->child_end(); | 
| 222 |  |  |  |  |  |  |  | } | 
| 223 |  |  |  |  |  |  |  |  | 
| 224 | 639 |  |  |  |  |  | 17270 | pipe $reader_end, $writer_end; | 
| 225 |  |  |  |  |  |  |  | } | 
| 226 |  |  |  |  |  |  |  |  | 
| 227 | 241 |  |  |  |  |  | 514780 | my $pid = fork; | 
| 228 |  |  |  |  |  |  |  |  | 
| 229 | 241 | 50 |  |  |  |  | 17824 | die "fork failed: $ERRNO" unless defined $pid; | 
| 230 |  |  |  |  |  |  |  |  | 
| 231 | 241 | 100 |  |  |  |  | 8193 | if ( $pid == 0 )    # child | 
| 232 |  |  |  |  |  |  |  | { | 
| 233 |  |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  |  | # these are for safety later to help lessen autovifying, | 
| 235 |  |  |  |  |  |  |  | # speed things up, and make the code smaller | 
| 236 | 55 |  |  |  |  |  | 5139 | my $stdin  = $fhs{stdin}; | 
| 237 | 55 |  |  |  |  |  | 2372 | my $stdout = $fhs{stdout}; | 
| 238 | 55 |  |  |  |  |  | 1835 | my $stderr = $fhs{stderr}; | 
| 239 |  |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  |  | # Paul Walmsley says: | 
| 241 |  |  |  |  |  |  |  | # Perl 5.6's POSIX.pm has a typo in it that prevents us from | 
| 242 |  |  |  |  |  |  |  | # importing STDERR_FILENO. So we resort to requiring it. | 
| 243 | 55 |  |  |  |  |  | 129043 | require POSIX; | 
| 244 |  |  |  |  |  |  |  |  | 
| 245 | 55 |  |  |  |  |  | 539265 | my $standard_out | 
| 246 |  |  |  |  |  |  |  | = IO::Handle->new_from_fd( &POSIX::STDOUT_FILENO, 'w' ); | 
| 247 | 55 |  |  |  |  |  | 17239 | my $standard_in | 
| 248 |  |  |  |  |  |  |  | = IO::Handle->new_from_fd( &POSIX::STDIN_FILENO, 'r' ); | 
| 249 |  |  |  |  |  |  |  |  | 
| 250 |  |  |  |  |  |  |  | # Paul Walmsley says: | 
| 251 |  |  |  |  |  |  |  | # this mess is due to a typo in POSIX.pm on Perl 5.6 | 
| 252 | 55 |  |  |  |  |  | 5317 | my $stderr_fd = eval {&POSIX::STDERR_FILENO}; | 
|  | 55 |  |  |  |  |  | 456 |  | 
| 253 | 55 | 50 |  |  |  |  | 668 | $stderr_fd = 2 unless defined $stderr_fd; | 
| 254 | 55 |  |  |  |  |  | 578 | my $standard_err = IO::Handle->new_from_fd( $stderr_fd, 'w' ); | 
| 255 |  |  |  |  |  |  |  |  | 
| 256 |  |  |  |  |  |  |  | # If she wants to dup the kid's stderr onto her stdout I need to | 
| 257 |  |  |  |  |  |  |  | # save a copy of her stdout before I put something else there. | 
| 258 | 55 | 50 |  | 66 |  |  | 7324 | if (    $stdout->parent_end() ne $stderr->parent_end() | 
|  |  |  |  | 66 |  |  |  |  | 
| 259 |  |  |  |  |  |  |  | and $stderr->direct() | 
| 260 |  |  |  |  |  |  |  | and my_fileno( $stderr->parent_end() ) | 
| 261 |  |  |  |  |  |  |  | == my_fileno($standard_out) ) { | 
| 262 | 0 |  |  |  |  |  | 0 | my $tmp = IO::Handle->new(); | 
| 263 | 0 |  |  |  |  |  | 0 | open $tmp, '>&' . my_fileno( $stderr->parent_end() ); | 
| 264 | 0 |  |  |  |  |  | 0 | $stderr->parent_end($tmp); | 
| 265 |  |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  |  | 
| 267 | 55 | 100 |  |  |  |  | 9388 | if ( $stdin->direct() ) { | 
| 268 | 21 | 100 |  |  |  |  | 619 | open $standard_in, '<&' . my_fileno( $stdin->parent_end() ) | 
| 269 |  |  |  |  |  |  |  | unless my_fileno($standard_in) | 
| 270 |  |  |  |  |  |  |  | == my_fileno( $stdin->parent_end() ); | 
| 271 |  |  |  |  |  |  |  | } | 
| 272 |  |  |  |  |  |  |  | else { | 
| 273 | 34 |  |  |  |  |  | 1312 | close $stdin->parent_end(); | 
| 274 | 34 |  |  |  |  |  | 4830 | open $standard_in, '<&=' . my_fileno( $stdin->child_end() ); | 
| 275 |  |  |  |  |  |  |  | } | 
| 276 |  |  |  |  |  |  |  |  | 
| 277 | 55 | 100 |  |  |  |  | 5078 | if ( $stdout->direct() ) { | 
| 278 | 5 | 50 |  |  |  |  | 75 | open $standard_out, '>&' . my_fileno( $stdout->parent_end() ) | 
| 279 |  |  |  |  |  |  |  | unless my_fileno($standard_out) | 
| 280 |  |  |  |  |  |  |  | == my_fileno( $stdout->parent_end() ); | 
| 281 |  |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | else { | 
| 283 | 50 |  |  |  |  |  | 1658 | close $stdout->parent_end(); | 
| 284 | 50 |  |  |  |  |  | 4547 | open $standard_out, '>&=' . my_fileno( $stdout->child_end() ); | 
| 285 |  |  |  |  |  |  |  | } | 
| 286 |  |  |  |  |  |  |  |  | 
| 287 | 55 | 50 |  |  |  |  | 4192 | if ( $stdout->parent_end() ne $stderr->parent_end() ) { | 
| 288 |  |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  |  | # I have to use a fileno here because in this one case | 
| 290 |  |  |  |  |  |  |  | # I'm doing a dup but the filehandle might be a reference | 
| 291 |  |  |  |  |  |  |  | # (from the special case above). | 
| 292 | 55 | 100 |  |  |  |  | 2359 | if ( $stderr->direct() ) { | 
| 293 | 16 | 50 |  |  |  |  | 251 | open $standard_err, '>&' . my_fileno( $stderr->parent_end() ) | 
| 294 |  |  |  |  |  |  |  | unless my_fileno($standard_err) | 
| 295 |  |  |  |  |  |  |  | == my_fileno( $stderr->parent_end() ); | 
| 296 |  |  |  |  |  |  |  | } | 
| 297 |  |  |  |  |  |  |  | else { | 
| 298 | 39 |  |  |  |  |  | 1099 | close $stderr->parent_end(); | 
| 299 | 39 |  |  |  |  |  | 2912 | open $standard_err, '>&=' . my_fileno( $stderr->child_end() ); | 
| 300 |  |  |  |  |  |  |  | } | 
| 301 |  |  |  |  |  |  |  | } | 
| 302 |  |  |  |  |  |  |  | else { | 
| 303 | 0 | 0 |  |  |  |  | 0 | open $standard_err, '>&STDOUT' | 
| 304 |  |  |  |  |  |  |  | unless my_fileno($standard_err) == my_fileno($standard_out); | 
| 305 |  |  |  |  |  |  |  | } | 
| 306 |  |  |  |  |  |  |  |  | 
| 307 | 55 |  |  |  |  |  | 2891 | foreach my $fh_name ( keys %fhs ) { | 
| 308 | 209 |  |  |  |  |  | 9831 | my $entry = $fhs{$fh_name}; | 
| 309 | 209 | 100 |  |  |  |  | 4667 | next if $entry->is_std(); | 
| 310 |  |  |  |  |  |  |  |  | 
| 311 | 44 |  |  |  |  |  | 1163 | my $parent_end = $entry->parent_end(); | 
| 312 | 44 |  |  |  |  |  | 1233 | my $child_end  = $entry->child_end(); | 
| 313 |  |  |  |  |  |  |  |  | 
| 314 | 44 | 100 |  |  |  |  | 1215 | if ( $entry->direct() ) { | 
| 315 | 1 | 50 |  |  |  |  | 36 | if ( $entry->name_shows_dup() ) { | 
| 316 | 0 | 0 |  |  |  |  | 0 | my $open_prefix | 
| 317 |  |  |  |  |  |  |  | = $entry->parent_is_source() ? '<&' : '>&'; | 
| 318 | 0 |  |  |  |  |  | 0 | open $child_end, $open_prefix . $parent_end; | 
| 319 |  |  |  |  |  |  |  | } | 
| 320 |  |  |  |  |  |  |  | else { | 
| 321 | 1 |  |  |  |  |  | 13 | $child_end = $parent_end; | 
| 322 | 1 |  |  |  |  |  | 18 | $entry->child_end($child_end); | 
| 323 |  |  |  |  |  |  |  | } | 
| 324 |  |  |  |  |  |  |  | } | 
| 325 |  |  |  |  |  |  |  | else { | 
| 326 | 43 |  |  |  |  |  | 1188 | close $parent_end; | 
| 327 |  |  |  |  |  |  |  | } | 
| 328 |  |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  |  | # we want these fh's to stay open after the exec | 
| 330 | 44 |  |  |  |  |  | 3242 | fcntl $child_end, F_SETFD, 0; | 
| 331 |  |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  |  | # now set the options for the call to GnuPG | 
| 333 | 44 |  |  |  |  |  | 1735 | my $fileno = my_fileno($child_end); | 
| 334 | 44 |  |  |  |  |  | 363 | my $option = $fh_name . '_fd'; | 
| 335 | 44 |  |  |  |  |  | 2523 | $self->options->$option($fileno); | 
| 336 |  |  |  |  |  |  |  | } | 
| 337 |  |  |  |  |  |  |  |  | 
| 338 | 55 |  |  |  |  |  | 4971 | my @args = $self->options->get_args(); | 
| 339 |  |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  |  | # Get around a bug in 2.2, see also https://dev.gnupg.org/T4667 | 
| 341 |  |  |  |  |  |  |  | # this covers both --delete-secret-key(s) and --delete-secret-and-public-key(s) | 
| 342 | 55 | 50 |  | 100 |  |  | 3463 | if ( $self->version && $self->cmp_version( $self->version, 2.2 ) >= 0 && $commands[0] =~ /^--delete-secret-.*keys?$/ ) { | 
|  |  |  |  | 66 |  |  |  |  | 
| 343 | 0 |  |  |  |  |  | 0 | push @args, '--yes'; | 
| 344 |  |  |  |  |  |  |  | } | 
| 345 |  |  |  |  |  |  |  |  | 
| 346 | 55 | 50 |  |  |  |  | 376 | push @args, '--pinentry-mode', 'loopback' | 
| 347 |  |  |  |  |  |  |  | if $use_loopback_pinentry; | 
| 348 |  |  |  |  |  |  |  |  | 
| 349 | 55 |  |  |  |  |  | 3559 | my @command = ( | 
| 350 |  |  |  |  |  |  |  | $self->call(), @args, | 
| 351 |  |  |  |  |  |  |  | @commands,     @command_args | 
| 352 |  |  |  |  |  |  |  | ); | 
| 353 |  |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  |  | # On Unix, PATH is by default '.' and Perl >= v5.38 rejects '.' | 
| 355 |  |  |  |  |  |  |  | # being in the path when in taint mode. Set a path, if running | 
| 356 |  |  |  |  |  |  |  | # in taint mode whomever is calling us should be providing the | 
| 357 |  |  |  |  |  |  |  | # path to the gpg program to use. | 
| 358 | 55 | 100 |  |  |  |  | 3602 | local $ENV{PATH} = '/usr/bin' if tainted $ENV{PATH}; | 
| 359 | 55 | 0 |  |  |  |  | 0 | exec @command or die "exec() error: $ERRNO"; | 
| 360 |  |  |  |  |  |  |  | } | 
| 361 |  |  |  |  |  |  |  |  | 
| 362 |  |  |  |  |  |  |  | # parent | 
| 363 |  |  |  |  |  |  |  |  | 
| 364 |  |  |  |  |  |  |  | # close the child end of any pipes (non-direct stuff) | 
| 365 | 186 |  |  |  |  |  | 17132 | foreach my $fh_name ( keys %fhs ) { | 
| 366 | 710 |  |  |  |  |  | 52322 | my $entry = $fhs{$fh_name}; | 
| 367 | 710 | 100 |  |  |  |  | 57336 | close $entry->child_end() unless $entry->direct(); | 
| 368 |  |  |  |  |  |  |  | } | 
| 369 |  |  |  |  |  |  |  |  | 
| 370 | 186 |  |  |  |  |  | 10389 | foreach my $fh_name ( keys %fhs ) { | 
| 371 | 710 |  |  |  |  |  | 4451 | my $entry = $fhs{$fh_name}; | 
| 372 | 710 | 100 |  |  |  |  | 16020 | next unless $entry->parent_is_source(); | 
| 373 |  |  |  |  |  |  |  |  | 
| 374 | 335 |  |  |  |  |  | 10622 | my $parent_end = $entry->parent_end(); | 
| 375 |  |  |  |  |  |  |  |  | 
| 376 |  |  |  |  |  |  |  | # close any writing handles if they were a dup | 
| 377 |  |  |  |  |  |  |  | #any real reason for this?  It bombs if we're doing | 
| 378 |  |  |  |  |  |  |  | #the automagic >& stuff. | 
| 379 |  |  |  |  |  |  |  | #close $parent_end if $entry->direct(); | 
| 380 |  |  |  |  |  |  |  |  | 
| 381 |  |  |  |  |  |  |  | # unbuffer pipes | 
| 382 | 335 | 50 |  |  |  |  | 12907 | select( ( select($parent_end), $OUTPUT_AUTOFLUSH = 1 )[0] ) | 
| 383 |  |  |  |  |  |  |  | if $parent_end; | 
| 384 |  |  |  |  |  |  |  | } | 
| 385 |  |  |  |  |  |  |  |  | 
| 386 | 186 |  |  |  |  |  | 48225 | return $pid; | 
| 387 |  |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  |  |  | 
| 389 |  |  |  |  |  |  |  | sub my_fileno { | 
| 390 | 78 |  |  |  | 78 |  | 764 | no strict 'refs'; | 
|  | 78 |  |  |  |  |  | 258 |  | 
|  | 78 |  |  |  |  |  | 271338 |  | 
| 391 | 297 |  |  |  | 297 | 0 | 5108 | my ($fh) = @_; | 
| 392 | 297 | 50 |  |  |  |  | 1021 | croak "fh is undefined" unless defined $fh; | 
| 393 | 297 | 50 |  |  |  |  | 2840 | return $1 if $fh =~ /^=?(\d+)$/;    # is it a fd in itself? | 
| 394 | 297 |  |  |  |  |  | 1136 | my $fileno = fileno $fh; | 
| 395 | 297 | 50 |  |  |  |  | 798 | croak "error determining fileno for $fh: $ERRNO" unless defined $fileno; | 
| 396 | 297 |  |  |  |  |  | 7455 | return $fileno; | 
| 397 |  |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  |  | sub unescape_string { | 
| 401 | 19 |  |  |  | 19 | 0 | 48 | my($str) = splice(@_); | 
| 402 | 19 |  |  |  |  |  | 55 | $str =~ s/\\x(..)/chr(hex($1))/eg; | 
|  | 0 |  |  |  |  |  | 0 |  | 
| 403 | 19 |  |  |  |  |  | 365 | return $str; | 
| 404 |  |  |  |  |  |  |  | } | 
| 405 |  |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  |  | ################################################################### | 
| 407 |  |  |  |  |  |  |  |  | 
| 408 |  |  |  |  |  |  |  | sub get_public_keys ( $@ ) { | 
| 409 | 4 |  |  |  | 4 | 1 | 13344 | my ( $self, @key_ids ) = @_; | 
| 410 |  |  |  |  |  |  |  |  | 
| 411 | 4 |  |  |  |  |  | 124 | return $self->get_keys( | 
| 412 |  |  |  |  |  |  |  | commands     => ['--list-public-keys'], | 
| 413 |  |  |  |  |  |  |  | command_args => [@key_ids], | 
| 414 |  |  |  |  |  |  |  | ); | 
| 415 |  |  |  |  |  |  |  | } | 
| 416 |  |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  |  | sub get_secret_keys ( $@ ) { | 
| 418 | 2 |  |  |  | 2 | 1 | 2432 | my ( $self, @key_ids ) = @_; | 
| 419 |  |  |  |  |  |  |  |  | 
| 420 | 2 |  |  |  |  |  | 14 | return $self->get_keys( | 
| 421 |  |  |  |  |  |  |  | commands     => ['--list-secret-keys'], | 
| 422 |  |  |  |  |  |  |  | command_args => [@key_ids], | 
| 423 |  |  |  |  |  |  |  | ); | 
| 424 |  |  |  |  |  |  |  | } | 
| 425 |  |  |  |  |  |  |  |  | 
| 426 |  |  |  |  |  |  |  | sub get_public_keys_with_sigs ( $@ ) { | 
| 427 | 2 |  |  |  | 2 | 1 | 2570 | my ( $self, @key_ids ) = @_; | 
| 428 |  |  |  |  |  |  |  |  | 
| 429 | 2 |  |  |  |  |  | 14 | return $self->get_keys( | 
| 430 |  |  |  |  |  |  |  | commands     => ['--check-sigs'], | 
| 431 |  |  |  |  |  |  |  | command_args => [@key_ids], | 
| 432 |  |  |  |  |  |  |  | ); | 
| 433 |  |  |  |  |  |  |  | } | 
| 434 |  |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  |  | sub get_keys { | 
| 436 | 8 |  |  |  | 8 | 0 | 110 | my ( $self, %args ) = @_; | 
| 437 |  |  |  |  |  |  |  |  | 
| 438 | 8 |  |  |  |  |  | 328 | my $saved_options = $self->options(); | 
| 439 | 8 |  |  |  |  |  | 372 | my $new_options   = $self->options->copy(); | 
| 440 | 8 |  |  |  |  |  | 590 | $self->options($new_options); | 
| 441 | 8 |  |  |  |  |  | 1334 | $self->options->push_extra_args( | 
| 442 |  |  |  |  |  |  |  | '--with-colons', | 
| 443 |  |  |  |  |  |  |  | '--fixed-list-mode', | 
| 444 |  |  |  |  |  |  |  | '--with-fingerprint', | 
| 445 |  |  |  |  |  |  |  | '--with-fingerprint', | 
| 446 |  |  |  |  |  |  |  | '--with-key-data', | 
| 447 |  |  |  |  |  |  |  | ); | 
| 448 |  |  |  |  |  |  |  |  | 
| 449 | 8 |  |  |  |  |  | 1794 | my $stdin  = IO::Handle->new(); | 
| 450 | 8 |  |  |  |  |  | 278 | my $stdout = IO::Handle->new(); | 
| 451 |  |  |  |  |  |  |  |  | 
| 452 | 8 |  |  |  |  |  | 462 | my $handles = GnuPG::Handles->new( | 
| 453 |  |  |  |  |  |  |  | stdin  => $stdin, | 
| 454 |  |  |  |  |  |  |  | stdout => $stdout, | 
| 455 |  |  |  |  |  |  |  | ); | 
| 456 |  |  |  |  |  |  |  |  | 
| 457 | 8 |  |  |  |  |  | 454 | my $pid = $self->wrap_call( | 
| 458 |  |  |  |  |  |  |  | handles => $handles, | 
| 459 |  |  |  |  |  |  |  | %args, | 
| 460 |  |  |  |  |  |  |  | ); | 
| 461 |  |  |  |  |  |  |  |  | 
| 462 | 5 |  |  |  |  |  | 289 | my @returned_keys; | 
| 463 |  |  |  |  |  |  |  | my $current_primary_key; | 
| 464 | 5 |  |  |  |  |  | 0 | my $current_signed_item; | 
| 465 | 5 |  |  |  |  |  | 0 | my $current_key; | 
| 466 |  |  |  |  |  |  |  |  | 
| 467 | 5 |  |  |  |  |  | 5690 | require GnuPG::PublicKey; | 
| 468 | 5 |  |  |  |  |  | 2271 | require GnuPG::SecretKey; | 
| 469 | 5 |  |  |  |  |  | 1675 | require GnuPG::SubKey; | 
| 470 | 5 |  |  |  |  |  | 2461 | require GnuPG::Fingerprint; | 
| 471 | 5 |  |  |  |  |  | 2435 | require GnuPG::UserId; | 
| 472 | 5 |  |  |  |  |  | 2403 | require GnuPG::UserAttribute; | 
| 473 | 5 |  |  |  |  |  | 2412 | require GnuPG::Signature; | 
| 474 | 5 |  |  |  |  |  | 2396 | require GnuPG::Revoker; | 
| 475 |  |  |  |  |  |  |  |  | 
| 476 | 5 |  |  |  |  |  | 3000026 | while (<$stdout>) { | 
| 477 | 75 |  |  |  |  |  | 113463 | my $line = $_; | 
| 478 | 75 |  |  |  |  |  | 362 | chomp $line; | 
| 479 | 75 |  |  |  |  |  | 459 | my @fields = split ':', $line, -1; | 
| 480 | 75 | 50 |  |  |  |  | 270 | next unless @fields > 3; | 
| 481 |  |  |  |  |  |  |  |  | 
| 482 | 75 |  |  |  |  |  | 223 | my $record_type = $fields[0]; | 
| 483 |  |  |  |  |  |  |  |  | 
| 484 | 75 | 100 |  | 100 |  |  | 1086 | if ( $record_type eq 'pub' or $record_type eq 'sec' ) { | 
|  |  | 100 |  | 66 |  |  |  |  | 
|  |  | 100 |  | 100 |  |  |  |  | 
|  |  | 100 |  | 33 |  |  |  |  | 
|  |  | 50 |  |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  |  | 
|  |  | 100 |  |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  |  | 
| 485 | 5 | 50 |  |  |  |  | 81 | push @returned_keys, $current_primary_key | 
| 486 |  |  |  |  |  |  |  | if $current_primary_key; | 
| 487 |  |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  |  | my ( | 
| 489 | 5 |  |  |  |  |  | 113 | $user_id_validity, $key_length, $algo_num, $hex_key_id, | 
| 490 |  |  |  |  |  |  |  | $creation_date, $expiration_date, | 
| 491 |  |  |  |  |  |  |  | $local_id, $owner_trust, $user_id_string, | 
| 492 |  |  |  |  |  |  |  | $sigclass, #unused | 
| 493 |  |  |  |  |  |  |  | $usage_flags, | 
| 494 |  |  |  |  |  |  |  | ) = @fields[ 1 .. $#fields ]; | 
| 495 |  |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  |  | # --fixed-list-mode uses epoch time for creation and expiration date strings. | 
| 497 |  |  |  |  |  |  |  | # For backward compatibility, we convert them back using GMT; | 
| 498 | 5 |  |  |  |  |  | 37 | my $expiration_date_string; | 
| 499 | 5 | 50 |  |  |  |  | 61 | if ($expiration_date eq '') { | 
| 500 | 5 |  |  |  |  |  | 32 | $expiration_date = undef; | 
| 501 |  |  |  |  |  |  |  | } else { | 
| 502 | 0 |  |  |  |  |  | 0 | $expiration_date_string = $self->_downrez_date($expiration_date); | 
| 503 |  |  |  |  |  |  |  | } | 
| 504 | 5 |  |  |  |  |  | 193 | my $creation_date_string = $self->_downrez_date($creation_date); | 
| 505 |  |  |  |  |  |  |  |  | 
| 506 | 5 | 100 |  |  |  |  | 348 | $current_primary_key = $current_key | 
| 507 |  |  |  |  |  |  |  | = $record_type eq 'pub' | 
| 508 |  |  |  |  |  |  |  | ? GnuPG::PublicKey->new() | 
| 509 |  |  |  |  |  |  |  | : GnuPG::SecretKey->new(); | 
| 510 |  |  |  |  |  |  |  |  | 
| 511 | 5 |  |  |  |  |  | 141 | $current_primary_key->hash_init( | 
| 512 |  |  |  |  |  |  |  | length                 => $key_length, | 
| 513 |  |  |  |  |  |  |  | algo_num               => $algo_num, | 
| 514 |  |  |  |  |  |  |  | hex_id                 => $hex_key_id, | 
| 515 |  |  |  |  |  |  |  | local_id               => $local_id, | 
| 516 |  |  |  |  |  |  |  | owner_trust            => $owner_trust, | 
| 517 |  |  |  |  |  |  |  | creation_date          => $creation_date, | 
| 518 |  |  |  |  |  |  |  | expiration_date        => $expiration_date, | 
| 519 |  |  |  |  |  |  |  | creation_date_string   => $creation_date_string, | 
| 520 |  |  |  |  |  |  |  | expiration_date_string => $expiration_date_string, | 
| 521 |  |  |  |  |  |  |  | usage_flags            => $usage_flags, | 
| 522 |  |  |  |  |  |  |  | ); | 
| 523 |  |  |  |  |  |  |  |  | 
| 524 | 5 |  |  |  |  |  | 391 | $current_signed_item = $current_primary_key; | 
| 525 |  |  |  |  |  |  |  | } | 
| 526 |  |  |  |  |  |  |  | elsif ( $record_type eq 'fpr' ) { | 
| 527 | 10 |  |  |  |  |  | 64 | my $hex = $fields[9]; | 
| 528 | 10 |  |  |  |  |  | 205 | my $f = GnuPG::Fingerprint->new( as_hex_string => $hex ); | 
| 529 | 10 |  |  |  |  |  | 2132 | $current_key->fingerprint($f); | 
| 530 |  |  |  |  |  |  |  | } | 
| 531 |  |  |  |  |  |  |  | elsif ( $record_type eq 'sig' or | 
| 532 |  |  |  |  |  |  |  | $record_type eq 'rev' | 
| 533 |  |  |  |  |  |  |  | ) { | 
| 534 |  |  |  |  |  |  |  | my ( | 
| 535 | 9 |  |  |  |  |  | 41 | $validity, | 
| 536 |  |  |  |  |  |  |  | $algo_num,              $hex_key_id, | 
| 537 |  |  |  |  |  |  |  | $signature_date, | 
| 538 |  |  |  |  |  |  |  | $expiration_date, | 
| 539 |  |  |  |  |  |  |  | $user_id_string, | 
| 540 |  |  |  |  |  |  |  | $sig_type, | 
| 541 |  |  |  |  |  |  |  | ) = @fields[ 1, 3 .. 6, 9, 10 ]; | 
| 542 |  |  |  |  |  |  |  |  | 
| 543 | 9 |  |  |  |  |  | 15 | my $expiration_date_string; | 
| 544 | 9 | 50 |  |  |  |  | 17 | if ($expiration_date eq '') { | 
| 545 | 9 |  |  |  |  |  | 15 | $expiration_date = undef; | 
| 546 |  |  |  |  |  |  |  | } else { | 
| 547 | 0 |  |  |  |  |  | 0 | $expiration_date_string = $self->_downrez_date($expiration_date); | 
| 548 |  |  |  |  |  |  |  | } | 
| 549 | 9 |  |  |  |  |  | 32 | my $signature_date_string = $self->_downrez_date($signature_date); | 
| 550 |  |  |  |  |  |  |  |  | 
| 551 | 9 |  |  |  |  |  | 18 | my ($sig_class, $is_exportable); | 
| 552 | 9 | 50 |  |  |  |  | 46 | if ($sig_type =~ /^([[:xdigit:]]{2})([xl])$/ ) { | 
| 553 | 9 |  |  |  |  |  | 25 | $sig_class = hex($1); | 
| 554 | 9 |  |  |  |  |  | 23 | $is_exportable = ('x' eq $2); | 
| 555 |  |  |  |  |  |  |  | } | 
| 556 |  |  |  |  |  |  |  |  | 
| 557 | 9 |  |  |  |  |  | 32 | my $signature = GnuPG::Signature->new( | 
| 558 |  |  |  |  |  |  |  | validity       => $validity, | 
| 559 |  |  |  |  |  |  |  | algo_num       => $algo_num, | 
| 560 |  |  |  |  |  |  |  | hex_id         => $hex_key_id, | 
| 561 |  |  |  |  |  |  |  | date           => $signature_date, | 
| 562 |  |  |  |  |  |  |  | date_string    => $signature_date_string, | 
| 563 |  |  |  |  |  |  |  | expiration_date => $expiration_date, | 
| 564 |  |  |  |  |  |  |  | expiration_date_string => $expiration_date_string, | 
| 565 |  |  |  |  |  |  |  | user_id_string => unescape_string($user_id_string), | 
| 566 |  |  |  |  |  |  |  | sig_class      => $sig_class, | 
| 567 |  |  |  |  |  |  |  | is_exportable  => $is_exportable, | 
| 568 |  |  |  |  |  |  |  | ); | 
| 569 |  |  |  |  |  |  |  |  | 
| 570 | 9 | 50 |  | 100 |  |  | 7367 | if ( $current_signed_item->isa('GnuPG::Key') || | 
|  |  |  |  | 66 |  |  |  |  | 
|  |  |  |  | 33 |  |  |  |  | 
| 571 |  |  |  |  |  |  |  | $current_signed_item->isa('GnuPG::UserId') || | 
| 572 |  |  |  |  |  |  |  | $current_signed_item->isa('GnuPG::Revoker') || | 
| 573 |  |  |  |  |  |  |  | $current_signed_item->isa('GnuPG::UserAttribute')) { | 
| 574 | 9 | 50 |  |  |  |  | 26 | if ($record_type eq 'sig') { | 
|  |  | 0 |  |  |  |  |  |  | 
| 575 | 9 |  |  |  |  |  | 47 | $current_signed_item->push_signatures($signature); | 
| 576 |  |  |  |  |  |  |  | } elsif ($record_type eq 'rev') { | 
| 577 | 0 |  |  |  |  |  | 0 | $current_signed_item->push_revocations($signature); | 
| 578 |  |  |  |  |  |  |  | } | 
| 579 |  |  |  |  |  |  |  | } else { | 
| 580 | 0 |  |  |  |  |  | 0 | warn "do not know how to handle signature line: $line\n"; | 
| 581 |  |  |  |  |  |  |  | } | 
| 582 |  |  |  |  |  |  |  | } | 
| 583 |  |  |  |  |  |  |  | elsif ( $record_type eq 'uid' ) { | 
| 584 | 10 |  |  |  |  |  | 54 | my ( $validity, $user_id_string ) = @fields[ 1, 9 ]; | 
| 585 |  |  |  |  |  |  |  |  | 
| 586 | 10 |  |  |  |  |  | 46 | $current_signed_item = GnuPG::UserId->new( | 
| 587 |  |  |  |  |  |  |  | validity  => $validity, | 
| 588 |  |  |  |  |  |  |  | as_string => unescape_string($user_id_string), | 
| 589 |  |  |  |  |  |  |  | ); | 
| 590 |  |  |  |  |  |  |  |  | 
| 591 | 10 |  |  |  |  |  | 993 | $current_primary_key->push_user_ids($current_signed_item); | 
| 592 |  |  |  |  |  |  |  | } | 
| 593 |  |  |  |  |  |  |  | elsif ( $record_type eq 'uat' ) { | 
| 594 | 0 |  |  |  |  |  | 0 | my ( $validity, $subpacket ) = @fields[ 1, 9 ]; | 
| 595 |  |  |  |  |  |  |  |  | 
| 596 | 0 |  |  |  |  |  | 0 | my ( $subpacket_count, $subpacket_total_size ) = split(/ /,$subpacket); | 
| 597 |  |  |  |  |  |  |  |  | 
| 598 | 0 |  |  |  |  |  | 0 | $current_signed_item = GnuPG::UserAttribute->new( | 
| 599 |  |  |  |  |  |  |  | validity  => $validity, | 
| 600 |  |  |  |  |  |  |  | subpacket_count => $subpacket_count, | 
| 601 |  |  |  |  |  |  |  | subpacket_total_size => $subpacket_total_size, | 
| 602 |  |  |  |  |  |  |  | ); | 
| 603 |  |  |  |  |  |  |  |  | 
| 604 | 0 |  |  |  |  |  | 0 | $current_primary_key->push_user_attributes($current_signed_item); | 
| 605 |  |  |  |  |  |  |  | } | 
| 606 |  |  |  |  |  |  |  | elsif ( $record_type eq 'sub' or $record_type eq 'ssb' ) { | 
| 607 |  |  |  |  |  |  |  | my ( | 
| 608 | 5 |  |  |  |  |  | 74 | $validity, $key_length, $algo_num, $hex_id, | 
| 609 |  |  |  |  |  |  |  | $creation_date, $expiration_date, | 
| 610 |  |  |  |  |  |  |  | $local_id, | 
| 611 |  |  |  |  |  |  |  | $dummy0, $dummy1, $dummy2, #unused | 
| 612 |  |  |  |  |  |  |  | $usage_flags, | 
| 613 |  |  |  |  |  |  |  | ) = @fields[ 1 .. 11 ]; | 
| 614 |  |  |  |  |  |  |  |  | 
| 615 | 5 |  |  |  |  |  | 15 | my $expiration_date_string; | 
| 616 | 5 | 50 |  |  |  |  | 21 | if ($expiration_date eq '') { | 
| 617 | 5 |  |  |  |  |  | 18 | $expiration_date = undef; | 
| 618 |  |  |  |  |  |  |  | } else { | 
| 619 | 0 |  |  |  |  |  | 0 | $expiration_date_string = $self->_downrez_date($expiration_date); | 
| 620 |  |  |  |  |  |  |  | } | 
| 621 | 5 |  |  |  |  |  | 47 | my $creation_date_string = $self->_downrez_date($creation_date); | 
| 622 |  |  |  |  |  |  |  |  | 
| 623 | 5 |  |  |  |  |  | 87 | $current_signed_item = $current_key | 
| 624 |  |  |  |  |  |  |  | = GnuPG::SubKey->new( | 
| 625 |  |  |  |  |  |  |  | validity               => $validity, | 
| 626 |  |  |  |  |  |  |  | length                 => $key_length, | 
| 627 |  |  |  |  |  |  |  | algo_num               => $algo_num, | 
| 628 |  |  |  |  |  |  |  | hex_id                 => $hex_id, | 
| 629 |  |  |  |  |  |  |  | creation_date          => $creation_date, | 
| 630 |  |  |  |  |  |  |  | expiration_date        => $expiration_date, | 
| 631 |  |  |  |  |  |  |  | creation_date_string   => $creation_date_string, | 
| 632 |  |  |  |  |  |  |  | expiration_date_string => $expiration_date_string, | 
| 633 |  |  |  |  |  |  |  | local_id               => $local_id, | 
| 634 |  |  |  |  |  |  |  | usage_flags            => $usage_flags, | 
| 635 |  |  |  |  |  |  |  | ); | 
| 636 |  |  |  |  |  |  |  |  | 
| 637 | 5 |  |  |  |  |  | 392 | $current_primary_key->push_subkeys($current_signed_item); | 
| 638 |  |  |  |  |  |  |  | } | 
| 639 |  |  |  |  |  |  |  | elsif ($record_type eq 'rvk') { | 
| 640 | 4 |  |  |  |  |  | 39 | my ($algo_num, $fpr, $class) = @fields[ 3,9,10 ]; | 
| 641 | 4 |  |  |  |  |  | 73 | my $rvk = GnuPG::Revoker->new( | 
| 642 |  |  |  |  |  |  |  | fingerprint => GnuPG::Fingerprint->new( as_hex_string => $fpr ), | 
| 643 |  |  |  |  |  |  |  | algo_num    => ($algo_num + 0), | 
| 644 |  |  |  |  |  |  |  | class       => hex($class), | 
| 645 |  |  |  |  |  |  |  | ); | 
| 646 |  |  |  |  |  |  |  | # pushing to either primary key or subkey, to handle | 
| 647 |  |  |  |  |  |  |  | # designated revokers to the subkeys too: | 
| 648 | 4 |  |  |  |  |  | 149 | $current_key->push_revokers($rvk); | 
| 649 |  |  |  |  |  |  |  | # revokers should be bound to the key with signatures: | 
| 650 | 4 |  |  |  |  |  | 110 | $current_signed_item = $rvk; | 
| 651 |  |  |  |  |  |  |  | } | 
| 652 |  |  |  |  |  |  |  | elsif ($record_type eq 'pkd') { | 
| 653 | 28 |  |  |  |  |  | 87 | my ($pos, $size, $data) = @fields[ 1,2,3 ]; | 
| 654 | 28 |  |  |  |  |  | 277 | $current_key->pubkey_data->[$pos+0] = Math::BigInt->from_hex('0x'.$data); | 
| 655 |  |  |  |  |  |  |  | } | 
| 656 |  |  |  |  |  |  |  | elsif ( $record_type ne 'tru' and $record_type ne 'grp' ) { | 
| 657 | 0 |  |  |  |  |  | 0 | warn "unknown record type $record_type"; | 
| 658 |  |  |  |  |  |  |  | } | 
| 659 |  |  |  |  |  |  |  | } | 
| 660 |  |  |  |  |  |  |  |  | 
| 661 | 5 |  |  |  |  |  | 13708 | waitpid $pid, 0; | 
| 662 |  |  |  |  |  |  |  |  | 
| 663 | 5 | 50 |  |  |  |  | 63 | push @returned_keys, $current_primary_key | 
| 664 |  |  |  |  |  |  |  | if $current_primary_key; | 
| 665 |  |  |  |  |  |  |  |  | 
| 666 | 5 |  |  |  |  |  | 202 | $self->options($saved_options); | 
| 667 |  |  |  |  |  |  |  |  | 
| 668 | 5 |  |  |  |  |  | 1129 | return @returned_keys; | 
| 669 |  |  |  |  |  |  |  | } | 
| 670 |  |  |  |  |  |  |  |  | 
| 671 |  |  |  |  |  |  |  | sub _downrez_date { | 
| 672 | 19 |  |  |  | 19 |  | 86 | my $self = shift; | 
| 673 | 19 |  |  |  |  |  | 57 | my $date = shift; | 
| 674 | 19 | 50 |  |  |  |  | 252 | if ($date =~  /^\d+$/) { | 
| 675 | 19 |  |  |  |  |  | 571 | my ($year,$month,$day) = (gmtime($date))[5,4,3]; | 
| 676 | 19 |  |  |  |  |  | 95 | $year += 1900; | 
| 677 | 19 |  |  |  |  |  | 44 | $month += 1; | 
| 678 | 19 |  |  |  |  |  | 212 | return    sprintf('%04d-%02d-%02d',   $year, $month, $day); | 
| 679 |  |  |  |  |  |  |  | } | 
| 680 | 0 |  |  |  |  |  | 0 | return $date; | 
| 681 |  |  |  |  |  |  |  | } | 
| 682 |  |  |  |  |  |  |  |  | 
| 683 |  |  |  |  |  |  |  |  | 
| 684 |  |  |  |  |  |  |  | ################################################################ | 
| 685 |  |  |  |  |  |  |  |  | 
| 686 |  |  |  |  |  |  |  | sub list_public_keys { | 
| 687 | 9 |  |  |  | 9 | 1 | 13853 | my ( $self, %args ) = @_; | 
| 688 | 9 |  |  |  |  |  | 228 | return $self->wrap_call( | 
| 689 |  |  |  |  |  |  |  | %args, | 
| 690 |  |  |  |  |  |  |  | commands => ['--list-public-keys'], | 
| 691 |  |  |  |  |  |  |  | ); | 
| 692 |  |  |  |  |  |  |  | } | 
| 693 |  |  |  |  |  |  |  |  | 
| 694 |  |  |  |  |  |  |  | sub list_sigs { | 
| 695 | 9 |  |  |  | 9 | 1 | 12661 | my ( $self, %args ) = @_; | 
| 696 | 9 |  |  |  |  |  | 136 | return $self->wrap_call( | 
| 697 |  |  |  |  |  |  |  | %args, | 
| 698 |  |  |  |  |  |  |  | commands => ['--list-sigs'], | 
| 699 |  |  |  |  |  |  |  | ); | 
| 700 |  |  |  |  |  |  |  | } | 
| 701 |  |  |  |  |  |  |  |  | 
| 702 |  |  |  |  |  |  |  | sub list_secret_keys { | 
| 703 | 9 |  |  |  | 9 | 1 | 12222 | my ( $self, %args ) = @_; | 
| 704 | 9 |  |  |  |  |  | 134 | return $self->wrap_call( | 
| 705 |  |  |  |  |  |  |  | %args, | 
| 706 |  |  |  |  |  |  |  | commands => ['--list-secret-keys'], | 
| 707 |  |  |  |  |  |  |  | ); | 
| 708 |  |  |  |  |  |  |  | } | 
| 709 |  |  |  |  |  |  |  |  | 
| 710 |  |  |  |  |  |  |  | sub encrypt( $% ) { | 
| 711 | 10 |  |  |  | 10 | 1 | 1004 | my ( $self, %args ) = @_; | 
| 712 | 10 |  |  |  |  |  | 749 | return $self->wrap_call( | 
| 713 |  |  |  |  |  |  |  | %args, | 
| 714 |  |  |  |  |  |  |  | commands => ['--encrypt'] | 
| 715 |  |  |  |  |  |  |  | ); | 
| 716 |  |  |  |  |  |  |  | } | 
| 717 |  |  |  |  |  |  |  |  | 
| 718 |  |  |  |  |  |  |  | sub encrypt_symmetrically( $% ) { | 
| 719 | 5 |  |  |  | 5 | 1 | 3802 | my ( $self, %args ) = @_; | 
| 720 |  |  |  |  |  |  |  | # Strip the homedir and put it back after encrypting; | 
| 721 | 5 |  |  |  |  |  | 145 | my $homedir = $self->options->homedir; | 
| 722 | 5 | 50 |  |  |  |  | 356 | $self->options->clear_homedir | 
| 723 |  |  |  |  |  |  |  | unless $self->cmp_version($self->version, '2.2') >= 0; | 
| 724 | 5 |  |  |  |  |  | 294 | my $pid = $self->wrap_call( | 
| 725 |  |  |  |  |  |  |  | %args, | 
| 726 |  |  |  |  |  |  |  | commands => ['--symmetric'] | 
| 727 |  |  |  |  |  |  |  | ); | 
| 728 | 3 | 50 |  |  |  |  | 216 | $self->options->homedir($homedir) | 
| 729 |  |  |  |  |  |  |  | unless $self->cmp_version($self->version, '2.2') >= 0; | 
| 730 | 3 |  |  |  |  |  | 636 | return $pid; | 
| 731 |  |  |  |  |  |  |  | } | 
| 732 |  |  |  |  |  |  |  |  | 
| 733 |  |  |  |  |  |  |  | sub sign( $% ) { | 
| 734 | 14 |  |  |  | 14 | 1 | 13493 | my ( $self, %args ) = @_; | 
| 735 | 14 |  |  |  |  |  | 179 | return $self->wrap_call( | 
| 736 |  |  |  |  |  |  |  | %args, | 
| 737 |  |  |  |  |  |  |  | commands => ['--sign'] | 
| 738 |  |  |  |  |  |  |  | ); | 
| 739 |  |  |  |  |  |  |  | } | 
| 740 |  |  |  |  |  |  |  |  | 
| 741 |  |  |  |  |  |  |  | sub clearsign( $% ) { | 
| 742 | 5 |  |  |  | 5 | 1 | 3406 | my ( $self, %args ) = @_; | 
| 743 | 5 |  |  |  |  |  | 55 | return $self->wrap_call( | 
| 744 |  |  |  |  |  |  |  | %args,, | 
| 745 |  |  |  |  |  |  |  | commands => ['--clearsign'] | 
| 746 |  |  |  |  |  |  |  | ); | 
| 747 |  |  |  |  |  |  |  | } | 
| 748 |  |  |  |  |  |  |  |  | 
| 749 |  |  |  |  |  |  |  | sub detach_sign( $% ) { | 
| 750 | 5 |  |  |  | 5 | 1 | 3828 | my ( $self, %args ) = @_; | 
| 751 | 5 |  |  |  |  |  | 64 | return $self->wrap_call( | 
| 752 |  |  |  |  |  |  |  | %args, | 
| 753 |  |  |  |  |  |  |  | commands => ['--detach-sign'] | 
| 754 |  |  |  |  |  |  |  | ); | 
| 755 |  |  |  |  |  |  |  | } | 
| 756 |  |  |  |  |  |  |  |  | 
| 757 |  |  |  |  |  |  |  | sub sign_and_encrypt( $% ) { | 
| 758 | 5 |  |  |  | 5 | 1 | 358 | my ( $self, %args ) = @_; | 
| 759 | 5 |  |  |  |  |  | 64 | return $self->wrap_call( | 
| 760 |  |  |  |  |  |  |  | %args, | 
| 761 |  |  |  |  |  |  |  | commands => [ | 
| 762 |  |  |  |  |  |  |  | '--sign', | 
| 763 |  |  |  |  |  |  |  | '--encrypt' | 
| 764 |  |  |  |  |  |  |  | ] | 
| 765 |  |  |  |  |  |  |  | ); | 
| 766 |  |  |  |  |  |  |  | } | 
| 767 |  |  |  |  |  |  |  |  | 
| 768 |  |  |  |  |  |  |  | sub decrypt( $% ) { | 
| 769 | 5 |  |  |  | 5 | 1 | 3345 | my ( $self, %args ) = @_; | 
| 770 | 5 |  |  |  |  |  | 79 | return $self->wrap_call( | 
| 771 |  |  |  |  |  |  |  | %args, | 
| 772 |  |  |  |  |  |  |  | commands => ['--decrypt'] | 
| 773 |  |  |  |  |  |  |  | ); | 
| 774 |  |  |  |  |  |  |  | } | 
| 775 |  |  |  |  |  |  |  |  | 
| 776 |  |  |  |  |  |  |  | sub verify( $% ) { | 
| 777 | 5 |  |  |  | 5 | 1 | 3421 | my ( $self, %args ) = @_; | 
| 778 | 5 |  |  |  |  |  | 49 | return $self->wrap_call( | 
| 779 |  |  |  |  |  |  |  | %args, | 
| 780 |  |  |  |  |  |  |  | commands => ['--verify'] | 
| 781 |  |  |  |  |  |  |  | ); | 
| 782 |  |  |  |  |  |  |  | } | 
| 783 |  |  |  |  |  |  |  |  | 
| 784 |  |  |  |  |  |  |  | sub import_keys( $% ) { | 
| 785 | 7 |  |  |  | 7 | 1 | 5807 | my ( $self, %args ) = @_; | 
| 786 | 7 |  |  |  |  |  | 62 | return $self->wrap_call( | 
| 787 |  |  |  |  |  |  |  | %args, | 
| 788 |  |  |  |  |  |  |  | commands => ['--import'] | 
| 789 |  |  |  |  |  |  |  | ); | 
| 790 |  |  |  |  |  |  |  | } | 
| 791 |  |  |  |  |  |  |  |  | 
| 792 |  |  |  |  |  |  |  | sub export_keys( $% ) { | 
| 793 | 5 |  |  |  | 5 | 1 | 3802 | my ( $self, %args ) = @_; | 
| 794 | 5 |  |  |  |  |  | 66 | return $self->wrap_call( | 
| 795 |  |  |  |  |  |  |  | %args, | 
| 796 |  |  |  |  |  |  |  | commands => ['--export'] | 
| 797 |  |  |  |  |  |  |  | ); | 
| 798 |  |  |  |  |  |  |  | } | 
| 799 |  |  |  |  |  |  |  |  | 
| 800 |  |  |  |  |  |  |  | sub recv_keys( $% ) { | 
| 801 | 0 |  |  |  | 0 | 1 | 0 | my ( $self, %args ) = @_; | 
| 802 | 0 |  |  |  |  |  | 0 | return $self->wrap_call( | 
| 803 |  |  |  |  |  |  |  | %args, | 
| 804 |  |  |  |  |  |  |  | commands => ['--recv-keys'] | 
| 805 |  |  |  |  |  |  |  | ); | 
| 806 |  |  |  |  |  |  |  | } | 
| 807 |  |  |  |  |  |  |  |  | 
| 808 |  |  |  |  |  |  |  | sub send_keys( $% ) { | 
| 809 | 0 |  |  |  | 0 | 1 | 0 | my ( $self, %args ) = @_; | 
| 810 | 0 |  |  |  |  |  | 0 | return $self->wrap_call( | 
| 811 |  |  |  |  |  |  |  | %args, | 
| 812 |  |  |  |  |  |  |  | commands => ['--send-keys'] | 
| 813 |  |  |  |  |  |  |  | ); | 
| 814 |  |  |  |  |  |  |  | } | 
| 815 |  |  |  |  |  |  |  |  | 
| 816 |  |  |  |  |  |  |  | sub search_keys( $% ) { | 
| 817 | 0 |  |  |  | 0 | 1 | 0 | my ( $self, %args ) = @_; | 
| 818 | 0 |  |  |  |  |  | 0 | return $self->wrap_call( | 
| 819 |  |  |  |  |  |  |  | %args, | 
| 820 |  |  |  |  |  |  |  | commands => ['--search-keys'] | 
| 821 |  |  |  |  |  |  |  | ); | 
| 822 |  |  |  |  |  |  |  | } | 
| 823 |  |  |  |  |  |  |  |  | 
| 824 |  |  |  |  |  |  |  | sub _version { | 
| 825 | 120 |  |  |  | 120 |  | 480 | my ( $self ) = @_; | 
| 826 |  |  |  |  |  |  |  |  | 
| 827 | 120 |  |  |  |  |  | 1899 | my $out = IO::Handle->new; | 
| 828 | 120 |  |  |  |  |  | 8818 | my $handles = GnuPG::Handles->new( stdout => $out ); | 
| 829 | 120 |  |  |  |  |  | 6965 | my $pid = $self->wrap_call( commands => [ '--no-options', '--version' ], handles => $handles ); | 
| 830 | 108 |  |  |  |  |  | 8961 | my $line = $out->getline; | 
| 831 | 108 |  |  |  |  |  | 65238124 | $line =~ /(\d+\.\d+\.\d+)/; | 
| 832 |  |  |  |  |  |  |  |  | 
| 833 | 108 |  |  |  |  |  | 2026 | my $version = $1; | 
| 834 | 108 | 50 |  | 33 |  |  | 2857 | unless ($self->cmp_version($version, '2.2') >= 0 or | 
|  |  |  |  | 66 |  |  |  |  | 
| 835 |  |  |  |  |  |  |  | ($self->cmp_version($version, '1.4') >= 0 and $self->cmp_version($version, '1.5') < 0 )) { | 
| 836 | 0 |  |  |  |  |  | 0 | croak "GnuPG Version 1.4 or 2.2+ required"; | 
| 837 |  |  |  |  |  |  |  | } | 
| 838 | 108 |  |  |  |  |  | 11602 | waitpid $pid, 0; | 
| 839 |  |  |  |  |  |  |  |  | 
| 840 | 108 |  |  |  |  |  | 27823 | return $version; | 
| 841 |  |  |  |  |  |  |  | } | 
| 842 |  |  |  |  |  |  |  |  | 
| 843 |  |  |  |  |  |  |  | sub cmp_version($$) { | 
| 844 | 506 |  |  |  | 506 | 0 | 2709988 | my ( $self, $a, $b ) = (@_); | 
| 845 | 506 |  |  |  |  |  | 5180 | my @a = split '\.', $a; | 
| 846 | 506 |  |  |  |  |  | 15998 | my @b = split '\.', $b; | 
| 847 | 506 | 50 |  |  |  |  | 4295 | @a > @b | 
| 848 |  |  |  |  |  |  |  | ? push @b, (0) x (@a-@b) | 
| 849 |  |  |  |  |  |  |  | : push @a, (0) x (@b-@a); | 
| 850 | 506 |  |  |  |  |  | 3157 | for ( my $i = 0; $i < @a; $i++ ) { | 
| 851 | 821 | 100 |  |  |  |  | 10769 | return $a[$i] <=> $b[$i] if $a[$i] <=> $b[$i]; | 
| 852 |  |  |  |  |  |  |  | } | 
| 853 | 0 |  |  |  |  |  | 0 | return 0; | 
| 854 |  |  |  |  |  |  |  | } | 
| 855 |  |  |  |  |  |  |  |  | 
| 856 |  |  |  |  |  |  |  | sub test_default_key_passphrase() { | 
| 857 | 4 |  |  |  | 4 | 1 | 5612 | my ($self) = @_; | 
| 858 |  |  |  |  |  |  |  |  | 
| 859 |  |  |  |  |  |  |  | # We can't do something like let the user pass | 
| 860 |  |  |  |  |  |  |  | # in a passphrase handle because we don't exist | 
| 861 |  |  |  |  |  |  |  | # anymore after the user runs off with the | 
| 862 |  |  |  |  |  |  |  | # attachments | 
| 863 | 4 | 50 |  |  |  |  | 112 | croak 'No passphrase defined to test!' | 
| 864 |  |  |  |  |  |  |  | unless defined $self->passphrase(); | 
| 865 |  |  |  |  |  |  |  |  | 
| 866 | 4 |  |  |  |  |  | 168 | my $stdin  = IO::Handle->new(); | 
| 867 | 4 |  |  |  |  |  | 88 | my $stdout = IO::Handle->new(); | 
| 868 | 4 |  |  |  |  |  | 80 | my $stderr = IO::Handle->new(); | 
| 869 | 4 |  |  |  |  |  | 144 | my $status = IO::Handle->new(); | 
| 870 |  |  |  |  |  |  |  |  | 
| 871 | 4 |  |  |  |  |  | 176 | my $handles = GnuPG::Handles->new( | 
| 872 |  |  |  |  |  |  |  | stdin  => $stdin, | 
| 873 |  |  |  |  |  |  |  | stdout => $stdout, | 
| 874 |  |  |  |  |  |  |  | stderr => $stderr, | 
| 875 |  |  |  |  |  |  |  | status => $status | 
| 876 |  |  |  |  |  |  |  | ); | 
| 877 |  |  |  |  |  |  |  |  | 
| 878 |  |  |  |  |  |  |  | # save this setting since we need to be in non-interactive mode | 
| 879 | 4 |  |  |  |  |  | 352 | my $saved_meta_interactive_option = $self->options->meta_interactive(); | 
| 880 | 4 |  |  |  |  |  | 260 | $self->options->clear_meta_interactive(); | 
| 881 |  |  |  |  |  |  |  |  | 
| 882 | 4 |  |  |  |  |  | 172 | my $pid = $self->sign( handles => $handles ); | 
| 883 |  |  |  |  |  |  |  |  | 
| 884 | 3 |  |  |  |  |  | 237 | close $stdin; | 
| 885 |  |  |  |  |  |  |  |  | 
| 886 |  |  |  |  |  |  |  | # restore this setting to its original setting | 
| 887 | 3 |  |  |  |  |  | 219 | $self->options->meta_interactive($saved_meta_interactive_option); | 
| 888 |  |  |  |  |  |  |  |  | 
| 889 |  |  |  |  |  |  |  | # all we realy want to check is the status fh | 
| 890 | 3 |  |  |  |  |  | 1940715 | while (<$status>) { | 
| 891 | 9 | 100 |  |  |  |  | 7656 | if (/^\[GNUPG:\]\s*(GOOD_PASSPHRASE|SIG_CREATED)/) { | 
| 892 | 3 |  |  |  |  |  | 11166 | waitpid $pid, 0; | 
| 893 | 3 |  |  |  |  |  | 900 | return 1; | 
| 894 |  |  |  |  |  |  |  | } | 
| 895 |  |  |  |  |  |  |  | } | 
| 896 |  |  |  |  |  |  |  |  | 
| 897 |  |  |  |  |  |  |  | # If we didn't catch the regexp above, we'll assume | 
| 898 |  |  |  |  |  |  |  | # that the passphrase was incorrect | 
| 899 | 0 |  |  |  |  |  |  | waitpid $pid, 0; | 
| 900 | 0 |  |  |  |  |  |  | return 0; | 
| 901 |  |  |  |  |  |  |  | } | 
| 902 |  |  |  |  |  |  |  |  | 
| 903 |  |  |  |  |  |  |  | 1; | 
| 904 |  |  |  |  |  |  |  |  | 
| 905 |  |  |  |  |  |  |  | ############################################################## | 
| 906 |  |  |  |  |  |  |  |  | 
| 907 |  |  |  |  |  |  |  | =head1 NAME | 
| 908 |  |  |  |  |  |  |  |  | 
| 909 |  |  |  |  |  |  |  | GnuPG::Interface - Perl interface to GnuPG | 
| 910 |  |  |  |  |  |  |  |  | 
| 911 |  |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 912 |  |  |  |  |  |  |  |  | 
| 913 |  |  |  |  |  |  |  | # A simple example | 
| 914 |  |  |  |  |  |  |  | use IO::Handle; | 
| 915 |  |  |  |  |  |  |  | use GnuPG::Interface; | 
| 916 |  |  |  |  |  |  |  |  | 
| 917 |  |  |  |  |  |  |  | # setting up the situation | 
| 918 |  |  |  |  |  |  |  | my $gnupg = GnuPG::Interface->new(); | 
| 919 |  |  |  |  |  |  |  | $gnupg->options->hash_init( armor   => 1, | 
| 920 |  |  |  |  |  |  |  | homedir => '/home/foobar' ); | 
| 921 |  |  |  |  |  |  |  |  | 
| 922 |  |  |  |  |  |  |  | # Note you can set the recipients even if you aren't encrypting! | 
| 923 |  |  |  |  |  |  |  | $gnupg->options->push_recipients( 'ftobin@cpan.org' ); | 
| 924 |  |  |  |  |  |  |  | $gnupg->options->meta_interactive( 0 ); | 
| 925 |  |  |  |  |  |  |  |  | 
| 926 |  |  |  |  |  |  |  | # how we create some handles to interact with GnuPG | 
| 927 |  |  |  |  |  |  |  | my $input   = IO::Handle->new(); | 
| 928 |  |  |  |  |  |  |  | my $output  = IO::Handle->new(); | 
| 929 |  |  |  |  |  |  |  | my $handles = GnuPG::Handles->new( stdin  => $input, | 
| 930 |  |  |  |  |  |  |  | stdout => $output ); | 
| 931 |  |  |  |  |  |  |  |  | 
| 932 |  |  |  |  |  |  |  | # Now we'll go about encrypting with the options already set | 
| 933 |  |  |  |  |  |  |  | my @plaintext = ( 'foobar' ); | 
| 934 |  |  |  |  |  |  |  | my $pid = $gnupg->encrypt( handles => $handles ); | 
| 935 |  |  |  |  |  |  |  |  | 
| 936 |  |  |  |  |  |  |  | # Now we write to the input of GnuPG | 
| 937 |  |  |  |  |  |  |  | print $input @plaintext; | 
| 938 |  |  |  |  |  |  |  | close $input; | 
| 939 |  |  |  |  |  |  |  |  | 
| 940 |  |  |  |  |  |  |  | # now we read the output | 
| 941 |  |  |  |  |  |  |  | my @ciphertext = <$output>; | 
| 942 |  |  |  |  |  |  |  | close $output; | 
| 943 |  |  |  |  |  |  |  |  | 
| 944 |  |  |  |  |  |  |  | waitpid $pid, 0; | 
| 945 |  |  |  |  |  |  |  |  | 
| 946 |  |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 947 |  |  |  |  |  |  |  |  | 
| 948 |  |  |  |  |  |  |  | GnuPG::Interface and its associated modules are designed to | 
| 949 |  |  |  |  |  |  |  | provide an object-oriented method for interacting with GnuPG, | 
| 950 |  |  |  |  |  |  |  | being able to perform functions such as but not limited | 
| 951 |  |  |  |  |  |  |  | to encrypting, signing, | 
| 952 |  |  |  |  |  |  |  | decryption, verification, and key-listing parsing. | 
| 953 |  |  |  |  |  |  |  |  | 
| 954 |  |  |  |  |  |  |  | =head2 How Data Member Accessor Methods are Created | 
| 955 |  |  |  |  |  |  |  |  | 
| 956 |  |  |  |  |  |  |  | Each module in the GnuPG::Interface bundle relies | 
| 957 |  |  |  |  |  |  |  | on Moo to generate the get/set methods | 
| 958 |  |  |  |  |  |  |  | used to set the object's data members. | 
| 959 |  |  |  |  |  |  |  | I<This is very important to realize.>  This means that | 
| 960 |  |  |  |  |  |  |  | any data member which is a list has special | 
| 961 |  |  |  |  |  |  |  | methods assigned to it for pushing, popping, and | 
| 962 |  |  |  |  |  |  |  | clearing the list. | 
| 963 |  |  |  |  |  |  |  |  | 
| 964 |  |  |  |  |  |  |  | =head2 Understanding Bidirectional Communication | 
| 965 |  |  |  |  |  |  |  |  | 
| 966 |  |  |  |  |  |  |  | It is also imperative to realize that this package | 
| 967 |  |  |  |  |  |  |  | uses interprocess communication methods similar to | 
| 968 |  |  |  |  |  |  |  | those used in L<IPC::Open3> | 
| 969 |  |  |  |  |  |  |  | and L<perlipc/"Bidirectional Communication with Another Process">, | 
| 970 |  |  |  |  |  |  |  | and that users of this package | 
| 971 |  |  |  |  |  |  |  | need to understand how to use this method because this package | 
| 972 |  |  |  |  |  |  |  | does not abstract these methods for the user greatly. | 
| 973 |  |  |  |  |  |  |  | This package is not designed | 
| 974 |  |  |  |  |  |  |  | to abstract this away entirely (partly for security purposes), but rather | 
| 975 |  |  |  |  |  |  |  | to simply help create 'proper', clean calls to GnuPG, and to implement | 
| 976 |  |  |  |  |  |  |  | key-listing parsing. | 
| 977 |  |  |  |  |  |  |  | Please see L<perlipc/"Bidirectional Communication with Another Process"> | 
| 978 |  |  |  |  |  |  |  | to learn how to deal with these methods. | 
| 979 |  |  |  |  |  |  |  |  | 
| 980 |  |  |  |  |  |  |  | Using this package to do message processing generally | 
| 981 |  |  |  |  |  |  |  | invovlves creating a GnuPG::Interface object, creating | 
| 982 |  |  |  |  |  |  |  | a GnuPG::Handles object, | 
| 983 |  |  |  |  |  |  |  | setting some options in its B<options> data member, | 
| 984 |  |  |  |  |  |  |  | and then calling a method which invokes GnuPG, such as | 
| 985 |  |  |  |  |  |  |  | B<clearsign>.  One then interacts with with the handles | 
| 986 |  |  |  |  |  |  |  | appropriately, as described in | 
| 987 |  |  |  |  |  |  |  | L<perlipc/"Bidirectional Communication with Another Process">. | 
| 988 |  |  |  |  |  |  |  |  | 
| 989 |  |  |  |  |  |  |  | =head1 GnuPG Versions | 
| 990 |  |  |  |  |  |  |  |  | 
| 991 |  |  |  |  |  |  |  | As of this version of GnuPG::Interface, there are two supported | 
| 992 |  |  |  |  |  |  |  | versions of GnuPG: 1.4.x and 2.2.x. The | 
| 993 |  |  |  |  |  |  |  | L<GnuPG download page|https://gnupg.org/download/index.html> has | 
| 994 |  |  |  |  |  |  |  | updated information on the currently supported versions. | 
| 995 |  |  |  |  |  |  |  |  | 
| 996 |  |  |  |  |  |  |  | GnuPG released 2.0 and 2.1 versions in the past and some packaging | 
| 997 |  |  |  |  |  |  |  | systems may still provide these if you install the default C<gpg>, | 
| 998 |  |  |  |  |  |  |  | C<gnupg>, C<gnupg2>, etc. packages. This modules supports only | 
| 999 |  |  |  |  |  |  |  | version 2.2.x, so you may need to find additional package | 
| 1000 |  |  |  |  |  |  |  | repositories or build from source to get the updated version. | 
| 1001 |  |  |  |  |  |  |  |  | 
| 1002 |  |  |  |  |  |  |  | =head1 OBJECT METHODS | 
| 1003 |  |  |  |  |  |  |  |  | 
| 1004 |  |  |  |  |  |  |  | =head2 Initialization Methods | 
| 1005 |  |  |  |  |  |  |  |  | 
| 1006 |  |  |  |  |  |  |  | =over 4 | 
| 1007 |  |  |  |  |  |  |  |  | 
| 1008 |  |  |  |  |  |  |  | =item new( I<%initialization_args> ) | 
| 1009 |  |  |  |  |  |  |  |  | 
| 1010 |  |  |  |  |  |  |  | This methods creates a new object.  The optional arguments are | 
| 1011 |  |  |  |  |  |  |  | initialization of data members. | 
| 1012 |  |  |  |  |  |  |  |  | 
| 1013 |  |  |  |  |  |  |  | =item hash_init( I<%args> ). | 
| 1014 |  |  |  |  |  |  |  |  | 
| 1015 |  |  |  |  |  |  |  |  | 
| 1016 |  |  |  |  |  |  |  | =back | 
| 1017 |  |  |  |  |  |  |  |  | 
| 1018 |  |  |  |  |  |  |  | =head2 Object Methods which use a GnuPG::Handles Object | 
| 1019 |  |  |  |  |  |  |  |  | 
| 1020 |  |  |  |  |  |  |  | =over 4 | 
| 1021 |  |  |  |  |  |  |  |  | 
| 1022 |  |  |  |  |  |  |  | =item list_public_keys( % ) | 
| 1023 |  |  |  |  |  |  |  |  | 
| 1024 |  |  |  |  |  |  |  | =item list_sigs( % ) | 
| 1025 |  |  |  |  |  |  |  |  | 
| 1026 |  |  |  |  |  |  |  | =item list_secret_keys( % ) | 
| 1027 |  |  |  |  |  |  |  |  | 
| 1028 |  |  |  |  |  |  |  | =item encrypt( % ) | 
| 1029 |  |  |  |  |  |  |  |  | 
| 1030 |  |  |  |  |  |  |  | =item encrypt_symmetrically( % ) | 
| 1031 |  |  |  |  |  |  |  |  | 
| 1032 |  |  |  |  |  |  |  | =item sign( % ) | 
| 1033 |  |  |  |  |  |  |  |  | 
| 1034 |  |  |  |  |  |  |  | =item clearsign( % ) | 
| 1035 |  |  |  |  |  |  |  |  | 
| 1036 |  |  |  |  |  |  |  | =item detach_sign( % ) | 
| 1037 |  |  |  |  |  |  |  |  | 
| 1038 |  |  |  |  |  |  |  | =item sign_and_encrypt( % ) | 
| 1039 |  |  |  |  |  |  |  |  | 
| 1040 |  |  |  |  |  |  |  | =item decrypt( % ) | 
| 1041 |  |  |  |  |  |  |  |  | 
| 1042 |  |  |  |  |  |  |  | =item verify( % ) | 
| 1043 |  |  |  |  |  |  |  |  | 
| 1044 |  |  |  |  |  |  |  | =item import_keys( % ) | 
| 1045 |  |  |  |  |  |  |  |  | 
| 1046 |  |  |  |  |  |  |  | =item export_keys( % ) | 
| 1047 |  |  |  |  |  |  |  |  | 
| 1048 |  |  |  |  |  |  |  | =item recv_keys( % ) | 
| 1049 |  |  |  |  |  |  |  |  | 
| 1050 |  |  |  |  |  |  |  | =item send_keys( % ) | 
| 1051 |  |  |  |  |  |  |  |  | 
| 1052 |  |  |  |  |  |  |  | =item search_keys( % ) | 
| 1053 |  |  |  |  |  |  |  |  | 
| 1054 |  |  |  |  |  |  |  | These methods each correspond directly to or are very similar | 
| 1055 |  |  |  |  |  |  |  | to a GnuPG command described in L<gpg>.  Each of these methods | 
| 1056 |  |  |  |  |  |  |  | takes a hash, which currently must contain a key of B<handles> | 
| 1057 |  |  |  |  |  |  |  | which has the value of a GnuPG::Handles object. | 
| 1058 |  |  |  |  |  |  |  | Another optional key is B<command_args> which should have the value of an | 
| 1059 |  |  |  |  |  |  |  | array reference; these arguments will be passed to GnuPG as command arguments. | 
| 1060 |  |  |  |  |  |  |  | These command arguments are used for such things as determining the keys to | 
| 1061 |  |  |  |  |  |  |  | list in the B<export_keys> method.  I<Please note that GnuPG command arguments | 
| 1062 |  |  |  |  |  |  |  | are not the same as GnuPG options>.  To understand what are options and | 
| 1063 |  |  |  |  |  |  |  | what are command arguments please read L<gpg/"COMMANDS"> and L<gpg/"OPTIONS">. | 
| 1064 |  |  |  |  |  |  |  |  | 
| 1065 |  |  |  |  |  |  |  | Each of these calls returns the PID for the resulting GnuPG process. | 
| 1066 |  |  |  |  |  |  |  | One can use this PID in a C<waitpid> call instead of a C<wait> call | 
| 1067 |  |  |  |  |  |  |  | if more precise process reaping is needed. | 
| 1068 |  |  |  |  |  |  |  |  | 
| 1069 |  |  |  |  |  |  |  | These methods will attach the handles specified in the B<handles> object | 
| 1070 |  |  |  |  |  |  |  | to the running GnuPG object, so that bidirectional communication | 
| 1071 |  |  |  |  |  |  |  | can be established.  That is, the optionally-defined B<stdin>, | 
| 1072 |  |  |  |  |  |  |  | B<stdout>, B<stderr>, B<status>, B<logger>, and | 
| 1073 |  |  |  |  |  |  |  | B<passphrase> handles will be attached to | 
| 1074 |  |  |  |  |  |  |  | GnuPG's input, output, standard error, | 
| 1075 |  |  |  |  |  |  |  | the handle created by setting B<status-fd>, the handle created by setting B<logger-fd>, and the handle created by setting | 
| 1076 |  |  |  |  |  |  |  | B<passphrase-fd> respectively. | 
| 1077 |  |  |  |  |  |  |  | This tying of handles of similar to the process | 
| 1078 |  |  |  |  |  |  |  | done in I<IPC::Open3>. | 
| 1079 |  |  |  |  |  |  |  |  | 
| 1080 |  |  |  |  |  |  |  | If you want the GnuPG process to read or write directly to an already-opened | 
| 1081 |  |  |  |  |  |  |  | filehandle, you cannot do this via the normal I<IPC::Open3> mechanisms. | 
| 1082 |  |  |  |  |  |  |  | In order to accomplish this, set the appropriate B<handles> data member | 
| 1083 |  |  |  |  |  |  |  | to the already-opened filehandle, and then set the option B<direct> to be true | 
| 1084 |  |  |  |  |  |  |  | for that handle, as described in L<GnuPG::Handles/options>.  For example, | 
| 1085 |  |  |  |  |  |  |  | to have GnuPG read from the file F<input.txt> and write to F<output.txt>, | 
| 1086 |  |  |  |  |  |  |  | the following snippet may do: | 
| 1087 |  |  |  |  |  |  |  |  | 
| 1088 |  |  |  |  |  |  |  | my $infile  = IO::File->new( 'input.txt' ); | 
| 1089 |  |  |  |  |  |  |  | my $outfile = IO::File->new( '>output.txt' ); | 
| 1090 |  |  |  |  |  |  |  | my $handles = GnuPG::Handles->new( stdin  => $infile, | 
| 1091 |  |  |  |  |  |  |  | stdout => $outfile, | 
| 1092 |  |  |  |  |  |  |  | ); | 
| 1093 |  |  |  |  |  |  |  | $handles->options( 'stdin'  )->{direct} = 1; | 
| 1094 |  |  |  |  |  |  |  | $handles->options( 'stdout' )->{direct} = 1; | 
| 1095 |  |  |  |  |  |  |  |  | 
| 1096 |  |  |  |  |  |  |  | If any handle in the B<handles> object is not defined, GnuPG's input, output, | 
| 1097 |  |  |  |  |  |  |  | and standard error will be tied to the running program's standard error, | 
| 1098 |  |  |  |  |  |  |  | standard output, or standard error.  If the B<status> or B<logger> handle | 
| 1099 |  |  |  |  |  |  |  | is not defined, this channel of communication is never established with GnuPG, | 
| 1100 |  |  |  |  |  |  |  | and so this information is not generated and does not come into play. | 
| 1101 |  |  |  |  |  |  |  |  | 
| 1102 |  |  |  |  |  |  |  | If the B<passphrase> data member handle of the B<handles> object | 
| 1103 |  |  |  |  |  |  |  | is not defined, but the the B<passphrase> data member handle of GnuPG::Interface | 
| 1104 |  |  |  |  |  |  |  | object is, GnuPG::Interface will handle passing this information into GnuPG | 
| 1105 |  |  |  |  |  |  |  | for the user as a convenience.  Note that this will result in | 
| 1106 |  |  |  |  |  |  |  | GnuPG::Interface storing the passphrase in memory, instead of having | 
| 1107 |  |  |  |  |  |  |  | it simply 'pass-through' to GnuPG via a handle. | 
| 1108 |  |  |  |  |  |  |  |  | 
| 1109 |  |  |  |  |  |  |  | If neither the B<passphrase> data member of the GnuPG::Interface nor | 
| 1110 |  |  |  |  |  |  |  | the B<passphrase> data member of the B<handles> object is defined, | 
| 1111 |  |  |  |  |  |  |  | then GnuPG::Interface assumes that access and control over the secret | 
| 1112 |  |  |  |  |  |  |  | key will be handled by the running gpg-agent process.  This represents | 
| 1113 |  |  |  |  |  |  |  | the simplest mode of operation with the GnuPG "stable" suite (version | 
| 1114 |  |  |  |  |  |  |  | 2.2 and later).  It is also the preferred mode for tools intended to | 
| 1115 |  |  |  |  |  |  |  | be user-facing, since the user will be prompted directly by gpg-agent | 
| 1116 |  |  |  |  |  |  |  | for use of the secret key material.  Note that for programmatic use, | 
| 1117 |  |  |  |  |  |  |  | this mode requires the gpg-agent and pinentry to already be correctly | 
| 1118 |  |  |  |  |  |  |  | configured. | 
| 1119 |  |  |  |  |  |  |  |  | 
| 1120 |  |  |  |  |  |  |  | =back | 
| 1121 |  |  |  |  |  |  |  |  | 
| 1122 |  |  |  |  |  |  |  | =head2 Other Methods | 
| 1123 |  |  |  |  |  |  |  |  | 
| 1124 |  |  |  |  |  |  |  | =over 4 | 
| 1125 |  |  |  |  |  |  |  |  | 
| 1126 |  |  |  |  |  |  |  | =item get_public_keys( @search_strings ) | 
| 1127 |  |  |  |  |  |  |  |  | 
| 1128 |  |  |  |  |  |  |  | =item get_secret_keys( @search_strings ) | 
| 1129 |  |  |  |  |  |  |  |  | 
| 1130 |  |  |  |  |  |  |  | =item get_public_keys_with_sigs( @search_strings ) | 
| 1131 |  |  |  |  |  |  |  |  | 
| 1132 |  |  |  |  |  |  |  | These methods create and return objects of the type GnuPG::PublicKey | 
| 1133 |  |  |  |  |  |  |  | or GnuPG::SecretKey respectively.  This is done by parsing the output | 
| 1134 |  |  |  |  |  |  |  | of GnuPG with the option B<with-colons> enabled.  The objects created | 
| 1135 |  |  |  |  |  |  |  | do or do not have signature information stored in them, depending | 
| 1136 |  |  |  |  |  |  |  | if the method ends in I<_sigs>; this separation of functionality is there | 
| 1137 |  |  |  |  |  |  |  | because of performance hits when listing information with signatures. | 
| 1138 |  |  |  |  |  |  |  |  | 
| 1139 |  |  |  |  |  |  |  | =item test_default_key_passphrase() | 
| 1140 |  |  |  |  |  |  |  |  | 
| 1141 |  |  |  |  |  |  |  | This method will return a true or false value, depending | 
| 1142 |  |  |  |  |  |  |  | on whether GnuPG reports a good passphrase was entered | 
| 1143 |  |  |  |  |  |  |  | while signing a short message using the values of | 
| 1144 |  |  |  |  |  |  |  | the B<passphrase> data member, and the default | 
| 1145 |  |  |  |  |  |  |  | key specified in the B<options> data member. | 
| 1146 |  |  |  |  |  |  |  |  | 
| 1147 |  |  |  |  |  |  |  | =item version() | 
| 1148 |  |  |  |  |  |  |  |  | 
| 1149 |  |  |  |  |  |  |  | Returns the version of GnuPG that GnuPG::Interface is running. | 
| 1150 |  |  |  |  |  |  |  |  | 
| 1151 |  |  |  |  |  |  |  | =back | 
| 1152 |  |  |  |  |  |  |  |  | 
| 1153 |  |  |  |  |  |  |  |  | 
| 1154 |  |  |  |  |  |  |  | =head1 Invoking GnuPG with a custom call | 
| 1155 |  |  |  |  |  |  |  |  | 
| 1156 |  |  |  |  |  |  |  | GnuPG::Interface attempts to cover a lot of the commands | 
| 1157 |  |  |  |  |  |  |  | of GnuPG that one would want to perform; however, there may be a lot | 
| 1158 |  |  |  |  |  |  |  | more calls that GnuPG is and will be capable of, so a generic command | 
| 1159 |  |  |  |  |  |  |  | interface is provided, C<wrap_call>. | 
| 1160 |  |  |  |  |  |  |  |  | 
| 1161 |  |  |  |  |  |  |  | =over 4 | 
| 1162 |  |  |  |  |  |  |  |  | 
| 1163 |  |  |  |  |  |  |  | =item wrap_call( %args ) | 
| 1164 |  |  |  |  |  |  |  |  | 
| 1165 |  |  |  |  |  |  |  | Call GnuPG with a custom command.  The %args hash must contain | 
| 1166 |  |  |  |  |  |  |  | at least the following keys: | 
| 1167 |  |  |  |  |  |  |  |  | 
| 1168 |  |  |  |  |  |  |  | =over 4 | 
| 1169 |  |  |  |  |  |  |  |  | 
| 1170 |  |  |  |  |  |  |  | =item commands | 
| 1171 |  |  |  |  |  |  |  |  | 
| 1172 |  |  |  |  |  |  |  | The value of this key in the hash must be a reference to a a list of | 
| 1173 |  |  |  |  |  |  |  | commands for GnuPG, such as C<[ qw( --encrypt --sign ) ]>. | 
| 1174 |  |  |  |  |  |  |  |  | 
| 1175 |  |  |  |  |  |  |  | =item handles | 
| 1176 |  |  |  |  |  |  |  |  | 
| 1177 |  |  |  |  |  |  |  | As with most other GnuPG::Interface methods, B<handles> | 
| 1178 |  |  |  |  |  |  |  | must be a GnuPG::Handles object. | 
| 1179 |  |  |  |  |  |  |  |  | 
| 1180 |  |  |  |  |  |  |  | =back | 
| 1181 |  |  |  |  |  |  |  |  | 
| 1182 |  |  |  |  |  |  |  | The following keys are optional. | 
| 1183 |  |  |  |  |  |  |  |  | 
| 1184 |  |  |  |  |  |  |  | =over 4 | 
| 1185 |  |  |  |  |  |  |  |  | 
| 1186 |  |  |  |  |  |  |  | =item command_args | 
| 1187 |  |  |  |  |  |  |  |  | 
| 1188 |  |  |  |  |  |  |  | As with other GnuPG::Interface methods, the value in hash | 
| 1189 |  |  |  |  |  |  |  | for this key must be a reference to a list of arguments | 
| 1190 |  |  |  |  |  |  |  | to be passed to the GnuPG command, such as which | 
| 1191 |  |  |  |  |  |  |  | keys to list in a key-listing. | 
| 1192 |  |  |  |  |  |  |  |  | 
| 1193 |  |  |  |  |  |  |  | =back | 
| 1194 |  |  |  |  |  |  |  |  | 
| 1195 |  |  |  |  |  |  |  | =back | 
| 1196 |  |  |  |  |  |  |  |  | 
| 1197 |  |  |  |  |  |  |  |  | 
| 1198 |  |  |  |  |  |  |  | =head1 OBJECT DATA MEMBERS | 
| 1199 |  |  |  |  |  |  |  |  | 
| 1200 |  |  |  |  |  |  |  | =over 4 | 
| 1201 |  |  |  |  |  |  |  |  | 
| 1202 |  |  |  |  |  |  |  | =item call | 
| 1203 |  |  |  |  |  |  |  |  | 
| 1204 |  |  |  |  |  |  |  | This defines the call made to invoke GnuPG.  Defaults to 'gpg'; this | 
| 1205 |  |  |  |  |  |  |  | should be changed if 'gpg' is not in your path, or there is a different | 
| 1206 |  |  |  |  |  |  |  | name for the binary on your system. | 
| 1207 |  |  |  |  |  |  |  |  | 
| 1208 |  |  |  |  |  |  |  | =item passphrase | 
| 1209 |  |  |  |  |  |  |  |  | 
| 1210 |  |  |  |  |  |  |  | In order to lessen the burden of using handles by the user of this package, | 
| 1211 |  |  |  |  |  |  |  | setting this option to one's passphrase for a secret key will allow | 
| 1212 |  |  |  |  |  |  |  | the package to enter the passphrase via a handle to GnuPG by itself | 
| 1213 |  |  |  |  |  |  |  | instead of leaving this to the user.  See also L<GnuPG::Handles/passphrase>. | 
| 1214 |  |  |  |  |  |  |  |  | 
| 1215 |  |  |  |  |  |  |  | =item options | 
| 1216 |  |  |  |  |  |  |  |  | 
| 1217 |  |  |  |  |  |  |  | This data member, of the type GnuPG::Options; the setting stored in this | 
| 1218 |  |  |  |  |  |  |  | data member are used to determine the options used when calling GnuPG | 
| 1219 |  |  |  |  |  |  |  | via I<any> of the object methods described in this package. | 
| 1220 |  |  |  |  |  |  |  | See L<GnuPG::Options> for more information. | 
| 1221 |  |  |  |  |  |  |  |  | 
| 1222 |  |  |  |  |  |  |  | =back | 
| 1223 |  |  |  |  |  |  |  |  | 
| 1224 |  |  |  |  |  |  |  | =head1 EXAMPLES | 
| 1225 |  |  |  |  |  |  |  |  | 
| 1226 |  |  |  |  |  |  |  | The following setup can be done before any of the following examples: | 
| 1227 |  |  |  |  |  |  |  |  | 
| 1228 |  |  |  |  |  |  |  | use IO::Handle; | 
| 1229 |  |  |  |  |  |  |  | use GnuPG::Interface; | 
| 1230 |  |  |  |  |  |  |  |  | 
| 1231 |  |  |  |  |  |  |  | my @original_plaintext = ( "How do you doo?" ); | 
| 1232 |  |  |  |  |  |  |  | my $passphrase = "Three Little Pigs"; | 
| 1233 |  |  |  |  |  |  |  |  | 
| 1234 |  |  |  |  |  |  |  | my $gnupg = GnuPG::Interface->new(); | 
| 1235 |  |  |  |  |  |  |  |  | 
| 1236 |  |  |  |  |  |  |  | $gnupg->options->hash_init( armor    => 1, | 
| 1237 |  |  |  |  |  |  |  | recipients => [ 'ftobin@uiuc.edu', | 
| 1238 |  |  |  |  |  |  |  | '0xABCD1234ABCD1234ABCD1234ABCD1234ABCD1234' ], | 
| 1239 |  |  |  |  |  |  |  | meta_interactive => 0 , | 
| 1240 |  |  |  |  |  |  |  | ); | 
| 1241 |  |  |  |  |  |  |  |  | 
| 1242 |  |  |  |  |  |  |  | $gnupg->options->debug_level(4); | 
| 1243 |  |  |  |  |  |  |  |  | 
| 1244 |  |  |  |  |  |  |  | $gnupg->options->logger_file("/tmp/gnupg-$$-decrypt-".time().".log"); | 
| 1245 |  |  |  |  |  |  |  |  | 
| 1246 |  |  |  |  |  |  |  |  | 
| 1247 |  |  |  |  |  |  |  | =head2 Encrypting | 
| 1248 |  |  |  |  |  |  |  |  | 
| 1249 |  |  |  |  |  |  |  | # We'll let the standard error of GnuPG pass through | 
| 1250 |  |  |  |  |  |  |  | # to our own standard error, by not creating | 
| 1251 |  |  |  |  |  |  |  | # a stderr-part of the $handles object. | 
| 1252 |  |  |  |  |  |  |  | my ( $input, $output ) = ( IO::Handle->new(), | 
| 1253 |  |  |  |  |  |  |  | IO::Handle->new() ); | 
| 1254 |  |  |  |  |  |  |  |  | 
| 1255 |  |  |  |  |  |  |  | my $handles = GnuPG::Handles->new( stdin    => $input, | 
| 1256 |  |  |  |  |  |  |  | stdout   => $output ); | 
| 1257 |  |  |  |  |  |  |  |  | 
| 1258 |  |  |  |  |  |  |  | # this sets up the communication | 
| 1259 |  |  |  |  |  |  |  | # Note that the recipients were specified earlier | 
| 1260 |  |  |  |  |  |  |  | # in the 'options' data member of the $gnupg object. | 
| 1261 |  |  |  |  |  |  |  | my $pid = $gnupg->encrypt( handles => $handles ); | 
| 1262 |  |  |  |  |  |  |  |  | 
| 1263 |  |  |  |  |  |  |  | # this passes in the plaintext | 
| 1264 |  |  |  |  |  |  |  | print $input @original_plaintext; | 
| 1265 |  |  |  |  |  |  |  |  | 
| 1266 |  |  |  |  |  |  |  | # this closes the communication channel, | 
| 1267 |  |  |  |  |  |  |  | # indicating we are done | 
| 1268 |  |  |  |  |  |  |  | close $input; | 
| 1269 |  |  |  |  |  |  |  |  | 
| 1270 |  |  |  |  |  |  |  | my @ciphertext = <$output>;  # reading the output | 
| 1271 |  |  |  |  |  |  |  |  | 
| 1272 |  |  |  |  |  |  |  | waitpid $pid, 0;  # clean up the finished GnuPG process | 
| 1273 |  |  |  |  |  |  |  |  | 
| 1274 |  |  |  |  |  |  |  | =head2 Signing | 
| 1275 |  |  |  |  |  |  |  |  | 
| 1276 |  |  |  |  |  |  |  | # This time we'll catch the standard error for our perusing | 
| 1277 |  |  |  |  |  |  |  | my ( $input, $output, $error ) = ( IO::Handle->new(), | 
| 1278 |  |  |  |  |  |  |  | IO::Handle->new(), | 
| 1279 |  |  |  |  |  |  |  | IO::Handle->new(), | 
| 1280 |  |  |  |  |  |  |  | ); | 
| 1281 |  |  |  |  |  |  |  |  | 
| 1282 |  |  |  |  |  |  |  | my $handles = GnuPG::Handles->new( stdin    => $input, | 
| 1283 |  |  |  |  |  |  |  | stdout   => $output, | 
| 1284 |  |  |  |  |  |  |  | stderr   => $error, | 
| 1285 |  |  |  |  |  |  |  | ); | 
| 1286 |  |  |  |  |  |  |  |  | 
| 1287 |  |  |  |  |  |  |  | # indicate our pasphrase through the | 
| 1288 |  |  |  |  |  |  |  | # convenience method | 
| 1289 |  |  |  |  |  |  |  | $gnupg->passphrase( $passphrase ); | 
| 1290 |  |  |  |  |  |  |  |  | 
| 1291 |  |  |  |  |  |  |  | # this sets up the communication | 
| 1292 |  |  |  |  |  |  |  | my $pid = $gnupg->sign( handles => $handles ); | 
| 1293 |  |  |  |  |  |  |  |  | 
| 1294 |  |  |  |  |  |  |  | # this passes in the plaintext | 
| 1295 |  |  |  |  |  |  |  | print $input @original_plaintext; | 
| 1296 |  |  |  |  |  |  |  |  | 
| 1297 |  |  |  |  |  |  |  | # this closes the communication channel, | 
| 1298 |  |  |  |  |  |  |  | # indicating we are done | 
| 1299 |  |  |  |  |  |  |  | close $input; | 
| 1300 |  |  |  |  |  |  |  |  | 
| 1301 |  |  |  |  |  |  |  | my @ciphertext   = <$output>;  # reading the output | 
| 1302 |  |  |  |  |  |  |  | my @error_output = <$error>;   # reading the error | 
| 1303 |  |  |  |  |  |  |  |  | 
| 1304 |  |  |  |  |  |  |  | close $output; | 
| 1305 |  |  |  |  |  |  |  | close $error; | 
| 1306 |  |  |  |  |  |  |  |  | 
| 1307 |  |  |  |  |  |  |  | waitpid $pid, 0;  # clean up the finished GnuPG process | 
| 1308 |  |  |  |  |  |  |  |  | 
| 1309 |  |  |  |  |  |  |  | =head2 Decryption | 
| 1310 |  |  |  |  |  |  |  |  | 
| 1311 |  |  |  |  |  |  |  | # This time we'll catch the standard error for our perusing | 
| 1312 |  |  |  |  |  |  |  | # as well as passing in the passphrase manually | 
| 1313 |  |  |  |  |  |  |  | # as well as the status information given by GnuPG | 
| 1314 |  |  |  |  |  |  |  | my ( $input, $output, $error, $passphrase_fh, $status_fh ) | 
| 1315 |  |  |  |  |  |  |  | = ( IO::Handle->new(), | 
| 1316 |  |  |  |  |  |  |  | IO::Handle->new(), | 
| 1317 |  |  |  |  |  |  |  | IO::Handle->new(), | 
| 1318 |  |  |  |  |  |  |  | IO::Handle->new(), | 
| 1319 |  |  |  |  |  |  |  | IO::Handle->new(), | 
| 1320 |  |  |  |  |  |  |  | ); | 
| 1321 |  |  |  |  |  |  |  |  | 
| 1322 |  |  |  |  |  |  |  | my $handles = GnuPG::Handles->new( stdin      => $input, | 
| 1323 |  |  |  |  |  |  |  | stdout     => $output, | 
| 1324 |  |  |  |  |  |  |  | stderr     => $error, | 
| 1325 |  |  |  |  |  |  |  | passphrase => $passphrase_fh, | 
| 1326 |  |  |  |  |  |  |  | status     => $status_fh, | 
| 1327 |  |  |  |  |  |  |  | ); | 
| 1328 |  |  |  |  |  |  |  |  | 
| 1329 |  |  |  |  |  |  |  | # this time we'll also demonstrate decrypting | 
| 1330 |  |  |  |  |  |  |  | # a file written to disk | 
| 1331 |  |  |  |  |  |  |  | # Make sure you "use IO::File" if you use this module! | 
| 1332 |  |  |  |  |  |  |  | my $cipher_file = IO::File->new( 'encrypted.gpg' ); | 
| 1333 |  |  |  |  |  |  |  |  | 
| 1334 |  |  |  |  |  |  |  | # this sets up the communication | 
| 1335 |  |  |  |  |  |  |  | my $pid = $gnupg->decrypt( handles => $handles ); | 
| 1336 |  |  |  |  |  |  |  |  | 
| 1337 |  |  |  |  |  |  |  | # This passes in the passphrase | 
| 1338 |  |  |  |  |  |  |  | print $passphrase_fh $passphrase; | 
| 1339 |  |  |  |  |  |  |  | close $passphrase_fh; | 
| 1340 |  |  |  |  |  |  |  |  | 
| 1341 |  |  |  |  |  |  |  | # this passes in the plaintext | 
| 1342 |  |  |  |  |  |  |  | print $input $_ while <$cipher_file>; | 
| 1343 |  |  |  |  |  |  |  |  | 
| 1344 |  |  |  |  |  |  |  | # this closes the communication channel, | 
| 1345 |  |  |  |  |  |  |  | # indicating we are done | 
| 1346 |  |  |  |  |  |  |  | close $input; | 
| 1347 |  |  |  |  |  |  |  | close $cipher_file; | 
| 1348 |  |  |  |  |  |  |  |  | 
| 1349 |  |  |  |  |  |  |  | my @plaintext    = <$output>;    # reading the output | 
| 1350 |  |  |  |  |  |  |  | my @error_output = <$error>;     # reading the error | 
| 1351 |  |  |  |  |  |  |  | my @status_info  = <$status_fh>; # read the status info | 
| 1352 |  |  |  |  |  |  |  |  | 
| 1353 |  |  |  |  |  |  |  | # clean up... | 
| 1354 |  |  |  |  |  |  |  | close $output; | 
| 1355 |  |  |  |  |  |  |  | close $error; | 
| 1356 |  |  |  |  |  |  |  | close $status_fh; | 
| 1357 |  |  |  |  |  |  |  |  | 
| 1358 |  |  |  |  |  |  |  | waitpid $pid, 0;  # clean up the finished GnuPG process | 
| 1359 |  |  |  |  |  |  |  |  | 
| 1360 |  |  |  |  |  |  |  | =head2 Printing Keys | 
| 1361 |  |  |  |  |  |  |  |  | 
| 1362 |  |  |  |  |  |  |  | # This time we'll just let GnuPG print to our own output | 
| 1363 |  |  |  |  |  |  |  | # and read from our input, because no input is needed! | 
| 1364 |  |  |  |  |  |  |  | my $handles = GnuPG::Handles->new(); | 
| 1365 |  |  |  |  |  |  |  |  | 
| 1366 |  |  |  |  |  |  |  | my @ids = ( 'ftobin', '0xABCD1234ABCD1234ABCD1234ABCD1234ABCD1234' ); | 
| 1367 |  |  |  |  |  |  |  |  | 
| 1368 |  |  |  |  |  |  |  | # this time we need to specify something for | 
| 1369 |  |  |  |  |  |  |  | # command_args because --list-public-keys takes | 
| 1370 |  |  |  |  |  |  |  | # search ids as arguments | 
| 1371 |  |  |  |  |  |  |  | my $pid = $gnupg->list_public_keys( handles      => $handles, | 
| 1372 |  |  |  |  |  |  |  | command_args => [ @ids ] ); | 
| 1373 |  |  |  |  |  |  |  |  | 
| 1374 |  |  |  |  |  |  |  | waitpid $pid, 0; | 
| 1375 |  |  |  |  |  |  |  |  | 
| 1376 |  |  |  |  |  |  |  | =head2 Creating GnuPG::PublicKey Objects | 
| 1377 |  |  |  |  |  |  |  |  | 
| 1378 |  |  |  |  |  |  |  | my @ids = [ 'ftobin', '0xABCD1234ABCD1234ABCD1234ABCD1234ABCD1234' ]; | 
| 1379 |  |  |  |  |  |  |  |  | 
| 1380 |  |  |  |  |  |  |  | my @keys = $gnupg->get_public_keys( @ids ); | 
| 1381 |  |  |  |  |  |  |  |  | 
| 1382 |  |  |  |  |  |  |  | # no wait is required this time; it's handled internally | 
| 1383 |  |  |  |  |  |  |  | # since the entire call is encapsulated | 
| 1384 |  |  |  |  |  |  |  |  | 
| 1385 |  |  |  |  |  |  |  | =head2 Custom GnuPG call | 
| 1386 |  |  |  |  |  |  |  |  | 
| 1387 |  |  |  |  |  |  |  | # assuming $handles is a GnuPG::Handles object | 
| 1388 |  |  |  |  |  |  |  | my $pid = $gnupg->wrap_call | 
| 1389 |  |  |  |  |  |  |  | ( commands     => [ qw( --list-packets ) ], | 
| 1390 |  |  |  |  |  |  |  | command_args => [ qw( test/key.1.asc ) ], | 
| 1391 |  |  |  |  |  |  |  | handles      => $handles, | 
| 1392 |  |  |  |  |  |  |  | ); | 
| 1393 |  |  |  |  |  |  |  |  | 
| 1394 |  |  |  |  |  |  |  | my @out = <$handles->stdout()>; | 
| 1395 |  |  |  |  |  |  |  | waitpid $pid, 0; | 
| 1396 |  |  |  |  |  |  |  |  | 
| 1397 |  |  |  |  |  |  |  |  | 
| 1398 |  |  |  |  |  |  |  | =head1 FAQ | 
| 1399 |  |  |  |  |  |  |  |  | 
| 1400 |  |  |  |  |  |  |  | =over 4 | 
| 1401 |  |  |  |  |  |  |  |  | 
| 1402 |  |  |  |  |  |  |  | =item How do I get GnuPG::Interface to read/write directly from | 
| 1403 |  |  |  |  |  |  |  | a filehandle? | 
| 1404 |  |  |  |  |  |  |  |  | 
| 1405 |  |  |  |  |  |  |  | You need to set GnuPG::Handles B<direct> option to be true for the | 
| 1406 |  |  |  |  |  |  |  | filehandles in concern.  See L<GnuPG::Handles/options> and | 
| 1407 |  |  |  |  |  |  |  | L<"Object Methods which use a GnuPG::Handles Object"> for more | 
| 1408 |  |  |  |  |  |  |  | information. | 
| 1409 |  |  |  |  |  |  |  |  | 
| 1410 |  |  |  |  |  |  |  | =item Why do you make it so difficult to get GnuPG to write/read | 
| 1411 |  |  |  |  |  |  |  | from a filehandle?  In the shell, I can just call GnuPG | 
| 1412 |  |  |  |  |  |  |  | with the --outfile option! | 
| 1413 |  |  |  |  |  |  |  |  | 
| 1414 |  |  |  |  |  |  |  | There are lots of issues when trying to tell GnuPG to read/write | 
| 1415 |  |  |  |  |  |  |  | directly from a file, such as if the file isn't there, or | 
| 1416 |  |  |  |  |  |  |  | there is a file, and you want to write over it!  What do you | 
| 1417 |  |  |  |  |  |  |  | want to happen then?  Having the user of this module handle | 
| 1418 |  |  |  |  |  |  |  | these questions beforehand by opening up filehandles to GnuPG | 
| 1419 |  |  |  |  |  |  |  | lets the user know fully what is going to happen in these circumstances, | 
| 1420 |  |  |  |  |  |  |  | and makes the module less error-prone. | 
| 1421 |  |  |  |  |  |  |  |  | 
| 1422 |  |  |  |  |  |  |  | =item When having GnuPG process a large message, sometimes it just | 
| 1423 |  |  |  |  |  |  |  | hanges there. | 
| 1424 |  |  |  |  |  |  |  |  | 
| 1425 |  |  |  |  |  |  |  | Your problem may be due to buffering issues; when GnuPG reads/writes | 
| 1426 |  |  |  |  |  |  |  | to B<non-direct> filehandles (those that are sent to filehandles | 
| 1427 |  |  |  |  |  |  |  | which you read to from into memory, not that those access the disk), | 
| 1428 |  |  |  |  |  |  |  | buffering issues can mess things up.  I recommend looking into | 
| 1429 |  |  |  |  |  |  |  | L<GnuPG::Handles/options>. | 
| 1430 |  |  |  |  |  |  |  |  | 
| 1431 |  |  |  |  |  |  |  | =back | 
| 1432 |  |  |  |  |  |  |  |  | 
| 1433 |  |  |  |  |  |  |  | =head1 NOTES | 
| 1434 |  |  |  |  |  |  |  |  | 
| 1435 |  |  |  |  |  |  |  | This package is the successor to PGP::GPG::MessageProcessor, | 
| 1436 |  |  |  |  |  |  |  | which I found to be too inextensible to carry on further. | 
| 1437 |  |  |  |  |  |  |  | A total redesign was needed, and this is the resulting | 
| 1438 |  |  |  |  |  |  |  | work. | 
| 1439 |  |  |  |  |  |  |  |  | 
| 1440 |  |  |  |  |  |  |  | After any call to a GnuPG-command method of GnuPG::Interface | 
| 1441 |  |  |  |  |  |  |  | in which one passes in the handles, | 
| 1442 |  |  |  |  |  |  |  | one should all B<wait> to clean up GnuPG from the process table. | 
| 1443 |  |  |  |  |  |  |  |  | 
| 1444 |  |  |  |  |  |  |  |  | 
| 1445 |  |  |  |  |  |  |  | =head1 BUGS | 
| 1446 |  |  |  |  |  |  |  |  | 
| 1447 |  |  |  |  |  |  |  | =head2 Large Amounts of Data | 
| 1448 |  |  |  |  |  |  |  |  | 
| 1449 |  |  |  |  |  |  |  | Currently there are problems when transmitting large quantities | 
| 1450 |  |  |  |  |  |  |  | of information over handles; I'm guessing this is due | 
| 1451 |  |  |  |  |  |  |  | to buffering issues.  This bug does not seem specific to this package; | 
| 1452 |  |  |  |  |  |  |  | IPC::Open3 also appears affected. | 
| 1453 |  |  |  |  |  |  |  |  | 
| 1454 |  |  |  |  |  |  |  | =head2 OpenPGP v3 Keys | 
| 1455 |  |  |  |  |  |  |  |  | 
| 1456 |  |  |  |  |  |  |  | I don't know yet how well this module handles parsing OpenPGP v3 keys. | 
| 1457 |  |  |  |  |  |  |  |  | 
| 1458 |  |  |  |  |  |  |  | =head2 RHEL 7 Test Failures | 
| 1459 |  |  |  |  |  |  |  |  | 
| 1460 |  |  |  |  |  |  |  | Testing with the updates for version 1.00 we saw intermittent test failures | 
| 1461 |  |  |  |  |  |  |  | on RHEL 7 with GnuPG version 2.2.20. In some cases the tests would all pass | 
| 1462 |  |  |  |  |  |  |  | for several runs, then one would fail. We're unable to reliably reproduce | 
| 1463 |  |  |  |  |  |  |  | this so we would be interested in feedback from other users. | 
| 1464 |  |  |  |  |  |  |  |  | 
| 1465 |  |  |  |  |  |  |  | =head1 SEE ALSO | 
| 1466 |  |  |  |  |  |  |  |  | 
| 1467 |  |  |  |  |  |  |  | L<GnuPG::Options>, | 
| 1468 |  |  |  |  |  |  |  | L<GnuPG::Handles>, | 
| 1469 |  |  |  |  |  |  |  | L<GnuPG::PublicKey>, | 
| 1470 |  |  |  |  |  |  |  | L<GnuPG::SecretKey>, | 
| 1471 |  |  |  |  |  |  |  | L<gpg>, | 
| 1472 |  |  |  |  |  |  |  | L<perlipc/"Bidirectional Communication with Another Process"> | 
| 1473 |  |  |  |  |  |  |  |  | 
| 1474 |  |  |  |  |  |  |  | =head1 LICENSE | 
| 1475 |  |  |  |  |  |  |  |  | 
| 1476 |  |  |  |  |  |  |  | This module is free software; you can redistribute it and/or modify it | 
| 1477 |  |  |  |  |  |  |  | under the same terms as Perl itself. | 
| 1478 |  |  |  |  |  |  |  |  | 
| 1479 |  |  |  |  |  |  |  | =head1 AUTHOR | 
| 1480 |  |  |  |  |  |  |  |  | 
| 1481 |  |  |  |  |  |  |  | GnuPG::Interface is currently maintained by Best Practical Solutions <BPS@cpan.org>. | 
| 1482 |  |  |  |  |  |  |  |  | 
| 1483 |  |  |  |  |  |  |  | Frank J. Tobin, ftobin@cpan.org was the original author of the package. | 
| 1484 |  |  |  |  |  |  |  |  | 
| 1485 |  |  |  |  |  |  |  | =cut | 
| 1486 |  |  |  |  |  |  |  |  | 
| 1487 |  |  |  |  |  |  |  | 1; | 
| 1488 |  |  |  |  |  |  |  |  |