diff options
Diffstat (limited to 'src/mailman_pgp')
| -rw-r--r-- | src/mailman_pgp/utils/pgp.py | 70 | ||||
| -rw-r--r-- | src/mailman_pgp/utils/tests/test_pgp.py | 22 |
2 files changed, 71 insertions, 21 deletions
diff --git a/src/mailman_pgp/utils/pgp.py b/src/mailman_pgp/utils/pgp.py index a8f06f2..be97a75 100644 --- a/src/mailman_pgp/utils/pgp.py +++ b/src/mailman_pgp/utils/pgp.py @@ -102,31 +102,39 @@ def revoc_from_blob(blob): @public -def key_usable(key, flags_required): - """ - Check that the `key` has the `flags_required` set of KeyFlags. - - Checks only non-expired, non-revoked key/subkeys. Validates revocations it - can, so not those made with some other designated revocation key. - - :param key: The key to check. - :type key: pgpy.PGPKey - :param flags_required: The set of flags required. - :type flags_required: set - :return: Whether the key has the flags_required. - :rtype: bool - """ +def key_flags(key): if key.is_expired: - return False + return set() for revoc in key.revocation_signatures: try: verified = key.verify(key, revoc) except PGPError: continue if bool(verified): - return False + return set() + + usage_flags = set() + uids = (uid for uid in key.userids if uid.is_primary) + uids = list(uids) + if len(uids) == 0: + uids = key.userids + + for uid in uids: + revoked = False + for sig in uid.signatures: + if sig.type is not SignatureType.CertRevocation: + continue + if sig.signer == key.fingerprint.keyid: + try: + verified = key.verify(uid, sig) + except PGPError: + continue + if bool(verified): + revoked = True + if not revoked: + usage_flags |= uid.selfsig.key_flags + break - usage_flags = key.usage_flags() for subkey in key.subkeys.values(): if subkey.is_expired: continue @@ -143,5 +151,31 @@ def key_usable(key, flags_required): if valid: usage_flags |= subkey.usage_flags() + return usage_flags + + +@public +def key_usable(key, flags_required): + """ + Check that the `key` has the `flags_required` set of KeyFlags. + + Checks only non-expired, non-revoked key/subkeys. Validates revocations it + can, so not those made with some other designated revocation key. - return flags_required.issubset(usage_flags) + :param key: The key to check. + :type key: pgpy.PGPKey + :param flags_required: The set of flags required. + :type flags_required: set + :return: Whether the key has the flags_required. + :rtype: bool + """ + 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 + return flags_required.issubset(key_flags(key)) diff --git a/src/mailman_pgp/utils/tests/test_pgp.py b/src/mailman_pgp/utils/tests/test_pgp.py index b6433d4..26b1be9 100644 --- a/src/mailman_pgp/utils/tests/test_pgp.py +++ b/src/mailman_pgp/utils/tests/test_pgp.py @@ -54,6 +54,14 @@ class TestPGPUtils(TestCase): def test_revoc_from_blob_invalid(self, blob): self.assertRaises(ValueError, revoc_from_blob, blob) + def test_key_usable(self): + key = load_key('rsa_1024.priv.asc') + + self.assertTrue(key_usable(key.pubkey, + {KeyFlags.Certify, KeyFlags.Sign, + KeyFlags.EncryptCommunications, + KeyFlags.EncryptStorage})) + def test_key_usable_expired(self): key = PGPKey.new(PubKeyAlgorithm.ECDSA, EllipticCurveOID.SECP256K1) uid = PGPUID.new('Some Name', email='anne@example.org') @@ -68,14 +76,21 @@ class TestPGPUtils(TestCase): time.sleep(2) - self.assertFalse(key_usable(key, set())) + self.assertFalse(key_usable(key.pubkey, set())) + + def test_key_usable_revoked_uid(self): + key = load_key('ecc_p256.priv.asc') + uid = next(iter(key.userids)) + rsig = key.revoke(uid) + uid |= rsig + self.assertFalse(key_usable(key.pubkey, {KeyFlags.Sign})) def test_key_usable_revoked(self): key = load_key('ecc_p256.priv.asc') rsig = key.revoke(key) key |= rsig - self.assertFalse(key_usable(key, set())) + self.assertFalse(key_usable(key.pubkey, set())) def test_key_usable_subkey_revoked(self): key = load_key('ecc_p256.priv.asc') @@ -83,4 +98,5 @@ class TestPGPUtils(TestCase): rsig = key.revoke(sub) sub |= rsig - self.assertFalse(key_usable(key, {KeyFlags.EncryptCommunications})) + self.assertFalse( + key_usable(key.pubkey, {KeyFlags.EncryptCommunications})) |
