diff options
| author | J08nY | 2017-08-02 00:15:21 +0200 |
|---|---|---|
| committer | J08nY | 2017-08-02 01:35:10 +0200 |
| commit | fa2b97fb2e6e75af8bfc0bc3620b1a37179bdedc (patch) | |
| tree | 5dee4554ab4b99fb2dd9b93f8e43a4978ad0d469 | |
| parent | dff7befbc5860f2f78f63ab694ef88d21a53771f (diff) | |
| download | mailman-pgp-fa2b97fb2e6e75af8bfc0bc3620b1a37179bdedc.tar.gz mailman-pgp-fa2b97fb2e6e75af8bfc0bc3620b1a37179bdedc.tar.zst mailman-pgp-fa2b97fb2e6e75af8bfc0bc3620b1a37179bdedc.zip | |
| -rw-r--r-- | src/mailman_pgp/commands/eml_key.py | 2 | ||||
| -rw-r--r-- | src/mailman_pgp/commands/tests/test_key.py | 34 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/inline.py | 17 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/mime.py | 60 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/test_inline.py | 11 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/test_mime.py | 22 | ||||
| -rw-r--r-- | src/mailman_pgp/testing/pgp.py | 27 | ||||
| -rw-r--r-- | src/mailman_pgp/utils/email.py | 20 |
8 files changed, 139 insertions, 54 deletions
diff --git a/src/mailman_pgp/commands/eml_key.py b/src/mailman_pgp/commands/eml_key.py index 1f39888..bea9745 100644 --- a/src/mailman_pgp/commands/eml_key.py +++ b/src/mailman_pgp/commands/eml_key.py @@ -270,7 +270,7 @@ def _cmd_receive(pgp_list, mlist, msg, msgdata, arguments, results): msg['MIME-Version'] = '1.0' msg.attach(MIMEText('Here is the public key you requested.')) wrapped = MIMEWrapper(msg) - msg = wrapped.attach_key(pgp_list.pubkey) + msg = wrapped.attach_keys(pgp_list.pubkey) msg.send(mlist) return ContinueProcessing.yes diff --git a/src/mailman_pgp/commands/tests/test_key.py b/src/mailman_pgp/commands/tests/test_key.py index cfda3e8..88b0bb4 100644 --- a/src/mailman_pgp/commands/tests/test_key.py +++ b/src/mailman_pgp/commands/tests/test_key.py @@ -145,7 +145,7 @@ class TestPreSubscription(unittest.TestCase): set_message = _create_mixed('bart@example.com', 'test@example.com', 'Re: key set {}'.format(token)) wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.bart_key.pubkey) mm_config.switchboards['command'].enqueue(set_message, listid='test.example.com') @@ -186,7 +186,7 @@ class TestPreSubscription(unittest.TestCase): set_message = _create_mixed('bart@example.com', 'test@example.com', 'Re: key set {}'.format(token)) wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.bart_key.pubkey) wrapped_set_message = MIMEWrapper(set_message) set_message = wrapped_set_message.encrypt(self.pgp_list.pubkey, self.bart_key.pubkey) @@ -246,9 +246,9 @@ class TestPreSubscription(unittest.TestCase): set_message = _create_mixed('bart@example.com', 'test@example.com', 'Re: key set token') wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.bart_key.pubkey) wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.anne_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.anne_key.pubkey) mm_config.switchboards['command'].enqueue(set_message, listid='test.example.com') @@ -263,7 +263,7 @@ class TestPreSubscription(unittest.TestCase): set_message = _create_mixed('bart@example.com', 'test@example.com', 'Re: key set token') wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_key) + set_message = wrapped_set_message.attach_keys(self.bart_key) mm_config.switchboards['command'].enqueue(set_message, listid='test.example.com') @@ -293,7 +293,7 @@ class TestPreSubscription(unittest.TestCase): def test_set_no_email(self): message = _create_mixed('', 'test@example.com', 'key set token') wrapped_message = MIMEWrapper(message) - message = wrapped_message.attach_key(self.bart_key.pubkey) + message = wrapped_message.attach_keys(self.bart_key.pubkey) mm_config.switchboards['command'].enqueue(message, listid='test.example.com') @@ -307,7 +307,7 @@ class TestPreSubscription(unittest.TestCase): set_message = _create_mixed('bart@example.com', 'test@example.com', 'key set token') wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.bart_key.pubkey) mm_config.switchboards['command'].enqueue(set_message, listid='test.example.com') @@ -326,7 +326,7 @@ class TestPreSubscription(unittest.TestCase): set_message = _create_mixed('bart@example.com', 'test@example.com', 'key set token') wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.bart_key.pubkey) mm_config.switchboards['command'].enqueue(set_message, listid='test.example.com') @@ -349,7 +349,7 @@ class TestPreSubscription(unittest.TestCase): set_message = _create_mixed('bart@example.com', 'test@example.com', 'key set token') wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.bart_key.pubkey) mm_config.switchboards['command'].enqueue(set_message, listid='test.example.com') @@ -628,7 +628,7 @@ class TestAfterSubscription(unittest.TestCase): message = _create_mixed('bart@example.com', 'test@example.com', 'key change') wrapped_message = MIMEWrapper(message) - message = wrapped_message.attach_key(self.bart_new_key.pubkey) + message = wrapped_message.attach_keys(self.bart_new_key.pubkey) mm_config.switchboards['command'].enqueue(message, listid='test.example.com') @@ -663,7 +663,7 @@ class TestAfterSubscription(unittest.TestCase): message = _create_mixed('bart@example.com', 'test@example.com', 'key change') wrapped_message = MIMEWrapper(message) - message = wrapped_message.attach_key(self.bart_new_key.pubkey) + message = wrapped_message.attach_keys(self.bart_new_key.pubkey) wrapped_message = MIMEWrapper(message) message = wrapped_message.encrypt(self.pgp_list.pubkey) @@ -700,7 +700,7 @@ class TestAfterSubscription(unittest.TestCase): message = _create_mixed('bart@example.com', 'test@example.com', 'key change') wrapped_message = MIMEWrapper(message) - message = wrapped_message.attach_key(self.bart_new_key.pubkey) + message = wrapped_message.attach_keys(self.bart_new_key.pubkey) mm_config.switchboards['command'].enqueue(message, listid='test.example.com') @@ -751,7 +751,7 @@ class TestAfterSubscription(unittest.TestCase): def test_change_no_email(self): message = _create_mixed('', 'test@example.com', 'key change') wrapped_message = MIMEWrapper(message) - message = wrapped_message.attach_key(self.bart_key.pubkey) + message = wrapped_message.attach_keys(self.bart_key.pubkey) mm_config.switchboards['command'].enqueue(message, listid='test.example.com') @@ -765,7 +765,7 @@ class TestAfterSubscription(unittest.TestCase): message = _create_mixed('bart@example.com', 'test@example.com', 'key change') wrapped_message = MIMEWrapper(message) - message = wrapped_message.attach_key(self.bart_key.pubkey) + message = wrapped_message.attach_keys(self.bart_key.pubkey) mm_config.switchboards['command'].enqueue(message, listid='test.example.com') @@ -810,9 +810,9 @@ class TestAfterSubscription(unittest.TestCase): 'key change') wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.bart_key.pubkey) wrapped_set_message = MIMEWrapper(set_message) - set_message = wrapped_set_message.attach_key(self.bart_new_key.pubkey) + set_message = wrapped_set_message.attach_keys(self.bart_new_key.pubkey) mm_config.switchboards['command'].enqueue(set_message, listid='test.example.com') @@ -835,7 +835,7 @@ class TestAfterSubscription(unittest.TestCase): message = _create_mixed('bart@example.com', 'test@example.com', 'key change') wrapped_message = MIMEWrapper(message) - message = wrapped_message.attach_key(self.bart_key) + message = wrapped_message.attach_keys(self.bart_key) mm_config.switchboards['command'].enqueue(message, listid='test.example.com') diff --git a/src/mailman_pgp/pgp/inline.py b/src/mailman_pgp/pgp/inline.py index cf92ffc..49f0a6e 100644 --- a/src/mailman_pgp/pgp/inline.py +++ b/src/mailman_pgp/pgp/inline.py @@ -18,11 +18,13 @@ """Strict inline PGP message wrapper.""" import copy from email.iterators import walk +from email.mime.text import MIMEText from pgpy import PGPMessage from pgpy.constants import SymmetricKeyAlgorithm from public import public +from mailman_pgp.utils.email import make_multipart from mailman_pgp.utils.pgp import key_from_blob, revoc_from_blob @@ -211,6 +213,21 @@ class InlineWrapper: continue yield revoc + def attach_revocs(self, *key_revocations): + """ + Attach a key revocation signature to the message. + + :param key_revocations: A key revocation signature to attach. + :type key_revocations: pgpy.PGPSignature + :return: The message with the signature attached. + :rtype: mailman.email.message.Message + """ + out = make_multipart(self.msg) + for key_revocation in key_revocations: + revoc_part = MIMEText(str(key_revocation)) + out.attach(revoc_part) + return out + def verify(self, key): """ Verify the signatures of this message with key. diff --git a/src/mailman_pgp/pgp/mime.py b/src/mailman_pgp/pgp/mime.py index e40f581..837e619 100644 --- a/src/mailman_pgp/pgp/mime.py +++ b/src/mailman_pgp/pgp/mime.py @@ -28,7 +28,7 @@ from pgpy import PGPDetachedSignature, PGPMessage from pgpy.constants import HashAlgorithm, SymmetricKeyAlgorithm from public import public -from mailman_pgp.utils.email import copy_headers +from mailman_pgp.utils.email import copy_headers, make_multipart from mailman_pgp.utils.pgp import key_from_blob, revoc_from_blob @@ -186,26 +186,27 @@ class MIMEWrapper: continue yield key - def attach_key(self, key): + def attach_keys(self, *keys): """ Attach a key to this message, as per RFC3156 section 7. - :param key: A key to attach. - :type key: pgpy.PGPKey + :param keys: A key to attach. + :type keys: pgpy.PGPKey :return: The message with the key attached. :rtype: mailman.email.message.Message """ - filename = '0x' + key.fingerprint.keyid + '.asc' - key_part = MIMEApplication(_data=str(key), - _subtype=MIMEWrapper._keys_subtype, - _encoder=encode_7or8bit, - name=filename) - key_part.add_header('Content-Description', - 'OpenPGP key') - key_part.add_header('Content-Disposition', 'attachment', - filename=filename) - out = copy.deepcopy(self.msg) - out.attach(key_part) + out = make_multipart(self.msg) + for key in keys: + filename = '0x' + key.fingerprint.keyid + '.asc' + key_part = MIMEApplication(_data=str(key), + _subtype=MIMEWrapper._keys_subtype, + _encoder=encode_7or8bit, + name=filename) + key_part.add_header('Content-Description', + 'OpenPGP key') + key_part.add_header('Content-Disposition', 'attachment', + filename=filename) + out.attach(key_part) return out def _is_revoc(self, part): @@ -239,26 +240,27 @@ class MIMEWrapper: continue yield revoc - def attach_revoc(self, key_revocation): + def attach_revocs(self, *key_revocations): """ Attach a key revocation signature to the message, as a key subpart. - :param key_revocation: A key revocation signature to attach. - :type key_revocation: pgpy.PGPSignature + :param key_revocations: A key revocation signature to attach. + :type key_revocations: pgpy.PGPSignature :return: The message with the signature attached. :rtype: mailman.email.message.Message """ - filename = '0x' + key_revocation.signer + '.asc' - key_part = MIMEApplication(_data=str(key_revocation), - _subtype=MIMEWrapper._keys_subtype, - _encoder=encode_7or8bit, - name=filename) - key_part.add_header('Content-Description', - 'OpenPGP key') - key_part.add_header('Content-Disposition', 'attachment', - filename=filename) - out = copy.deepcopy(self.msg) - out.attach(key_part) + out = make_multipart(self.msg) + for key_revocation in key_revocations: + filename = '0x' + key_revocation.signer + '.asc' + revoc_part = MIMEApplication(_data=str(key_revocation), + _subtype=MIMEWrapper._keys_subtype, + _encoder=encode_7or8bit, + name=filename) + revoc_part.add_header('Content-Description', + 'OpenPGP key') + revoc_part.add_header('Content-Disposition', 'attachment', + filename=filename) + out.attach(revoc_part) return out def verify(self, key): diff --git a/src/mailman_pgp/pgp/tests/test_inline.py b/src/mailman_pgp/pgp/tests/test_inline.py index b409bee..1f1f687 100644 --- a/src/mailman_pgp/pgp/tests/test_inline.py +++ b/src/mailman_pgp/pgp/tests/test_inline.py @@ -248,6 +248,17 @@ class TestRevocs(InlineWrapperTestCase): def test_revocs(self, message, revocs): self.revocs(message, revocs) + @parameterized.expand([ + (load_message('clear.eml'), + [load_revoc('rsa_1024.revoc.asc'), + load_revoc('ecc_p256.revoc.asc')]), + (load_message('clear_multipart.eml'), + [load_revoc('rsa_1024.revoc.asc'), + load_revoc('ecc_p256.revoc.asc')]) + ]) + def test_attach_revocs(self, message, revocs): + self.attach_revocs(message, revocs) + class TestCombined(InlineWrapperTestCase): @parameterized.expand([ diff --git a/src/mailman_pgp/pgp/tests/test_mime.py b/src/mailman_pgp/pgp/tests/test_mime.py index ec2542a..f059c8d 100644 --- a/src/mailman_pgp/pgp/tests/test_mime.py +++ b/src/mailman_pgp/pgp/tests/test_mime.py @@ -179,6 +179,17 @@ class TestKeys(MIMEWrapperTestCase): def test_keys(self, message, keys): self.keys(message, keys) + @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_attach_keys(self, message, keys): + self.attach_keys(message, keys) + class TestRevocs(MIMEWrapperTestCase): @parameterized.expand([ @@ -202,6 +213,17 @@ class TestRevocs(MIMEWrapperTestCase): def test_revocs(self, message, revocs): self.revocs(message, revocs) + @parameterized.expand([ + (load_message('clear.eml'), + [load_revoc('rsa_1024.revoc.asc'), + load_revoc('ecc_p256.revoc.asc')]), + (load_message('clear_multipart.eml'), + [load_revoc('rsa_1024.revoc.asc'), + load_revoc('ecc_p256.revoc.asc')]) + ]) + def test_attach_revocs(self, message, revocs): + self.attach_revocs(message, revocs) + class TestCombined(MIMEWrapperTestCase): @parameterized.expand([ diff --git a/src/mailman_pgp/testing/pgp.py b/src/mailman_pgp/testing/pgp.py index 7f207e3..90deb7a 100644 --- a/src/mailman_pgp/testing/pgp.py +++ b/src/mailman_pgp/testing/pgp.py @@ -142,20 +142,21 @@ class WrapperTestCase(TestCase): loaded = list(wrapped.keys()) self.assertEqual(len(loaded), len(keys)) - loaded_fingerprints = list(map(lambda key: key.fingerprint, loaded)) - fingerprints = list(map(lambda key: key.fingerprint, keys)) + get_fingerprint = lambda key: key.fingerprint + loaded_fingerprints = list(map(get_fingerprint, loaded)) + fingerprints = list(map(get_fingerprint, keys)) self.assertListEqual(loaded_fingerprints, fingerprints) def attach_keys(self, message, keys): wrapped = self.wrap(message) - for key in keys: - attached = wrapped.attach_key(key) - wrapped = self.wrap(attached) + attached = wrapped.attach_keys(*keys) + wrapped = self.wrap(attached) loaded = list(wrapped.keys()) self.assertTrue(wrapped.has_keys()) - loaded_fingerprints = list(map(lambda key: key.fingerprint, loaded)) - fingerprints = list(map(lambda key: key.fingerprint, keys)) + get_fingerprint = lambda key: key.fingerprint + loaded_fingerprints = list(map(get_fingerprint, loaded)) + fingerprints = list(map(get_fingerprint, keys)) self.assertListEqual(loaded_fingerprints, fingerprints) def has_revocs(self, message, has_revocs): @@ -176,6 +177,18 @@ class WrapperTestCase(TestCase): issuers = list(map(get_issuer, revocs)) self.assertListEqual(loaded_issuers, issuers) + def attach_revocs(self, message, revocs): + wrapped = self.wrap(message) + attached = wrapped.attach_revocs(*revocs) + wrapped = self.wrap(attached) + loaded = list(wrapped.revocs()) + + self.assertTrue(wrapped.has_revocs()) + get_issuer = lambda revoc: revoc.signer + loaded_issuers = list(map(get_issuer, loaded)) + issuers = list(map(get_issuer, revocs)) + self.assertListEqual(loaded_issuers, issuers) + def sign_encrypt_decrypt_verify(self, message, sign_key, encrypt_key): wrapped = self.wrap(message) encrypted = wrapped.sign_encrypt(sign_key, encrypt_key.pubkey) diff --git a/src/mailman_pgp/utils/email.py b/src/mailman_pgp/utils/email.py index a936458..9eff313 100644 --- a/src/mailman_pgp/utils/email.py +++ b/src/mailman_pgp/utils/email.py @@ -16,8 +16,10 @@ # this program. If not, see <http://www.gnu.org/licenses/>. """""" +import copy from email.utils import parseaddr +from mailman.email.message import MultipartDigestMessage from public import public @@ -62,6 +64,24 @@ def overwrite_message(from_msg, to_msg): @public +def make_multipart(msg): + """ + + :param msg: + :type msg: email.message.Message + :return: + :rtype: email.message.MIMEMultipart|mailman.email.message.MultipartDigestMessage + """ + if msg.is_multipart(): + out = copy.deepcopy(msg) + else: + out = MultipartDigestMessage() + out.attach(msg) + copy_headers(msg, out) + return out + + +@public def get_email(msg): display_name, email = parseaddr(msg['from']) # Address could be None or the empty string. |
