| File: | Dpkg/OpenPGP.pm |
| Coverage: | 75.2% |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | # Copyright © 2017 Guillem Jover <guillem@debian.org> | ||||||
| 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 <https://www.gnu.org/licenses/>. | ||||||
| 15 | |||||||
| 16 | =encoding utf8 | ||||||
| 17 | |||||||
| 18 - 28 | =head1 NAME Dpkg::OpenPGP - multi-backend OpenPGP support =head1 DESCRIPTION This module provides a class for transparent multi-backend OpenPGP support. B<Note>: This is a private module, its API can change at any time. =cut | ||||||
| 29 | |||||||
| 30 | package Dpkg::OpenPGP 0.01; | ||||||
| 31 | |||||||
| 32 | 216 216 216 | 570 216 4455 | use strict; | ||||
| 33 | 216 216 216 | 495 144 6786 | use warnings; | ||||
| 34 | |||||||
| 35 | 216 216 216 | 495 72 7374 | use List::Util qw(none); | ||||
| 36 | |||||||
| 37 | 216 216 216 | 501 207 7035 | use Dpkg::Gettext; | ||||
| 38 | 216 216 216 | 495 213 9231 | use Dpkg::ErrorHandling; | ||||
| 39 | 216 216 216 | 498 210 4629 | use Dpkg::IPC; | ||||
| 40 | 216 216 216 | 432 207 96942 | use Dpkg::Path qw(find_command); | ||||
| 41 | |||||||
| 42 | my @BACKENDS = qw( | ||||||
| 43 | sop | ||||||
| 44 | sq | ||||||
| 45 | gpg | ||||||
| 46 | ); | ||||||
| 47 | my %BACKEND = ( | ||||||
| 48 | sop => 'SOP', | ||||||
| 49 | sq => 'Sequoia', | ||||||
| 50 | gpg => 'GnuPG', | ||||||
| 51 | ); | ||||||
| 52 | |||||||
| 53 | sub new { | ||||||
| 54 | 735 | 0 | 2927 | my ($this, %opts) = @_; | |||
| 55 | 735 | 4432 | my $class = ref($this) || $this; | ||||
| 56 | |||||||
| 57 | 735 | 844 | my $self = {}; | ||||
| 58 | 735 | 911 | bless $self, $class; | ||||
| 59 | |||||||
| 60 | 735 | 1823 | my $backend = $opts{backend} // 'auto'; | ||||
| 61 | my %backend_opts = ( | ||||||
| 62 | cmdv => $opts{cmdv} // 'auto', | ||||||
| 63 | 735 | 4726 | cmd => $opts{cmd} // 'auto', | ||||
| 64 | ); | ||||||
| 65 | |||||||
| 66 | 735 | 2554 | if ($backend eq 'auto') { | ||||
| 67 | # Defaults for stateless full API auto-detection. | ||||||
| 68 | 216 | 1047 | $opts{needs}{api} //= 'full'; | ||||
| 69 | 216 | 576 | $opts{needs}{keystore} //= 0; | ||||
| 70 | |||||||
| 71 | 216 225 | 1224 642 | if (none { $opts{needs}{api} eq $_ } qw(full verify)) { | ||||
| 72 | 0 | 0 | error(g_('unknown OpenPGP api requested %s'), $opts{needs}{api}); | ||||
| 73 | } | ||||||
| 74 | |||||||
| 75 | 216 | 708 | $self->{backend} = $self->_auto_backend($opts{needs}, %backend_opts); | ||||
| 76 | } elsif (exists $BACKEND{$backend}) { | ||||||
| 77 | 519 | 2806 | $self->{backend} = $self->_load_backend($BACKEND{$backend}, %backend_opts); | ||||
| 78 | 519 | 2782 | if (! $self->{backend}) { | ||||
| 79 | 0 | 0 | error(g_('cannot load OpenPGP backend %s'), $backend); | ||||
| 80 | } | ||||||
| 81 | } else { | ||||||
| 82 | 0 | 0 | error(g_('unknown OpenPGP backend %s'), $backend); | ||||
| 83 | } | ||||||
| 84 | |||||||
| 85 | 735 | 7628 | return $self; | ||||
| 86 | } | ||||||
| 87 | |||||||
| 88 | sub _load_backend { | ||||||
| 89 | 735 | 2156 | my ($self, $backend, %opts) = @_; | ||||
| 90 | |||||||
| 91 | 735 | 1148 | my $module = "Dpkg::OpenPGP::Backend::$backend"; | ||||
| 92 | 735 | 58995 | eval qq{ | ||||
| 93 | require $module; | ||||||
| 94 | }; | ||||||
| 95 | 735 | 3608 | return if $@; | ||||
| 96 | |||||||
| 97 | 735 | 12252 | return $module->new(%opts); | ||||
| 98 | } | ||||||
| 99 | |||||||
| 100 | sub _auto_backend { | ||||||
| 101 | 216 | 291 | my ($self, $needs, %opts) = @_; | ||||
| 102 | |||||||
| 103 | 216 | 282 | foreach my $backend (@BACKENDS) { | ||||
| 104 | 216 | 426 | my $module = $self->_load_backend($BACKEND{$backend}, %opts); | ||||
| 105 | |||||||
| 106 | 216 | 504 | if ($needs->{api} eq 'verify') { | ||||
| 107 | 9 | 18 | next if ! $module->has_verify_cmd(); | ||||
| 108 | } else { | ||||||
| 109 | 207 | 483 | next if ! $module->has_backend_cmd(); | ||||
| 110 | } | ||||||
| 111 | 216 | 435 | next if $needs->{keystore} && ! $module->has_keystore(); | ||||
| 112 | |||||||
| 113 | 216 | 711 | return $module; | ||||
| 114 | } | ||||||
| 115 | |||||||
| 116 | # Otherwise load a dummy backend. | ||||||
| 117 | 0 | 0 | return Dpkg::OpenPGP::Backend->new(); | ||||
| 118 | } | ||||||
| 119 | |||||||
| 120 | sub can_use_secrets { | ||||||
| 121 | 570 | 0 | 1286 | my ($self, $key) = @_; | |||
| 122 | |||||||
| 123 | 570 | 3752 | return 0 unless $self->{backend}->has_backend_cmd(); | ||||
| 124 | 570 | 2285 | return 0 if $key->type eq 'keyfile' && ! -f $key->handle; | ||||
| 125 | 570 | 994 | return 0 if $key->type eq 'keystore' && ! -e $key->handle; | ||||
| 126 | 570 | 3369 | return 0 unless $self->{backend}->can_use_key($key); | ||||
| 127 | 570 | 1244 | return 1; | ||||
| 128 | } | ||||||
| 129 | |||||||
| 130 | sub get_trusted_keyrings { | ||||||
| 131 | 0 | 0 | 0 | my $self = shift; | |||
| 132 | |||||||
| 133 | 0 | 0 | return $self->{backend}->get_trusted_keyrings(); | ||||
| 134 | } | ||||||
| 135 | |||||||
| 136 | sub armor { | ||||||
| 137 | 2121 | 0 | 8131 | my ($self, $type, $in, $out) = @_; | |||
| 138 | |||||||
| 139 | 2121 | 10303 | return $self->{backend}->armor($type, $in, $out); | ||||
| 140 | } | ||||||
| 141 | |||||||
| 142 | sub dearmor { | ||||||
| 143 | 1404 | 0 | 4896 | my ($self, $type, $in, $out) = @_; | |||
| 144 | |||||||
| 145 | 1404 | 5504 | return $self->{backend}->dearmor($type, $in, $out); | ||||
| 146 | } | ||||||
| 147 | |||||||
| 148 | sub inline_verify { | ||||||
| 149 | 1854 | 0 | 7034 | my ($self, $inlinesigned, $data, @certs) = @_; | |||
| 150 | |||||||
| 151 | 1854 | 9362 | return $self->{backend}->inline_verify($inlinesigned, $data, @certs); | ||||
| 152 | } | ||||||
| 153 | |||||||
| 154 | sub verify { | ||||||
| 155 | 1212 | 0 | 3329 | my ($self, $data, $sig, @certs) = @_; | |||
| 156 | |||||||
| 157 | 1212 | 5697 | return $self->{backend}->verify($data, $sig, @certs); | ||||
| 158 | } | ||||||
| 159 | |||||||
| 160 | sub inline_sign { | ||||||
| 161 | 570 | 0 | 1105 | my ($self, $data, $inlinesigned, $key) = @_; | |||
| 162 | |||||||
| 163 | 570 | 1559 | return $self->{backend}->inline_sign($data, $inlinesigned, $key); | ||||
| 164 | } | ||||||
| 165 | |||||||
| 166 - 172 | =head1 CHANGES =head2 Version 0.xx This is a private module. =cut | ||||||
| 173 | |||||||
| 174 | 1; | ||||||