# Copyright (C) 2017 Jan Jancar # # This file is a part of the Mailman PGP plugin. # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . """Miscellaneous PGP utilities.""" 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 @public def verifies(verifications): """ :param verifications: :type verifications: typing.Sequence[pgpy.types.SignatureVerification] :return: bool """ return all(bool(verification) and all(not sigsubj.signature.is_expired for sigsubj in verification.good_signatures) for verification in verifications) @public def hashes(verifications): """ :param verifications: :return: :rtype: typing.Generator[bytes] """ for verification in verifications: for sigsubj in verification.good_signatures: data = sigsubj.signature.hashdata(sigsubj.subject) hasher = sigsubj.signature.hash_algorithm.hasher hasher.update(data) yield hasher.digest() @public def key_from_blob(blob): """ :param blob: :return: :rtype: pgpy.PGPKey """ key, _ = PGPKey.from_blob(blob) return key @public def key_from_file(file): """ :param file: :return: :rtype: pgpy.PGPKey """ key, _ = PGPKey.from_file(file) return key @public def revoc_from_blob(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): """ :param key: :type key: pgpy.PGPKey :param flags_required: :type flags_required: set :return: :rtype: bool """ if key.is_expired: return False primary_revocs = (sig for sig in key.self_signatures if sig.sigtype is SignatureType.KeyRevocation) for revoc in primary_revocs: 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(): usage_flags |= subkey.usage_flags() return flags_required.issubset(usage_flags)