Commit 097ff8e6 authored by paz's avatar paz

Fix handling protected subject.

Enigmail sends a "protected subject" since v2.0, which leaked due to the
way mail-gpg copies headers from and to mime-parts.
Also since the first mime-part in those messages is always a "protected
headers" part, request-messages were bounced as empty because we only
look into the first mime part.

This fix still has one shortcoming: the real, "protected" subject is not
included into the primary mime-headers of the encrypted content. It is
only contained in the "protected headers" mime-part which people get to
read as part of the body. We need a change in mail-gpg to fix this.
parent d81e0996
Pipeline #13178 passed with stages
in 27 minutes and 6 seconds
......@@ -11,6 +11,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
* To identify broken Microsoft Exchange messages, check if the headers include 'X-MS-Exchange' instead of specific domain names. Before this, we've missed mails sent by Exchange installations not operated by Microsoft or mails with a different "originating organisation domain" than Hotmail or Outlook. (#333)
* Do not anymore fail on emails containing any PGP boundaries as part of their plain text. As a sideeffect we will not anymore validate an email a second time. Hence, a message part containing an additional signature within an encrypted (and possibly signed) email won't be validated and removed. (#261)
* Exit with code 1 if a CLI-subcommand was not found (#339).
* Fix finding keywords in request-messages that were sent from Thunderbird/Enigmail with enabled "protected subject".
* Fix leaking the "protected subject" sent from Thunderbird/Enigmail.
### Changed
......
......@@ -16,6 +16,7 @@ module Mail
attr_accessor :recipient
attr_accessor :original_message
attr_accessor :list
attr_accessor :protected_subject
# TODO: This should be in initialize(), but I couldn't understand the
# strange errors about wrong number of arguments when overriding
......@@ -46,6 +47,20 @@ module Mail
self.dynamic_pseudoheaders.each do |str|
new.add_pseudoheader(str)
end
# Store previously protected subject for later access.
# mail-gpg pulls headers from the decrypted mime parts "up" into the main
# headers, which reveals protected subjects.
if self.subject != new.subject
new.protected_subject = self.subject.dup
# Delete the protected headers which might leak information.
if new.parts.first.content_type == "text/rfc822-headers; protected-headers=v1"
new.parts.shift
end
end
new
end
......@@ -54,7 +69,7 @@ module Mail
clean.list = self.list
clean.gpg self.list.gpg_sign_options
clean.from = list.email
clean.subject = self.subject
clean.subject = self.protected_subject || self.subject
clean.add_msgids(list, self)
clean.add_list_headers(list)
......@@ -66,6 +81,13 @@ module Mail
clean.add_part new_part
end
if self.protected_subject.present?
new_part = Mail::Part.new
new_part.content_type = "text/rfc822-headers; protected-headers=v1"
new_part.body = "Subject: #{self.subject}\n"
clean.add_part new_part
end
# Attach body or mime-parts in a new wrapper-part, to preserve the
# original mime-structure.
# We can't use self.to_s here — that includes all the headers we *don't*
......
From - Fri Sep 29 10:33:00 2017
Subject: Encrypted Message
From: paz <paz@nadir.org>
To: schleuder-request@example.org
Message-ID: <f87a8288-a7cd-4ab0-1b2b-f5ea48cff2e2@nadir.org>
Date: Fri, 29 Sep 2017 10:33:00 +0200
MIME-Version: 1.0
Content-Type: multipart/encrypted;
protocol="application/pgp-encrypted";
boundary="NNqdAeeD0BMoMnLVbGvlJ93USlrgv66Hi"
This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)
--NNqdAeeD0BMoMnLVbGvlJ93USlrgv66Hi
Content-Type: application/pgp-encrypted
Content-Description: PGP/MIME version identification
Version: 1
--NNqdAeeD0BMoMnLVbGvlJ93USlrgv66Hi
Content-Type: application/octet-stream; name="encrypted.asc"
Content-Description: OpenPGP encrypted message
Content-Disposition: inline; filename="encrypted.asc"
-----BEGIN PGP MESSAGE-----
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
QO+1dOvJpclKws4ZKEkZcAjxKCd+DPjodK4=
=msZE
-----END PGP MESSAGE-----
--NNqdAeeD0BMoMnLVbGvlJ93USlrgv66Hi--
From - Fri Sep 29 10:33:00 2017
Subject: Encrypted Message
From: paz <paz@nadir.org>
To: schleuder@example.org
Message-ID: <f87a8288-a7cd-4ab0-1b2b-f5ea48cff2e2@nadir.org>
Date: Fri, 29 Sep 2017 10:33:00 +0200
MIME-Version: 1.0
Content-Type: multipart/encrypted;
protocol="application/pgp-encrypted";
boundary="NNqdAeeD0BMoMnLVbGvlJ93USlrgv66Hi"
This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)
--NNqdAeeD0BMoMnLVbGvlJ93USlrgv66Hi
Content-Type: application/pgp-encrypted
Content-Description: PGP/MIME version identification
Version: 1
--NNqdAeeD0BMoMnLVbGvlJ93USlrgv66Hi
Content-Type: application/octet-stream; name="encrypted.asc"
Content-Description: OpenPGP encrypted message
Content-Disposition: inline; filename="encrypted.asc"
-----BEGIN PGP MESSAGE-----
hQIMA691X8Gl2MArAQ/9EkuJLshPrMOSe38BjyUBe+1L2hUQOxBd0MI0d/C0Yadj
7YtlwveeqTpLGuT7H+ecaVlhMC9KFL4NT8v64D2e4S68wymVHUqO8SezMW8Bp5ut
2psZb+/KqF7oKLkkOu6neKo8PODrDcPK5pQGBBdV9DP2Z7uNfSyTJvVfNsf/3Q7e
mpQAgj9g2uooMPSqNRhOOrLPL6uWPIkfcvnt1gb4eG++ltpBD243yRxnUFrUxghq
rVH6V1la0d/WO3sLOu3oVAC71NPNq5DilVFfKl+/H5BwK54pmmuvu05JKgZw1QqJ
lImWRFv8GPmeyvqu9F0A4E0e4aFIly5/uHrBq0uw7R/gmeUICcwb28/ZftPj2ZEr
O9C0flYVwWB3cor5owM0rOtcgbwBI6EvSQ1d51qNA1PnpIu7woptFl10tguBiJ5X
HmrK+nOaXy1Rf/clrrmd/BeLtuXheb+N6WpWgiwV1MSZqP8IFBYq7R/STQpWyhxO
qmMGx27iJmTHx1nQpfzZybiecws1oOHY/gOc7uI1I4+zfitdRBsOozQDB8K8lEjK
3lsDmQoCu8GUQJj6t6OGn5YlEQ+oSGNc189sDThgGG5KDVGqd5OoI0ckxWam1GeR
b40imecyWm5v2aejOaHisK463YsUSO8HsIUDEtCllvl4gF1dxeUvflWKSNqqwrPS
wS4BC3VdOj2RY6vxtTBpfWLqLqsMQ970wXV9oKCLSrbobgJSwUleU3I1WGhXegDI
hBxRFvYIDr3R6OTDnbGTnB7We//mk5GN5eXAMs5o7Zqcn54Mox471x8Veg1dUoj2
2c6/Vgg5yX1cy+5SaZGSYDeKbyx2PSoMXZZWQHQ+KPe527gLAzpoeUAWN1H+lU6y
eORjBBlk/GQF15r5BmytQraTqsJTRG22SpycpYNugzgJPzozdjXGZ5Vdz9UHo3FC
Ch6gNXjeDXNCJ8PRQr3LQKrIsT6nE7zmF0N69LwJfMSm5MYIJnkhJ5tzJ/7MmcUr
OfgVkorhjM2oz4w8imI+2xFy4LhOKYEr0JHBN8X5QZ5yYQ2CVPDX3MwvpW0qn5PH
iQSC99Kabne9rmCByx7Ue+WUCZkuTJq201U0iSf2gNu2e8ebz+Y0ZxJ7JgH1eqyU
MLfSxyFry3JQ84zHgIFJV6EPmk4W+JhsdoPGTYghsUYpBaGsn/e1JPhpn3+mQnPV
+KH+x2ES9EmSMmHYBV5RY7YQB31hqnazY+omqSCgZotBq18/jHg2fnzEtvzj0fEr
PgMyC/zUcSTWknToRhU7dVFzYs19/1vnJJthAQxH7Zbx5kfisYVMcyh2OSEpaPH/
C1d7wjZUT2goLpGaDYK+xQ==
=u70c
-----END PGP MESSAGE-----
--NNqdAeeD0BMoMnLVbGvlJ93USlrgv66Hi--
require "spec_helper"
describe "protected subject" do
it "is not leaked" do
list = create(:list)
list.subscribe("schleuder@example.org", '59C71FB38AEE22E091C78259D06350440F759BD3', true)
mail = Mail.read("spec/fixtures/mails/protected-headers.eml")
mail.deliver
encrypted_mail = Mail::TestMailer.deliveries.first
Mail::TestMailer.deliveries.clear
begin
Schleuder::Runner.new().run(encrypted_mail.to_s, list.email)
rescue SystemExit
end
raw = Mail::TestMailer.deliveries.first
expect(raw.subject).to eql('Encrypted Message')
teardown_list_and_mailer(list)
end
it "is included as mime-part in body" do
list = create(:list)
list.subscribe("schleuder@example.org", '59C71FB38AEE22E091C78259D06350440F759BD3', true)
mail = Mail.read("spec/fixtures/mails/protected-headers.eml")
mail.deliver
encrypted_mail = Mail::TestMailer.deliveries.first
Mail::TestMailer.deliveries.clear
begin
Schleuder::Runner.new().run(encrypted_mail.to_s, list.email)
rescue SystemExit
end
raw = Mail::TestMailer.deliveries.first
message = Mail.create_message_to_list(raw.to_s, list.request_address, list).setup
expect(message.parts[1].body.to_s).to eql("Subject: Re: the real subject\n")
teardown_list_and_mailer(list)
end
it "don't block request-messages" do
list = create(:list, email: 'something@example.org')
list.subscribe("schleuder@example.org", '59C71FB38AEE22E091C78259D06350440F759BD3', true)
mail = Mail.read("spec/fixtures/mails/protected-headers-request.eml")
mail.deliver
encrypted_mail = Mail::TestMailer.deliveries.first
Mail::TestMailer.deliveries.clear
begin
Schleuder::Runner.new().run(encrypted_mail.to_s, list.request_address)
rescue SystemExit
end
raw = Mail::TestMailer.deliveries.first
message = Mail.create_message_to_list(raw.to_s, list.request_address, list).setup
expect(message.body.to_s).to include('59C71FB38AEE22E091C78259D06350440F759BD3')
teardown_list_and_mailer(list)
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment