Browse Source

Fixes #3147 - S/MIME signing fails because of message encoding.

Rolf Schmidt 4 years ago
parent
commit
900d8fcd44
2 changed files with 52 additions and 1 deletions
  1. 20 0
      lib/secure_mailing/smime/outgoing.rb
  2. 32 1
      spec/lib/secure_mailing/smime_spec.rb

+ 20 - 0
lib/secure_mailing/smime/outgoing.rb

@@ -8,6 +8,8 @@ class SecureMailing::SMIME::Outgoing < SecureMailing::Backend::Handler
   def process
     return if !process?
 
+    @mail = workaround_mail_bit_encoding_issue(@mail)
+
     if @security[:sign][:success] && @security[:encryption][:success]
       processed = encrypt(signed)
       log('sign', 'success')
@@ -30,6 +32,24 @@ class SecureMailing::SMIME::Outgoing < SecureMailing::Backend::Handler
     @security[:sign][:success] || @security[:encryption][:success]
   end
 
+  # S/MIME signing fails because of message encoding #3147
+  # workaround for https://github.com/mikel/mail/issues/1190
+  def workaround_mail_bit_encoding_issue(mail)
+
+    # change 7bit/8bit encoding to binary so that
+    # base64 will be used to encode the content
+    if mail.body.encoding.include?('bit')
+      mail.body.encoding = :binary
+    end
+
+    # go into recursion for nested parts
+    mail.parts&.each do |part|
+      workaround_mail_bit_encoding_issue(part)
+    end
+
+    mail
+  end
+
   def overwrite_mail(processed)
     @mail.body = nil
     @mail.body = processed.body.encoded

+ 32 - 1
spec/lib/secure_mailing/smime_spec.rb

@@ -17,12 +17,14 @@ RSpec.describe SecureMailing::SMIME do
 
   let(:ca_certificate_subject) { '/emailAddress=ca@example.com/C=DE/ST=Berlin/L=Berlin/O=Example Security/OU=IT Department/CN=example.com' }
 
+  let(:content_type) { 'text/plain' }
+
   def build_mail
     Channel::EmailBuild.build(
       from:         sender_email_address,
       to:           recipient_email_address,
       body:         raw_body,
-      content_type: 'text/plain',
+      content_type: content_type,
       security:     security_preferences
     )
   end
@@ -92,6 +94,35 @@ RSpec.describe SecureMailing::SMIME do
 
           it_behaves_like 'HttpLog writer', 'failed'
         end
+
+        context 'when message is 7bit or 8bit encoded' do
+
+          let(:mail) do
+            smime_mail = build_mail
+
+            mail = Channel::EmailParser.new.parse(smime_mail.to_s)
+            SecureMailing.incoming(mail)
+
+            mail
+          end
+
+          context 'when Content-Type is text/plain' do
+            let(:raw_body) { "\r\n\r\n@john.doe, now known as John Dóe has accepted your invitation to join the Administrator / htmltest project.\r\n\r\nhttp://169.254.169.254:3000/root/htmltest\r\n\r\n-- \r\nYou're receiving this email because of your account on 169.254.169.254.\r\n\r\n\r\n\r\n" }
+
+            it 'verifies' do
+              expect(mail['x-zammad-article-preferences']['security']['sign']['success']).to be true
+            end
+          end
+
+          context 'when Content-Type is text/html' do
+            let(:content_type) { 'text/html' }
+            let(:raw_body) { "<div><ul><li><p>an \nexample „Text“ with ümläütß. </p></li></ul></div>" }
+
+            it 'verifies' do
+              expect(mail['x-zammad-article-preferences']['security']['sign']['success']).to be true
+            end
+          end
+        end
       end
 
       context 'no private key present' do