diff options
| -rw-r--r-- | src/mailman_pgp/rules/signature.py | 9 | ||||
| -rw-r--r-- | src/mailman_pgp/rules/tests/test_signature.py | 31 | ||||
| -rw-r--r-- | src/mailman_pgp/utils/pgp.py | 72 |
3 files changed, 87 insertions, 25 deletions
diff --git a/src/mailman_pgp/rules/signature.py b/src/mailman_pgp/rules/signature.py index b7d4b5c..ae27bb5 100644 --- a/src/mailman_pgp/rules/signature.py +++ b/src/mailman_pgp/rules/signature.py @@ -35,7 +35,7 @@ from mailman_pgp.model.sighash import PGPSigHash from mailman_pgp.pgp.wrapper import PGPWrapper from mailman_pgp.utils.email import get_email from mailman_pgp.utils.moderation import record_action -from mailman_pgp.utils.pgp import hashes, verifies, expired +from mailman_pgp.utils.pgp import hashes, verifies, expired, revoked @public @@ -106,6 +106,13 @@ class Signature: 'Signature is expired.') return True + if revoked(verifications): + action = pgp_list.revoked_sig_action + if action != Action.defer: + record_action(msg, msgdata, action, email, + 'Signature is made by a revoked key.') + return True + # Take the `invalid_sig_action` if the verification failed. if not verifies(verifications): action = pgp_list.invalid_sig_action diff --git a/src/mailman_pgp/rules/tests/test_signature.py b/src/mailman_pgp/rules/tests/test_signature.py index 72f2c70..ec49a18 100644 --- a/src/mailman_pgp/rules/tests/test_signature.py +++ b/src/mailman_pgp/rules/tests/test_signature.py @@ -37,6 +37,7 @@ from mailman_pgp.database import mm_transaction, transaction from mailman_pgp.model.address import PGPAddress from mailman_pgp.model.list import PGPMailingList from mailman_pgp.model.sighash import PGPSigHash +from mailman_pgp.pgp.inline import InlineWrapper from mailman_pgp.pgp.mime import MIMEWrapper from mailman_pgp.pgp.wrapper import PGPWrapper from mailman_pgp.rules.signature import Signature @@ -181,6 +182,36 @@ To: test@example.com self.assertTrue(matches) self.assertAction(msgdata, Action.hold, ['Signature is expired.']) + msgdata = {} + wrapped = InlineWrapper(self.msg_clear) + msg = wrapped.sign(self.sender_key, expires=timedelta(seconds=1)) + time.sleep(2) + matches = self.rule.check(self.mlist, msg, msgdata) + + self.assertTrue(matches) + self.assertAction(msgdata, Action.hold, ['Signature is expired.']) + + def test_revoked_sig_action(self): + with transaction(): + self.pgp_list.unsigned_msg_action = Action.defer + self.pgp_list.inline_pgp_action = Action.defer + self.pgp_list.expired_sig_action = Action.defer + self.pgp_list.revoked_sig_action = Action.hold + self.pgp_list.invalid_sig_action = Action.defer + self.pgp_list.duplicate_sig_action = Action.defer + + rsig = self.sender_key.revoke(self.pgp_sender.key) + self.pgp_sender.key |= rsig + + msgdata = {} + wrapped = MIMEWrapper(self.msg_clear) + msg = wrapped.sign(self.sender_key) + matches = self.rule.check(self.mlist, msg, msgdata) + + self.assertTrue(matches) + self.assertAction(msgdata, Action.hold, + ['Signature is made by a revoked key.']) + def test_invalid_sig_action(self): with transaction(): self.pgp_list.unsigned_msg_action = Action.defer diff --git a/src/mailman_pgp/utils/pgp.py b/src/mailman_pgp/utils/pgp.py index c44a27e..46fc797 100644 --- a/src/mailman_pgp/utils/pgp.py +++ b/src/mailman_pgp/utils/pgp.py @@ -31,7 +31,19 @@ def expired(verifications): :param verifications: :return: """ - return any(any(sigsubj.signature.is_expired + return any(any(sigsubj.signature.is_expired or sigsubj.by.is_expired + for sigsubj in verification.good_signatures) + for verification in verifications) + + +@public +def revoked(verifications): + """ + + :param verifications: + :return: + """ + return any(any(key_revoked(sigsubj.by) for sigsubj in verification.good_signatures) for verification in verifications) @@ -114,16 +126,43 @@ def revoc_from_blob(blob): @public -def key_flags(key): - if key.is_expired: - return set() +def key_revoked(key): + """ + + :param key: + :type key: pgpy.PGPKey + :return: + :rtype: bool + """ + if key.is_primary: + verifier = key + else: + verifier = key.parent + for revoc in key.revocation_signatures: try: - verified = key.verify(key, revoc) + verified = verifier.verify(key, revoc) except PGPError: continue if bool(verified): - return set() + return True + + return False + + +@public +def key_flags(key): + """ + + :param key: + :type key: pgpy.PGPKey + :return: + :rtype: Set[pgpy.constants.KeyFlags] + """ + if key.is_expired: + return set() + if key_revoked(key): + return set() usage_flags = set() uids = (uid for uid in key.userids if uid.is_primary) @@ -151,17 +190,7 @@ def key_flags(key): if subkey.is_expired: continue - valid = True - for revoc in subkey.revocation_signatures: - try: - verified = key.verify(subkey, revoc) - except PGPError: - continue - if bool(verified): - valid = False - break - - if valid: + if not key_revoked(subkey): usage_flags |= subkey.usage_flags() return usage_flags @@ -183,13 +212,8 @@ def key_usable(key, flags_required): """ if key.is_expired: return False - for revoc in key.revocation_signatures: - try: - verified = key.verify(key, revoc) - except PGPError: - continue - if bool(verified): - return False + if key_revoked(key): + return False return flags_required.issubset(key_flags(key)) |
