aboutsummaryrefslogtreecommitdiff
path: root/src/mailman_pgp/pgp/mime_multisig.py
diff options
context:
space:
mode:
authorJ08nY2017-07-27 21:14:35 +0200
committerJ08nY2017-07-27 21:14:35 +0200
commita6e81421f0db2e741baee2ec0cedd2a285c6f233 (patch)
treed018b95dff266182c99ede54e406a32bfdf6a950 /src/mailman_pgp/pgp/mime_multisig.py
parent25134df48508444c6a31ca299341bd09dca1ac82 (diff)
downloadmailman-pgp-a6e81421f0db2e741baee2ec0cedd2a285c6f233.tar.gz
mailman-pgp-a6e81421f0db2e741baee2ec0cedd2a285c6f233.tar.zst
mailman-pgp-a6e81421f0db2e741baee2ec0cedd2a285c6f233.zip
Diffstat (limited to 'src/mailman_pgp/pgp/mime_multisig.py')
-rw-r--r--src/mailman_pgp/pgp/mime_multisig.py77
1 files changed, 74 insertions, 3 deletions
diff --git a/src/mailman_pgp/pgp/mime_multisig.py b/src/mailman_pgp/pgp/mime_multisig.py
index ff9039e..ced90fa 100644
--- a/src/mailman_pgp/pgp/mime_multisig.py
+++ b/src/mailman_pgp/pgp/mime_multisig.py
@@ -21,24 +21,62 @@ from email import message_from_string
from email.encoders import encode_7or8bit
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
+from email.utils import collapse_rfc2231_value
from mailman.email.message import MultipartDigestMessage, Message
+from pgpy import PGPSignature, PGPDetachedSignature
from mailman_pgp.pgp.mime import MIMEWrapper
from mailman_pgp.utils.email import copy_headers
class MIMEMultiSigWrapper(MIMEWrapper):
- """"""
+ """https://tools.ietf.org/html/draft-ietf-openpgp-multsig-02"""
+
_signature_preamble = \
'This is an OpepPGP/MIME signed message' \
'(RFC 4880, 3156 and draft-ietf-openpgp-multsig).\n' \
'see https://tools.ietf.org/html/draft-ietf-openpgp-multsig-02' \
'for more details.'
+ def is_signed(self):
+ """
+ Whether the whole message is MIME signed as per draft-ietf-openpgp-multsig-02.
+
+ :return: If the message is MIME signed.
+ :rtype: bool
+ """
+ if not self._is_mime():
+ return False
+ second_part = self.msg.get_payload(1)
+ second_type = second_part.get_content_type()
+ protocol_param = collapse_rfc2231_value(self.msg.get_param('protocol',
+ ''))
+ content_subtype = self.msg.get_content_subtype()
+
+ return (second_part.is_multipart() and
+ second_type == 'multipart/mixed' and
+ content_subtype == 'signed' and
+ protocol_param == 'multipart/mixed' and
+ all(part.get_content_type() == MIMEWrapper._signed_type
+ for part in second_part.get_payload()))
+
+ def get_signature(self):
+ """
+
+ :return:
+ :rtype: typing.Generator[pgpy.PGPSignature]
+ """
+ for part in self.msg.get_payload(1).get_payload():
+ try:
+ sig = PGPSignature.from_blob(part.get_payload())
+ except:
+ continue
+ yield sig
+
def _wrap_signed_multiple(self, msg, signature):
"""
- As per https://tools.ietf.org/html/draft-ietf-openpgp-multsig-02.
+ As per draft-ietf-openpgp-multsig-02.
:param msg:
:param signature:
@@ -67,15 +105,48 @@ class MIMEMultiSigWrapper(MIMEWrapper):
return out
def sign(self, key, hash=None):
+ """
+ Sign a message with key.
+
+ :param key: The key to sign with.
+ :type key: pgpy.PGPKey
+ :param hash:
+ :type hash: pgpy.constants.HashAlgorithm
+ :return: The signed message.
+ :rtype: mailman.email.message.Message
+ """
if self.is_signed():
payload = next(iter(self.get_signed()))
- signature = next(iter(self.get_signature()))
+ signature = PGPDetachedSignature()
+ for sig in self.get_signature():
+ signature |= sig
signature |= key.sign(payload, hash=hash)
return self._wrap_signed_multiple(self.msg, signature)
else:
super().sign(key, hash)
+ def verify(self, key):
+ """
+ Verify the signature of this message with key.
+
+ :param key: The key to verify with.
+ :type key: pgpy.PGPKey
+ :return: The verified signature.
+ :rtype: Generator[pgpy.types.SignatureVerification]
+ """
+ clear_text = next(iter(self.get_signed()))
+ for signature in self.get_signature():
+ yield key.verify(clear_text, signature)
+
def decrypt(self, key):
+ """
+ Decrypt this message with key.
+
+ :param key: The key to decrypt with.
+ :type key: pgpy.PGPKey
+ :return: The decrypted message.
+ :rtype: mailman.email.message.Message
+ """
pmsg = next(iter(self.get_encrypted()))
decrypted = key.decrypt(pmsg)