1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
# 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 <http://www.gnu.org/licenses/>.
"""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:
: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()
if flags_required not in usage_flags:
return False
return True
|