CryptoDataHub 0.12.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CryptoDataHub-0.12.6.dist-info/LICENSE.txt +373 -0
- CryptoDataHub-0.12.6.dist-info/METADATA +119 -0
- CryptoDataHub-0.12.6.dist-info/RECORD +70 -0
- CryptoDataHub-0.12.6.dist-info/WHEEL +5 -0
- CryptoDataHub-0.12.6.dist-info/top_level.txt +1 -0
- cryptodatahub/__init__.py +0 -0
- cryptodatahub/__setup__.py +10 -0
- cryptodatahub/common/__init__.py +0 -0
- cryptodatahub/common/algorithm.py +164 -0
- cryptodatahub/common/attack-named.json +74 -0
- cryptodatahub/common/attack-type.json +58 -0
- cryptodatahub/common/authentication.json +113 -0
- cryptodatahub/common/block-cipher-mode.json +75 -0
- cryptodatahub/common/block-cipher.json +474 -0
- cryptodatahub/common/certificate-transparency-log.json +2394 -0
- cryptodatahub/common/client.json +20 -0
- cryptodatahub/common/dhparam-well-known.json +1975 -0
- cryptodatahub/common/ecparam-well-known.json +1868 -0
- cryptodatahub/common/entity.json +269 -0
- cryptodatahub/common/entity.py +110 -0
- cryptodatahub/common/exception.py +28 -0
- cryptodatahub/common/grade.py +200 -0
- cryptodatahub/common/hash.json +273 -0
- cryptodatahub/common/key-exchange.json +140 -0
- cryptodatahub/common/key.py +571 -0
- cryptodatahub/common/mac.json +404 -0
- cryptodatahub/common/named-group.json +902 -0
- cryptodatahub/common/parameter.py +149 -0
- cryptodatahub/common/root-certificate.json +19240 -0
- cryptodatahub/common/server.json +56 -0
- cryptodatahub/common/signature.json +233 -0
- cryptodatahub/common/standard.json +57 -0
- cryptodatahub/common/stores.py +323 -0
- cryptodatahub/common/types.py +524 -0
- cryptodatahub/common/utils.py +112 -0
- cryptodatahub/common/vulnerability.json +2 -0
- cryptodatahub/dnsrec/__init__.py +0 -0
- cryptodatahub/dnsrec/algorithm.json +114 -0
- cryptodatahub/dnsrec/algorithm.py +87 -0
- cryptodatahub/dnsrec/digest-type.json +26 -0
- cryptodatahub/dnsrec/rr-type.json +805 -0
- cryptodatahub/ssh/__init__.py +0 -0
- cryptodatahub/ssh/algorithm.py +194 -0
- cryptodatahub/ssh/compression-algorithm.json +24 -0
- cryptodatahub/ssh/elliptic-curve-identifier.json +50 -0
- cryptodatahub/ssh/encryption-algorithm.json +587 -0
- cryptodatahub/ssh/host-key-algorithm.json +482 -0
- cryptodatahub/ssh/kex-algorithm.json +709 -0
- cryptodatahub/ssh/mac-algorithm.json +566 -0
- cryptodatahub/tls/__init__.py +0 -0
- cryptodatahub/tls/algorithm.py +324 -0
- cryptodatahub/tls/certificate-compression-algorithm.json +14 -0
- cryptodatahub/tls/cipher-kind.json +171 -0
- cryptodatahub/tls/cipher-suite-extension.json +10 -0
- cryptodatahub/tls/cipher-suite.json +5098 -0
- cryptodatahub/tls/client.json +4757 -0
- cryptodatahub/tls/client.py +220 -0
- cryptodatahub/tls/compression-method.json +20 -0
- cryptodatahub/tls/ec-point-format.json +20 -0
- cryptodatahub/tls/extension-type.json +282 -0
- cryptodatahub/tls/grease-one-byte.json +34 -0
- cryptodatahub/tls/grease-two-byte.json +66 -0
- cryptodatahub/tls/hash-and-signature-algorithm.json +266 -0
- cryptodatahub/tls/named-curve.json +292 -0
- cryptodatahub/tls/next-protocol-name.json +20 -0
- cryptodatahub/tls/protocol-name.json +71 -0
- cryptodatahub/tls/psk-key-exchange-mode.json +10 -0
- cryptodatahub/tls/token-binding-paramater.json +14 -0
- cryptodatahub/tls/version.json +154 -0
- cryptodatahub/tls/version.py +17 -0
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
import abc
|
|
4
|
+
import base64
|
|
5
|
+
import collections
|
|
6
|
+
import datetime
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
from collections import OrderedDict
|
|
10
|
+
|
|
11
|
+
import six
|
|
12
|
+
import asn1crypto.keys
|
|
13
|
+
import asn1crypto.pem
|
|
14
|
+
import asn1crypto.x509
|
|
15
|
+
import attr
|
|
16
|
+
|
|
17
|
+
from cryptodatahub.common.algorithm import Authentication, KeyExchange, Hash, NamedGroup, Signature
|
|
18
|
+
from cryptodatahub.common.exception import InvalidValue
|
|
19
|
+
from cryptodatahub.common.grade import (
|
|
20
|
+
AttackNamed,
|
|
21
|
+
AttackType,
|
|
22
|
+
Grade,
|
|
23
|
+
GradeableComplex,
|
|
24
|
+
GradeableVulnerabilities,
|
|
25
|
+
Vulnerability,
|
|
26
|
+
)
|
|
27
|
+
from cryptodatahub.common.types import _ConverterBase
|
|
28
|
+
from cryptodatahub.common.utils import bytes_to_hex_string, hash_bytes
|
|
29
|
+
|
|
30
|
+
from cryptodatahub.tls.algorithm import TlsExtensionType
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@attr.s(frozen=True)
|
|
34
|
+
class _PublicKeySizeGradeable(GradeableVulnerabilities):
|
|
35
|
+
@classmethod
|
|
36
|
+
def get_gradeable_name(cls):
|
|
37
|
+
return 'public key size'
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@attr.s(frozen=True)
|
|
41
|
+
class PublicKeySize(GradeableComplex):
|
|
42
|
+
_FINITE_FIELD_TYPES = [Authentication.RSA, Authentication.DSS, KeyExchange.ADH, KeyExchange.DH, KeyExchange.DHE]
|
|
43
|
+
_ELLIPTIC_CURVE_TYPES = [Authentication.ECDSA, Authentication.EDDSA, KeyExchange.ECDH, KeyExchange.ECDHE]
|
|
44
|
+
|
|
45
|
+
key_type = attr.ib(validator=attr.validators.instance_of((Authentication, KeyExchange)))
|
|
46
|
+
value = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
47
|
+
|
|
48
|
+
@value.validator
|
|
49
|
+
def _value_validator(self, attribute, value): # pylint: disable=unused-argument
|
|
50
|
+
if value <= 0:
|
|
51
|
+
raise InvalidValue(value, type(self), 'value')
|
|
52
|
+
|
|
53
|
+
def __attrs_post_init__(self):
|
|
54
|
+
if self.key_type in self._ELLIPTIC_CURVE_TYPES:
|
|
55
|
+
gradeables = []
|
|
56
|
+
attack_type = AttackType.DISCRETE_LOGARITHM
|
|
57
|
+
if self.value <= 112:
|
|
58
|
+
gradeables.append(Vulnerability(attack_type=attack_type, grade=Grade.INSECURE, named=None))
|
|
59
|
+
elif self.value <= 160:
|
|
60
|
+
gradeables.append(Vulnerability(attack_type=attack_type, grade=Grade.WEAK, named=None))
|
|
61
|
+
gradeables = [_PublicKeySizeGradeable(gradeables)]
|
|
62
|
+
elif self.key_type in self._FINITE_FIELD_TYPES:
|
|
63
|
+
gradeables = []
|
|
64
|
+
attack_type = AttackType.INTEGER_FACTORIZATION
|
|
65
|
+
if self.value <= 768:
|
|
66
|
+
if self.key_type == Authentication.RSA:
|
|
67
|
+
attack_named = AttackNamed.FREAK
|
|
68
|
+
elif isinstance(self.key_type, KeyExchange):
|
|
69
|
+
attack_named = AttackNamed.WEAK_DH
|
|
70
|
+
else:
|
|
71
|
+
attack_named = None
|
|
72
|
+
|
|
73
|
+
gradeables.append(Vulnerability(attack_type=attack_type, grade=Grade.INSECURE, named=attack_named))
|
|
74
|
+
elif self.value <= 1024:
|
|
75
|
+
gradeables.append(Vulnerability(attack_type=attack_type, grade=Grade.WEAK, named=None))
|
|
76
|
+
elif self.key_type in [KeyExchange.ADH, KeyExchange.DH, KeyExchange.DHE] and self.value > 4096:
|
|
77
|
+
gradeables.append(
|
|
78
|
+
Vulnerability(attack_type=AttackType.DOS_ATTACK, grade=Grade.WEAK, named=AttackNamed.DHEAT_ATTACK)
|
|
79
|
+
)
|
|
80
|
+
gradeables = [_PublicKeySizeGradeable(gradeables)]
|
|
81
|
+
elif self.key_type == KeyExchange.HYBRID_PQS:
|
|
82
|
+
gradeables = []
|
|
83
|
+
else:
|
|
84
|
+
gradeables = None
|
|
85
|
+
|
|
86
|
+
object.__setattr__(self, 'gradeables', gradeables)
|
|
87
|
+
|
|
88
|
+
def __str__(self):
|
|
89
|
+
return str(self.value)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@attr.s(repr=False, slots=True, hash=True)
|
|
93
|
+
class _PublicKeySizeConverter(_ConverterBase):
|
|
94
|
+
key_exchange = attr.ib(validator=attr.validators.instance_of(KeyExchange))
|
|
95
|
+
|
|
96
|
+
def __call__(self, value):
|
|
97
|
+
if value is None:
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
return PublicKeySize(self.key_exchange, value)
|
|
102
|
+
except (TypeError, InvalidValue):
|
|
103
|
+
return value
|
|
104
|
+
|
|
105
|
+
def __repr__(self):
|
|
106
|
+
return '<public key size converter>'
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def convert_public_key_size(key_exchange):
|
|
110
|
+
return _PublicKeySizeConverter(key_exchange)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@attr.s(frozen=True)
|
|
114
|
+
class PublicKeyParamBase(object):
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@attr.s(frozen=True)
|
|
119
|
+
class PublicKeyParamsDsa(PublicKeyParamBase):
|
|
120
|
+
prime = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
121
|
+
generator = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
122
|
+
order = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
123
|
+
public_key_value = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@attr.s(frozen=True)
|
|
127
|
+
class PublicKeyParamsEcdsa(PublicKeyParamBase):
|
|
128
|
+
named_group = attr.ib(validator=attr.validators.instance_of(NamedGroup))
|
|
129
|
+
point_x = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
130
|
+
point_y = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def from_octet_bit_string(cls, named_group, octet_bit_string):
|
|
134
|
+
point_x, point_y = asn1crypto.keys.ECPointBitString(bytes(octet_bit_string)).to_coords()
|
|
135
|
+
return cls(
|
|
136
|
+
named_group,
|
|
137
|
+
point_x,
|
|
138
|
+
point_y,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def octet_bit_string(self):
|
|
143
|
+
return bytes(asn1crypto.keys.ECPointBitString.from_coords(self.point_x, self.point_y))
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@attr.s(frozen=True)
|
|
147
|
+
class PublicKeyParamsEddsa(PublicKeyParamBase):
|
|
148
|
+
curve_type = attr.ib(validator=attr.validators.instance_of(NamedGroup))
|
|
149
|
+
key_data = attr.ib(validator=attr.validators.instance_of((bytes, bytearray)))
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@attr.s(frozen=True)
|
|
153
|
+
class PublicKeyParamsRsa(PublicKeyParamBase):
|
|
154
|
+
modulus = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
155
|
+
public_exponent = attr.ib(validator=attr.validators.instance_of(six.integer_types))
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@attr.s(eq=False, frozen=True)
|
|
159
|
+
class PublicKey(object):
|
|
160
|
+
_public_key = attr.ib(validator=attr.validators.instance_of(asn1crypto.keys.PublicKeyInfo))
|
|
161
|
+
|
|
162
|
+
@classmethod
|
|
163
|
+
def from_der(cls, der):
|
|
164
|
+
return cls(asn1crypto.keys.PublicKeyInfo.load(bytes(der)))
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def from_pem(cls, pem):
|
|
168
|
+
return cls.from_der(asn1crypto.pem.unarmor(pem.encode('ascii'))[2])
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def from_pem_lines(cls, pem_lines):
|
|
172
|
+
return cls.from_pem(os.linesep.join(pem_lines))
|
|
173
|
+
|
|
174
|
+
@classmethod
|
|
175
|
+
def from_params(cls, params):
|
|
176
|
+
if isinstance(params, PublicKeyParamsDsa):
|
|
177
|
+
algorithm_id = asn1crypto.keys.PublicKeyAlgorithmId(six.u('dsa'))
|
|
178
|
+
parameters = asn1crypto.keys.DSAParams({
|
|
179
|
+
'p': params.prime, 'g': params.generator, 'q': params.order,
|
|
180
|
+
})
|
|
181
|
+
public_key = asn1crypto.keys.PublicKeyInfo({
|
|
182
|
+
'algorithm': asn1crypto.keys.PublicKeyAlgorithm({
|
|
183
|
+
'algorithm': algorithm_id,
|
|
184
|
+
'parameters': parameters,
|
|
185
|
+
}),
|
|
186
|
+
'public_key': params.public_key_value,
|
|
187
|
+
})
|
|
188
|
+
elif isinstance(params, PublicKeyParamsEddsa):
|
|
189
|
+
if params.curve_type == NamedGroup.CURVE25519:
|
|
190
|
+
algorithm_name = six.u('ed25519')
|
|
191
|
+
elif params.curve_type == NamedGroup.CURVE448:
|
|
192
|
+
algorithm_name = six.u('ed448')
|
|
193
|
+
else:
|
|
194
|
+
raise NotImplementedError()
|
|
195
|
+
|
|
196
|
+
algorithm_id = asn1crypto.keys.PublicKeyAlgorithmId(algorithm_name)
|
|
197
|
+
public_key = asn1crypto.keys.PublicKeyInfo({
|
|
198
|
+
'algorithm': asn1crypto.keys.PublicKeyAlgorithm({
|
|
199
|
+
'algorithm': algorithm_id,
|
|
200
|
+
}),
|
|
201
|
+
'public_key': asn1crypto.core.OctetBitString(bytes(params.key_data)),
|
|
202
|
+
})
|
|
203
|
+
elif isinstance(params, PublicKeyParamsRsa):
|
|
204
|
+
algorithm_id = asn1crypto.keys.PublicKeyAlgorithmId(six.u('rsa'))
|
|
205
|
+
public_key = asn1crypto.keys.PublicKeyInfo({
|
|
206
|
+
'algorithm': asn1crypto.keys.PublicKeyAlgorithm({'algorithm': algorithm_id}),
|
|
207
|
+
'public_key': asn1crypto.keys.RSAPublicKey(
|
|
208
|
+
attr.asdict(params, recurse=False, value_serializer=None)
|
|
209
|
+
)
|
|
210
|
+
})
|
|
211
|
+
elif isinstance(params, PublicKeyParamsEcdsa):
|
|
212
|
+
algorithm_id = asn1crypto.keys.PublicKeyAlgorithmId(six.u('ec'))
|
|
213
|
+
parameters = asn1crypto.keys.ECDomainParameters({
|
|
214
|
+
'named': params.named_group.value.oid
|
|
215
|
+
})
|
|
216
|
+
|
|
217
|
+
public_key = asn1crypto.keys.PublicKeyInfo({
|
|
218
|
+
'algorithm': asn1crypto.keys.PublicKeyAlgorithm({
|
|
219
|
+
'algorithm': algorithm_id,
|
|
220
|
+
'parameters': parameters,
|
|
221
|
+
}),
|
|
222
|
+
'public_key': asn1crypto.keys.ECPointBitString.from_coords(params.point_x, params.point_y)
|
|
223
|
+
})
|
|
224
|
+
else:
|
|
225
|
+
raise NotImplementedError(type(params))
|
|
226
|
+
|
|
227
|
+
return cls(public_key)
|
|
228
|
+
|
|
229
|
+
@property
|
|
230
|
+
def params(self):
|
|
231
|
+
if self.key_type == Authentication.DSS:
|
|
232
|
+
public_key = self._public_key['public_key'].parsed
|
|
233
|
+
parameters = self._public_key['algorithm']['parameters']
|
|
234
|
+
return PublicKeyParamsDsa(
|
|
235
|
+
prime=parameters['p'].native,
|
|
236
|
+
generator=parameters['g'].native,
|
|
237
|
+
order=parameters['q'].native,
|
|
238
|
+
public_key_value=public_key.native,
|
|
239
|
+
)
|
|
240
|
+
if self.key_type == Authentication.ECDSA:
|
|
241
|
+
public_key = self._public_key['public_key']
|
|
242
|
+
parameters = self._public_key['algorithm']['parameters']
|
|
243
|
+
|
|
244
|
+
return PublicKeyParamsEcdsa(
|
|
245
|
+
NamedGroup.from_oid(parameters.chosen.dotted),
|
|
246
|
+
*public_key.to_coords()
|
|
247
|
+
)
|
|
248
|
+
if self.key_type == Authentication.EDDSA:
|
|
249
|
+
algorithm = self._public_key['algorithm']['algorithm']
|
|
250
|
+
signature = Signature.from_oid(algorithm.dotted)
|
|
251
|
+
if signature == Signature.ED25519:
|
|
252
|
+
curve_type = NamedGroup.CURVE25519
|
|
253
|
+
elif signature == Signature.ED448:
|
|
254
|
+
curve_type = NamedGroup.CURVE448
|
|
255
|
+
else:
|
|
256
|
+
raise NotImplementedError()
|
|
257
|
+
|
|
258
|
+
return PublicKeyParamsEddsa(
|
|
259
|
+
curve_type=curve_type,
|
|
260
|
+
key_data=self._public_key['public_key'].native
|
|
261
|
+
)
|
|
262
|
+
if self.key_type == Authentication.RSA:
|
|
263
|
+
public_key = self._public_key['public_key'].parsed
|
|
264
|
+
return PublicKeyParamsRsa(
|
|
265
|
+
modulus=public_key['modulus'].native,
|
|
266
|
+
public_exponent=public_key['public_exponent'].native,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
raise NotImplementedError(self.key_type)
|
|
270
|
+
|
|
271
|
+
@classmethod
|
|
272
|
+
def _get_type_name(cls):
|
|
273
|
+
return 'public key'
|
|
274
|
+
|
|
275
|
+
def __eq__(self, other):
|
|
276
|
+
return self.der == other.der
|
|
277
|
+
|
|
278
|
+
@property
|
|
279
|
+
def der(self):
|
|
280
|
+
return self._public_key.dump()
|
|
281
|
+
|
|
282
|
+
@property
|
|
283
|
+
def pem(self):
|
|
284
|
+
return six.ensure_str(asn1crypto.pem.armor(six.u(self._get_type_name().upper()), self.der))
|
|
285
|
+
|
|
286
|
+
@property
|
|
287
|
+
def key_type(self):
|
|
288
|
+
try:
|
|
289
|
+
key_type_oid = self._public_key['algorithm']['algorithm'].dotted
|
|
290
|
+
except KeyError as e:
|
|
291
|
+
key_type_oid = e.args[0]
|
|
292
|
+
|
|
293
|
+
try:
|
|
294
|
+
return Signature.from_oid(key_type_oid).value.key_type
|
|
295
|
+
except InvalidValue:
|
|
296
|
+
return Authentication.from_oid(key_type_oid)
|
|
297
|
+
|
|
298
|
+
@property
|
|
299
|
+
def key_size(self):
|
|
300
|
+
if self.key_type == Authentication.GOST_R3410_12_256:
|
|
301
|
+
return 256
|
|
302
|
+
if self.key_type == Authentication.GOST_R3410_12_512:
|
|
303
|
+
return 512
|
|
304
|
+
if self.key_type == Authentication.GOST_R3410_01:
|
|
305
|
+
return 256
|
|
306
|
+
if self.key_type == Authentication.EDDSA:
|
|
307
|
+
return self.params.curve_type.value.size
|
|
308
|
+
|
|
309
|
+
return int(self._public_key.bit_size)
|
|
310
|
+
|
|
311
|
+
@property
|
|
312
|
+
def key_bytes(self):
|
|
313
|
+
return PublicKey.der.fget(self)
|
|
314
|
+
|
|
315
|
+
def get_digest(self, hash_type):
|
|
316
|
+
return hash_bytes(hash_type, self.der)
|
|
317
|
+
|
|
318
|
+
def fingerprint(self, hash_type):
|
|
319
|
+
return bytes_to_hex_string(self.get_digest(hash_type), ':')
|
|
320
|
+
|
|
321
|
+
@property
|
|
322
|
+
def fingerprints(self):
|
|
323
|
+
return OrderedDict([
|
|
324
|
+
(hash_type, self.fingerprint(hash_type))
|
|
325
|
+
for hash_type in [Hash.MD5, Hash.SHA1, Hash.SHA2_256]
|
|
326
|
+
])
|
|
327
|
+
|
|
328
|
+
def _asdict(self):
|
|
329
|
+
return collections.OrderedDict([
|
|
330
|
+
('algorithm', self.key_type),
|
|
331
|
+
('size', PublicKeySize(self.key_type, self.key_size)),
|
|
332
|
+
('fingerprints', self.fingerprints),
|
|
333
|
+
])
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
class PublicKeySigned(PublicKey):
|
|
337
|
+
@property
|
|
338
|
+
@abc.abstractmethod
|
|
339
|
+
def valid_not_before(self):
|
|
340
|
+
raise NotImplementedError()
|
|
341
|
+
|
|
342
|
+
@property
|
|
343
|
+
@abc.abstractmethod
|
|
344
|
+
def valid_not_after(self):
|
|
345
|
+
raise NotImplementedError()
|
|
346
|
+
|
|
347
|
+
@property
|
|
348
|
+
def validity_period(self):
|
|
349
|
+
return self.valid_not_after - self.valid_not_before
|
|
350
|
+
|
|
351
|
+
@property
|
|
352
|
+
def validity_remaining_time(self):
|
|
353
|
+
now = datetime.datetime.now(asn1crypto.util.timezone.utc)
|
|
354
|
+
return self.valid_not_after - now if now < self.valid_not_after else None
|
|
355
|
+
|
|
356
|
+
@property
|
|
357
|
+
def expired(self):
|
|
358
|
+
return datetime.datetime.now(asn1crypto.util.timezone.utc) > self.valid_not_after
|
|
359
|
+
|
|
360
|
+
@property
|
|
361
|
+
@abc.abstractmethod
|
|
362
|
+
def signature_hash_algorithm(self):
|
|
363
|
+
raise NotImplementedError()
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@attr.s(eq=False, init=False, frozen=True)
|
|
367
|
+
class PublicKeyX509Base(PublicKeySigned): # pylint: disable=too-many-public-methods
|
|
368
|
+
_EV_OIDS_BY_CA = {
|
|
369
|
+
'A-Trust': ('1.2.40.0.17.1.22', ),
|
|
370
|
+
'Actalis': ('1.3.159.1.17.1', ),
|
|
371
|
+
'AffirmTrust': (
|
|
372
|
+
'1.3.6.1.4.1.34697.2.1',
|
|
373
|
+
'1.3.6.1.4.1.34697.2.2',
|
|
374
|
+
'1.3.6.1.4.1.34697.2.3',
|
|
375
|
+
'1.3.6.1.4.1.34697.2.4',
|
|
376
|
+
),
|
|
377
|
+
'Buypass': ('2.16.578.1.26.1.3.3', ),
|
|
378
|
+
'Camerfirma': (
|
|
379
|
+
'1.3.6.1.4.1.17326.10.14.2.1.2',
|
|
380
|
+
'1.3.6.1.4.1.17326.10.8.12.1.2',
|
|
381
|
+
),
|
|
382
|
+
'Comodo Group': ('1.3.6.1.4.1.6449.1.2.1.5.1', ),
|
|
383
|
+
'DigiCert': (
|
|
384
|
+
'2.16.840.1.114412.1.3.0.2',
|
|
385
|
+
'2.16.840.1.114412.2.1',
|
|
386
|
+
),
|
|
387
|
+
'DigiNotar': ('2.16.528.1.1001.1.1.1.12.6.1.1.1', ),
|
|
388
|
+
'E-Tugra': ('2.16.792.3.0.4.1.1.4', ),
|
|
389
|
+
'ETSI': (
|
|
390
|
+
'0.4.0.2042.1.4',
|
|
391
|
+
'0.4.0.2042.1.5',
|
|
392
|
+
),
|
|
393
|
+
'Entrust': ('2.16.840.1.114028.10.1.2', ),
|
|
394
|
+
'Firmaprofesional': ('1.3.6.1.4.1.13177.10.1.3.10', ),
|
|
395
|
+
'GeoTrust': ('1.3.6.1.4.1.14370.1.6', ),
|
|
396
|
+
'GlobalSign': ('1.3.6.1.4.1.4146.1.1', ),
|
|
397
|
+
'Go Daddy': ('2.16.840.1.114413.1.7.23.3', ),
|
|
398
|
+
'Izenpe': ('1.3.6.1.4.1.14777.6.1.1', ),
|
|
399
|
+
'Kamu Sertifikasyon Merkezi': ('2.16.792.1.2.1.1.5.7.1.9', ),
|
|
400
|
+
'Logius PKIoverheid': ('2.16.528.1.1003.1.2.7', ),
|
|
401
|
+
'Network Solutions': ('1.3.6.1.4.1.782.1.2.1.8.1', ),
|
|
402
|
+
'OpenTrust/DocuSign France': ('1.3.6.1.4.1.22234.2.5.2.3.1', ),
|
|
403
|
+
'QuoVadis': ('1.3.6.1.4.1.8024.0.2.100.1.2', ),
|
|
404
|
+
'SECOM Trust Systems': ('1.2.392.200091.100.721.1', ),
|
|
405
|
+
'SHECA': ('1.2.156.112570.1.1.3', ),
|
|
406
|
+
'Starfield Technologies': ('2.16.840.1.114414.1.7.23.3', ),
|
|
407
|
+
'StartCom Certification Authority': (
|
|
408
|
+
'1.3.6.1.4.1.23223.1.1.1',
|
|
409
|
+
'1.3.6.1.4.1.23223.2',
|
|
410
|
+
),
|
|
411
|
+
'SwissSign': ('2.16.756.1.89.1.2.1.1', ),
|
|
412
|
+
'Swisscom': ('2.16.756.1.83.21.0', ),
|
|
413
|
+
'Symantec (VeriSign)': ('2.16.840.1.113733.1.7.23.6', ),
|
|
414
|
+
'T-Systems': ('1.3.6.1.4.1.7879.13.24.1', ),
|
|
415
|
+
'Thawte': ('2.16.840.1.113733.1.7.48.1', ),
|
|
416
|
+
'Trustwave': ('2.16.840.1.114404.1.1.2.4.1', ),
|
|
417
|
+
'Verizon Business (formerly Cybertrust)': ('1.3.6.1.4.1.6334.1.100.1', ),
|
|
418
|
+
'Wells Fargo': ('2.16.840.1.114171.500.9', ),
|
|
419
|
+
'WoSign': ('1.3.6.1.4.1.36305.2', ),
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
_certificate = attr.ib(validator=attr.validators.instance_of(asn1crypto.x509.Certificate))
|
|
423
|
+
|
|
424
|
+
def __init__(self, certificate):
|
|
425
|
+
super(PublicKeySigned, self).__init__(certificate.public_key)
|
|
426
|
+
|
|
427
|
+
object.__setattr__(self, '_certificate', certificate)
|
|
428
|
+
|
|
429
|
+
@classmethod
|
|
430
|
+
def _get_type_name(cls):
|
|
431
|
+
return 'certificate'
|
|
432
|
+
|
|
433
|
+
@classmethod
|
|
434
|
+
def from_der(cls, der):
|
|
435
|
+
return cls(asn1crypto.x509.Certificate.load(bytes(der)))
|
|
436
|
+
|
|
437
|
+
@property
|
|
438
|
+
def der(self):
|
|
439
|
+
return self._certificate.dump()
|
|
440
|
+
|
|
441
|
+
@property
|
|
442
|
+
def valid_not_before(self):
|
|
443
|
+
return self._certificate.not_valid_before
|
|
444
|
+
|
|
445
|
+
@property
|
|
446
|
+
def valid_not_after(self):
|
|
447
|
+
return self._certificate.not_valid_after
|
|
448
|
+
|
|
449
|
+
@property
|
|
450
|
+
def signature_hash_algorithm(self):
|
|
451
|
+
try:
|
|
452
|
+
signature_oid = self._certificate['signature_algorithm']['algorithm'].dotted
|
|
453
|
+
except KeyError as e:
|
|
454
|
+
signature_oid = e.args[0]
|
|
455
|
+
|
|
456
|
+
return Signature.from_oid(signature_oid)
|
|
457
|
+
|
|
458
|
+
@property
|
|
459
|
+
def public_key(self):
|
|
460
|
+
return PublicKey(self._public_key)
|
|
461
|
+
|
|
462
|
+
@property
|
|
463
|
+
def public_key_pin(self):
|
|
464
|
+
return base64.b64encode(hash_bytes(Hash.SHA2_256, self.key_bytes)).decode('ascii')
|
|
465
|
+
|
|
466
|
+
def _has_any_policy_value(self, oid_values):
|
|
467
|
+
if self._certificate.certificate_policies_value is None:
|
|
468
|
+
return False
|
|
469
|
+
|
|
470
|
+
for policy_information in self._certificate.certificate_policies_value:
|
|
471
|
+
if policy_information['policy_identifier'].dotted in oid_values:
|
|
472
|
+
return True
|
|
473
|
+
|
|
474
|
+
return False
|
|
475
|
+
|
|
476
|
+
@property
|
|
477
|
+
def extended_validation(self):
|
|
478
|
+
return any(map(self._has_any_policy_value, self._EV_OIDS_BY_CA.values()))
|
|
479
|
+
|
|
480
|
+
@property
|
|
481
|
+
def tls_features(self):
|
|
482
|
+
tls_feature_value = self._certificate.tls_feature_value
|
|
483
|
+
if tls_feature_value is None:
|
|
484
|
+
return []
|
|
485
|
+
|
|
486
|
+
return list(map(lambda feature: TlsExtensionType.from_code(feature.native), tls_feature_value))
|
|
487
|
+
|
|
488
|
+
@property
|
|
489
|
+
def serial_number(self):
|
|
490
|
+
return self._certificate.serial_number
|
|
491
|
+
|
|
492
|
+
@property
|
|
493
|
+
def subject(self):
|
|
494
|
+
return OrderedDict([
|
|
495
|
+
(six.ensure_str(name), value)
|
|
496
|
+
for name, value in self._certificate.subject.native.items()
|
|
497
|
+
])
|
|
498
|
+
|
|
499
|
+
@property
|
|
500
|
+
def issuer(self):
|
|
501
|
+
return self._certificate.issuer.native
|
|
502
|
+
|
|
503
|
+
@property
|
|
504
|
+
def valid_domains(self):
|
|
505
|
+
return self._certificate.valid_domains
|
|
506
|
+
|
|
507
|
+
def is_subject_matches(self, host_name):
|
|
508
|
+
return self._certificate.is_valid_domain_ip(six.u(host_name))
|
|
509
|
+
|
|
510
|
+
@property
|
|
511
|
+
def subject_alternative_names(self):
|
|
512
|
+
if self._certificate.subject_alt_name_value is None:
|
|
513
|
+
return []
|
|
514
|
+
|
|
515
|
+
return self._certificate.subject_alt_name_value.native
|
|
516
|
+
|
|
517
|
+
@property
|
|
518
|
+
def crl_distribution_points(self):
|
|
519
|
+
if self._certificate.crl_distribution_points_value is None:
|
|
520
|
+
return []
|
|
521
|
+
|
|
522
|
+
return [
|
|
523
|
+
crl_distribution_point.url
|
|
524
|
+
for crl_distribution_point in self._certificate.crl_distribution_points_value
|
|
525
|
+
]
|
|
526
|
+
|
|
527
|
+
@property
|
|
528
|
+
def ocsp_responders(self):
|
|
529
|
+
return self._certificate.ocsp_urls
|
|
530
|
+
|
|
531
|
+
@property
|
|
532
|
+
def is_ca(self):
|
|
533
|
+
return self._certificate.ca
|
|
534
|
+
|
|
535
|
+
@property
|
|
536
|
+
def is_self_signed(self):
|
|
537
|
+
return self._certificate.self_issued
|
|
538
|
+
|
|
539
|
+
def _asdict(self):
|
|
540
|
+
items = [
|
|
541
|
+
('algorithm', self.key_type),
|
|
542
|
+
('size', PublicKeySize(self.key_type, self.key_size)),
|
|
543
|
+
('version', self._certificate['tbs_certificate']['version'].native),
|
|
544
|
+
('serial_number', str(self.serial_number)),
|
|
545
|
+
('subject', self.subject),
|
|
546
|
+
('subject_alternative_names', sorted(self.subject_alternative_names)),
|
|
547
|
+
('issuer', self.issuer),
|
|
548
|
+
('signature_hash_algorithm', self.signature_hash_algorithm),
|
|
549
|
+
('validity', collections.OrderedDict([
|
|
550
|
+
('not_before', str(self.valid_not_before)),
|
|
551
|
+
('not_after', str(self.valid_not_after)),
|
|
552
|
+
('period', str(self.validity_period)),
|
|
553
|
+
('remaining', str(self.validity_remaining_time.days) if self.validity_remaining_time else None),
|
|
554
|
+
])),
|
|
555
|
+
('revocation', collections.OrderedDict([
|
|
556
|
+
('crl_distribution_points', self.crl_distribution_points),
|
|
557
|
+
('ocsp_responders', self.ocsp_responders),
|
|
558
|
+
])),
|
|
559
|
+
('fingerprints', self.fingerprints),
|
|
560
|
+
('public_key_pin', self.public_key_pin),
|
|
561
|
+
]
|
|
562
|
+
|
|
563
|
+
if not self.is_ca:
|
|
564
|
+
items += [
|
|
565
|
+
('end_entity', collections.OrderedDict([
|
|
566
|
+
('extended_validation', self.extended_validation),
|
|
567
|
+
('tls_features', list(map(lambda feature: feature.name, self.tls_features))),
|
|
568
|
+
]))
|
|
569
|
+
]
|
|
570
|
+
|
|
571
|
+
return collections.OrderedDict(items)
|