diff options
Diffstat (limited to 'src/mailman_pgp/pgp/mime_multisig.py')
| -rw-r--r-- | src/mailman_pgp/pgp/mime_multisig.py | 123 |
1 files changed, 66 insertions, 57 deletions
diff --git a/src/mailman_pgp/pgp/mime_multisig.py b/src/mailman_pgp/pgp/mime_multisig.py index d7ad00a..1dbb73c 100644 --- a/src/mailman_pgp/pgp/mime_multisig.py +++ b/src/mailman_pgp/pgp/mime_multisig.py @@ -23,8 +23,8 @@ from email.mime.application import MIMEApplication from email.mime.multipart import MIMEMultipart from email.utils import collapse_rfc2231_value -from mailman.email.message import Message, MultipartDigestMessage -from pgpy import PGPDetachedSignature, PGPSignature +from mailman.email.message import Message +from pgpy import PGPSignature from mailman_pgp.pgp.mime import MIMEWrapper from mailman_pgp.utils.email import copy_headers @@ -74,30 +74,20 @@ class MIMEMultiSigWrapper(MIMEWrapper): continue yield sig - def _wrap_signed_multiple(self, msg, payload_msg, sig_msgs, signatures, - signature): + def sign(self, key, **kwargs): """ - As per draft-ietf-openpgp-multsig-02. + Sign a message with key. - :param msg: - :param payload_msg: - :param sig_msgs: - :param signatures: - :param signature: + :param key: The key to sign with. + :type key: pgpy.PGPKey :return: + :rtype: MIMEMultiSigWrapper """ - micalg = ', '.join(self._micalg(sig.hash_algorithm) - for sig in signatures + signature.signatures) - out = MultipartDigestMessage('signed', micalg=micalg, - protocol='multipart/mixed') - out.preamble = MIMEMultiSigWrapper._signature_preamble - second_part = MIMEMultipart() - for sig_msg in sig_msgs: - second_part.attach(copy.deepcopy(sig_msg)) - - for sig in signature.signatures: - sig_part = MIMEApplication(_data=str(sig), + if self.is_signed(): + signed = next(iter(self.get_signed())) + signature = key.sign(signed, **kwargs) + sig_part = MIMEApplication(_data=str(signature), _subtype=MIMEWrapper._signature_subtype, _encoder=encode_7or8bit, name='signature.asc') @@ -105,36 +95,34 @@ class MIMEMultiSigWrapper(MIMEWrapper): 'OpenPGP digital signature') sig_part.add_header('Content-Disposition', 'attachment', filename='signature.asc') - second_part.attach(sig_part) - - out.attach(copy.deepcopy(payload_msg)) - out.attach(second_part) - copy_headers(msg, out) - return out - - def sign(self, key, **kwargs): - """ - Sign a message with key. - - :param key: The key to sign with. - :type key: pgpy.PGPKey - :return: The signed message. - :rtype: mailman.email.message.Message - """ - - if self.is_signed(): - payload_msg = self.msg.get_payload(0) - sig_msgs = [part for part in self.msg.get_payload(1).get_payload()] + micalg = self.msg.get_param('micalg') + micalg += ',' + self._micalg(signature.hash_algorithm) + self.msg.set_param('micalg', micalg) + self.msg.get_payload(1).attach(sig_part) else: - payload_msg = self.msg - sig_msgs = [] - # TODO: exception safe this - signatures = [PGPSignature.from_blob(sig_msg.get_payload()) - for sig_msg in sig_msgs] - signature = PGPDetachedSignature() - signature |= key.sign(payload_msg.as_string(), **kwargs) - return self._wrap_signed_multiple(self.msg, payload_msg, sig_msgs, - signatures, signature) + original_msg = copy.deepcopy(self.msg) + to_sign = next(iter(self.get_payload())) + signature = key.sign(to_sign, **kwargs) + self.msg.set_payload([]) + self.msg.attach(original_msg) + self.msg.set_type('multipart/signed') + self.msg['MIME-Version'] = '1.0' + self.msg.set_param('protocol', 'multipart/mixed') + self.msg.set_param('micalg', + self._micalg(signature.hash_algorithm)) + sig_part = MIMEApplication(_data=str(signature), + _subtype=MIMEWrapper._signature_subtype, + _encoder=encode_7or8bit, + name='signature.asc') + sig_part.add_header('Content-Description', + 'OpenPGP digital signature') + sig_part.add_header('Content-Disposition', 'attachment', + filename='signature.asc') + second_part = MIMEMultipart() + second_part.attach(sig_part) + self.msg.attach(second_part) + self.msg.preamble = MIMEMultiSigWrapper._signature_preamble + return self def verify(self, key): """ @@ -159,11 +147,10 @@ class MIMEMultiSigWrapper(MIMEWrapper): :param key: The key to decrypt with. :type key: pgpy.PGPKey - :return: The decrypted message. - :rtype: mailman.email.message.Message + :return: + :rtype: MIMEMultiSigWrapper """ pmsg = next(iter(self.get_encrypted())) - # TODO: exception safe this decrypted = key.decrypt(pmsg) dmsg = decrypted.message @@ -172,8 +159,30 @@ class MIMEMultiSigWrapper(MIMEWrapper): out = message_from_string(dmsg, _class=Message) if decrypted.is_signed: - out = self._wrap_signed_multiple(self.msg, out, [], [], - decrypted.detached_signature) + # result should be a multisig signed thing, so [out, ] + self.msg.set_payload([]) + self.msg.attach(out) + self.msg.set_type('multipart/signed') + self.msg['MIME-Version'] = '1.0' + self.msg.set_param('protocol', 'multipart/mixed') + micalg = ', '.join(self._micalg(sig.hash_algorithm) + for sig in decrypted.signatures) + self.msg.set_param('micalg', micalg) + second_part = MIMEMultipart() + for signature in decrypted.signatures: + sig_part = MIMEApplication(_data=str(signature), + _subtype=MIMEWrapper._signature_subtype, + _encoder=encode_7or8bit, + name='signature.asc') + sig_part.add_header('Content-Description', + 'OpenPGP digital signature') + sig_part.add_header('Content-Disposition', 'attachment', + filename='signature.asc') + second_part.attach(sig_part) + self.msg.attach(second_part) else: - copy_headers(self.msg, out) - return out + # result should be + self.msg.set_payload(out.get_payload()) + copy_headers(out, self.msg, True) + + return self |
