summaryrefslogtreecommitdiffstats
path: root/extensions/SecureMail
diff options
context:
space:
mode:
authorDylan William Hardison <dylan@hardison.net>2018-07-08 06:59:55 +0200
committerDylan William Hardison <dylan@hardison.net>2018-07-08 06:59:55 +0200
commitbe1f92450788dc89280c9e04a4bf983b5d7fac54 (patch)
treeb5513fd846597fe5f152177dbbda88dca08fdf5f /extensions/SecureMail
parent9bbd8d368598046c47964ee043620621b6c3634b (diff)
parent446a08b30b0dbaac9f2b88e0a5cad410f0446140 (diff)
downloadbugzilla-be1f92450788dc89280c9e04a4bf983b5d7fac54.tar.gz
bugzilla-be1f92450788dc89280c9e04a4bf983b5d7fac54.tar.xz
Merge remote-tracking branch 'bmo/master'
Diffstat (limited to 'extensions/SecureMail')
-rw-r--r--extensions/SecureMail/Extension.pm61
-rw-r--r--extensions/SecureMail/lib/TCT.pm112
-rw-r--r--extensions/SecureMail/template/en/default/hook/admin/users/userdata-end.html.tmpl4
3 files changed, 142 insertions, 35 deletions
diff --git a/extensions/SecureMail/Extension.pm b/extensions/SecureMail/Extension.pm
index 1595fe98c..2b5e1bdd6 100644
--- a/extensions/SecureMail/Extension.pm
+++ b/extensions/SecureMail/Extension.pm
@@ -27,6 +27,7 @@ use warnings;
use base qw(Bugzilla::Extension);
+use Bugzilla::Logging;
use Bugzilla::Attachment;
use Bugzilla::Comment;
use Bugzilla::Group;
@@ -35,6 +36,7 @@ use Bugzilla::User;
use Bugzilla::Util qw(trim trick_taint is_7bit_clean);
use Bugzilla::Error;
use Bugzilla::Mailer;
+use Bugzilla::Extension::SecureMail::TCT;
use Crypt::OpenPGP::Armour;
use Crypt::OpenPGP::KeyRing;
@@ -128,9 +130,12 @@ sub object_validators {
if ($value =~ /PUBLIC KEY/) {
# PGP keys must be ASCII-armoured.
- if (!Crypt::OpenPGP::Armour->unarmour($value)) {
- ThrowUserError('securemail_invalid_key',
- { errstr => Crypt::OpenPGP::Armour->errstr });
+ my $tct = Bugzilla::Extension::SecureMail::TCT->new(
+ public_key => $value,
+ command => Bugzilla->localconfig->{tct_bin},
+ );
+ unless ($tct->is_valid->get) {
+ ThrowUserError( 'securemail_invalid_key', { errstr => 'key is invalid or expired' } );
}
}
elsif ($value =~ /BEGIN CERTIFICATE/) {
@@ -471,8 +476,10 @@ sub _make_secure {
# PGP Encryption #
##################
- my $pubring = new Crypt::OpenPGP::KeyRing(Data => $key);
- my $pgp = new Crypt::OpenPGP(PubRing => $pubring);
+ my $tct = Bugzilla::Extension::SecureMail::TCT->new(
+ public_key => $key,
+ command => Bugzilla->localconfig->{tct_bin},
+ );
if (scalar $email->parts > 1) {
my $old_boundary = $email->{ct}{attributes}{boundary};
@@ -511,7 +518,7 @@ sub _make_secure {
disposition => 'inline',
encoding => '7bit',
},
- body => _pgp_encrypt($pgp, $to_encrypt, $bug_id)
+ body => _tct_encrypt($tct, $to_encrypt, $bug_id)
),
);
$email->parts_set(\@new_parts);
@@ -528,7 +535,7 @@ sub _make_secure {
if ($sanitise_subject) {
_insert_subject($email, $subject);
}
- $email->body_set(_pgp_encrypt($pgp, $email->body, $bug_id));
+ $email->body_set(_tct_encrypt($tct, $email->body, $bug_id));
}
}
@@ -604,33 +611,21 @@ sub _make_secure {
}
}
-sub _pgp_encrypt {
- my ($pgp, $text, $bug_id) = @_;
- # "@" matches every key in the public key ring, which is fine,
- # because there's only one key in our keyring.
- #
- # We use the CAST5 cipher because the Rijndael (AES) module doesn't
- # like us for some reason I don't have time to debug fully.
- # ("key must be an untainted string scalar")
- my $encrypted = $pgp->encrypt(
- Data => $text,
- Recipients => "@",
- Cipher => 'CAST5',
- Armour => 0
- );
- if (!defined $encrypted) {
- return 'Error during Encryption: ' . $pgp->errstr;
+sub _tct_encrypt {
+ my ($tct, $text, $bug_id) = @_;
+
+ my $comment = Bugzilla->localconfig->{urlbase} . ( $bug_id ? 'show_bug.cgi?id=' . $bug_id : '' );
+ my $encrypted;
+ my $ok = eval { $encrypted = $tct->encrypt( $text, $comment )->get; 1 };
+ if (!$ok) {
+ WARN("Error: $@");
+ $encrypted = "$comment\nOpenPGP Encryption failed. Check if your key is expired.";
}
- $encrypted = Crypt::OpenPGP::Armour->armour(
- Data => $encrypted,
- Object => 'MESSAGE',
- Headers => {
- Comment => Bugzilla->localconfig->{urlbase} . ($bug_id ? 'show_bug.cgi?id=' . $bug_id : ''),
- },
- );
- # until Crypt::OpenPGP makes the Version header optional we have to strip
- # it out manually (bug 1181406).
- $encrypted =~ s/\nVersion:[^\n]+//;
+ elsif (!$encrypted) {
+ WARN('message empty!');
+ $encrypted = "$comment\nOpenPGP Encryption failed for unknown reason.";
+ }
+
return $encrypted;
}
diff --git a/extensions/SecureMail/lib/TCT.pm b/extensions/SecureMail/lib/TCT.pm
new file mode 100644
index 000000000..3a16309c2
--- /dev/null
+++ b/extensions/SecureMail/lib/TCT.pm
@@ -0,0 +1,112 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+# This Source Code Form is "Incompatible With Secondary Licenses", as
+# defined by the Mozilla Public License, v. 2.0.
+
+package Bugzilla::Extension::SecureMail::TCT;
+use 5.10.1;
+use Moo;
+
+use Bugzilla::DaemonControl qw( on_finish on_exception );
+use File::Temp;
+use Future::Utils qw(call);
+use Future;
+use IO::Async::Process;
+
+has 'public_key' => ( is => 'ro', required => 1 );
+has 'public_key_file' => ( is => 'lazy' );
+has 'is_valid' => ( is => 'lazy' );
+has 'command' => ( is => 'ro', default => 'tct' );
+
+sub _build_public_key_file {
+ my ($self) = @_;
+ my $fh = File::Temp->new(SUFFIX => '.pubkey');
+ $fh->print($self->public_key);
+ $fh->close;
+ return $fh;
+}
+
+sub _build_is_valid {
+ my ($self) = @_;
+
+ my $loop = IO::Async::Loop->new;
+ my $exit_f = $loop->new_future;
+ my ($stderr, $stdout);
+ my $process = IO::Async::Process->new(
+ command => [$self->command, 'check', '-k', $self->public_key_file ],
+ stderr => {
+ into => \$stderr,
+ },
+ stdout => {
+ into => \$stdout,
+ },
+ on_finish => on_finish($exit_f),
+ on_exception => on_exception($self->command, $exit_f),
+ );
+ $loop->add($process);
+
+ return $exit_f->then(
+ sub {
+ my ($rv) = @_;
+ Future->wrap($rv == 0);
+ }
+ );
+}
+
+sub encrypt {
+ my ($self, $input, $comment) = @_;
+ $self->is_valid->then(
+ sub {
+ my ($is_valid) = @_;
+ call {
+ die 'invalid public key!' unless $is_valid;
+
+ my $output;
+ my $loop = IO::Async::Loop->new;
+ my $exit_f = $loop->new_future;
+ my @command = ( $self->command, 'encrypt', '-k', $self->public_key_file );
+ push @command, '--comment', $comment if $comment;
+ my $process = IO::Async::Process->new(
+ command => \@command,
+ stdin => {
+ from => $input,
+ },
+ stdout => {
+ into => \$output,
+ },
+ on_finish => on_finish($exit_f),
+ on_exception => on_exception($self->command, $exit_f),
+ );
+ $loop->add($process);
+
+ return $exit_f->then(sub { Future->wrap($output) });
+ }
+ }
+ );
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Extension::SecureMail::TCT - An interface to the tct program
+
+=head1 SYNOPSIS
+
+ my $key = <<'PUBLIC_KEY';
+ -----BEGIN PGP PUBLIC KEY BLOCK-----
+
+ mQINBFakJSsBEACbDwHztgZaVhIb6f4PN0KbXv5BEciqKNbdVLgWQJyqgEMIwTF7
+ ...
+ o858gRM=
+ =t9lA
+ -----END PGP PUBLIC KEY BLOCK-----
+ PUBLIC_KEY
+
+ my $tct = Bugzilla::Extension::SecureMail::TCT->new(public_key => $key);
+ my $encrypted = $tct->encrypt("message", "comment goes here")->get;
+
diff --git a/extensions/SecureMail/template/en/default/hook/admin/users/userdata-end.html.tmpl b/extensions/SecureMail/template/en/default/hook/admin/users/userdata-end.html.tmpl
index a90266dae..e5e299ef9 100644
--- a/extensions/SecureMail/template/en/default/hook/admin/users/userdata-end.html.tmpl
+++ b/extensions/SecureMail/template/en/default/hook/admin/users/userdata-end.html.tmpl
@@ -6,7 +6,7 @@
# defined by the Mozilla Public License, v. 2.0.
#%]
-[% RETURN UNLESS otheruser.id %]
+[% RETURN UNLESS otheruser.id && user.in_group('editusers') %]
<tr>
<th>Has Secure Mail Key/Cert:</th>
@@ -14,7 +14,7 @@
[% otheruser.public_key ? "Yes" : "No" %]
</td>
</tr>
-
+
<tr>
<th>Member of Secure Mail Group:</th>
<td>