diff options
Diffstat (limited to 'src/mailman_pgp')
| -rw-r--r-- | src/mailman_pgp/pgp/inline.py | 22 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/mime.py | 25 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/base.py | 25 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/data/messages/clear_multipart.eml | 30 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/data/messages/inline_encrypted_multipart.eml | 30 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/data/messages/inline_signed_multipart.eml | 31 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/test_inline.py | 52 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/test_mime.py | 38 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/test_wrapper.py | 16 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/wrapper.py | 3 |
10 files changed, 245 insertions, 27 deletions
diff --git a/src/mailman_pgp/pgp/inline.py b/src/mailman_pgp/pgp/inline.py index d2ea05e..81e0839 100644 --- a/src/mailman_pgp/pgp/inline.py +++ b/src/mailman_pgp/pgp/inline.py @@ -91,10 +91,15 @@ class InlineWrapper: """ :return: + :rtype: typing.Generator[pgpy.PGPMessage] """ for part in walk(self.msg): if not part.is_multipart() and self._is_signed(part): - yield part.get_payload() + try: + msg = PGPMessage.from_blob(part.get_payload()) + except: + continue + yield msg def _is_encrypted(self, part): try: @@ -126,10 +131,15 @@ class InlineWrapper: """ :return: + :rtype: typing.Generator[pgpy.PGPMessage] """ for part in walk(self.msg): if not part.is_multipart() and self._is_encrypted(part): - yield part.get_payload() + try: + msg = PGPMessage.from_blob(part.get_payload()) + except: + continue + yield msg def _has_keys(self, part): try: @@ -178,10 +188,6 @@ class InlineWrapper: continue yield key - def _verify(self, part, key): - message = PGPMessage.from_blob(part.get_payload()) - return key.verify(message) - def verify(self, key): """ Verify the signatures of this message with key. @@ -191,9 +197,7 @@ class InlineWrapper: :return: The verified signatures. :rtype: Generator[pgpy.types.SignatureVerification] """ - for part in walk(self.msg): - if not part.is_multipart() and self._is_signed(part): - yield self._verify(part, key) + yield from map(key.verify, self.get_signature()) def _sign(self, pmsg, key, hash): smsg = copy.copy(pmsg) diff --git a/src/mailman_pgp/pgp/mime.py b/src/mailman_pgp/pgp/mime.py index c702eb8..2801b0f 100644 --- a/src/mailman_pgp/pgp/mime.py +++ b/src/mailman_pgp/pgp/mime.py @@ -98,8 +98,13 @@ class MIMEWrapper: """ :return: + :rtype: typing.Generator[pgpy.PGPSignature] """ - yield self.msg.get_payload(1).get_payload() + try: + msg = PGPSignature.from_blob(self.msg.get_payload(1).get_payload()) + except: + return + yield msg def is_encrypted(self): """ @@ -130,8 +135,13 @@ class MIMEWrapper: """ :return: + :rtype: typing.Generator[pgpy.PGPMessage] """ - yield self.msg.get_payload(1).get_payload() + try: + msg = PGPMessage.from_blob(self.msg.get_payload(1).get_payload()) + except: + return + yield msg def is_keys(self): """ @@ -202,9 +212,8 @@ class MIMEWrapper: :return: The verified signature. :rtype: Generator[pgpy.types.SignatureVerification] """ - clear_text = self.msg.get_payload(0).as_string() - sig_text = self.msg.get_payload(1).get_payload() - signature = PGPSignature.from_blob(sig_text) + clear_text = next(iter(self.get_signed())) + signature = next(iter(self.get_signature())) yield key.verify(clear_text, signature) def _micalg(self, hash_algo): @@ -250,7 +259,7 @@ class MIMEWrapper: :return: The signed message. :rtype: mailman.email.message.Message """ - payload = self.msg.as_string() + payload = next(iter(self.get_payload())) signature = key.sign(payload, hash=hash) return self._wrap_signed(self.msg, signature) @@ -263,7 +272,7 @@ class MIMEWrapper: :return: The decrypted message. :rtype: mailman.email.message.Message """ - msg_text = self.msg.get_payload(1).get_payload() + msg_text = next(iter(self.get_encrypted())) pmsg = PGPMessage() pmsg.parse(msg_text) decrypted = key.decrypt(pmsg) @@ -357,7 +366,7 @@ class MIMEWrapper: if len(keys) == 0: raise ValueError('At least one key necessary.') - payload = self.msg.as_string() + payload = next(iter(self.get_payload())) pmsg = PGPMessage.new(payload) pmsg |= key.sign(pmsg, hash=hash) pmsg = self._encrypt(pmsg, *keys, cipher=cipher, **kwargs) diff --git a/src/mailman_pgp/pgp/tests/base.py b/src/mailman_pgp/pgp/tests/base.py index 47d333c..e16c95e 100644 --- a/src/mailman_pgp/pgp/tests/base.py +++ b/src/mailman_pgp/pgp/tests/base.py @@ -41,9 +41,24 @@ def load_key(path): return key +def payload_equal(one_msg, other_msg): + one_payload = one_msg.get_payload() + other_payload = other_msg.get_payload() + if isinstance(one_payload, list) and isinstance(other_payload, list): + if len(one_payload) != len(other_payload): + return False + for one_inner, other_inner in zip(one_payload, other_payload): + if not payload_equal(one_inner, other_inner): + return False + return True + else: + return one_payload == other_payload + + class WrapperTestCase(TestCase): layer = PGPLayer wrapper = None + maxDiff = None def wrap(self, message): return self.wrapper(message) @@ -52,6 +67,10 @@ class WrapperTestCase(TestCase): wrapped = self.wrap(message) self.assertEqual(wrapped.is_signed(), signed) + def has_signature(self, message, has): + wrapped = self.wrap(message) + self.assertEqual(wrapped.has_signature(), has) + def sign(self, message, key): wrapped = self.wrap(message) signed = wrapped.sign(key) @@ -74,6 +93,10 @@ class WrapperTestCase(TestCase): wrapped = self.wrap(message) self.assertEqual(wrapped.is_encrypted(), encrypted) + def has_encryption(self, message, has): + wrapped = self.wrap(message) + self.assertEqual(wrapped.has_encryption(), has) + def encrypt(self, message, *keys, **kwargs): wrapped = self.wrap(message) encrypted = wrapped.encrypt(*keys, **kwargs) @@ -89,7 +112,7 @@ class WrapperTestCase(TestCase): decrypted_wrapped = self.wrap(decrypted) self.assertFalse(decrypted_wrapped.is_encrypted()) - self.assertEqual(decrypted.get_payload(), message.get_payload()) + self.assertTrue(payload_equal(decrypted, message)) def decrypt(self, message, key, clear): wrapped = self.wrap(message) diff --git a/src/mailman_pgp/pgp/tests/data/messages/clear_multipart.eml b/src/mailman_pgp/pgp/tests/data/messages/clear_multipart.eml new file mode 100644 index 0000000..bb3d638 --- /dev/null +++ b/src/mailman_pgp/pgp/tests/data/messages/clear_multipart.eml @@ -0,0 +1,30 @@ +To: nobody@example.org +From: RSA 1024b example <RSA-1024b@example.org> +Subject: Some subject. +Message-ID: <76a591ed-bfc4-d08b-73d3-fc2489148fd7@example.org> +Date: Wed, 21 Jun 2017 13:50:59 +0200 +User-Agent: Mutt/1.7.2 (2016-11-26) +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="------------8C227B46966E9FEACCAF3A2A" + +This is a multi-part message in MIME format. +--------------8C227B46966E9FEACCAF3A2A +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Some text. + +--------------8C227B46966E9FEACCAF3A2A +Content-Type: text/plain; charset=UTF-8; + name="unittest.cfg" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="unittest.cfg" + +W3VuaXR0ZXN0XQp2ZXJib3NlID0gMgpwbHVnaW5zID0gbm9zZTIucGx1Z2lucy5sYXllcnMK +ICAgICAgICAgIGZsdWZsLnRlc3Rpbmcubm9zZQoKW2xvZy1jYXB0dXJlXQphbHdheXMtb24g +PSBGYWxzZQoKW2xheWVyLXJlcG9ydGVyXQphbHdheXMtb24gPSBUcnVlCmNvbG9ycyA9IFRy +dWUKCltmbHVmbC50ZXN0aW5nXQphbHdheXMtb24gPSBUcnVlCnBhY2thZ2UgPSBtYWlsbWFu +X3BncApzdGFydF9ydW4gPSBtYWlsbWFuX3BncC50ZXN0aW5nLnN0YXJ0LnN0YXJ0X3J1bgo= +--------------8C227B46966E9FEACCAF3A2A-- diff --git a/src/mailman_pgp/pgp/tests/data/messages/inline_encrypted_multipart.eml b/src/mailman_pgp/pgp/tests/data/messages/inline_encrypted_multipart.eml new file mode 100644 index 0000000..9b29bf6 --- /dev/null +++ b/src/mailman_pgp/pgp/tests/data/messages/inline_encrypted_multipart.eml @@ -0,0 +1,30 @@ +To: nobody@example.org +From: RSA 1024b example <RSA-1024b@example.org> +Subject: Some subject. +Message-ID: <76a591ed-bfc4-d08b-73d3-fc2489148fd7@example.org> +Date: Wed, 21 Jun 2017 13:50:59 +0200 +User-Agent: Mutt/1.7.2 (2016-11-26) +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="abjqkjsfwqsfa546qw2wfq6sdq2sqwr56qqs" + +--abjqkjsfwqsfa546qw2wfq6sdq2sqwr56qqs +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +-----BEGIN PGP MESSAGE----- + +hIwD9aW4UkhFqMoBA/9MpeKT7jjrQGIDTH+3Hj5pzIwOsoYLeCETXkgWcACfozUh +bK5IP7W76jO2MPG/PQsa1cP0x25nH4kdYmsa4dzY+gWNfedspT2qGZvAM+zZ12nm +mTr+DmnAMgKIg95CPkAth8bIQUm4i0HGj3j0TjY/I9CSdxJu7twsf3E38yqpJtJR +AW2qZQM7waSpGjoSGhxS4mtFCjNRz7N6hXiG8DfuDdEUodXeGYTHuEU516W+Vv9f +LpjD8AZOm+L6QDpZ0pf7grIh3kQXx7OvyaLliy+OMxXq +=prUG +-----END PGP MESSAGE----- + +--abjqkjsfwqsfa546qw2wfq6sdq2sqwr56qqs +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Some cleartext. + +--abjqkjsfwqsfa546qw2wfq6sdq2sqwr56qqs--
\ No newline at end of file diff --git a/src/mailman_pgp/pgp/tests/data/messages/inline_signed_multipart.eml b/src/mailman_pgp/pgp/tests/data/messages/inline_signed_multipart.eml new file mode 100644 index 0000000..4bcca28 --- /dev/null +++ b/src/mailman_pgp/pgp/tests/data/messages/inline_signed_multipart.eml @@ -0,0 +1,31 @@ +To: nobody@example.org +From: RSA 1024b example <RSA-1024b@example.org> +Subject: Some subject. +Message-ID: <76a591ed-bfc4-d08b-73d3-fc2489148fd7@example.org> +Date: Wed, 21 Jun 2017 13:50:59 +0200 +User-Agent: Mutt/1.7.2 (2016-11-26) +MIME-Version: 1.0 +Content-Type: multipart/mixed; boundary="abjqkjsfwqsfa546qw2wfq6sdq2sqwr56qqs" + +--abjqkjsfwqsfa546qw2wfq6sdq2sqwr56qqs +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +-----BEGIN PGP MESSAGE----- + +owGbwMvMyMHo/pGHo6JlewTjackShkifww7B+bmpCsWZ6XmpKQolqRUlerxcHadY +GBk5GEzEFFmurPRo23hKYdoy174YmFZWJpA+MZmi4kRdQwMjkySH1IrE3IKcVL38 +onQGLk4BmEI7fRaGc493KbduNVhXdJ2xkTXCu+Hdj4B495MLzmn5c+6yVl/9Jluw +ckr44WOlYbsjuj/LtTnpiC54/Pho+a8AFo7YFU/efJp/LqbBc+uFmhUMPdzlv1+U +F+1/tvH/hrr/8wWPi13qSHkjceh1dT2z8ZWdvmbL5zPeu79flUVWVn+25dGOY8dP +yzJtAwA= +=jjlW +-----END PGP MESSAGE----- + +--abjqkjsfwqsfa546qw2wfq6sdq2sqwr56qqs +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Some cleartext. + +--abjqkjsfwqsfa546qw2wfq6sdq2sqwr56qqs--
\ No newline at end of file diff --git a/src/mailman_pgp/pgp/tests/test_inline.py b/src/mailman_pgp/pgp/tests/test_inline.py index 0a012f7..e2fccb7 100644 --- a/src/mailman_pgp/pgp/tests/test_inline.py +++ b/src/mailman_pgp/pgp/tests/test_inline.py @@ -37,8 +37,12 @@ class TestSigning(InlineWrapperTestCase): True), (load_message('inline_signed_corrupted.eml'), False), + (load_message('inline_signed_multipart.eml'), + False), (load_message('clear.eml'), False), + (load_message('clear_multipart.eml'), + False), (load_message('inline_encrypted.eml'), False) ]) @@ -46,9 +50,22 @@ class TestSigning(InlineWrapperTestCase): self.is_signed(message, signed) @parameterized.expand([ + (load_message('inline_signed_multipart.eml'), + True), + (load_message('inline_signed.eml'), + True), (load_message('clear.eml'), - load_key('rsa_1024.priv.asc')), + False), + (load_message('clear_multipart.eml'), + False) + ]) + def test_has_signature(self, message, has): + self.has_signature(message, has) + + @parameterized.expand([ (load_message('clear.eml'), + load_key('rsa_1024.priv.asc')), + (load_message('clear_multipart.eml'), load_key('ecc_p256.priv.asc')) ]) def test_sign(self, message, key): @@ -58,7 +75,7 @@ class TestSigning(InlineWrapperTestCase): (load_message('clear.eml'), load_key('rsa_1024.priv.asc'), load_key('rsa_1024.pub.asc')), - (load_message('clear.eml'), + (load_message('clear_multipart.eml'), load_key('ecc_p256.priv.asc'), load_key('ecc_p256.pub.asc')) ]) @@ -87,6 +104,8 @@ class TestEncryption(InlineWrapperTestCase): @parameterized.expand([ (load_message('inline_encrypted.eml'), True), + (load_message('inline_encrypted_multipart.eml'), + False), (load_message('inline_cleartext_signed.eml'), False), (load_message('inline_cleartext_signed_invalid.eml'), @@ -96,17 +115,34 @@ class TestEncryption(InlineWrapperTestCase): (load_message('inline_signed_corrupted.eml'), False), (load_message('clear.eml'), + False), + (load_message('clear_multipart.eml'), False) ]) def test_is_encrypted(self, message, encrypted): self.is_encrypted(message, encrypted) @parameterized.expand([ + (load_message('inline_encrypted.eml'), + True), + (load_message('inline_encrypted_multipart.eml'), + True), + (load_message('clear.eml'), + False), + (load_message('clear_multipart.eml'), + False) + ]) + def test_has_encryption(self, message, has): + self.has_encryption(message, has) + + @parameterized.expand([ (load_message('clear.eml'), load_key('rsa_1024.pub.asc')), (load_message('clear.eml'), (load_key('rsa_1024.pub.asc'), - load_key('ecc_p256.pub.asc'))) + load_key('ecc_p256.pub.asc'))), + (load_message('clear_multipart.eml'), + load_key('rsa_1024.pub.asc')), ]) def test_encrypt(self, message, keys, **kwargs): if isinstance(keys, tuple): @@ -118,7 +154,7 @@ class TestEncryption(InlineWrapperTestCase): (load_message('clear.eml'), load_key('rsa_1024.pub.asc'), load_key('rsa_1024.priv.asc')), - (load_message('clear.eml'), + (load_message('clear_multipart.eml'), load_key('ecc_p256.pub.asc'), load_key('ecc_p256.priv.asc')) ]) @@ -142,6 +178,8 @@ class TestKeys(InlineWrapperTestCase): True), (load_message('clear.eml'), False), + (load_message('clear_multipart.eml'), + False), (load_message('inline_cleartext_signed.eml'), False) ]) @@ -162,6 +200,9 @@ class TestCombined(InlineWrapperTestCase): @parameterized.expand([ (load_message('clear.eml'), load_key('rsa_1024.priv.asc'), + load_key('ecc_p256.priv.asc')), + (load_message('clear_multipart.eml'), + load_key('rsa_1024.priv.asc'), load_key('ecc_p256.priv.asc')) ]) def test_sign_encrypt_decrypt_verify(self, message, sign_key, encrypt_key): @@ -170,6 +211,9 @@ class TestCombined(InlineWrapperTestCase): @parameterized.expand([ (load_message('clear.eml'), load_key('rsa_1024.priv.asc'), + load_key('ecc_p256.priv.asc')), + (load_message('clear_multipart.eml'), + load_key('rsa_1024.priv.asc'), load_key('ecc_p256.priv.asc')) ]) def test_sign_then_encrypt_decrypt_verify(self, message, sign_key, diff --git a/src/mailman_pgp/pgp/tests/test_mime.py b/src/mailman_pgp/pgp/tests/test_mime.py index b45d924..5d983b8 100644 --- a/src/mailman_pgp/pgp/tests/test_mime.py +++ b/src/mailman_pgp/pgp/tests/test_mime.py @@ -34,15 +34,30 @@ class TestSigning(MIMEWrapperTestCase): (load_message('mime_signed_invalid.eml'), True), (load_message('clear.eml'), + False), + (load_message('clear_multipart.eml'), False) ]) def test_is_signed(self, message, signed): self.is_signed(message, signed) @parameterized.expand([ + (load_message('mime_signed.eml'), + True), + (load_message('mime_signed_invalid.eml'), + True), (load_message('clear.eml'), - load_key('rsa_1024.priv.asc')), + False), + (load_message('clear_multipart.eml'), + False) + ]) + def test_has_signature(self, message, has): + self.has_signature(message, has) + + @parameterized.expand([ (load_message('clear.eml'), + load_key('rsa_1024.priv.asc')), + (load_message('clear_multipart.eml'), load_key('ecc_p256.priv.asc')) ]) def test_sign(self, message, key): @@ -52,7 +67,7 @@ class TestSigning(MIMEWrapperTestCase): (load_message('clear.eml'), load_key('rsa_1024.priv.asc'), load_key('rsa_1024.pub.asc')), - (load_message('clear.eml'), + (load_message('clear_multipart.eml'), load_key('ecc_p256.priv.asc'), load_key('ecc_p256.pub.asc')) ]) @@ -82,9 +97,18 @@ class TestEncryption(MIMEWrapperTestCase): self.is_encrypted(message, encrypted) @parameterized.expand([ + (load_message('mime_encrypted.eml'), + True), + (load_message('mime_encrypted_then_signed.eml'), + True) + ]) + def test_has_encryption(self, message, has): + self.has_encryption(message, has) + + @parameterized.expand([ (load_message('clear.eml'), load_key('rsa_1024.pub.asc')), - (load_message('clear.eml'), + (load_message('clear_multipart.eml'), (load_key('rsa_1024.pub.asc'), load_key('ecc_p256.pub.asc'))) ]) @@ -98,7 +122,7 @@ class TestEncryption(MIMEWrapperTestCase): (load_message('clear.eml'), load_key('rsa_1024.pub.asc'), load_key('rsa_1024.priv.asc')), - (load_message('clear.eml'), + (load_message('clear_multipart.eml'), load_key('ecc_p256.pub.asc'), load_key('ecc_p256.priv.asc')) ]) @@ -142,6 +166,9 @@ class TestCombined(MIMEWrapperTestCase): @parameterized.expand([ (load_message('clear.eml'), load_key('rsa_1024.priv.asc'), + load_key('ecc_p256.priv.asc')), + (load_message('clear_multipart.eml'), + load_key('rsa_1024.priv.asc'), load_key('ecc_p256.priv.asc')) ]) def test_sign_encrypt_decrypt_verify(self, message, sign_key, encrypt_key): @@ -150,6 +177,9 @@ class TestCombined(MIMEWrapperTestCase): @parameterized.expand([ (load_message('clear.eml'), load_key('rsa_1024.priv.asc'), + load_key('ecc_p256.priv.asc')), + (load_message('clear_multipart.eml'), + load_key('rsa_1024.priv.asc'), load_key('ecc_p256.priv.asc')) ]) def test_sign_then_encrypt_decrypt_verify(self, message, sign_key, diff --git a/src/mailman_pgp/pgp/tests/test_wrapper.py b/src/mailman_pgp/pgp/tests/test_wrapper.py index 6e8715c..730d068 100644 --- a/src/mailman_pgp/pgp/tests/test_wrapper.py +++ b/src/mailman_pgp/pgp/tests/test_wrapper.py @@ -48,6 +48,22 @@ class TestSigning(PGPWrapperTestCase): def test_is_signed(self, message, signed): self.is_signed(message, signed) + + @parameterized.expand([ + (load_message('inline_signed_multipart.eml'), + True), + (load_message('inline_signed.eml'), + True), + (load_message('mime_signed.eml'), + True), + (load_message('mime_signed_invalid.eml'), + True), + (load_message('clear.eml'), + False) + ]) + def test_has_signature(self, message, has): + self.has_signature(message, has) + @parameterized.expand([ (load_message('clear.eml'), load_key('rsa_1024.priv.asc')), diff --git a/src/mailman_pgp/pgp/wrapper.py b/src/mailman_pgp/pgp/wrapper.py index a1041ad..af6ce44 100644 --- a/src/mailman_pgp/pgp/wrapper.py +++ b/src/mailman_pgp/pgp/wrapper.py @@ -85,6 +85,7 @@ class PGPWrapper(): """ :return: + :rtype: typing.Generator[pgpy.PGPMessage|pgpy.PGPSignature] """ if self.mime.is_signed(): yield from self.mime.get_signature() @@ -139,11 +140,11 @@ class PGPWrapper(): """ return self.mime.has_encryption() or self.inline.has_encryption() - def get_encrypted(self): """ :return: + :rtype: typing.Generator[pgpy.PGPMessage] """ if self.mime.is_signed(): yield from self.mime.get_encrypted() |
