aboutsummaryrefslogtreecommitdiff
path: root/src/mailman_pgp/pgp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailman_pgp/pgp')
-rw-r--r--src/mailman_pgp/pgp/inline.py53
-rw-r--r--src/mailman_pgp/pgp/mime.py89
-rw-r--r--src/mailman_pgp/pgp/tests/data/messages/inline_revoc.eml19
-rw-r--r--src/mailman_pgp/pgp/tests/data/messages/inline_revoc_multipart.eml30
-rw-r--r--src/mailman_pgp/pgp/tests/data/messages/mime_revoc.eml35
-rw-r--r--src/mailman_pgp/pgp/tests/data/revocs/dsa_elgamal_1024.revoc.asc8
-rw-r--r--src/mailman_pgp/pgp/tests/data/revocs/ecc_curve25519.revoc.asc8
-rw-r--r--src/mailman_pgp/pgp/tests/data/revocs/ecc_p256.revoc.asc8
-rw-r--r--src/mailman_pgp/pgp/tests/data/revocs/ecc_secp256k1.revoc.asc8
-rw-r--r--src/mailman_pgp/pgp/tests/data/revocs/rsa_1024.revoc.asc9
-rw-r--r--src/mailman_pgp/pgp/tests/test_inline.py43
-rw-r--r--src/mailman_pgp/pgp/tests/test_mime.py48
-rw-r--r--src/mailman_pgp/pgp/tests/test_wrapper.py38
-rw-r--r--src/mailman_pgp/pgp/wrapper.py31
14 files changed, 402 insertions, 25 deletions
diff --git a/src/mailman_pgp/pgp/inline.py b/src/mailman_pgp/pgp/inline.py
index bb0971d..49f0a6e 100644
--- a/src/mailman_pgp/pgp/inline.py
+++ b/src/mailman_pgp/pgp/inline.py
@@ -18,12 +18,14 @@
"""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.pgp import key_from_blob
+from mailman_pgp.utils.email import make_multipart
+from mailman_pgp.utils.pgp import key_from_blob, revoc_from_blob
@public
@@ -95,7 +97,7 @@ class InlineWrapper:
:rtype: typing.Generator[pgpy.PGPMessage]
"""
for part in walk(self.msg):
- if not part.is_multipart() and self._is_signed(part):
+ if not part.is_multipart():
try:
msg = PGPMessage.from_blob(part.get_payload())
except:
@@ -135,7 +137,7 @@ class InlineWrapper:
:rtype: typing.Generator[pgpy.PGPMessage]
"""
for part in walk(self.msg):
- if not part.is_multipart() and self._is_encrypted(part):
+ if not part.is_multipart():
try:
msg = PGPMessage.from_blob(part.get_payload())
except:
@@ -176,13 +178,56 @@ class InlineWrapper:
:rtype: Generator[pgpy.PGPKey]
"""
for part in walk(self.msg):
- if not part.is_multipart() and self._has_keys(part):
+ if not part.is_multipart():
try:
key = key_from_blob(part.get_payload())
except:
continue
yield key
+ def _is_revoc(self, part):
+ try:
+ revoc_from_blob(part.get_payload())
+ except ValueError:
+ return False
+ return True
+
+ def is_revocs(self):
+ for part in walk(self.msg):
+ if (not part.is_multipart() and not self._is_revoc(part)):
+ return False
+ return True
+
+ def has_revocs(self):
+ for part in walk(self.msg):
+ if (not part.is_multipart() and self._is_revoc(part)):
+ return True
+ return False
+
+ def revocs(self):
+ for part in walk(self.msg):
+ if not part.is_multipart():
+ try:
+ revoc = revoc_from_blob(part.get_payload())
+ except:
+ 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 a1303c9..03177ab 100644
--- a/src/mailman_pgp/pgp/mime.py
+++ b/src/mailman_pgp/pgp/mime.py
@@ -28,8 +28,8 @@ 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.pgp import key_from_blob
+from mailman_pgp.utils.email import copy_headers, make_multipart
+from mailman_pgp.utils.pgp import key_from_blob, revoc_from_blob
@public
@@ -63,7 +63,7 @@ class MIMEWrapper:
def _is_mime(self):
is_multipart = self.msg.is_multipart()
- payloads = len(self.msg.get_payload())
+ payloads = len(self.msg.get_payload()) if self.msg.get_payload() else 0
return is_multipart and payloads == 2
@@ -186,26 +186,81 @@ 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):
+ if part.get_content_type() != MIMEWrapper._keys_type:
+ return False
+ try:
+ revoc_from_blob(part.get_payload())
+ except ValueError:
+ return False
+ return True
+
+ def is_revocs(self):
+ for part in walk(self.msg):
+ if (not part.is_multipart() and not self._is_revoc(part)):
+ return False
+ return True
+
+ def has_revocs(self):
+ for part in walk(self.msg):
+ if (not part.is_multipart() and self._is_revoc(part)):
+ return True
+ return False
+
+ def revocs(self):
+ for part in walk(self.msg):
+ if (not part.is_multipart() # noqa
+ and part.get_content_type() == MIMEWrapper._keys_type):
+ try:
+ revoc = revoc_from_blob(part.get_payload())
+ except:
+ continue
+ yield revoc
+
+ def attach_revocs(self, *key_revocations):
+ """
+ Attach a key revocation signature to the message, as a key subpart.
+
+ :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:
+ 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/data/messages/inline_revoc.eml b/src/mailman_pgp/pgp/tests/data/messages/inline_revoc.eml
new file mode 100644
index 0000000..f215777
--- /dev/null
+++ b/src/mailman_pgp/pgp/tests/data/messages/inline_revoc.eml
@@ -0,0 +1,19 @@
+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: text/plain; charset=utf-8
+Content-Transfer-Encoding: 8bit
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: This is a revocation certificate
+
+iLYEIAEIACAWIQTUqUiGscoglqZFjlxH8QwIeIS3WAUCWYClvgIdAgAKCRBH8QwI
+eIS3WLpBBADCUtyYmI2Z8DCOnKUW4nRjHc3ZVMoZJlwceJCWhSybBrnjo6LWzvBy
+eKke4qHlh+jmSk3/Qyio6vYzvicOayDwhr0s/1X26MiYorthfiCQOg2WQ0YiRuMC
+/Ml8rukvBTRGvXikcIuBw5MFqCWsWI7ExPKaaresnHaCn37KF0A6hw==
+=4oku
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/mailman_pgp/pgp/tests/data/messages/inline_revoc_multipart.eml b/src/mailman_pgp/pgp/tests/data/messages/inline_revoc_multipart.eml
new file mode 100644
index 0000000..a1052d6
--- /dev/null
+++ b/src/mailman_pgp/pgp/tests/data/messages/inline_revoc_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 PUBLIC KEY BLOCK-----
+Comment: This is a revocation certificate
+
+iLYEIAEIACAWIQTUqUiGscoglqZFjlxH8QwIeIS3WAUCWYClvgIdAgAKCRBH8QwI
+eIS3WLpBBADCUtyYmI2Z8DCOnKUW4nRjHc3ZVMoZJlwceJCWhSybBrnjo6LWzvBy
+eKke4qHlh+jmSk3/Qyio6vYzvicOayDwhr0s/1X26MiYorthfiCQOg2WQ0YiRuMC
+/Ml8rukvBTRGvXikcIuBw5MFqCWsWI7ExPKaaresnHaCn37KF0A6hw==
+=4oku
+-----END PGP PUBLIC KEY BLOCK-----
+
+--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/mime_revoc.eml b/src/mailman_pgp/pgp/tests/data/messages/mime_revoc.eml
new file mode 100644
index 0000000..e1055a3
--- /dev/null
+++ b/src/mailman_pgp/pgp/tests/data/messages/mime_revoc.eml
@@ -0,0 +1,35 @@
+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="------------A851F166D50529639139DD0B"
+
+This is a multi-part message in MIME format.
+--------------A851F166D50529639139DD0B
+Content-Type: text/plain; charset=utf-8
+Content-Transfer-Encoding: 7bit
+
+Some other text.
+
+--------------A851F166D50529639139DD0B
+Content-Type: application/pgp-keys;
+ name="0x7884B758.asc"
+Content-Transfer-Encoding: 7bit
+Content-Disposition: attachment;
+ filename="0x7884B758.asc"
+
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: This is a revocation certificate
+
+iLYEIAEIACAWIQTUqUiGscoglqZFjlxH8QwIeIS3WAUCWYClvgIdAgAKCRBH8QwI
+eIS3WLpBBADCUtyYmI2Z8DCOnKUW4nRjHc3ZVMoZJlwceJCWhSybBrnjo6LWzvBy
+eKke4qHlh+jmSk3/Qyio6vYzvicOayDwhr0s/1X26MiYorthfiCQOg2WQ0YiRuMC
+/Ml8rukvBTRGvXikcIuBw5MFqCWsWI7ExPKaaresnHaCn37KF0A6hw==
+=4oku
+-----END PGP PUBLIC KEY BLOCK-----
+
+--------------A851F166D50529639139DD0B--
diff --git a/src/mailman_pgp/pgp/tests/data/revocs/dsa_elgamal_1024.revoc.asc b/src/mailman_pgp/pgp/tests/data/revocs/dsa_elgamal_1024.revoc.asc
new file mode 100644
index 0000000..80b002e
--- /dev/null
+++ b/src/mailman_pgp/pgp/tests/data/revocs/dsa_elgamal_1024.revoc.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: This is a revocation certificate
+
+iGAEIBECACAWIQRR5fGEErwNQ8nevZPDzAoGOEHHpwUCWYCmxwIdAgAKCRDDzAoG
+OEHHp+nYAJwM095Qv9qxaMfqx8xSLD5eKeExgQCeNA5z7zZZcgtUTTqW/o4baX6D
+X8E=
+=vVlH
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/mailman_pgp/pgp/tests/data/revocs/ecc_curve25519.revoc.asc b/src/mailman_pgp/pgp/tests/data/revocs/ecc_curve25519.revoc.asc
new file mode 100644
index 0000000..df7d593
--- /dev/null
+++ b/src/mailman_pgp/pgp/tests/data/revocs/ecc_curve25519.revoc.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: This is a revocation certificate
+
+iHgEIBYIACAWIQQFsA605escSIQh4V/6me+juNPIugUCWYCmggIdAgAKCRD6me+j
+uNPIuuVxAP4mr8PXnLIzqdysvMo5Mo0QbIck6NgO/rOJC4Kj/tGjyQD/QMo4ON/1
+cxzD068xWtlDpPYjtPBFuNYrLOPDYvqjGAg=
+=0TTd
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/mailman_pgp/pgp/tests/data/revocs/ecc_p256.revoc.asc b/src/mailman_pgp/pgp/tests/data/revocs/ecc_p256.revoc.asc
new file mode 100644
index 0000000..9571cd2
--- /dev/null
+++ b/src/mailman_pgp/pgp/tests/data/revocs/ecc_p256.revoc.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: This is a revocation certificate
+
+iHgEIBMIACAWIQSyKLDm+5ZVhlrf0j03k3IFvhWo0AUCWYCmZAIdAgAKCRA3k3IF
+vhWo0HAZAP9qFHrB6d+hNpYDT9jVCDIURh8Ml711hi8zsDhSkRZ4yAEAgzlmzjPZ
+VhgcOemgbYTKO7Kj8q61KpVP9oZ9l7Z4c/I=
+=ZZsy
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/mailman_pgp/pgp/tests/data/revocs/ecc_secp256k1.revoc.asc b/src/mailman_pgp/pgp/tests/data/revocs/ecc_secp256k1.revoc.asc
new file mode 100644
index 0000000..e91a62a
--- /dev/null
+++ b/src/mailman_pgp/pgp/tests/data/revocs/ecc_secp256k1.revoc.asc
@@ -0,0 +1,8 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: This is a revocation certificate
+
+iHgEIBMIACAWIQRi7dSuUMnX5cDo6nvIw1p/AFOkvwUCWYCmEwIdAgAKCRDIw1p/
+AFOkv5zZAQDiOzuQWpL2cvm+Jz4XyeLWebiOe7zirM9oMP03rmzQxgD/UIzBnqq9
+iy6oREDvbNw1sCB8/90ihlkB3iM8eOW9iSk=
+=lj1I
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/mailman_pgp/pgp/tests/data/revocs/rsa_1024.revoc.asc b/src/mailman_pgp/pgp/tests/data/revocs/rsa_1024.revoc.asc
new file mode 100644
index 0000000..ddb8974
--- /dev/null
+++ b/src/mailman_pgp/pgp/tests/data/revocs/rsa_1024.revoc.asc
@@ -0,0 +1,9 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: This is a revocation certificate
+
+iLYEIAEIACAWIQTUqUiGscoglqZFjlxH8QwIeIS3WAUCWYClvgIdAgAKCRBH8QwI
+eIS3WLpBBADCUtyYmI2Z8DCOnKUW4nRjHc3ZVMoZJlwceJCWhSybBrnjo6LWzvBy
+eKke4qHlh+jmSk3/Qyio6vYzvicOayDwhr0s/1X26MiYorthfiCQOg2WQ0YiRuMC
+/Ml8rukvBTRGvXikcIuBw5MFqCWsWI7ExPKaaresnHaCn37KF0A6hw==
+=4oku
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/src/mailman_pgp/pgp/tests/test_inline.py b/src/mailman_pgp/pgp/tests/test_inline.py
index 7f82ab4..d9f8c8a 100644
--- a/src/mailman_pgp/pgp/tests/test_inline.py
+++ b/src/mailman_pgp/pgp/tests/test_inline.py
@@ -20,7 +20,8 @@
from parameterized import parameterized
from mailman_pgp.pgp.inline import InlineWrapper
-from mailman_pgp.testing.pgp import load_key, load_message, WrapperTestCase
+from mailman_pgp.testing.pgp import (
+ load_key, load_message, load_revoc, WrapperTestCase)
class InlineWrapperTestCase(WrapperTestCase):
@@ -219,6 +220,46 @@ class TestKeys(InlineWrapperTestCase):
self.keys(message, keys)
+class TestRevocs(InlineWrapperTestCase):
+ @parameterized.expand([
+ (load_message('inline_revoc.eml'),
+ True),
+ (load_message('inline_revoc_multipart.eml'),
+ True)
+ ])
+ def test_has_revocs(self, message, has_revocs):
+ self.has_revocs(message, has_revocs)
+
+ @parameterized.expand([
+ (load_message('inline_revoc.eml'),
+ True),
+ (load_message('inline_revoc_multipart.eml'),
+ False)
+ ])
+ def test_is_revocs(self, message, is_revocs):
+ self.is_revocs(message, is_revocs)
+
+ @parameterized.expand([
+ (load_message('inline_revoc.eml'),
+ (load_revoc('rsa_1024.revoc.asc'),)),
+ (load_message('inline_revoc_multipart.eml'),
+ (load_revoc('rsa_1024.revoc.asc'),))
+ ])
+ 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([
(load_message('clear.eml'),
diff --git a/src/mailman_pgp/pgp/tests/test_mime.py b/src/mailman_pgp/pgp/tests/test_mime.py
index 78c9e71..e9951cf 100644
--- a/src/mailman_pgp/pgp/tests/test_mime.py
+++ b/src/mailman_pgp/pgp/tests/test_mime.py
@@ -20,7 +20,8 @@
from parameterized import parameterized
from mailman_pgp.pgp.mime import MIMEWrapper
-from mailman_pgp.testing.pgp import load_key, load_message, WrapperTestCase
+from mailman_pgp.testing.pgp import (
+ load_key, load_message, load_revoc, WrapperTestCase)
class MIMEWrapperTestCase(WrapperTestCase):
@@ -178,6 +179,51 @@ 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([
+ (load_message('mime_revoc.eml'),
+ True)
+ ])
+ def test_has_revocs(self, message, has_revocs):
+ self.has_revocs(message, has_revocs)
+
+ @parameterized.expand([
+ (load_message('mime_revoc.eml'),
+ False)
+ ])
+ def test_is_revocs(self, message, is_revocs):
+ self.is_revocs(message, is_revocs)
+
+ @parameterized.expand([
+ (load_message('mime_revoc.eml'),
+ (load_revoc('rsa_1024.revoc.asc'),))
+ ])
+ 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/pgp/tests/test_wrapper.py b/src/mailman_pgp/pgp/tests/test_wrapper.py
index f1f7621..b9c157a 100644
--- a/src/mailman_pgp/pgp/tests/test_wrapper.py
+++ b/src/mailman_pgp/pgp/tests/test_wrapper.py
@@ -22,7 +22,8 @@ from mailman_pgp.pgp.inline import InlineWrapper
from mailman_pgp.pgp.mime import MIMEWrapper
from mailman_pgp.pgp.mime_multisig import MIMEMultiSigWrapper
from mailman_pgp.pgp.wrapper import PGPWrapper
-from mailman_pgp.testing.pgp import load_key, load_message, WrapperTestCase
+from mailman_pgp.testing.pgp import (
+ load_key, load_message, load_revoc, WrapperTestCase)
class PGPWrapperTestCase(WrapperTestCase):
@@ -180,6 +181,41 @@ class TestKeys(PGPWrapperTestCase):
self.keys(message, keys)
+class TestRevocs(PGPWrapperTestCase):
+ @parameterized.expand([
+ (load_message('mime_revoc.eml'),
+ True),
+ (load_message('inline_revoc.eml'),
+ True),
+ (load_message('inline_revoc_multipart.eml'),
+ True)
+ ])
+ def test_has_revocs(self, message, has_revocs):
+ self.has_revocs(message, has_revocs)
+
+ @parameterized.expand([
+ (load_message('mime_revoc.eml'),
+ False),
+ (load_message('inline_revoc.eml'),
+ True),
+ (load_message('inline_revoc_multipart.eml'),
+ False)
+ ])
+ def test_is_revocs(self, message, is_revocs):
+ self.is_revocs(message, is_revocs)
+
+ @parameterized.expand([
+ (load_message('mime_revoc.eml'),
+ (load_revoc('rsa_1024.revoc.asc'),)),
+ (load_message('inline_revoc.eml'),
+ (load_revoc('rsa_1024.revoc.asc'),)),
+ (load_message('inline_revoc_multipart.eml'),
+ (load_revoc('rsa_1024.revoc.asc'),))
+ ])
+ def test_revocs(self, message, revocs):
+ self.revocs(message, revocs)
+
+
class TestCombined(PGPWrapperTestCase):
@parameterized.expand([
(load_message('clear.eml'),
diff --git a/src/mailman_pgp/pgp/wrapper.py b/src/mailman_pgp/pgp/wrapper.py
index 6193b57..f0519cb 100644
--- a/src/mailman_pgp/pgp/wrapper.py
+++ b/src/mailman_pgp/pgp/wrapper.py
@@ -270,7 +270,7 @@ class PGPWrapper():
Get the collection of keys in this message.
:return: A collection of keys.
- :rtype: Generator[pgpy.PGPKey]
+ :rtype: typing.Generator[pgpy.PGPKey]
"""
if self.mime.has_keys():
yield from self.mime.keys()
@@ -278,3 +278,32 @@ class PGPWrapper():
yield from self.multisig.keys()
elif self.inline.has_keys():
yield from self.inline.keys()
+
+ def has_revocs(self):
+ """
+
+ :return:
+ :rtype: bool
+ """
+ return any(wrapper.has_revocs() for wrapper in self.wrappers)
+
+ def is_revocs(self):
+ """
+
+ :return:
+ :rtype: bool
+ """
+ return any(wrapper.is_revocs() for wrapper in self.wrappers)
+
+ def revocs(self):
+ """
+
+ :return:
+ :rtype: typing.Generator[pgpy.PGPSignature]
+ """
+ if self.mime.has_revocs():
+ yield from self.mime.revocs()
+ elif self.multisig.has_revocs():
+ yield from self.multisig.revocs()
+ elif self.inline.has_revocs():
+ yield from self.inline.revocs()