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   104158 use strict;
  2         4  
  2         61  
19 2     2   13 use warnings;
  2         4  
  2         64  
20              
21 2     2   11 use POSIX qw(:sys_wait_h);
  2         5  
  2         17  
22 2     2   412 use Exporter qw(import);
  2         5  
  2         55  
23 2     2   856 use File::Temp;
  2         10529  
  2         158  
24 2     2   561 use File::Copy;
  2         2446  
  2         130  
25              
26 2     2   17 use Dpkg::Gettext;
  2         4  
  2         128  
27 2     2   13 use Dpkg::ErrorHandling;
  2         5  
  2         179  
28 2     2   488 use Dpkg::IPC;
  2         7  
  2         109  
29 2     2   485 use Dpkg::Path qw(find_command);
  2         5  
  2         2310  
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       75 open my $fh_asc, '>', $asc
42             or syserr(g_('cannot create signature file %s'), $asc);
43 1 50       3523 open my $fh_gpg, '-|', 'gpg', @gpg_opts, '-o', '-', '--enarmor', $sig
44             or syserr(g_('cannot execute %s program'), 'gpg');
45 1         2867 while (my $line = <$fh_gpg>) {
46 18 100       67 next if $line =~ m/^Version: /;
47 17 100       44 next if $line =~ m/^Comment: /;
48              
49 16         55 $line =~ s/ARMORED FILE/SIGNATURE/;
50              
51 16         25 print { $fh_asc } $line;
  16         358  
52             }
53              
54 1 50       90 close $fh_gpg or subprocerr('gpg');
55 1 50       63 close $fh_asc or syserr(g_('cannot write signature file %s'), $asc);
56              
57 1         114 return $asc;
58             }
59              
60             sub openpgp_sig_to_asc
61             {
62 3     3 0 622 my ($sig, $asc) = @_;
63              
64 3 100       75 if (-e $sig) {
65 2         5 my $is_openpgp_ascii_armor = 0;
66              
67 2 50       81 open my $fh_sig, '<', $sig or syserr(g_('cannot open %s'), $sig);
68 2         56 while (<$fh_sig>) {
69 5 100       37 if (m/^-----BEGIN PGP /) {
70 1         10 $is_openpgp_ascii_armor = 1;
71 1         11 last;
72             }
73             }
74 2         23 close $fh_sig;
75              
76 2 100       8 if ($is_openpgp_ascii_armor) {
77 1         22 notice(g_('signature file is already OpenPGP ASCII armor, copying'));
78 1         21 copy($sig, $asc);
79 1         413 return $asc;
80             }
81              
82 1 50       4 if (find_command('gpg')) {
83 1         8 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         12 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;