summaryrefslogtreecommitdiff
path: root/src/mailman_pgp/utils/pgp.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/mailman_pgp/utils/pgp.py')
-rw-r--r--src/mailman_pgp/utils/pgp.py75
1 files changed, 74 insertions, 1 deletions
diff --git a/src/mailman_pgp/utils/pgp.py b/src/mailman_pgp/utils/pgp.py
index 4251693..a8f06f2 100644
--- a/src/mailman_pgp/utils/pgp.py
+++ b/src/mailman_pgp/utils/pgp.py
@@ -16,7 +16,11 @@
# this program. If not, see <http://www.gnu.org/licenses/>.
"""Miscellaneous PGP utilities."""
-from pgpy import PGPKey
+from pgpy import PGPKey, PGPSignature
+from pgpy.constants import SignatureType
+from pgpy.errors import PGPError
+from pgpy.packet import Packet, Signature
+from pgpy.types import Armorable
from public import public
@@ -72,3 +76,72 @@ def key_from_file(file):
"""
key, _ = PGPKey.from_file(file)
return key
+
+
+@public
+def revoc_from_blob(blob):
+ """
+ Load a key revocation signature from an ASCII-Armored blob.
+
+ :param blob:
+ :return:
+ :rtype: pgpy.PGPSignature
+ """
+ dearm = Armorable.ascii_unarmor(blob)
+ p = Packet(dearm['body'])
+
+ if not isinstance(p, Signature):
+ raise ValueError('Not a key revocation signature.')
+ if p.sigtype not in (SignatureType.KeyRevocation,
+ SignatureType.SubkeyRevocation):
+ raise ValueError('Not a key revocation.')
+
+ sig = PGPSignature()
+ sig |= p
+ return sig
+
+
+@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
+ """
+ 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
+
+ usage_flags = key.usage_flags()
+ for subkey in key.subkeys.values():
+ 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:
+ usage_flags |= subkey.usage_flags()
+
+ return flags_required.issubset(usage_flags)