diff options
| author | J08nY | 2017-07-27 21:14:35 +0200 |
|---|---|---|
| committer | J08nY | 2017-07-27 21:14:35 +0200 |
| commit | a6e81421f0db2e741baee2ec0cedd2a285c6f233 (patch) | |
| tree | d018b95dff266182c99ede54e406a32bfdf6a950 /src/mailman_pgp/pgp/mime_multisig.py | |
| parent | 25134df48508444c6a31ca299341bd09dca1ac82 (diff) | |
| download | mailman-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.py | 77 |
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) |
