[Rt-commit] rt branch, 4.4/crypt-minor-fixes, updated. rt-4.4.4-243-gcce6227e08

Dianne Skoll dianne at bestpractical.com
Fri Feb 5 16:09:40 EST 2021


The branch, 4.4/crypt-minor-fixes has been updated
       via  cce6227e080013764694b0a38aa0b95cc70ab08c (commit)
      from  53e13897f11ac805df63f1c6d9c0a713ac9cad9e (commit)

Summary of changes:
 lib/RT/Crypt/SMIME.pm              | 49 ++++++++++++++++++++++++++++++++++++++
 share/html/Crypt/GetSMIMECert.html | 23 +++++++++++++-----
 2 files changed, 66 insertions(+), 6 deletions(-)

- Log -----------------------------------------------------------------
commit cce6227e080013764694b0a38aa0b95cc70ab08c
Author: Dianne Skoll <dianne at bestpractical.com>
Date:   Fri Feb 5 16:09:00 2021 -0500

    Download S/MIME certificate attached to transaction rather than user
    
    This guarantees that the certificate we download is the one that
    was actually used to sign the mail attached to the transaction.

diff --git a/lib/RT/Crypt/SMIME.pm b/lib/RT/Crypt/SMIME.pm
index e7540bb558..29b7295228 100644
--- a/lib/RT/Crypt/SMIME.pm
+++ b/lib/RT/Crypt/SMIME.pm
@@ -1255,4 +1255,53 @@ sub SupportsCRLfile {
     return $OpenSSL_Supports_CRLfile;
 };
 
+# Given a Transaction object, find the application/x-rt-original-message
+# (if any).  If found, try to find the S/MIME signature.  Return
+# the certificate found in that signature.
+# Returns: undef if we could not find a certificate; otherwise, an
+# S/MIME certificate in PEM format.
+sub GetCertificateForTransaction {
+    my ($self, $txn) = @_;
+
+    my $attachments = $txn->Attachments;
+    my $found;
+
+    # Look for the application/x-rt-original-message attachment
+    while (my $a = $attachments->Next) {
+        if (lc($a->ContentType) eq 'application/x-rt-original-message') {
+            $found = $a;
+            last;
+        }
+    }
+    return undef unless $found;
+
+    my $str = $found->Content;
+    return undef unless $str;
+
+    my $tmpdir = File::Temp::tempdir( TMPDIR => 1, CLEANUP => 1 );
+    my $p = MIME::Parser->new();
+    $p->output_dir($tmpdir);
+    my $entity = $p->parse_data($str);
+    return undef unless $entity;
+
+    # Now look for application/pkcs7-signature
+    $found = undef;
+    foreach my $part ($entity->parts_DFS) {
+        if (lc($part->mime_type) eq 'application/pkcs7-signature') {
+            $found = $part;
+            last;
+        }
+    }
+    return undef unless $found;
+    return undef unless $found->bodyhandle;
+
+    # Feed to openssl and extract the certificate
+    my $pkcs7 = $found->bodyhandle->as_string;
+    my $out = '';
+    my $err = '';
+    safe_run_child { run3( [$self->OpenSSLPath, 'pkcs7', '-inform', 'DER', '-print_certs' ],
+                           \$pkcs7, \$out, \$err ) };
+    return undef unless $out =~ /-----BEGIN CERTIFICATE-----/;
+    return $out;
+}
 1;
diff --git a/share/html/Crypt/GetSMIMECert.html b/share/html/Crypt/GetSMIMECert.html
index 99c9f1948b..e7b0bf822b 100644
--- a/share/html/Crypt/GetSMIMECert.html
+++ b/share/html/Crypt/GetSMIMECert.html
@@ -67,15 +67,26 @@ if (!$TxnId || $TxnId !~ /^\d+$/) {
     if (!$status) {
         push(@results, $msg);
     } else {
-        my $u = RT::User->new(RT->SystemUser);
-        $u->Load($txn->Creator);
-        if (!$u->id || !$u->SMIMECertificate) {
-            push(@results, loc('Could not find S/MIME certificate for specified user'));
+        my $cert = RT::Crypt::SMIME->GetCertificateForTransaction($txn);
+        if (!$cert) {
+            push(@results, loc('Could not find S/MIME certificate for specified transaction'));
         } else {
-            my $name = $u->EmailAddress || $u->Name || $u->id;
+            # We don't really need the user, but we try to get it
+            # anyway just to give the certificate a sensible filename
+            # when it is downloaded.  If we can't get the user, or the
+            # user lacks and email address and name, we just default
+            # to "smime.crt" for the download filename.
+            my $u = RT::User->new(RT->SystemUser);
+            my $name;
+            if ($txn->Creator) {
+                $u->Load($txn->Creator);
+                $name = $u->EmailAddress || $u->Name || "smime";
+            } else {
+                $name = "smime";
+            }
             $r->content_type('application/x-x509-user-cert');
             $r->header_out('Content-Disposition' => "attachment; filename=\"$name.crt\"");
-            $m->out($u->SMIMECertificate);
+            $m->out($cert);
             $m->flush_buffer;
             $m->abort();
         }

-----------------------------------------------------------------------


More information about the rt-commit mailing list