[Rt-commit] rt branch, smime, updated. rt-3.8.7-175-g3416f00
Ruslan Zakirov
ruz at bestpractical.com
Tue Feb 9 19:18:51 EST 2010
The branch, smime has been updated
via 3416f000dea20885ee2816f7ec320d9f91b613b9 (commit)
via 61e51f51aa4d3d923a8d2a21af6f9eba5e643e76 (commit)
via d29f81a0191ecfa3d87898e31b4cbf03e34d3348 (commit)
via 66b0cfc384fb107172a314746db239195716e5e8 (commit)
via 3e293e66602e9695a56d7582a10eda3a6c4ddd6d (commit)
via 2f2caa898166c76cfed3961dd0e403d57f6c685c (commit)
via 9ce9b9472d5598e1d7d4d0d29483bd8c6498b6ee (commit)
from cf1b8997220d5efe1e07e8592b5903225febf0b3 (commit)
Summary of changes:
lib/RT/Crypt/SMIME.pm | 164 +++++++++++++++++++++++++++++-----
lib/RT/Interface/Email/Auth/Crypt.pm | 7 +-
t/mail/smime/realmail.t | 4 +-
3 files changed, 148 insertions(+), 27 deletions(-)
- Log -----------------------------------------------------------------
commit 9ce9b9472d5598e1d7d4d0d29483bd8c6498b6ee
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Feb 10 03:06:09 2010 +0300
fix number of tests and signer idententity
diff --git a/t/mail/smime/realmail.t b/t/mail/smime/realmail.t
index 65c6f23..1d710c4 100644
--- a/t/mail/smime/realmail.t
+++ b/t/mail/smime/realmail.t
@@ -2,7 +2,7 @@
use strict;
use warnings;
-use RT::Test tests => 197;
+use RT::Test tests => 89;
my $openssl = RT::Test->find_executable('openssl');
plan skip_all => 'openssl executable is required.'
@@ -116,7 +116,7 @@ sub email_ok {
if ($usage =~ /signed/) {
is( $msg->GetHeader('X-RT-Incoming-Signature'),
- 'RT Test <sender at example.com>',
+ '"sender" <sender at example.com>',
"$eid: recorded incoming mail that is signed"
);
}
commit 2f2caa898166c76cfed3961dd0e403d57f6c685c
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Feb 10 03:08:18 2010 +0300
one entity may have information about multiple crypt runs
diff --git a/lib/RT/Interface/Email/Auth/Crypt.pm b/lib/RT/Interface/Email/Auth/Crypt.pm
index b716f82..7d87147 100644
--- a/lib/RT/Interface/Email/Auth/Crypt.pm
+++ b/lib/RT/Interface/Email/Auth/Crypt.pm
@@ -144,12 +144,13 @@ sub GetCurrentUser {
my $decrypted;
foreach my $protocol ( @check_protocols ) {
- my $status = $part->head->get( "X-RT-$protocol-Status" );
- next unless $status;
+ my @status = grep defined && length,
+ $part->head->get( "X-RT-$protocol-Status" );
+ next unless @status;
push @found, $protocol;
- for ( RT::Crypt->ParseStatus( Protocol => $protocol, Status => $status ) ) {
+ for ( map RT::Crypt->ParseStatus( Protocol => $protocol, Status => "$_" ), @status ) {
if ( $_->{Operation} eq 'Decrypt' && $_->{Status} eq 'DONE' ) {
$decrypted = 1;
}
commit 3e293e66602e9695a56d7582a10eda3a6c4ddd6d
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Feb 10 03:11:21 2010 +0300
ParsePKCS7Info - to figure out who signed a message
diff --git a/lib/RT/Crypt/SMIME.pm b/lib/RT/Crypt/SMIME.pm
index f9f49e8..0739117 100644
--- a/lib/RT/Crypt/SMIME.pm
+++ b/lib/RT/Crypt/SMIME.pm
@@ -522,6 +522,22 @@ sub GetCertificateInfo {
return %res;
}
+my %SHORT_NAMES = (
+ C => 'Country',
+ ST => 'StateOrProvince',
+ O => 'Organization',
+ OU => 'OrganizationUnit',
+ CN => 'Name',
+);
+my %LONG_NAMES = (
+ countryName => 'Country',
+ stateOrProvinceName => 'StateOrProvince',
+ organizationName => 'Organization',
+ organizationalUnitName => 'OrganizationUnit',
+ commonName => 'Name',
+ emailAddress => 'EmailAddress',
+);
+
sub CanonicalizeInfo {
my $self = shift;
my %info = @_;
@@ -530,19 +546,17 @@ sub CanonicalizeInfo {
# XXX: trust is not implmented for SMIME
TrustLevel => 1,
);
- {
- my $subject = delete $info{'Certificate'}{'Data'}{'Subject'};
- $res{'User'} = [{
- Country => $subject->{'countryName'},
- StateOrProvince => $subject->{'stateOrProvinceName'},
- Organization => $subject->{'organizationName'},
- OrganizationUnit => $subject->{'organizationalUnitName'},
- }];
- my $email = Email::Address->new( @{$subject}{'commonName', 'emailAddress'} );
- $res{'User'}[-1]{'String'} = $email->format;
+ if ( my $subject = delete $info{'Certificate'}{'Data'}{'Subject'} ) {
+ $res{'User'} = [
+ { $self->CanonicalizeUserInfo( %$subject ) },
+ ];
}
- {
- my $validity = delete $info{'Certificate'}{'Data'}{'Validity'};
+ if ( my $issuer = delete $info{'Certificate'}{'Data'}{'Issuer'} ) {
+ $res{'Issuer'} = [
+ { $self->CanonicalizeUserInfo( %$issuer ) },
+ ];
+ }
+ if ( my $validity = delete $info{'Certificate'}{'Data'}{'Validity'} ) {
$res{'Created'} = $self->ParseDate( $validity->{'Not Before'} );
$res{'Expire'} = $self->ParseDate( $validity->{'Not After'} );
}
@@ -597,5 +611,52 @@ sub ParseCertificateInfo {
return %res;
}
+sub ParsePKCS7Info {
+ my $self = shift;
+ my $string = shift;
+
+ return () unless defined $string && length $string && $string =~ /\S/;
+
+ my @res = ({});
+ foreach my $str ( split /\r*\n/, $string ) {
+ if ( $str =~ /^\s*$/ ) {
+ push @res, {} if keys %{ $res[-1] };
+ } elsif ( my ($who, $values) = ($str =~ /^(subject|issuer)=(.*)$/i) ) {
+ my %info;
+ while ( $values =~ s{^/([a-z]+)=(.*?)(?=$|/[a-z]+=)}{}i ) {
+ $info{ $1 } = $2;
+ }
+ die "Couldn't parse PKCS7 info: $string" if $values;
+
+ $res[-1]{ ucfirst lc $who } = { $self->CanonicalizeUserInfo( %info ) };
+ }
+ else {
+ $res[-1]{'Content'} ||= '';
+ $res[-1]{'Content'} .= $str ."\n";
+ }
+ }
+
+ # oddly, but a certificate can be duplicated
+ my %seen;
+ @res = grep !$seen{ $_->{'Content'} }++, grep keys %$_, @res;
+ $_->{'User'} = delete $_->{'Subject'} foreach @res;
+
+ return @res;
+}
+
+sub CanonicalizeUserInfo {
+ my $self = shift;
+ my %info = @_;
+
+ my %res;
+ while ( my ($k, $v) = each %info ) {
+ $res{ $SHORT_NAMES{$k} || $LONG_NAMES{$k} || $k } = $v;
+ }
+ if ( $res{'EmailAddress'} ) {
+ my $email = Email::Address->new( @res{'Name', 'EmailAddress'} );
+ $res{'String'} = $email->format;
+ }
+ return %res;
+}
1;
commit 66b0cfc384fb107172a314746db239195716e5e8
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Feb 10 03:13:06 2010 +0300
FormatStatus function instead of composing string all the time
diff --git a/lib/RT/Crypt/SMIME.pm b/lib/RT/Crypt/SMIME.pm
index 0739117..789964b 100644
--- a/lib/RT/Crypt/SMIME.pm
+++ b/lib/RT/Crypt/SMIME.pm
@@ -262,6 +262,11 @@ sub DecryptRFC3851 {
if ( $res{'exit_code'} ) {
$res{'message'} = "openssl exitted with error code ". ($? >> 8)
." and error: $res{stderr}";
+ $res{'status'} = $self->FormatStatus({
+ Operation => 'Decrypt', Status => 'ERROR',
+ Message => 'Decryption failed',
+ EncryptedTo => $address,
+ });
return %res;
}
@@ -272,14 +277,30 @@ sub DecryptRFC3851 {
$args{'Data'}->parts([ $res_entity->parts ]);
$args{'Data'}->make_singlepart;
- $res{'status'} =
- "Operation: Decrypt\nStatus: DONE\n"
- ."Message: Decryption process succeeded\n"
- ."EncryptedTo: $address\n";
+ $res{'status'} = $self->FormatStatus({
+ Operation => 'Decrypt', Status => 'DONE',
+ Message => 'Decryption process succeeded',
+ EncryptedTo => $address,
+ });
return %res;
}
+sub FormatStatus {
+ my $self = shift;
+ my @status = @_;
+
+ my $res = '';
+ foreach ( @status ) {
+ $res .= "\n" if $res;
+ while ( my ($k, $v) = each %$_ ) {
+ $res .= $k .": ". $v ."\n";
+ }
+ }
+
+ return $res;
+}
+
sub ParseStatus {
my $self = shift;
my $status = shift;
commit d29f81a0191ecfa3d87898e31b4cbf03e34d3348
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Feb 10 03:15:55 2010 +0300
check that key file exists beforehead
diff --git a/lib/RT/Crypt/SMIME.pm b/lib/RT/Crypt/SMIME.pm
index 789964b..b385e3f 100644
--- a/lib/RT/Crypt/SMIME.pm
+++ b/lib/RT/Crypt/SMIME.pm
@@ -237,6 +237,8 @@ sub DecryptRFC3851 {
my $self = shift;
my %args = (Data => undef, Queue => undef, @_ );
+ my %res;
+
my $msg = $args{'Data'}->as_string;
my $action = 'correspond';
@@ -245,8 +247,25 @@ sub DecryptRFC3851 {
my $address = $action eq 'correspond'
? $args{'Queue'}->CorrespondAddress || RT->Config->Get('CorrespondAddress')
: $args{'Queue'}->CommentAddress || RT->Config->Get('CommentAddress');
+ my $key_file = File::Spec->catfile(
+ RT->Config->Get('SMIME')->{'Keyring'}, $address .'.pem'
+ );
+ unless ( -e $key_file && -r _ ) {
+ $res{'exit_code'} = 1;
+ $res{'status'} = $self->FormatStatus({
+ Operation => 'KeyCheck',
+ Status => 'MISSING',
+ Message => "Secret key for '$address' is not available",
+ Key => $address,
+ KeyType => 'secret',
+ });
+ $res{'User'} = {
+ String => $address,
+ SecretKeyMissing => 1,
+ };
+ return %res;
+ }
- my %res;
my $buf;
{
local $ENV{SMIME_PASS} = $self->GetPassphrase( Address => $address );
@@ -254,7 +273,7 @@ sub DecryptRFC3851 {
my $cmd = join( ' ', shell_quote(
$self->OpenSSLPath,
qw(smime -decrypt -passin env:SMIME_PASS),
- -recip => RT->Config->Get('SMIME')->{'Keyring'} .'/'. $address .'.pem',
+ -recip => $key_file,
) );
safe_run_child { run3( $cmd, \$msg, \$buf, \$res{'stderr'} ) };
$res{'exit_code'} = $?;
commit 61e51f51aa4d3d923a8d2a21af6f9eba5e643e76
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Feb 10 03:17:08 2010 +0300
message extracting exact option and postprocessing
diff --git a/lib/RT/Crypt/SMIME.pm b/lib/RT/Crypt/SMIME.pm
index b385e3f..5355b3e 100644
--- a/lib/RT/Crypt/SMIME.pm
+++ b/lib/RT/Crypt/SMIME.pm
@@ -289,7 +289,7 @@ sub DecryptRFC3851 {
return %res;
}
- my $res_entity = _extract_msg_from_buf( \$buf );
+ my $res_entity = _extract_msg_from_buf( \$buf, 1 );
$res_entity->make_multipart( 'mixed', Force => 1 );
$args{'Data'}->make_multipart( 'mixed', Force => 1 );
@@ -341,9 +341,11 @@ sub ParseStatus {
sub _extract_msg_from_buf {
my $buf = shift;
+ my $exact = shift;
my $rtparser = RT::EmailParser->new();
my $parser = MIME::Parser->new();
$rtparser->_SetupMIMEParser($parser);
+ $parser->decode_bodies(0) if $exact;
$parser->output_to_core(1);
unless ( $rtparser->{'entity'} = $parser->parse_data($$buf) ) {
$RT::Logger->crit("Couldn't parse MIME stream and extract the submessages");
@@ -355,7 +357,6 @@ sub _extract_msg_from_buf {
return (undef);
}
}
- $rtparser->_PostProcessNewEntity;
return $rtparser->Entity;
}
commit 3416f000dea20885ee2816f7ec320d9f91b613b9
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date: Wed Feb 10 03:18:19 2010 +0300
figure out signer of the message
diff --git a/lib/RT/Crypt/SMIME.pm b/lib/RT/Crypt/SMIME.pm
index 5355b3e..ae20332 100644
--- a/lib/RT/Crypt/SMIME.pm
+++ b/lib/RT/Crypt/SMIME.pm
@@ -32,7 +32,6 @@ sub SignEncrypt {
my $entity = $args{'Entity'};
-
my %res = (exit_code => 0, status => '');
my @keys;
@@ -210,15 +209,33 @@ sub VerifyRFC3851 {
if ( $res{'exit_code'} ) {
$res{'message'} = "openssl exitted with error code ". ($? >> 8)
." and error: $res{stderr}";
+ $RT::Logger->error($res{'message'});
return %res;
}
- my $res_entity = _extract_msg_from_buf( \$buf );
+ my @signers;
+ {
+ my $pkcs7_info;
+ local $SIG{CHLD} = 'DEFAULT';
+ my $cmd = join( ' ', shell_quote(
+ $self->OpenSSLPath, qw(smime -pk7out),
+ ) );
+ $cmd .= ' | '. join( ' ', shell_quote(
+ $self->OpenSSLPath, qw(pkcs7 -print_certs),
+ ) );
+ safe_run_child { run3( $cmd, \$msg, \$pkcs7_info, \$res{'stderr'} ) };
+ unless ( $? ) {
+ @signers = $self->ParsePKCS7Info( $pkcs7_info );
+ }
+ }
+
+ my $res_entity = _extract_msg_from_buf( \$buf, 1 );
unless ( $res_entity ) {
$res{'exit_code'} = 1;
$res{'message'} = "verified message, but couldn't parse result";
return %res;
}
+
$res_entity->make_multipart( 'mixed', Force => 1 );
$args{'Data'}->make_multipart( 'mixed', Force => 1 );
@@ -228,6 +245,7 @@ sub VerifyRFC3851 {
$res{'status'} =
"Operation: Verify\nStatus: DONE\n"
."Message: The signature is good\n"
+ ."UserString: ". $signers[0]{'User'}{'String'} ."\n"
;
return %res;
-----------------------------------------------------------------------
More information about the Rt-commit
mailing list