File Coverage

blib/lib/Dpkg/OpenPGP.pm
Criterion Covered Total %
statement 59 110 53.6
branch 16 50 32.0
condition 0 16 0.0
subroutine 12 14 85.7
pod 0 3 0.0
total 87 193 45.0


line stmt bran cond sub pod time code
1             # Copyright © 2017 Guillem Jover
2             #
3             # This program is free software; you can redistribute it and/or modify
4             # it under the terms of the GNU General Public License as published by
5             # the Free Software Foundation; either version 2 of the License, or
6             # (at your option) any later version.
7             #
8             # This program is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11             # GNU General Public License for more details.
12             #
13             # You should have received a copy of the GNU General Public License
14             # along with this program. If not, see .
15              
16             package Dpkg::OpenPGP;
17              
18 2     2   99938 use strict;
  2         5  
  2         59  
19 2     2   10 use warnings;
  2         3  
  2         62  
20              
21 2     2   10 use POSIX qw(:sys_wait_h);
  2         4  
  2         16  
22 2     2   377 use Exporter qw(import);
  2         5  
  2         52  
23 2     2   787 use File::Temp;
  2         9814  
  2         153  
24 2     2   523 use File::Copy;
  2         2433  
  2         111  
25              
26 2     2   14 use Dpkg::Gettext;
  2         7  
  2         115  
27 2     2   14 use Dpkg::ErrorHandling;
  2         6  
  2         157  
28 2     2   474 use Dpkg::IPC;
  2         6  
  2         104  
29 2     2   494 use Dpkg::Path qw(find_command);
  2         5  
  2         2250  
30              
31             our $VERSION = '0.01';
32             our @EXPORT = qw(
33             openpgp_sig_to_asc
34             );
35              
36             sub _armor_gpg {
37 1     1   2 my ($sig, $asc) = @_;
38              
39 1         3 my @gpg_opts = qw(--no-options);
40              
41 1 50       68 open my $fh_asc, '>', $asc
42             or syserr(g_('cannot create signature file %s'), $asc);
43 1 50       3703 open my $fh_gpg, '-|', 'gpg', @gpg_opts, '-o', '-', '--enarmor', $sig
44             or syserr(g_('cannot execute %s program'), 'gpg');
45 1         2441 while (my $line = <$fh_gpg>) {
46 18 100       73 next if $line =~ m/^Version: /;
47 17 100       46 next if $line =~ m/^Comment: /;
48              
49 16         49 $line =~ s/ARMORED FILE/SIGNATURE/;
50              
51 16         29 print { $fh_asc } $line;
  16         84  
52             }
53              
54 1 50       79 close $fh_gpg or subprocerr('gpg');
55 1 50       59 close $fh_asc or syserr(g_('cannot write signature file %s'), $asc);
56              
57 1         97 return $asc;
58             }
59              
60             sub openpgp_sig_to_asc
61             {
62 3     3 0 583 my ($sig, $asc) = @_;
63              
64 3 100       70 if (-e $sig) {
65 2         6 my $is_openpgp_ascii_armor = 0;
66              
67 2 50       82 open my $fh_sig, '<', $sig or syserr(g_('cannot open %s'), $sig);
68 2         46 while (<$fh_sig>) {
69 5 100       39 if (m/^-----BEGIN PGP /) {
70 1         3 $is_openpgp_ascii_armor = 1;
71 1         10 last;
72             }
73             }
74 2         28 close $fh_sig;
75              
76 2 100       7 if ($is_openpgp_ascii_armor) {
77 1         20 notice(g_('signature file is already OpenPGP ASCII armor, copying'));
78 1         19 copy($sig, $asc);
79 1         390 return $asc;
80             }
81              
82 1 50       4 if (find_command('gpg')) {
83 1         6 return _armor_gpg($sig, $asc);
84             } else {
85 0         0 warning(g_('cannot OpenPGP ASCII armor signature file due to missing gpg'));
86             }
87             }
88              
89 1         7 return;
90             }
91              
92             sub import_key {
93 0     0 0   my ($asc, %opts) = @_;
94              
95 0   0       $opts{require_valid_signature} //= 1;
96              
97 0           my @exec;
98 0 0         if (find_command('gpg')) {
    0          
99 0           push @exec, 'gpg';
100             } elsif ($opts{require_valid_signature}) {
101 0           error(g_('cannot import key in %s since GnuPG is not installed'),
102             $asc);
103             } else {
104 0           warning(g_('cannot import key in %s since GnuPG is not installed'),
105             $asc);
106 0           return;
107             }
108              
109 0           my $gpghome = File::Temp->newdir('dpkg-import-key.XXXXXXXX', TMPDIR => 1);
110              
111 0           push @exec, '--homedir', $gpghome;
112 0           push @exec, '--no-options', '--no-default-keyring', '-q', '--import';
113 0           push @exec, '--keyring', $opts{keyring};
114 0           push @exec, $asc;
115              
116 0           my ($stdout, $stderr);
117 0           spawn(exec => \@exec, wait_child => 1, nocheck => 1, timeout => 10,
118             to_string => \$stdout, error_to_string => \$stderr);
119 0 0         if (WIFEXITED($?)) {
120 0           my $status = WEXITSTATUS($?);
121 0 0         print { *STDERR } "$stdout$stderr" if $status;
  0            
122 0 0 0       if ($status == 1 or ($status && $opts{require_valid_signature})) {
    0 0        
123 0           error(g_('failed to import key in %s'), $asc);
124             } elsif ($status) {
125 0           warning(g_('failed to import key in %s'), $asc);
126             }
127             } else {
128 0           subprocerr("@exec");
129             }
130             }
131              
132             sub verify_signature {
133 0     0 0   my ($sig, %opts) = @_;
134              
135 0   0       $opts{require_valid_signature} //= 1;
136              
137 0           my @exec;
138 0 0         if (find_command('gpgv')) {
    0          
    0          
139 0           push @exec, 'gpgv';
140             } elsif (find_command('gpg')) {
141 0           my @gpg_opts = qw(--no-options --no-default-keyring -q);
142 0           push @exec, 'gpg', @gpg_opts, '--verify';
143             } elsif ($opts{require_valid_signature}) {
144 0           error(g_('cannot verify signature on %s since GnuPG is not installed'),
145             $sig);
146             } else {
147 0           warning(g_('cannot verify signature on %s since GnuPG is not installed'),
148             $sig);
149 0           return;
150             }
151              
152 0           my $gpghome = File::Temp->newdir('dpkg-verify-sig.XXXXXXXX', TMPDIR => 1);
153 0           push @exec, '--homedir', $gpghome;
154 0           foreach my $keyring (@{$opts{keyrings}}) {
  0            
155 0           push @exec, '--keyring', $keyring;
156             }
157 0           push @exec, $sig;
158 0 0         push @exec, $opts{datafile} if exists $opts{datafile};
159              
160 0           my ($stdout, $stderr);
161 0           spawn(exec => \@exec, wait_child => 1, nocheck => 1, timeout => 10,
162             to_string => \$stdout, error_to_string => \$stderr);
163 0 0         if (WIFEXITED($?)) {
164 0           my $status = WEXITSTATUS($?);
165 0 0         print { *STDERR } "$stdout$stderr" if $status;
  0            
166 0 0 0       if ($status == 1 or ($status && $opts{require_valid_signature})) {
    0 0        
167 0           error(g_('failed to verify signature on %s'), $sig);
168             } elsif ($status) {
169 0           warning(g_('failed to verify signature on %s'), $sig);
170             }
171             } else {
172 0           subprocerr("@exec");
173             }
174             }
175              
176             1;