blob: 599929f2329eaac7bdd2a09c8d9e155ceea88c4c [file] [log] [blame]
wbonde91513e2015-06-03 14:52:18 -04001# coding: utf-8
wbondea25fc22015-06-19 15:07:04 -04002
3"""
4ASN.1 type classes for public and private keys. Exports the following items:
5
6 - DSAPrivateKey()
7 - ECPrivateKey()
8 - EncryptedPrivateKeyInfo()
9 - PrivateKeyInfo()
10 - PublicKeyInfo()
11 - RSAPrivateKey()
12 - RSAPublicKey()
13
14Other type classes are defined that help compose the types listed above.
15"""
16
wbond6b66ab52015-06-21 10:26:45 -040017from __future__ import unicode_literals, division, absolute_import, print_function
wbonde91513e2015-06-03 14:52:18 -040018
19import hashlib
wbondf937f482015-06-19 01:51:11 -040020import math
wbonde91513e2015-06-03 14:52:18 -040021
wbond564e7442019-07-13 07:04:14 -040022from ._errors import unwrap, APIException
23from ._types import type_name, byte_cls
wbonda8fa8c52019-10-04 19:46:27 -040024from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm, RSAESOAEPParams, RSASSAPSSParams
wbonde91513e2015-06-03 14:52:18 -040025from .core import (
26 Any,
wbond8b59e052015-06-16 00:13:05 -040027 Asn1Value,
wbond88ba5ee2016-03-17 11:39:22 -040028 BitString,
wbonde91513e2015-06-03 14:52:18 -040029 Choice,
30 Integer,
wbonde91513e2015-06-03 14:52:18 -040031 IntegerOctetString,
32 Null,
33 ObjectIdentifier,
34 OctetBitString,
35 OctetString,
wbonde5a1c6e2015-08-03 07:42:28 -040036 ParsableOctetString,
37 ParsableOctetBitString,
wbonde91513e2015-06-03 14:52:18 -040038 Sequence,
39 SequenceOf,
40 SetOf,
41)
wbonde3e4bcd2015-07-30 08:58:20 -040042from .util import int_from_bytes, int_to_bytes
wbonde91513e2015-06-03 14:52:18 -040043
44
45class OtherPrimeInfo(Sequence):
46 """
47 Source: https://tools.ietf.org/html/rfc3447#page-46
48 """
49
50 _fields = [
51 ('prime', Integer),
52 ('exponent', Integer),
53 ('coefficient', Integer),
54 ]
55
56
57class OtherPrimeInfos(SequenceOf):
58 """
59 Source: https://tools.ietf.org/html/rfc3447#page-46
60 """
61
62 _child_spec = OtherPrimeInfo
63
64
65class RSAPrivateKeyVersion(Integer):
66 """
67 Original Name: Version
68 Source: https://tools.ietf.org/html/rfc3447#page-45
69 """
70
71 _map = {
72 0: 'two-prime',
73 1: 'multi',
74 }
75
76
77class RSAPrivateKey(Sequence):
78 """
79 Source: https://tools.ietf.org/html/rfc3447#page-45
80 """
81
82 _fields = [
83 ('version', RSAPrivateKeyVersion),
84 ('modulus', Integer),
85 ('public_exponent', Integer),
86 ('private_exponent', Integer),
87 ('prime1', Integer),
88 ('prime2', Integer),
89 ('exponent1', Integer),
90 ('exponent2', Integer),
91 ('coefficient', Integer),
92 ('other_prime_infos', OtherPrimeInfos, {'optional': True})
93 ]
94
95
96class RSAPublicKey(Sequence):
97 """
98 Source: https://tools.ietf.org/html/rfc3447#page-44
99 """
100
101 _fields = [
102 ('modulus', Integer),
103 ('public_exponent', Integer)
104 ]
105
106
107class DSAPrivateKey(Sequence):
108 """
wbondd913db52015-08-06 12:44:15 -0400109 The ASN.1 structure that OpenSSL uses to store a DSA private key that is
wbonde91513e2015-06-03 14:52:18 -0400110 not part of a PKCS#8 structure. Reversed engineered from english-language
111 description on linked OpenSSL documentation page.
112
113 Original Name: None
114 Source: https://www.openssl.org/docs/apps/dsa.html
115 """
116
117 _fields = [
118 ('version', Integer),
119 ('p', Integer),
120 ('q', Integer),
121 ('g', Integer),
122 ('public_key', Integer),
123 ('private_key', Integer),
124 ]
125
126
wbondb6971732015-07-29 21:32:52 -0400127class _ECPoint():
128 """
129 In both PublicKeyInfo and PrivateKeyInfo, the EC public key is a byte
130 string that is encoded as a bit string. This class adds convenience
131 methods for converting to and from the byte string to a pair of integers
132 that are the X and Y coordinates.
133 """
134
135 @classmethod
136 def from_coords(cls, x, y):
137 """
138 Creates an ECPoint object from the X and Y integer coordinates of the
139 point
140
141 :param x:
142 The X coordinate, as an integer
143
144 :param y:
145 The Y coordinate, as an integer
146
147 :return:
148 An ECPoint object
149 """
150
151 x_bytes = int(math.ceil(math.log(x, 2) / 8.0))
152 y_bytes = int(math.ceil(math.log(y, 2) / 8.0))
153
154 num_bytes = max(x_bytes, y_bytes)
155
156 byte_string = b'\x04'
157 byte_string += int_to_bytes(x, width=num_bytes)
158 byte_string += int_to_bytes(y, width=num_bytes)
159
160 return cls(byte_string)
161
162 def to_coords(self):
163 """
164 Returns the X and Y coordinates for this EC point, as native Python
165 integers
166
167 :return:
168 A 2-element tuple containing integers (X, Y)
169 """
170
171 data = self.native
172 first_byte = data[0:1]
173
174 # Uncompressed
175 if first_byte == b'\x04':
176 remaining = data[1:]
177 field_len = len(remaining) // 2
178 x = int_from_bytes(remaining[0:field_len])
179 y = int_from_bytes(remaining[field_len:])
180 return (x, y)
181
wbond407e9e32015-08-24 09:35:28 -0400182 if first_byte not in set([b'\x02', b'\x03']):
wbonda26664f2015-10-07 11:57:35 -0400183 raise ValueError(unwrap(
184 '''
185 Invalid EC public key - first byte is incorrect
186 '''
187 ))
wbondb6971732015-07-29 21:32:52 -0400188
wbonda26664f2015-10-07 11:57:35 -0400189 raise ValueError(unwrap(
190 '''
191 Compressed representations of EC public keys are not supported due
192 to patent US6252960
193 '''
194 ))
wbondb6971732015-07-29 21:32:52 -0400195
196
197class ECPoint(OctetString, _ECPoint):
198
199 pass
200
201
202class ECPointBitString(OctetBitString, _ECPoint):
203
204 pass
205
206
wbonde91513e2015-06-03 14:52:18 -0400207class SpecifiedECDomainVersion(Integer):
208 """
209 Source: http://www.secg.org/sec1-v2.pdf page 104
210 """
211 _map = {
212 1: 'ecdpVer1',
213 2: 'ecdpVer2',
214 3: 'ecdpVer3',
215 }
216
217
218class FieldType(ObjectIdentifier):
219 """
220 Original Name: None
221 Source: http://www.secg.org/sec1-v2.pdf page 101
222 """
223
224 _map = {
225 '1.2.840.10045.1.1': 'prime_field',
226 '1.2.840.10045.1.2': 'characteristic_two_field',
227 }
228
229
230class CharacteristicTwoBasis(ObjectIdentifier):
231 """
232 Original Name: None
233 Source: http://www.secg.org/sec1-v2.pdf page 102
234 """
235
236 _map = {
237 '1.2.840.10045.1.2.1.1': 'gn_basis',
238 '1.2.840.10045.1.2.1.2': 'tp_basis',
239 '1.2.840.10045.1.2.1.3': 'pp_basis',
240 }
241
242
243class Pentanomial(Sequence):
244 """
245 Source: http://www.secg.org/sec1-v2.pdf page 102
246 """
247
248 _fields = [
249 ('k1', Integer),
250 ('k2', Integer),
251 ('k3', Integer),
252 ]
253
254
255class CharacteristicTwo(Sequence):
256 """
257 Original Name: Characteristic-two
258 Source: http://www.secg.org/sec1-v2.pdf page 101
259 """
260
261 _fields = [
262 ('m', Integer),
263 ('basis', CharacteristicTwoBasis),
264 ('parameters', Any),
265 ]
266
267 _oid_pair = ('basis', 'parameters')
268 _oid_specs = {
269 'gn_basis': Null,
270 'tp_basis': Integer,
271 'pp_basis': Pentanomial,
272 }
273
274
275class FieldID(Sequence):
276 """
277 Source: http://www.secg.org/sec1-v2.pdf page 100
278 """
279
280 _fields = [
281 ('field_type', FieldType),
282 ('parameters', Any),
283 ]
284
285 _oid_pair = ('field_type', 'parameters')
286 _oid_specs = {
287 'prime_field': Integer,
288 'characteristic_two_field': CharacteristicTwo,
289 }
290
291
292class Curve(Sequence):
293 """
294 Source: http://www.secg.org/sec1-v2.pdf page 104
295 """
296
297 _fields = [
298 ('a', OctetString),
299 ('b', OctetString),
300 ('seed', OctetBitString, {'optional': True}),
301 ]
302
303
304class SpecifiedECDomain(Sequence):
305 """
306 Source: http://www.secg.org/sec1-v2.pdf page 103
307 """
308
309 _fields = [
310 ('version', SpecifiedECDomainVersion),
311 ('field_id', FieldID),
312 ('curve', Curve),
wbondb6971732015-07-29 21:32:52 -0400313 ('base', ECPoint),
wbonde91513e2015-06-03 14:52:18 -0400314 ('order', Integer),
315 ('cofactor', Integer, {'optional': True}),
316 ('hash', DigestAlgorithm, {'optional': True}),
317 ]
318
319
320class NamedCurve(ObjectIdentifier):
321 """
322 Various named curves
323
324 Original Name: None
325 Source: https://tools.ietf.org/html/rfc3279#page-23,
326 https://tools.ietf.org/html/rfc5480#page-5
327 """
328
329 _map = {
330 # https://tools.ietf.org/html/rfc3279#page-23
331 '1.2.840.10045.3.0.1': 'c2pnb163v1',
332 '1.2.840.10045.3.0.2': 'c2pnb163v2',
333 '1.2.840.10045.3.0.3': 'c2pnb163v3',
334 '1.2.840.10045.3.0.4': 'c2pnb176w1',
335 '1.2.840.10045.3.0.5': 'c2tnb191v1',
336 '1.2.840.10045.3.0.6': 'c2tnb191v2',
337 '1.2.840.10045.3.0.7': 'c2tnb191v3',
338 '1.2.840.10045.3.0.8': 'c2onb191v4',
339 '1.2.840.10045.3.0.9': 'c2onb191v5',
340 '1.2.840.10045.3.0.10': 'c2pnb208w1',
341 '1.2.840.10045.3.0.11': 'c2tnb239v1',
342 '1.2.840.10045.3.0.12': 'c2tnb239v2',
343 '1.2.840.10045.3.0.13': 'c2tnb239v3',
344 '1.2.840.10045.3.0.14': 'c2onb239v4',
345 '1.2.840.10045.3.0.15': 'c2onb239v5',
346 '1.2.840.10045.3.0.16': 'c2pnb272w1',
347 '1.2.840.10045.3.0.17': 'c2pnb304w1',
348 '1.2.840.10045.3.0.18': 'c2tnb359v1',
349 '1.2.840.10045.3.0.19': 'c2pnb368w1',
350 '1.2.840.10045.3.0.20': 'c2tnb431r1',
wbonde91513e2015-06-03 14:52:18 -0400351 '1.2.840.10045.3.1.2': 'prime192v2',
352 '1.2.840.10045.3.1.3': 'prime192v3',
353 '1.2.840.10045.3.1.4': 'prime239v1',
354 '1.2.840.10045.3.1.5': 'prime239v2',
355 '1.2.840.10045.3.1.6': 'prime239v3',
wbonde91513e2015-06-03 14:52:18 -0400356 # https://tools.ietf.org/html/rfc5480#page-5
wbond4b0557e2019-10-12 04:50:57 -0400357 # http://www.secg.org/SEC2-Ver-1.0.pdf
358 '1.2.840.10045.3.1.1': 'secp192r1',
359 '1.2.840.10045.3.1.7': 'secp256r1',
wbonde91513e2015-06-03 14:52:18 -0400360 '1.3.132.0.1': 'sect163k1',
wbond4b0557e2019-10-12 04:50:57 -0400361 '1.3.132.0.2': 'sect163r1',
362 '1.3.132.0.3': 'sect239k1',
363 '1.3.132.0.4': 'sect113r1',
364 '1.3.132.0.5': 'sect113r2',
365 '1.3.132.0.6': 'secp112r1',
366 '1.3.132.0.7': 'secp112r2',
367 '1.3.132.0.8': 'secp160r1',
368 '1.3.132.0.9': 'secp160k1',
nkostoulas6a6e6302019-02-14 16:03:40 +0000369 '1.3.132.0.10': 'secp256k1',
wbonde91513e2015-06-03 14:52:18 -0400370 '1.3.132.0.15': 'sect163r2',
wbonde91513e2015-06-03 14:52:18 -0400371 '1.3.132.0.16': 'sect283k1',
372 '1.3.132.0.17': 'sect283r1',
wbond4b0557e2019-10-12 04:50:57 -0400373 '1.3.132.0.22': 'sect131r1',
374 '1.3.132.0.23': 'sect131r2',
375 '1.3.132.0.24': 'sect193r1',
376 '1.3.132.0.25': 'sect193r2',
377 '1.3.132.0.26': 'sect233k1',
378 '1.3.132.0.27': 'sect233r1',
379 '1.3.132.0.28': 'secp128r1',
380 '1.3.132.0.29': 'secp128r2',
381 '1.3.132.0.30': 'secp160r2',
382 '1.3.132.0.31': 'secp192k1',
383 '1.3.132.0.32': 'secp224k1',
384 '1.3.132.0.33': 'secp224r1',
wbonde91513e2015-06-03 14:52:18 -0400385 '1.3.132.0.34': 'secp384r1',
wbond4b0557e2019-10-12 04:50:57 -0400386 '1.3.132.0.35': 'secp521r1',
wbonde91513e2015-06-03 14:52:18 -0400387 '1.3.132.0.36': 'sect409k1',
388 '1.3.132.0.37': 'sect409r1',
wbonde91513e2015-06-03 14:52:18 -0400389 '1.3.132.0.38': 'sect571k1',
390 '1.3.132.0.39': 'sect571r1',
Jörn Heissler754aa9d2019-11-03 10:40:57 +0100391 # https://tools.ietf.org/html/rfc5639#section-4.1
392 '1.3.36.3.3.2.8.1.1.1': 'brainpoolp160r1',
393 '1.3.36.3.3.2.8.1.1.2': 'brainpoolp160t1',
394 '1.3.36.3.3.2.8.1.1.3': 'brainpoolp192r1',
395 '1.3.36.3.3.2.8.1.1.4': 'brainpoolp192t1',
396 '1.3.36.3.3.2.8.1.1.5': 'brainpoolp224r1',
397 '1.3.36.3.3.2.8.1.1.6': 'brainpoolp224t1',
398 '1.3.36.3.3.2.8.1.1.7': 'brainpoolp256r1',
399 '1.3.36.3.3.2.8.1.1.8': 'brainpoolp256t1',
400 '1.3.36.3.3.2.8.1.1.9': 'brainpoolp320r1',
401 '1.3.36.3.3.2.8.1.1.10': 'brainpoolp320t1',
402 '1.3.36.3.3.2.8.1.1.11': 'brainpoolp384r1',
403 '1.3.36.3.3.2.8.1.1.12': 'brainpoolp384t1',
404 '1.3.36.3.3.2.8.1.1.13': 'brainpoolp512r1',
405 '1.3.36.3.3.2.8.1.1.14': 'brainpoolp512t1',
wbonde91513e2015-06-03 14:52:18 -0400406 }
407
wbond61ae7d72019-06-29 10:27:40 -0400408 _key_sizes = {
409 # Order values used to compute these sourced from
410 # http://cr.openjdk.java.net/~vinnie/7194075/webrev-3/src/share/classes/sun/security/ec/CurveDB.java.html
411 '1.2.840.10045.3.0.1': 21,
412 '1.2.840.10045.3.0.2': 21,
413 '1.2.840.10045.3.0.3': 21,
414 '1.2.840.10045.3.0.4': 21,
415 '1.2.840.10045.3.0.5': 24,
416 '1.2.840.10045.3.0.6': 24,
417 '1.2.840.10045.3.0.7': 24,
418 '1.2.840.10045.3.0.8': 24,
419 '1.2.840.10045.3.0.9': 24,
420 '1.2.840.10045.3.0.10': 25,
421 '1.2.840.10045.3.0.11': 30,
422 '1.2.840.10045.3.0.12': 30,
423 '1.2.840.10045.3.0.13': 30,
424 '1.2.840.10045.3.0.14': 30,
425 '1.2.840.10045.3.0.15': 30,
426 '1.2.840.10045.3.0.16': 33,
427 '1.2.840.10045.3.0.17': 37,
428 '1.2.840.10045.3.0.18': 45,
429 '1.2.840.10045.3.0.19': 45,
430 '1.2.840.10045.3.0.20': 53,
431 '1.2.840.10045.3.1.2': 24,
432 '1.2.840.10045.3.1.3': 24,
433 '1.2.840.10045.3.1.4': 30,
434 '1.2.840.10045.3.1.5': 30,
435 '1.2.840.10045.3.1.6': 30,
436 # Order values used to compute these sourced from
437 # http://www.secg.org/SEC2-Ver-1.0.pdf
Jörn Heisslerdcb9ea52019-11-03 10:30:18 +0100438 # ceil(n.bit_length() / 8)
wbond4b0557e2019-10-12 04:50:57 -0400439 '1.2.840.10045.3.1.1': 24,
440 '1.2.840.10045.3.1.7': 32,
wbond61ae7d72019-06-29 10:27:40 -0400441 '1.3.132.0.1': 21,
wbond4b0557e2019-10-12 04:50:57 -0400442 '1.3.132.0.2': 21,
Jörn Heisslerdcb9ea52019-11-03 10:30:18 +0100443 '1.3.132.0.3': 30,
444 '1.3.132.0.4': 15,
445 '1.3.132.0.5': 15,
wbond4b0557e2019-10-12 04:50:57 -0400446 '1.3.132.0.6': 14,
447 '1.3.132.0.7': 14,
Jörn Heisslerdcb9ea52019-11-03 10:30:18 +0100448 '1.3.132.0.8': 21,
449 '1.3.132.0.9': 21,
wbond61ae7d72019-06-29 10:27:40 -0400450 '1.3.132.0.10': 32,
451 '1.3.132.0.15': 21,
wbond61ae7d72019-06-29 10:27:40 -0400452 '1.3.132.0.16': 36,
453 '1.3.132.0.17': 36,
wbond4b0557e2019-10-12 04:50:57 -0400454 '1.3.132.0.22': 17,
455 '1.3.132.0.23': 17,
Jörn Heisslerdcb9ea52019-11-03 10:30:18 +0100456 '1.3.132.0.24': 25,
457 '1.3.132.0.25': 25,
wbond4b0557e2019-10-12 04:50:57 -0400458 '1.3.132.0.26': 29,
Jörn Heisslerdcb9ea52019-11-03 10:30:18 +0100459 '1.3.132.0.27': 30,
wbond4b0557e2019-10-12 04:50:57 -0400460 '1.3.132.0.28': 16,
461 '1.3.132.0.29': 16,
Jörn Heisslerdcb9ea52019-11-03 10:30:18 +0100462 '1.3.132.0.30': 21,
wbond4b0557e2019-10-12 04:50:57 -0400463 '1.3.132.0.31': 24,
Jörn Heisslerdcb9ea52019-11-03 10:30:18 +0100464 '1.3.132.0.32': 29,
wbond4b0557e2019-10-12 04:50:57 -0400465 '1.3.132.0.33': 28,
wbond61ae7d72019-06-29 10:27:40 -0400466 '1.3.132.0.34': 48,
wbond4b0557e2019-10-12 04:50:57 -0400467 '1.3.132.0.35': 66,
wbond61ae7d72019-06-29 10:27:40 -0400468 '1.3.132.0.36': 51,
Jörn Heisslerdcb9ea52019-11-03 10:30:18 +0100469 '1.3.132.0.37': 52,
wbond61ae7d72019-06-29 10:27:40 -0400470 '1.3.132.0.38': 72,
471 '1.3.132.0.39': 72,
Jörn Heissler754aa9d2019-11-03 10:40:57 +0100472 # Order values used to compute these sourced from
473 # https://tools.ietf.org/html/rfc5639#section-3
474 # ceil(q.bit_length() / 8)
475 '1.3.36.3.3.2.8.1.1.1': 20,
476 '1.3.36.3.3.2.8.1.1.2': 20,
477 '1.3.36.3.3.2.8.1.1.3': 24,
478 '1.3.36.3.3.2.8.1.1.4': 24,
479 '1.3.36.3.3.2.8.1.1.5': 28,
480 '1.3.36.3.3.2.8.1.1.6': 28,
481 '1.3.36.3.3.2.8.1.1.7': 32,
482 '1.3.36.3.3.2.8.1.1.8': 32,
483 '1.3.36.3.3.2.8.1.1.9': 40,
484 '1.3.36.3.3.2.8.1.1.10': 40,
485 '1.3.36.3.3.2.8.1.1.11': 48,
486 '1.3.36.3.3.2.8.1.1.12': 48,
487 '1.3.36.3.3.2.8.1.1.13': 64,
488 '1.3.36.3.3.2.8.1.1.14': 64,
wbond61ae7d72019-06-29 10:27:40 -0400489 }
490
491 @classmethod
492 def register(cls, name, oid, key_size):
493 """
494 Registers a new named elliptic curve that is not included in the
495 default list of named curves
496
497 :param name:
498 A unicode string of the curve name
499
500 :param oid:
501 A unicode string of the dotted format OID
502
503 :param key_size:
504 An integer of the number of bytes the private key should be
505 encoded to
506 """
507
508 cls._map[oid] = name
wbond35d68672019-09-10 07:32:58 -0400509 if cls._reverse_map is not None:
510 cls._reverse_map[name] = oid
wbond61ae7d72019-06-29 10:27:40 -0400511 cls._key_sizes[oid] = key_size
512
wbonde91513e2015-06-03 14:52:18 -0400513
514class ECDomainParameters(Choice):
515 """
516 Source: http://www.secg.org/sec1-v2.pdf page 102
517 """
518
519 _alternatives = [
520 ('specified', SpecifiedECDomain),
521 ('named', NamedCurve),
522 ('implicit_ca', Null),
523 ]
524
wbond61ae7d72019-06-29 10:27:40 -0400525 @property
526 def key_size(self):
527 if self.name == 'implicit_ca':
528 raise ValueError(unwrap(
529 '''
530 Unable to calculate key_size from ECDomainParameters
531 that are implicitly defined by the CA key
532 '''
533 ))
534
535 if self.name == 'specified':
536 order = self.chosen['order'].native
537 return math.ceil(math.log(order, 2.0) / 8.0)
538
539 oid = self.chosen.dotted
540 if oid not in NamedCurve._key_sizes:
541 raise ValueError(unwrap(
542 '''
543 The asn1crypto.keys.NamedCurve %s does not have a registered key length,
544 please call asn1crypto.keys.NamedCurve.register()
545 ''',
546 repr(oid)
547 ))
548 return NamedCurve._key_sizes[oid]
549
wbonde91513e2015-06-03 14:52:18 -0400550
551class ECPrivateKeyVersion(Integer):
552 """
553 Original Name: None
554 Source: http://www.secg.org/sec1-v2.pdf page 108
555 """
556
557 _map = {
558 1: 'ecPrivkeyVer1',
559 }
560
561
562class ECPrivateKey(Sequence):
563 """
564 Source: http://www.secg.org/sec1-v2.pdf page 108
565 """
566
567 _fields = [
568 ('version', ECPrivateKeyVersion),
569 ('private_key', IntegerOctetString),
wbondd62ed9a2017-09-15 07:13:52 -0400570 ('parameters', ECDomainParameters, {'explicit': 0, 'optional': True}),
571 ('public_key', ECPointBitString, {'explicit': 1, 'optional': True}),
wbonde91513e2015-06-03 14:52:18 -0400572 ]
573
wbond61ae7d72019-06-29 10:27:40 -0400574 # Ensures the key is set to the correct length when encoding
575 _key_size = None
576
577 # This is necessary to ensure the private_key IntegerOctetString is encoded properly
578 def __setitem__(self, key, value):
579 res = super(ECPrivateKey, self).__setitem__(key, value)
580
581 if key == 'private_key':
582 if self._key_size is None:
583 # Infer the key_size from the existing private key if possible
584 pkey_contents = self['private_key'].contents
585 if isinstance(pkey_contents, byte_cls) and len(pkey_contents) > 1:
586 self.set_key_size(len(self['private_key'].contents))
587
588 elif self._key_size is not None:
589 self._update_key_size()
590
591 elif key == 'parameters' and isinstance(self['parameters'], ECDomainParameters) and \
592 self['parameters'].name != 'implicit_ca':
593 self.set_key_size(self['parameters'].key_size)
594
595 return res
596
597 def set_key_size(self, key_size):
598 """
599 Sets the key_size to ensure the private key is encoded to the proper length
600
601 :param key_size:
602 An integer byte length to encode the private_key to
603 """
604
605 self._key_size = key_size
606 self._update_key_size()
607
608 def _update_key_size(self):
609 """
610 Ensure the private_key explicit encoding width is set
611 """
612
613 if self._key_size is not None and isinstance(self['private_key'], IntegerOctetString):
614 self['private_key'].set_encoded_width(self._key_size)
615
wbonde91513e2015-06-03 14:52:18 -0400616
wbonde91513e2015-06-03 14:52:18 -0400617class DSAParams(Sequence):
618 """
619 Parameters for a DSA public or private key
620
621 Original Name: Dss-Parms
622 Source: https://tools.ietf.org/html/rfc3279#page-9
623 """
624
625 _fields = [
626 ('p', Integer),
627 ('q', Integer),
628 ('g', Integer),
629 ]
630
631
632class Attribute(Sequence):
633 """
634 Source: https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.501-198811-S!!PDF-E&type=items page 8
635 """
636
637 _fields = [
638 ('type', ObjectIdentifier),
639 ('values', SetOf, {'spec': Any}),
640 ]
641
642
643class Attributes(SetOf):
644 """
645 Source: https://tools.ietf.org/html/rfc5208#page-3
646 """
647
648 _child_spec = Attribute
649
650
651class PrivateKeyAlgorithmId(ObjectIdentifier):
652 """
653 These OIDs for various public keys are reused when storing private keys
654 inside of a PKCS#8 structure
655
656 Original Name: None
657 Source: https://tools.ietf.org/html/rfc3279
658 """
659
660 _map = {
661 # https://tools.ietf.org/html/rfc3279#page-19
662 '1.2.840.113549.1.1.1': 'rsa',
spchan14d22d22019-04-29 09:47:01 +0800663 # https://tools.ietf.org/html/rfc4055#page-8
664 '1.2.840.113549.1.1.10': 'rsassa_pss',
wbonde91513e2015-06-03 14:52:18 -0400665 # https://tools.ietf.org/html/rfc3279#page-18
666 '1.2.840.10040.4.1': 'dsa',
667 # https://tools.ietf.org/html/rfc3279#page-13
wbond680cba12015-07-01 23:53:54 -0400668 '1.2.840.10045.2.1': 'ec',
wbonde91513e2015-06-03 14:52:18 -0400669 }
670
671
wbond381a4da2016-08-30 11:39:54 -0400672class PrivateKeyAlgorithm(_ForceNullParameters, Sequence):
wbonde91513e2015-06-03 14:52:18 -0400673 """
674 Original Name: PrivateKeyAlgorithmIdentifier
675 Source: https://tools.ietf.org/html/rfc5208#page-3
676 """
677
678 _fields = [
679 ('algorithm', PrivateKeyAlgorithmId),
680 ('parameters', Any, {'optional': True}),
681 ]
682
683 _oid_pair = ('algorithm', 'parameters')
684 _oid_specs = {
wbonde91513e2015-06-03 14:52:18 -0400685 'dsa': DSAParams,
wbond680cba12015-07-01 23:53:54 -0400686 'ec': ECDomainParameters,
spchan14d22d22019-04-29 09:47:01 +0800687 'rsassa_pss': RSASSAPSSParams,
wbonde91513e2015-06-03 14:52:18 -0400688 }
689
690
691class PrivateKeyInfo(Sequence):
692 """
693 Source: https://tools.ietf.org/html/rfc5208#page-3
694 """
695
696 _fields = [
697 ('version', Integer),
698 ('private_key_algorithm', PrivateKeyAlgorithm),
wbonde5a1c6e2015-08-03 07:42:28 -0400699 ('private_key', ParsableOctetString),
wbondd62ed9a2017-09-15 07:13:52 -0400700 ('attributes', Attributes, {'implicit': 0, 'optional': True}),
wbonde91513e2015-06-03 14:52:18 -0400701 ]
702
703 def _private_key_spec(self):
704 algorithm = self['private_key_algorithm']['algorithm'].native
705 return {
706 'rsa': RSAPrivateKey,
spchan14d22d22019-04-29 09:47:01 +0800707 'rsassa_pss': RSAPrivateKey,
wbonde91513e2015-06-03 14:52:18 -0400708 'dsa': Integer,
wbond680cba12015-07-01 23:53:54 -0400709 'ec': ECPrivateKey,
wbonde91513e2015-06-03 14:52:18 -0400710 }[algorithm]
711
712 _spec_callbacks = {
713 'private_key': _private_key_spec
714 }
715
wbondf937f482015-06-19 01:51:11 -0400716 _algorithm = None
717 _bit_size = None
wbondeb5eb6e2015-06-18 14:14:12 -0400718 _public_key = None
wbonde91513e2015-06-03 14:52:18 -0400719 _fingerprint = None
720
wbond8b59e052015-06-16 00:13:05 -0400721 @classmethod
722 def wrap(cls, private_key, algorithm):
723 """
724 Wraps a private key in a PrivateKeyInfo structure
725
726 :param private_key:
727 A byte string or Asn1Value object of the private key
728
729 :param algorithm:
wbond680cba12015-07-01 23:53:54 -0400730 A unicode string of "rsa", "dsa" or "ec"
wbond8b59e052015-06-16 00:13:05 -0400731
732 :return:
733 A PrivateKeyInfo object
734 """
735
736 if not isinstance(private_key, byte_cls) and not isinstance(private_key, Asn1Value):
wbonda26664f2015-10-07 11:57:35 -0400737 raise TypeError(unwrap(
738 '''
739 private_key must be a byte string or Asn1Value, not %s
740 ''',
741 type_name(private_key)
742 ))
wbond8b59e052015-06-16 00:13:05 -0400743
744 if algorithm == 'rsa':
745 if not isinstance(private_key, RSAPrivateKey):
746 private_key = RSAPrivateKey.load(private_key)
747 params = Null()
748 elif algorithm == 'dsa':
749 if not isinstance(private_key, DSAPrivateKey):
750 private_key = DSAPrivateKey.load(private_key)
751 params = DSAParams()
752 params['p'] = private_key['p']
753 params['q'] = private_key['q']
754 params['g'] = private_key['g']
wbondeb5eb6e2015-06-18 14:14:12 -0400755 public_key = private_key['public_key']
wbonda4bfddd2015-06-17 23:36:16 -0400756 private_key = private_key['private_key']
wbond680cba12015-07-01 23:53:54 -0400757 elif algorithm == 'ec':
wbond8b59e052015-06-16 00:13:05 -0400758 if not isinstance(private_key, ECPrivateKey):
759 private_key = ECPrivateKey.load(private_key)
wbond88eb8482016-08-05 06:33:27 -0400760 else:
761 private_key = private_key.copy()
wbond8b59e052015-06-16 00:13:05 -0400762 params = private_key['parameters']
wbonda4bfddd2015-06-17 23:36:16 -0400763 del private_key['parameters']
wbond8b59e052015-06-16 00:13:05 -0400764 else:
wbonda26664f2015-10-07 11:57:35 -0400765 raise ValueError(unwrap(
766 '''
767 algorithm must be one of "rsa", "dsa", "ec", not %s
768 ''',
769 repr(algorithm)
770 ))
wbond8b59e052015-06-16 00:13:05 -0400771
772 private_key_algo = PrivateKeyAlgorithm()
773 private_key_algo['algorithm'] = PrivateKeyAlgorithmId(algorithm)
774 private_key_algo['parameters'] = params
775
776 container = cls()
wbonda26664f2015-10-07 11:57:35 -0400777 container._algorithm = algorithm
wbond8b59e052015-06-16 00:13:05 -0400778 container['version'] = Integer(0)
779 container['private_key_algorithm'] = private_key_algo
wbonde5a1c6e2015-08-03 07:42:28 -0400780 container['private_key'] = private_key
wbond8b59e052015-06-16 00:13:05 -0400781
wbondeb5eb6e2015-06-18 14:14:12 -0400782 # Here we save the DSA public key if possible since it is not contained
783 # within the PKCS#8 structure for a DSA key
784 if algorithm == 'dsa':
wbonda26664f2015-10-07 11:57:35 -0400785 container._public_key = public_key
wbondeb5eb6e2015-06-18 14:14:12 -0400786
wbond8b59e052015-06-16 00:13:05 -0400787 return container
788
wbond61ae7d72019-06-29 10:27:40 -0400789 # This is necessary to ensure any contained ECPrivateKey is the
790 # correct size
791 def __setitem__(self, key, value):
792 res = super(PrivateKeyInfo, self).__setitem__(key, value)
793
794 algorithm = self['private_key_algorithm']
795
796 # When possible, use the parameter info to make sure the private key encoding
797 # retains any necessary leading bytes, instead of them being dropped
798 if (key == 'private_key_algorithm' or key == 'private_key') and \
799 algorithm['algorithm'].native == 'ec' and \
800 isinstance(algorithm['parameters'], ECDomainParameters) and \
801 algorithm['parameters'].name != 'implicit_ca' and \
802 isinstance(self['private_key'], ParsableOctetString) and \
803 isinstance(self['private_key'].parsed, ECPrivateKey):
804 self['private_key'].parsed.set_key_size(algorithm['parameters'].key_size)
805
806 return res
807
wbondeb5eb6e2015-06-18 14:14:12 -0400808 def unwrap(self):
809 """
810 Unwraps the private key into an RSAPrivateKey, DSAPrivateKey or
811 ECPrivateKey object
812
813 :return:
814 An RSAPrivateKey, DSAPrivateKey or ECPrivateKey object
815 """
816
wbond564e7442019-07-13 07:04:14 -0400817 raise APIException(
818 'asn1crypto.keys.PrivateKeyInfo().unwrap() has been removed, '
819 'please use oscrypto.asymmetric.PrivateKey().unwrap() instead')
wbondeb5eb6e2015-06-18 14:14:12 -0400820
821 @property
wbondf937f482015-06-19 01:51:11 -0400822 def curve(self):
823 """
wbond680cba12015-07-01 23:53:54 -0400824 Returns information about the curve used for an EC key
wbondf937f482015-06-19 01:51:11 -0400825
826 :raises:
wbond680cba12015-07-01 23:53:54 -0400827 ValueError - when the key is not an EC key
wbondf937f482015-06-19 01:51:11 -0400828
829 :return:
830 A two-element tuple, with the first element being a unicode string
831 of "implicit_ca", "specified" or "named". If the first element is
832 "implicit_ca", the second is None. If "specified", the second is
833 an OrderedDict that is the native version of SpecifiedECDomain. If
834 "named", the second is a unicode string of the curve name.
835 """
836
wbond680cba12015-07-01 23:53:54 -0400837 if self.algorithm != 'ec':
wbonda26664f2015-10-07 11:57:35 -0400838 raise ValueError(unwrap(
839 '''
840 Only EC keys have a curve, this key is %s
841 ''',
842 self.algorithm.upper()
843 ))
wbondf937f482015-06-19 01:51:11 -0400844
845 params = self['private_key_algorithm']['parameters']
846 chosen = params.chosen
847
848 if params.name == 'implicit_ca':
849 value = None
850 else:
851 value = chosen.native
852
853 return (params.name, value)
854
855 @property
wbond1b00a592015-06-28 12:58:26 -0400856 def hash_algo(self):
857 """
858 Returns the name of the family of hash algorithms used to generate a
859 DSA key
860
861 :raises:
862 ValueError - when the key is not a DSA key
863
864 :return:
865 A unicode string of "sha1" or "sha2"
866 """
867
868 if self.algorithm != 'dsa':
wbonda26664f2015-10-07 11:57:35 -0400869 raise ValueError(unwrap(
870 '''
871 Only DSA keys are generated using a hash algorithm, this key is
872 %s
873 ''',
874 self.algorithm.upper()
875 ))
wbond1b00a592015-06-28 12:58:26 -0400876
877 byte_len = math.log(self['private_key_algorithm']['parameters']['q'].native, 2) / 8
878
879 return 'sha1' if byte_len <= 20 else 'sha2'
880
881 @property
wbondf937f482015-06-19 01:51:11 -0400882 def algorithm(self):
883 """
884 :return:
wbond680cba12015-07-01 23:53:54 -0400885 A unicode string of "rsa", "dsa" or "ec"
wbondf937f482015-06-19 01:51:11 -0400886 """
887
888 if self._algorithm is None:
889 self._algorithm = self['private_key_algorithm']['algorithm'].native
890 return self._algorithm
891
892 @property
893 def bit_size(self):
894 """
895 :return:
wbondf4f176c2015-07-07 23:27:19 -0400896 The bit size of the private key, as an integer
wbondf937f482015-06-19 01:51:11 -0400897 """
898
899 if self._bit_size is None:
900 if self.algorithm == 'rsa':
wbondf4f176c2015-07-07 23:27:19 -0400901 prime = self['private_key'].parsed['modulus'].native
wbondf937f482015-06-19 01:51:11 -0400902 elif self.algorithm == 'dsa':
903 prime = self['private_key_algorithm']['parameters']['p'].native
wbond680cba12015-07-01 23:53:54 -0400904 elif self.algorithm == 'ec':
wbondf937f482015-06-19 01:51:11 -0400905 prime = self['private_key'].parsed['private_key'].native
wbondf4f176c2015-07-07 23:27:19 -0400906 self._bit_size = int(math.ceil(math.log(prime, 2)))
wbond69d96d82016-06-15 06:02:18 -0400907 modulus = self._bit_size % 8
908 if modulus != 0:
909 self._bit_size += 8 - modulus
wbondf937f482015-06-19 01:51:11 -0400910 return self._bit_size
911
912 @property
wbondf4f176c2015-07-07 23:27:19 -0400913 def byte_size(self):
914 """
915 :return:
916 The byte size of the private key, as an integer
917 """
918
919 return int(math.ceil(self.bit_size / 8))
920
921 @property
wbondeb5eb6e2015-06-18 14:14:12 -0400922 def public_key(self):
wbondf937f482015-06-19 01:51:11 -0400923 """
924 :return:
925 If an RSA key, an RSAPublicKey object. If a DSA key, an Integer
wbondb6971732015-07-29 21:32:52 -0400926 object. If an EC key, an ECPointBitString object.
wbondf937f482015-06-19 01:51:11 -0400927 """
928
wbond564e7442019-07-13 07:04:14 -0400929 raise APIException(
930 'asn1crypto.keys.PrivateKeyInfo().public_key has been removed, '
931 'please use oscrypto.asymmetric.PrivateKey().public_key.unwrap() instead')
wbond488eac32015-06-17 23:35:05 -0400932
wbonde91513e2015-06-03 14:52:18 -0400933 @property
Peter Sagersonbcb42292016-01-21 17:37:09 -0800934 def public_key_info(self):
935 """
936 :return:
937 A PublicKeyInfo object derived from this private key.
938 """
Peter Sagersonbcb42292016-01-21 17:37:09 -0800939
wbond564e7442019-07-13 07:04:14 -0400940 raise APIException(
941 'asn1crypto.keys.PrivateKeyInfo().public_key_info has been removed, '
942 'please use oscrypto.asymmetric.PrivateKey().public_key.asn1 instead')
Peter Sagersonbcb42292016-01-21 17:37:09 -0800943
944 @property
wbonde91513e2015-06-03 14:52:18 -0400945 def fingerprint(self):
946 """
947 Creates a fingerprint that can be compared with a public key to see if
948 the two form a pair.
949
Ryan Guestb1f50412017-07-26 20:24:36 -0700950 This fingerprint is not compatible with fingerprints generated by any
wbonde91513e2015-06-03 14:52:18 -0400951 other software.
952
wbonde91513e2015-06-03 14:52:18 -0400953 :return:
954 A byte string that is a sha256 hash of selected components (based
955 on the key type)
956 """
957
wbond564e7442019-07-13 07:04:14 -0400958 raise APIException(
959 'asn1crypto.keys.PrivateKeyInfo().fingerprint has been removed, '
960 'please use oscrypto.asymmetric.PrivateKey().fingerprint instead')
wbonde91513e2015-06-03 14:52:18 -0400961
962
963class EncryptedPrivateKeyInfo(Sequence):
964 """
965 Source: https://tools.ietf.org/html/rfc5208#page-4
966 """
967
968 _fields = [
wbond59af99d2015-06-15 16:19:04 -0400969 ('encryption_algorithm', EncryptionAlgorithm),
wbonde91513e2015-06-03 14:52:18 -0400970 ('encrypted_data', OctetString),
971 ]
972
973
974# These structures are from https://tools.ietf.org/html/rfc3279
975
wbond88ba5ee2016-03-17 11:39:22 -0400976class ValidationParms(Sequence):
977 """
978 Source: https://tools.ietf.org/html/rfc3279#page-10
979 """
980
981 _fields = [
982 ('seed', BitString),
983 ('pgen_counter', Integer),
984 ]
985
986
987class DomainParameters(Sequence):
988 """
989 Source: https://tools.ietf.org/html/rfc3279#page-10
990 """
991
992 _fields = [
993 ('p', Integer),
994 ('g', Integer),
995 ('q', Integer),
996 ('j', Integer, {'optional': True}),
997 ('validation_params', ValidationParms, {'optional': True}),
998 ]
999
1000
wbonde91513e2015-06-03 14:52:18 -04001001class PublicKeyAlgorithmId(ObjectIdentifier):
1002 """
1003 Original Name: None
1004 Source: https://tools.ietf.org/html/rfc3279
1005 """
1006
1007 _map = {
1008 # https://tools.ietf.org/html/rfc3279#page-19
1009 '1.2.840.113549.1.1.1': 'rsa',
wbonda11c4502017-11-22 11:13:00 -05001010 # https://tools.ietf.org/html/rfc3447#page-47
1011 '1.2.840.113549.1.1.7': 'rsaes_oaep',
spchan8a454162019-04-24 13:09:44 +08001012 # https://tools.ietf.org/html/rfc4055#page-8
1013 '1.2.840.113549.1.1.10': 'rsassa_pss',
wbonde91513e2015-06-03 14:52:18 -04001014 # https://tools.ietf.org/html/rfc3279#page-18
1015 '1.2.840.10040.4.1': 'dsa',
1016 # https://tools.ietf.org/html/rfc3279#page-13
wbond680cba12015-07-01 23:53:54 -04001017 '1.2.840.10045.2.1': 'ec',
wbond88ba5ee2016-03-17 11:39:22 -04001018 # https://tools.ietf.org/html/rfc3279#page-10
1019 '1.2.840.10046.2.1': 'dh',
wbonde91513e2015-06-03 14:52:18 -04001020 }
1021
1022
wbond381a4da2016-08-30 11:39:54 -04001023class PublicKeyAlgorithm(_ForceNullParameters, Sequence):
wbonde91513e2015-06-03 14:52:18 -04001024 """
1025 Original Name: AlgorithmIdentifier
1026 Source: https://tools.ietf.org/html/rfc5280#page-18
1027 """
1028
1029 _fields = [
1030 ('algorithm', PublicKeyAlgorithmId),
1031 ('parameters', Any, {'optional': True}),
1032 ]
1033
1034 _oid_pair = ('algorithm', 'parameters')
1035 _oid_specs = {
wbonde91513e2015-06-03 14:52:18 -04001036 'dsa': DSAParams,
wbond680cba12015-07-01 23:53:54 -04001037 'ec': ECDomainParameters,
wbond88ba5ee2016-03-17 11:39:22 -04001038 'dh': DomainParameters,
wbonda11c4502017-11-22 11:13:00 -05001039 'rsaes_oaep': RSAESOAEPParams,
spchan8a454162019-04-24 13:09:44 +08001040 'rsassa_pss': RSASSAPSSParams,
wbonde91513e2015-06-03 14:52:18 -04001041 }
1042
1043
1044class PublicKeyInfo(Sequence):
1045 """
1046 Original Name: SubjectPublicKeyInfo
1047 Source: https://tools.ietf.org/html/rfc5280#page-17
1048 """
1049
1050 _fields = [
1051 ('algorithm', PublicKeyAlgorithm),
wbonde5a1c6e2015-08-03 07:42:28 -04001052 ('public_key', ParsableOctetBitString),
wbonde91513e2015-06-03 14:52:18 -04001053 ]
1054
1055 def _public_key_spec(self):
1056 algorithm = self['algorithm']['algorithm'].native
1057 return {
1058 'rsa': RSAPublicKey,
wbonda11c4502017-11-22 11:13:00 -05001059 'rsaes_oaep': RSAPublicKey,
spchan8a454162019-04-24 13:09:44 +08001060 'rsassa_pss': RSAPublicKey,
wbonde91513e2015-06-03 14:52:18 -04001061 'dsa': Integer,
wbondb6971732015-07-29 21:32:52 -04001062 # We override the field spec with ECPoint so that users can easily
1063 # decompose the byte string into the constituent X and Y coords
1064 'ec': (ECPointBitString, None),
wbond88ba5ee2016-03-17 11:39:22 -04001065 'dh': Integer,
wbonde91513e2015-06-03 14:52:18 -04001066 }[algorithm]
1067
1068 _spec_callbacks = {
1069 'public_key': _public_key_spec
1070 }
1071
wbondf937f482015-06-19 01:51:11 -04001072 _algorithm = None
1073 _bit_size = None
wbonde91513e2015-06-03 14:52:18 -04001074 _fingerprint = None
wbond66babf62015-07-17 11:51:57 -04001075 _sha1 = None
1076 _sha256 = None
wbonde91513e2015-06-03 14:52:18 -04001077
wbond8b59e052015-06-16 00:13:05 -04001078 @classmethod
1079 def wrap(cls, public_key, algorithm):
1080 """
1081 Wraps a public key in a PublicKeyInfo structure
1082
1083 :param public_key:
1084 A byte string or Asn1Value object of the public key
1085
1086 :param algorithm:
1087 A unicode string of "rsa"
1088
1089 :return:
1090 A PublicKeyInfo object
1091 """
1092
1093 if not isinstance(public_key, byte_cls) and not isinstance(public_key, Asn1Value):
wbonda26664f2015-10-07 11:57:35 -04001094 raise TypeError(unwrap(
1095 '''
1096 public_key must be a byte string or Asn1Value, not %s
1097 ''',
1098 type_name(public_key)
1099 ))
wbond8b59e052015-06-16 00:13:05 -04001100
1101 if algorithm != 'rsa':
wbonda26664f2015-10-07 11:57:35 -04001102 raise ValueError(unwrap(
1103 '''
1104 algorithm must "rsa", not %s
1105 ''',
1106 repr(algorithm)
1107 ))
wbond8b59e052015-06-16 00:13:05 -04001108
1109 algo = PublicKeyAlgorithm()
1110 algo['algorithm'] = PublicKeyAlgorithmId(algorithm)
1111 algo['parameters'] = Null()
1112
1113 container = cls()
1114 container['algorithm'] = algo
1115 if isinstance(public_key, Asn1Value):
wbonde95da2c2015-06-19 01:49:44 -04001116 public_key = public_key.untag().dump()
wbonde5a1c6e2015-08-03 07:42:28 -04001117 container['public_key'] = ParsableOctetBitString(public_key)
wbond8b59e052015-06-16 00:13:05 -04001118
1119 return container
1120
wbondb924d332015-07-07 23:27:48 -04001121 def unwrap(self):
1122 """
1123 Unwraps an RSA public key into an RSAPublicKey object. Does not support
1124 DSA or EC public keys since they do not have an unwrapped form.
1125
1126 :return:
1127 An RSAPublicKey object
1128 """
1129
wbond564e7442019-07-13 07:04:14 -04001130 raise APIException(
1131 'asn1crypto.keys.PublicKeyInfo().unwrap() has been removed, '
1132 'please use oscrypto.asymmetric.PublicKey().unwrap() instead')
wbondb924d332015-07-07 23:27:48 -04001133
wbonde91513e2015-06-03 14:52:18 -04001134 @property
wbondf937f482015-06-19 01:51:11 -04001135 def curve(self):
1136 """
wbond680cba12015-07-01 23:53:54 -04001137 Returns information about the curve used for an EC key
wbondf937f482015-06-19 01:51:11 -04001138
1139 :raises:
wbond680cba12015-07-01 23:53:54 -04001140 ValueError - when the key is not an EC key
wbondf937f482015-06-19 01:51:11 -04001141
1142 :return:
1143 A two-element tuple, with the first element being a unicode string
1144 of "implicit_ca", "specified" or "named". If the first element is
1145 "implicit_ca", the second is None. If "specified", the second is
1146 an OrderedDict that is the native version of SpecifiedECDomain. If
1147 "named", the second is a unicode string of the curve name.
1148 """
1149
wbond680cba12015-07-01 23:53:54 -04001150 if self.algorithm != 'ec':
wbonda26664f2015-10-07 11:57:35 -04001151 raise ValueError(unwrap(
1152 '''
1153 Only EC keys have a curve, this key is %s
1154 ''',
1155 self.algorithm.upper()
1156 ))
wbondf937f482015-06-19 01:51:11 -04001157
1158 params = self['algorithm']['parameters']
1159 chosen = params.chosen
1160
1161 if params.name == 'implicit_ca':
1162 value = None
1163 else:
1164 value = chosen.native
1165
1166 return (params.name, value)
1167
1168 @property
wbond1b00a592015-06-28 12:58:26 -04001169 def hash_algo(self):
1170 """
1171 Returns the name of the family of hash algorithms used to generate a
1172 DSA key
1173
1174 :raises:
1175 ValueError - when the key is not a DSA key
1176
1177 :return:
wbond0d9d8332015-10-08 11:55:40 -04001178 A unicode string of "sha1" or "sha2" or None if no parameters are
1179 present
wbond1b00a592015-06-28 12:58:26 -04001180 """
1181
1182 if self.algorithm != 'dsa':
wbonda26664f2015-10-07 11:57:35 -04001183 raise ValueError(unwrap(
1184 '''
1185 Only DSA keys are generated using a hash algorithm, this key is
1186 %s
1187 ''',
1188 self.algorithm.upper()
1189 ))
wbond1b00a592015-06-28 12:58:26 -04001190
wbond0d9d8332015-10-08 11:55:40 -04001191 parameters = self['algorithm']['parameters']
1192 if parameters.native is None:
1193 return None
1194
1195 byte_len = math.log(parameters['q'].native, 2) / 8
wbond1b00a592015-06-28 12:58:26 -04001196
1197 return 'sha1' if byte_len <= 20 else 'sha2'
1198
1199 @property
wbondf937f482015-06-19 01:51:11 -04001200 def algorithm(self):
1201 """
1202 :return:
wbond680cba12015-07-01 23:53:54 -04001203 A unicode string of "rsa", "dsa" or "ec"
wbondf937f482015-06-19 01:51:11 -04001204 """
1205
1206 if self._algorithm is None:
1207 self._algorithm = self['algorithm']['algorithm'].native
1208 return self._algorithm
1209
1210 @property
1211 def bit_size(self):
1212 """
1213 :return:
wbondf4f176c2015-07-07 23:27:19 -04001214 The bit size of the public key, as an integer
wbondf937f482015-06-19 01:51:11 -04001215 """
1216
1217 if self._bit_size is None:
wbond680cba12015-07-01 23:53:54 -04001218 if self.algorithm == 'ec':
wbondf937f482015-06-19 01:51:11 -04001219 self._bit_size = ((len(self['public_key'].native) - 1) / 2) * 8
1220 else:
1221 if self.algorithm == 'rsa':
1222 prime = self['public_key'].parsed['modulus'].native
1223 elif self.algorithm == 'dsa':
wbondd6b8b2e2015-07-13 09:08:23 -04001224 prime = self['algorithm']['parameters']['p'].native
wbondf4f176c2015-07-07 23:27:19 -04001225 self._bit_size = int(math.ceil(math.log(prime, 2)))
wbond69d96d82016-06-15 06:02:18 -04001226 modulus = self._bit_size % 8
1227 if modulus != 0:
1228 self._bit_size += 8 - modulus
wbondf937f482015-06-19 01:51:11 -04001229
1230 return self._bit_size
1231
1232 @property
wbondf4f176c2015-07-07 23:27:19 -04001233 def byte_size(self):
1234 """
1235 :return:
1236 The byte size of the public key, as an integer
1237 """
1238
1239 return int(math.ceil(self.bit_size / 8))
1240
1241 @property
wbond66babf62015-07-17 11:51:57 -04001242 def sha1(self):
1243 """
1244 :return:
1245 The SHA1 hash of the DER-encoded bytes of this public key info
1246 """
1247
1248 if self._sha1 is None:
1249 self._sha1 = hashlib.sha1(byte_cls(self['public_key'])).digest()
1250 return self._sha1
1251
1252 @property
1253 def sha256(self):
1254 """
1255 :return:
1256 The SHA-256 hash of the DER-encoded bytes of this public key info
1257 """
1258
1259 if self._sha256 is None:
1260 self._sha256 = hashlib.sha256(byte_cls(self['public_key'])).digest()
1261 return self._sha256
1262
1263 @property
wbonde91513e2015-06-03 14:52:18 -04001264 def fingerprint(self):
1265 """
1266 Creates a fingerprint that can be compared with a private key to see if
1267 the two form a pair.
1268
Ryan Guestb1f50412017-07-26 20:24:36 -07001269 This fingerprint is not compatible with fingerprints generated by any
wbonde91513e2015-06-03 14:52:18 -04001270 other software.
1271
1272 :return:
1273 A byte string that is a sha256 hash of selected components (based
1274 on the key type)
1275 """
1276
wbond564e7442019-07-13 07:04:14 -04001277 raise APIException(
1278 'asn1crypto.keys.PublicKeyInfo().fingerprint has been removed, '
1279 'please use oscrypto.asymmetric.PublicKey().fingerprint instead')