25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 

1247 satır
34 KiB

  1. # coding: utf-8
  2. """
  3. ASN.1 type classes for public and private keys. Exports the following items:
  4. - DSAPrivateKey()
  5. - ECPrivateKey()
  6. - EncryptedPrivateKeyInfo()
  7. - PrivateKeyInfo()
  8. - PublicKeyInfo()
  9. - RSAPrivateKey()
  10. - RSAPublicKey()
  11. Other type classes are defined that help compose the types listed above.
  12. """
  13. from __future__ import unicode_literals, division, absolute_import, print_function
  14. import hashlib
  15. import math
  16. from ._errors import unwrap, APIException
  17. from ._types import type_name, byte_cls
  18. from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm, RSAESOAEPParams, RSASSAPSSParams
  19. from .core import (
  20. Any,
  21. Asn1Value,
  22. BitString,
  23. Choice,
  24. Integer,
  25. IntegerOctetString,
  26. Null,
  27. ObjectIdentifier,
  28. OctetBitString,
  29. OctetString,
  30. ParsableOctetString,
  31. ParsableOctetBitString,
  32. Sequence,
  33. SequenceOf,
  34. SetOf,
  35. )
  36. from .util import int_from_bytes, int_to_bytes
  37. class OtherPrimeInfo(Sequence):
  38. """
  39. Source: https://tools.ietf.org/html/rfc3447#page-46
  40. """
  41. _fields = [
  42. ('prime', Integer),
  43. ('exponent', Integer),
  44. ('coefficient', Integer),
  45. ]
  46. class OtherPrimeInfos(SequenceOf):
  47. """
  48. Source: https://tools.ietf.org/html/rfc3447#page-46
  49. """
  50. _child_spec = OtherPrimeInfo
  51. class RSAPrivateKeyVersion(Integer):
  52. """
  53. Original Name: Version
  54. Source: https://tools.ietf.org/html/rfc3447#page-45
  55. """
  56. _map = {
  57. 0: 'two-prime',
  58. 1: 'multi',
  59. }
  60. class RSAPrivateKey(Sequence):
  61. """
  62. Source: https://tools.ietf.org/html/rfc3447#page-45
  63. """
  64. _fields = [
  65. ('version', RSAPrivateKeyVersion),
  66. ('modulus', Integer),
  67. ('public_exponent', Integer),
  68. ('private_exponent', Integer),
  69. ('prime1', Integer),
  70. ('prime2', Integer),
  71. ('exponent1', Integer),
  72. ('exponent2', Integer),
  73. ('coefficient', Integer),
  74. ('other_prime_infos', OtherPrimeInfos, {'optional': True})
  75. ]
  76. class RSAPublicKey(Sequence):
  77. """
  78. Source: https://tools.ietf.org/html/rfc3447#page-44
  79. """
  80. _fields = [
  81. ('modulus', Integer),
  82. ('public_exponent', Integer)
  83. ]
  84. class DSAPrivateKey(Sequence):
  85. """
  86. The ASN.1 structure that OpenSSL uses to store a DSA private key that is
  87. not part of a PKCS#8 structure. Reversed engineered from english-language
  88. description on linked OpenSSL documentation page.
  89. Original Name: None
  90. Source: https://www.openssl.org/docs/apps/dsa.html
  91. """
  92. _fields = [
  93. ('version', Integer),
  94. ('p', Integer),
  95. ('q', Integer),
  96. ('g', Integer),
  97. ('public_key', Integer),
  98. ('private_key', Integer),
  99. ]
  100. class _ECPoint():
  101. """
  102. In both PublicKeyInfo and PrivateKeyInfo, the EC public key is a byte
  103. string that is encoded as a bit string. This class adds convenience
  104. methods for converting to and from the byte string to a pair of integers
  105. that are the X and Y coordinates.
  106. """
  107. @classmethod
  108. def from_coords(cls, x, y):
  109. """
  110. Creates an ECPoint object from the X and Y integer coordinates of the
  111. point
  112. :param x:
  113. The X coordinate, as an integer
  114. :param y:
  115. The Y coordinate, as an integer
  116. :return:
  117. An ECPoint object
  118. """
  119. x_bytes = int(math.ceil(math.log(x, 2) / 8.0))
  120. y_bytes = int(math.ceil(math.log(y, 2) / 8.0))
  121. num_bytes = max(x_bytes, y_bytes)
  122. byte_string = b'\x04'
  123. byte_string += int_to_bytes(x, width=num_bytes)
  124. byte_string += int_to_bytes(y, width=num_bytes)
  125. return cls(byte_string)
  126. def to_coords(self):
  127. """
  128. Returns the X and Y coordinates for this EC point, as native Python
  129. integers
  130. :return:
  131. A 2-element tuple containing integers (X, Y)
  132. """
  133. data = self.native
  134. first_byte = data[0:1]
  135. # Uncompressed
  136. if first_byte == b'\x04':
  137. remaining = data[1:]
  138. field_len = len(remaining) // 2
  139. x = int_from_bytes(remaining[0:field_len])
  140. y = int_from_bytes(remaining[field_len:])
  141. return (x, y)
  142. if first_byte not in set([b'\x02', b'\x03']):
  143. raise ValueError(unwrap(
  144. '''
  145. Invalid EC public key - first byte is incorrect
  146. '''
  147. ))
  148. raise ValueError(unwrap(
  149. '''
  150. Compressed representations of EC public keys are not supported due
  151. to patent US6252960
  152. '''
  153. ))
  154. class ECPoint(OctetString, _ECPoint):
  155. pass
  156. class ECPointBitString(OctetBitString, _ECPoint):
  157. pass
  158. class SpecifiedECDomainVersion(Integer):
  159. """
  160. Source: http://www.secg.org/sec1-v2.pdf page 104
  161. """
  162. _map = {
  163. 1: 'ecdpVer1',
  164. 2: 'ecdpVer2',
  165. 3: 'ecdpVer3',
  166. }
  167. class FieldType(ObjectIdentifier):
  168. """
  169. Original Name: None
  170. Source: http://www.secg.org/sec1-v2.pdf page 101
  171. """
  172. _map = {
  173. '1.2.840.10045.1.1': 'prime_field',
  174. '1.2.840.10045.1.2': 'characteristic_two_field',
  175. }
  176. class CharacteristicTwoBasis(ObjectIdentifier):
  177. """
  178. Original Name: None
  179. Source: http://www.secg.org/sec1-v2.pdf page 102
  180. """
  181. _map = {
  182. '1.2.840.10045.1.2.1.1': 'gn_basis',
  183. '1.2.840.10045.1.2.1.2': 'tp_basis',
  184. '1.2.840.10045.1.2.1.3': 'pp_basis',
  185. }
  186. class Pentanomial(Sequence):
  187. """
  188. Source: http://www.secg.org/sec1-v2.pdf page 102
  189. """
  190. _fields = [
  191. ('k1', Integer),
  192. ('k2', Integer),
  193. ('k3', Integer),
  194. ]
  195. class CharacteristicTwo(Sequence):
  196. """
  197. Original Name: Characteristic-two
  198. Source: http://www.secg.org/sec1-v2.pdf page 101
  199. """
  200. _fields = [
  201. ('m', Integer),
  202. ('basis', CharacteristicTwoBasis),
  203. ('parameters', Any),
  204. ]
  205. _oid_pair = ('basis', 'parameters')
  206. _oid_specs = {
  207. 'gn_basis': Null,
  208. 'tp_basis': Integer,
  209. 'pp_basis': Pentanomial,
  210. }
  211. class FieldID(Sequence):
  212. """
  213. Source: http://www.secg.org/sec1-v2.pdf page 100
  214. """
  215. _fields = [
  216. ('field_type', FieldType),
  217. ('parameters', Any),
  218. ]
  219. _oid_pair = ('field_type', 'parameters')
  220. _oid_specs = {
  221. 'prime_field': Integer,
  222. 'characteristic_two_field': CharacteristicTwo,
  223. }
  224. class Curve(Sequence):
  225. """
  226. Source: http://www.secg.org/sec1-v2.pdf page 104
  227. """
  228. _fields = [
  229. ('a', OctetString),
  230. ('b', OctetString),
  231. ('seed', OctetBitString, {'optional': True}),
  232. ]
  233. class SpecifiedECDomain(Sequence):
  234. """
  235. Source: http://www.secg.org/sec1-v2.pdf page 103
  236. """
  237. _fields = [
  238. ('version', SpecifiedECDomainVersion),
  239. ('field_id', FieldID),
  240. ('curve', Curve),
  241. ('base', ECPoint),
  242. ('order', Integer),
  243. ('cofactor', Integer, {'optional': True}),
  244. ('hash', DigestAlgorithm, {'optional': True}),
  245. ]
  246. class NamedCurve(ObjectIdentifier):
  247. """
  248. Various named curves
  249. Original Name: None
  250. Source: https://tools.ietf.org/html/rfc3279#page-23,
  251. https://tools.ietf.org/html/rfc5480#page-5
  252. """
  253. _map = {
  254. # https://tools.ietf.org/html/rfc3279#page-23
  255. '1.2.840.10045.3.0.1': 'c2pnb163v1',
  256. '1.2.840.10045.3.0.2': 'c2pnb163v2',
  257. '1.2.840.10045.3.0.3': 'c2pnb163v3',
  258. '1.2.840.10045.3.0.4': 'c2pnb176w1',
  259. '1.2.840.10045.3.0.5': 'c2tnb191v1',
  260. '1.2.840.10045.3.0.6': 'c2tnb191v2',
  261. '1.2.840.10045.3.0.7': 'c2tnb191v3',
  262. '1.2.840.10045.3.0.8': 'c2onb191v4',
  263. '1.2.840.10045.3.0.9': 'c2onb191v5',
  264. '1.2.840.10045.3.0.10': 'c2pnb208w1',
  265. '1.2.840.10045.3.0.11': 'c2tnb239v1',
  266. '1.2.840.10045.3.0.12': 'c2tnb239v2',
  267. '1.2.840.10045.3.0.13': 'c2tnb239v3',
  268. '1.2.840.10045.3.0.14': 'c2onb239v4',
  269. '1.2.840.10045.3.0.15': 'c2onb239v5',
  270. '1.2.840.10045.3.0.16': 'c2pnb272w1',
  271. '1.2.840.10045.3.0.17': 'c2pnb304w1',
  272. '1.2.840.10045.3.0.18': 'c2tnb359v1',
  273. '1.2.840.10045.3.0.19': 'c2pnb368w1',
  274. '1.2.840.10045.3.0.20': 'c2tnb431r1',
  275. '1.2.840.10045.3.1.2': 'prime192v2',
  276. '1.2.840.10045.3.1.3': 'prime192v3',
  277. '1.2.840.10045.3.1.4': 'prime239v1',
  278. '1.2.840.10045.3.1.5': 'prime239v2',
  279. '1.2.840.10045.3.1.6': 'prime239v3',
  280. # https://tools.ietf.org/html/rfc5480#page-5
  281. # http://www.secg.org/SEC2-Ver-1.0.pdf
  282. '1.2.840.10045.3.1.1': 'secp192r1',
  283. '1.2.840.10045.3.1.7': 'secp256r1',
  284. '1.3.132.0.1': 'sect163k1',
  285. '1.3.132.0.2': 'sect163r1',
  286. '1.3.132.0.3': 'sect239k1',
  287. '1.3.132.0.4': 'sect113r1',
  288. '1.3.132.0.5': 'sect113r2',
  289. '1.3.132.0.6': 'secp112r1',
  290. '1.3.132.0.7': 'secp112r2',
  291. '1.3.132.0.8': 'secp160r1',
  292. '1.3.132.0.9': 'secp160k1',
  293. '1.3.132.0.10': 'secp256k1',
  294. '1.3.132.0.15': 'sect163r2',
  295. '1.3.132.0.16': 'sect283k1',
  296. '1.3.132.0.17': 'sect283r1',
  297. '1.3.132.0.22': 'sect131r1',
  298. '1.3.132.0.23': 'sect131r2',
  299. '1.3.132.0.24': 'sect193r1',
  300. '1.3.132.0.25': 'sect193r2',
  301. '1.3.132.0.26': 'sect233k1',
  302. '1.3.132.0.27': 'sect233r1',
  303. '1.3.132.0.28': 'secp128r1',
  304. '1.3.132.0.29': 'secp128r2',
  305. '1.3.132.0.30': 'secp160r2',
  306. '1.3.132.0.31': 'secp192k1',
  307. '1.3.132.0.32': 'secp224k1',
  308. '1.3.132.0.33': 'secp224r1',
  309. '1.3.132.0.34': 'secp384r1',
  310. '1.3.132.0.35': 'secp521r1',
  311. '1.3.132.0.36': 'sect409k1',
  312. '1.3.132.0.37': 'sect409r1',
  313. '1.3.132.0.38': 'sect571k1',
  314. '1.3.132.0.39': 'sect571r1',
  315. }
  316. _key_sizes = {
  317. # Order values used to compute these sourced from
  318. # http://cr.openjdk.java.net/~vinnie/7194075/webrev-3/src/share/classes/sun/security/ec/CurveDB.java.html
  319. '1.2.840.10045.3.0.1': 21,
  320. '1.2.840.10045.3.0.2': 21,
  321. '1.2.840.10045.3.0.3': 21,
  322. '1.2.840.10045.3.0.4': 21,
  323. '1.2.840.10045.3.0.5': 24,
  324. '1.2.840.10045.3.0.6': 24,
  325. '1.2.840.10045.3.0.7': 24,
  326. '1.2.840.10045.3.0.8': 24,
  327. '1.2.840.10045.3.0.9': 24,
  328. '1.2.840.10045.3.0.10': 25,
  329. '1.2.840.10045.3.0.11': 30,
  330. '1.2.840.10045.3.0.12': 30,
  331. '1.2.840.10045.3.0.13': 30,
  332. '1.2.840.10045.3.0.14': 30,
  333. '1.2.840.10045.3.0.15': 30,
  334. '1.2.840.10045.3.0.16': 33,
  335. '1.2.840.10045.3.0.17': 37,
  336. '1.2.840.10045.3.0.18': 45,
  337. '1.2.840.10045.3.0.19': 45,
  338. '1.2.840.10045.3.0.20': 53,
  339. '1.2.840.10045.3.1.2': 24,
  340. '1.2.840.10045.3.1.3': 24,
  341. '1.2.840.10045.3.1.4': 30,
  342. '1.2.840.10045.3.1.5': 30,
  343. '1.2.840.10045.3.1.6': 30,
  344. # Order values used to compute these sourced from
  345. # http://www.secg.org/SEC2-Ver-1.0.pdf
  346. '1.2.840.10045.3.1.1': 24,
  347. '1.2.840.10045.3.1.7': 32,
  348. '1.3.132.0.1': 21,
  349. '1.3.132.0.2': 21,
  350. '1.3.132.0.3': 26,
  351. '1.3.132.0.4': 14,
  352. '1.3.132.0.5': 14,
  353. '1.3.132.0.6': 14,
  354. '1.3.132.0.7': 14,
  355. '1.3.132.0.8': 20,
  356. '1.3.132.0.9': 20,
  357. '1.3.132.0.10': 32,
  358. '1.3.132.0.15': 21,
  359. '1.3.132.0.16': 36,
  360. '1.3.132.0.17': 36,
  361. '1.3.132.0.22': 17,
  362. '1.3.132.0.23': 17,
  363. '1.3.132.0.24': 24,
  364. '1.3.132.0.25': 24,
  365. '1.3.132.0.26': 29,
  366. '1.3.132.0.27': 29,
  367. '1.3.132.0.28': 16,
  368. '1.3.132.0.29': 16,
  369. '1.3.132.0.30': 20,
  370. '1.3.132.0.31': 24,
  371. '1.3.132.0.32': 28,
  372. '1.3.132.0.33': 28,
  373. '1.3.132.0.34': 48,
  374. '1.3.132.0.35': 66,
  375. '1.3.132.0.36': 51,
  376. '1.3.132.0.37': 51,
  377. '1.3.132.0.38': 72,
  378. '1.3.132.0.39': 72,
  379. }
  380. @classmethod
  381. def register(cls, name, oid, key_size):
  382. """
  383. Registers a new named elliptic curve that is not included in the
  384. default list of named curves
  385. :param name:
  386. A unicode string of the curve name
  387. :param oid:
  388. A unicode string of the dotted format OID
  389. :param key_size:
  390. An integer of the number of bytes the private key should be
  391. encoded to
  392. """
  393. cls._map[oid] = name
  394. if cls._reverse_map is not None:
  395. cls._reverse_map[name] = oid
  396. cls._key_sizes[oid] = key_size
  397. class ECDomainParameters(Choice):
  398. """
  399. Source: http://www.secg.org/sec1-v2.pdf page 102
  400. """
  401. _alternatives = [
  402. ('specified', SpecifiedECDomain),
  403. ('named', NamedCurve),
  404. ('implicit_ca', Null),
  405. ]
  406. @property
  407. def key_size(self):
  408. if self.name == 'implicit_ca':
  409. raise ValueError(unwrap(
  410. '''
  411. Unable to calculate key_size from ECDomainParameters
  412. that are implicitly defined by the CA key
  413. '''
  414. ))
  415. if self.name == 'specified':
  416. order = self.chosen['order'].native
  417. return math.ceil(math.log(order, 2.0) / 8.0)
  418. oid = self.chosen.dotted
  419. if oid not in NamedCurve._key_sizes:
  420. raise ValueError(unwrap(
  421. '''
  422. The asn1crypto.keys.NamedCurve %s does not have a registered key length,
  423. please call asn1crypto.keys.NamedCurve.register()
  424. ''',
  425. repr(oid)
  426. ))
  427. return NamedCurve._key_sizes[oid]
  428. class ECPrivateKeyVersion(Integer):
  429. """
  430. Original Name: None
  431. Source: http://www.secg.org/sec1-v2.pdf page 108
  432. """
  433. _map = {
  434. 1: 'ecPrivkeyVer1',
  435. }
  436. class ECPrivateKey(Sequence):
  437. """
  438. Source: http://www.secg.org/sec1-v2.pdf page 108
  439. """
  440. _fields = [
  441. ('version', ECPrivateKeyVersion),
  442. ('private_key', IntegerOctetString),
  443. ('parameters', ECDomainParameters, {'explicit': 0, 'optional': True}),
  444. ('public_key', ECPointBitString, {'explicit': 1, 'optional': True}),
  445. ]
  446. # Ensures the key is set to the correct length when encoding
  447. _key_size = None
  448. # This is necessary to ensure the private_key IntegerOctetString is encoded properly
  449. def __setitem__(self, key, value):
  450. res = super(ECPrivateKey, self).__setitem__(key, value)
  451. if key == 'private_key':
  452. if self._key_size is None:
  453. # Infer the key_size from the existing private key if possible
  454. pkey_contents = self['private_key'].contents
  455. if isinstance(pkey_contents, byte_cls) and len(pkey_contents) > 1:
  456. self.set_key_size(len(self['private_key'].contents))
  457. elif self._key_size is not None:
  458. self._update_key_size()
  459. elif key == 'parameters' and isinstance(self['parameters'], ECDomainParameters) and \
  460. self['parameters'].name != 'implicit_ca':
  461. self.set_key_size(self['parameters'].key_size)
  462. return res
  463. def set_key_size(self, key_size):
  464. """
  465. Sets the key_size to ensure the private key is encoded to the proper length
  466. :param key_size:
  467. An integer byte length to encode the private_key to
  468. """
  469. self._key_size = key_size
  470. self._update_key_size()
  471. def _update_key_size(self):
  472. """
  473. Ensure the private_key explicit encoding width is set
  474. """
  475. if self._key_size is not None and isinstance(self['private_key'], IntegerOctetString):
  476. self['private_key'].set_encoded_width(self._key_size)
  477. class DSAParams(Sequence):
  478. """
  479. Parameters for a DSA public or private key
  480. Original Name: Dss-Parms
  481. Source: https://tools.ietf.org/html/rfc3279#page-9
  482. """
  483. _fields = [
  484. ('p', Integer),
  485. ('q', Integer),
  486. ('g', Integer),
  487. ]
  488. class Attribute(Sequence):
  489. """
  490. Source: https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.501-198811-S!!PDF-E&type=items page 8
  491. """
  492. _fields = [
  493. ('type', ObjectIdentifier),
  494. ('values', SetOf, {'spec': Any}),
  495. ]
  496. class Attributes(SetOf):
  497. """
  498. Source: https://tools.ietf.org/html/rfc5208#page-3
  499. """
  500. _child_spec = Attribute
  501. class PrivateKeyAlgorithmId(ObjectIdentifier):
  502. """
  503. These OIDs for various public keys are reused when storing private keys
  504. inside of a PKCS#8 structure
  505. Original Name: None
  506. Source: https://tools.ietf.org/html/rfc3279
  507. """
  508. _map = {
  509. # https://tools.ietf.org/html/rfc3279#page-19
  510. '1.2.840.113549.1.1.1': 'rsa',
  511. # https://tools.ietf.org/html/rfc4055#page-8
  512. '1.2.840.113549.1.1.10': 'rsassa_pss',
  513. # https://tools.ietf.org/html/rfc3279#page-18
  514. '1.2.840.10040.4.1': 'dsa',
  515. # https://tools.ietf.org/html/rfc3279#page-13
  516. '1.2.840.10045.2.1': 'ec',
  517. }
  518. class PrivateKeyAlgorithm(_ForceNullParameters, Sequence):
  519. """
  520. Original Name: PrivateKeyAlgorithmIdentifier
  521. Source: https://tools.ietf.org/html/rfc5208#page-3
  522. """
  523. _fields = [
  524. ('algorithm', PrivateKeyAlgorithmId),
  525. ('parameters', Any, {'optional': True}),
  526. ]
  527. _oid_pair = ('algorithm', 'parameters')
  528. _oid_specs = {
  529. 'dsa': DSAParams,
  530. 'ec': ECDomainParameters,
  531. 'rsassa_pss': RSASSAPSSParams,
  532. }
  533. class PrivateKeyInfo(Sequence):
  534. """
  535. Source: https://tools.ietf.org/html/rfc5208#page-3
  536. """
  537. _fields = [
  538. ('version', Integer),
  539. ('private_key_algorithm', PrivateKeyAlgorithm),
  540. ('private_key', ParsableOctetString),
  541. ('attributes', Attributes, {'implicit': 0, 'optional': True}),
  542. ]
  543. def _private_key_spec(self):
  544. algorithm = self['private_key_algorithm']['algorithm'].native
  545. return {
  546. 'rsa': RSAPrivateKey,
  547. 'rsassa_pss': RSAPrivateKey,
  548. 'dsa': Integer,
  549. 'ec': ECPrivateKey,
  550. }[algorithm]
  551. _spec_callbacks = {
  552. 'private_key': _private_key_spec
  553. }
  554. _algorithm = None
  555. _bit_size = None
  556. _public_key = None
  557. _fingerprint = None
  558. @classmethod
  559. def wrap(cls, private_key, algorithm):
  560. """
  561. Wraps a private key in a PrivateKeyInfo structure
  562. :param private_key:
  563. A byte string or Asn1Value object of the private key
  564. :param algorithm:
  565. A unicode string of "rsa", "dsa" or "ec"
  566. :return:
  567. A PrivateKeyInfo object
  568. """
  569. if not isinstance(private_key, byte_cls) and not isinstance(private_key, Asn1Value):
  570. raise TypeError(unwrap(
  571. '''
  572. private_key must be a byte string or Asn1Value, not %s
  573. ''',
  574. type_name(private_key)
  575. ))
  576. if algorithm == 'rsa':
  577. if not isinstance(private_key, RSAPrivateKey):
  578. private_key = RSAPrivateKey.load(private_key)
  579. params = Null()
  580. elif algorithm == 'dsa':
  581. if not isinstance(private_key, DSAPrivateKey):
  582. private_key = DSAPrivateKey.load(private_key)
  583. params = DSAParams()
  584. params['p'] = private_key['p']
  585. params['q'] = private_key['q']
  586. params['g'] = private_key['g']
  587. public_key = private_key['public_key']
  588. private_key = private_key['private_key']
  589. elif algorithm == 'ec':
  590. if not isinstance(private_key, ECPrivateKey):
  591. private_key = ECPrivateKey.load(private_key)
  592. else:
  593. private_key = private_key.copy()
  594. params = private_key['parameters']
  595. del private_key['parameters']
  596. else:
  597. raise ValueError(unwrap(
  598. '''
  599. algorithm must be one of "rsa", "dsa", "ec", not %s
  600. ''',
  601. repr(algorithm)
  602. ))
  603. private_key_algo = PrivateKeyAlgorithm()
  604. private_key_algo['algorithm'] = PrivateKeyAlgorithmId(algorithm)
  605. private_key_algo['parameters'] = params
  606. container = cls()
  607. container._algorithm = algorithm
  608. container['version'] = Integer(0)
  609. container['private_key_algorithm'] = private_key_algo
  610. container['private_key'] = private_key
  611. # Here we save the DSA public key if possible since it is not contained
  612. # within the PKCS#8 structure for a DSA key
  613. if algorithm == 'dsa':
  614. container._public_key = public_key
  615. return container
  616. # This is necessary to ensure any contained ECPrivateKey is the
  617. # correct size
  618. def __setitem__(self, key, value):
  619. res = super(PrivateKeyInfo, self).__setitem__(key, value)
  620. algorithm = self['private_key_algorithm']
  621. # When possible, use the parameter info to make sure the private key encoding
  622. # retains any necessary leading bytes, instead of them being dropped
  623. if (key == 'private_key_algorithm' or key == 'private_key') and \
  624. algorithm['algorithm'].native == 'ec' and \
  625. isinstance(algorithm['parameters'], ECDomainParameters) and \
  626. algorithm['parameters'].name != 'implicit_ca' and \
  627. isinstance(self['private_key'], ParsableOctetString) and \
  628. isinstance(self['private_key'].parsed, ECPrivateKey):
  629. self['private_key'].parsed.set_key_size(algorithm['parameters'].key_size)
  630. return res
  631. def unwrap(self):
  632. """
  633. Unwraps the private key into an RSAPrivateKey, DSAPrivateKey or
  634. ECPrivateKey object
  635. :return:
  636. An RSAPrivateKey, DSAPrivateKey or ECPrivateKey object
  637. """
  638. raise APIException(
  639. 'asn1crypto.keys.PrivateKeyInfo().unwrap() has been removed, '
  640. 'please use oscrypto.asymmetric.PrivateKey().unwrap() instead')
  641. @property
  642. def curve(self):
  643. """
  644. Returns information about the curve used for an EC key
  645. :raises:
  646. ValueError - when the key is not an EC key
  647. :return:
  648. A two-element tuple, with the first element being a unicode string
  649. of "implicit_ca", "specified" or "named". If the first element is
  650. "implicit_ca", the second is None. If "specified", the second is
  651. an OrderedDict that is the native version of SpecifiedECDomain. If
  652. "named", the second is a unicode string of the curve name.
  653. """
  654. if self.algorithm != 'ec':
  655. raise ValueError(unwrap(
  656. '''
  657. Only EC keys have a curve, this key is %s
  658. ''',
  659. self.algorithm.upper()
  660. ))
  661. params = self['private_key_algorithm']['parameters']
  662. chosen = params.chosen
  663. if params.name == 'implicit_ca':
  664. value = None
  665. else:
  666. value = chosen.native
  667. return (params.name, value)
  668. @property
  669. def hash_algo(self):
  670. """
  671. Returns the name of the family of hash algorithms used to generate a
  672. DSA key
  673. :raises:
  674. ValueError - when the key is not a DSA key
  675. :return:
  676. A unicode string of "sha1" or "sha2"
  677. """
  678. if self.algorithm != 'dsa':
  679. raise ValueError(unwrap(
  680. '''
  681. Only DSA keys are generated using a hash algorithm, this key is
  682. %s
  683. ''',
  684. self.algorithm.upper()
  685. ))
  686. byte_len = math.log(self['private_key_algorithm']['parameters']['q'].native, 2) / 8
  687. return 'sha1' if byte_len <= 20 else 'sha2'
  688. @property
  689. def algorithm(self):
  690. """
  691. :return:
  692. A unicode string of "rsa", "dsa" or "ec"
  693. """
  694. if self._algorithm is None:
  695. self._algorithm = self['private_key_algorithm']['algorithm'].native
  696. return self._algorithm
  697. @property
  698. def bit_size(self):
  699. """
  700. :return:
  701. The bit size of the private key, as an integer
  702. """
  703. if self._bit_size is None:
  704. if self.algorithm == 'rsa':
  705. prime = self['private_key'].parsed['modulus'].native
  706. elif self.algorithm == 'dsa':
  707. prime = self['private_key_algorithm']['parameters']['p'].native
  708. elif self.algorithm == 'ec':
  709. prime = self['private_key'].parsed['private_key'].native
  710. self._bit_size = int(math.ceil(math.log(prime, 2)))
  711. modulus = self._bit_size % 8
  712. if modulus != 0:
  713. self._bit_size += 8 - modulus
  714. return self._bit_size
  715. @property
  716. def byte_size(self):
  717. """
  718. :return:
  719. The byte size of the private key, as an integer
  720. """
  721. return int(math.ceil(self.bit_size / 8))
  722. @property
  723. def public_key(self):
  724. """
  725. :return:
  726. If an RSA key, an RSAPublicKey object. If a DSA key, an Integer
  727. object. If an EC key, an ECPointBitString object.
  728. """
  729. raise APIException(
  730. 'asn1crypto.keys.PrivateKeyInfo().public_key has been removed, '
  731. 'please use oscrypto.asymmetric.PrivateKey().public_key.unwrap() instead')
  732. @property
  733. def public_key_info(self):
  734. """
  735. :return:
  736. A PublicKeyInfo object derived from this private key.
  737. """
  738. raise APIException(
  739. 'asn1crypto.keys.PrivateKeyInfo().public_key_info has been removed, '
  740. 'please use oscrypto.asymmetric.PrivateKey().public_key.asn1 instead')
  741. @property
  742. def fingerprint(self):
  743. """
  744. Creates a fingerprint that can be compared with a public key to see if
  745. the two form a pair.
  746. This fingerprint is not compatible with fingerprints generated by any
  747. other software.
  748. :return:
  749. A byte string that is a sha256 hash of selected components (based
  750. on the key type)
  751. """
  752. raise APIException(
  753. 'asn1crypto.keys.PrivateKeyInfo().fingerprint has been removed, '
  754. 'please use oscrypto.asymmetric.PrivateKey().fingerprint instead')
  755. class EncryptedPrivateKeyInfo(Sequence):
  756. """
  757. Source: https://tools.ietf.org/html/rfc5208#page-4
  758. """
  759. _fields = [
  760. ('encryption_algorithm', EncryptionAlgorithm),
  761. ('encrypted_data', OctetString),
  762. ]
  763. # These structures are from https://tools.ietf.org/html/rfc3279
  764. class ValidationParms(Sequence):
  765. """
  766. Source: https://tools.ietf.org/html/rfc3279#page-10
  767. """
  768. _fields = [
  769. ('seed', BitString),
  770. ('pgen_counter', Integer),
  771. ]
  772. class DomainParameters(Sequence):
  773. """
  774. Source: https://tools.ietf.org/html/rfc3279#page-10
  775. """
  776. _fields = [
  777. ('p', Integer),
  778. ('g', Integer),
  779. ('q', Integer),
  780. ('j', Integer, {'optional': True}),
  781. ('validation_params', ValidationParms, {'optional': True}),
  782. ]
  783. class PublicKeyAlgorithmId(ObjectIdentifier):
  784. """
  785. Original Name: None
  786. Source: https://tools.ietf.org/html/rfc3279
  787. """
  788. _map = {
  789. # https://tools.ietf.org/html/rfc3279#page-19
  790. '1.2.840.113549.1.1.1': 'rsa',
  791. # https://tools.ietf.org/html/rfc3447#page-47
  792. '1.2.840.113549.1.1.7': 'rsaes_oaep',
  793. # https://tools.ietf.org/html/rfc4055#page-8
  794. '1.2.840.113549.1.1.10': 'rsassa_pss',
  795. # https://tools.ietf.org/html/rfc3279#page-18
  796. '1.2.840.10040.4.1': 'dsa',
  797. # https://tools.ietf.org/html/rfc3279#page-13
  798. '1.2.840.10045.2.1': 'ec',
  799. # https://tools.ietf.org/html/rfc3279#page-10
  800. '1.2.840.10046.2.1': 'dh',
  801. }
  802. class PublicKeyAlgorithm(_ForceNullParameters, Sequence):
  803. """
  804. Original Name: AlgorithmIdentifier
  805. Source: https://tools.ietf.org/html/rfc5280#page-18
  806. """
  807. _fields = [
  808. ('algorithm', PublicKeyAlgorithmId),
  809. ('parameters', Any, {'optional': True}),
  810. ]
  811. _oid_pair = ('algorithm', 'parameters')
  812. _oid_specs = {
  813. 'dsa': DSAParams,
  814. 'ec': ECDomainParameters,
  815. 'dh': DomainParameters,
  816. 'rsaes_oaep': RSAESOAEPParams,
  817. 'rsassa_pss': RSASSAPSSParams,
  818. }
  819. class PublicKeyInfo(Sequence):
  820. """
  821. Original Name: SubjectPublicKeyInfo
  822. Source: https://tools.ietf.org/html/rfc5280#page-17
  823. """
  824. _fields = [
  825. ('algorithm', PublicKeyAlgorithm),
  826. ('public_key', ParsableOctetBitString),
  827. ]
  828. def _public_key_spec(self):
  829. algorithm = self['algorithm']['algorithm'].native
  830. return {
  831. 'rsa': RSAPublicKey,
  832. 'rsaes_oaep': RSAPublicKey,
  833. 'rsassa_pss': RSAPublicKey,
  834. 'dsa': Integer,
  835. # We override the field spec with ECPoint so that users can easily
  836. # decompose the byte string into the constituent X and Y coords
  837. 'ec': (ECPointBitString, None),
  838. 'dh': Integer,
  839. }[algorithm]
  840. _spec_callbacks = {
  841. 'public_key': _public_key_spec
  842. }
  843. _algorithm = None
  844. _bit_size = None
  845. _fingerprint = None
  846. _sha1 = None
  847. _sha256 = None
  848. @classmethod
  849. def wrap(cls, public_key, algorithm):
  850. """
  851. Wraps a public key in a PublicKeyInfo structure
  852. :param public_key:
  853. A byte string or Asn1Value object of the public key
  854. :param algorithm:
  855. A unicode string of "rsa"
  856. :return:
  857. A PublicKeyInfo object
  858. """
  859. if not isinstance(public_key, byte_cls) and not isinstance(public_key, Asn1Value):
  860. raise TypeError(unwrap(
  861. '''
  862. public_key must be a byte string or Asn1Value, not %s
  863. ''',
  864. type_name(public_key)
  865. ))
  866. if algorithm != 'rsa':
  867. raise ValueError(unwrap(
  868. '''
  869. algorithm must "rsa", not %s
  870. ''',
  871. repr(algorithm)
  872. ))
  873. algo = PublicKeyAlgorithm()
  874. algo['algorithm'] = PublicKeyAlgorithmId(algorithm)
  875. algo['parameters'] = Null()
  876. container = cls()
  877. container['algorithm'] = algo
  878. if isinstance(public_key, Asn1Value):
  879. public_key = public_key.untag().dump()
  880. container['public_key'] = ParsableOctetBitString(public_key)
  881. return container
  882. def unwrap(self):
  883. """
  884. Unwraps an RSA public key into an RSAPublicKey object. Does not support
  885. DSA or EC public keys since they do not have an unwrapped form.
  886. :return:
  887. An RSAPublicKey object
  888. """
  889. raise APIException(
  890. 'asn1crypto.keys.PublicKeyInfo().unwrap() has been removed, '
  891. 'please use oscrypto.asymmetric.PublicKey().unwrap() instead')
  892. @property
  893. def curve(self):
  894. """
  895. Returns information about the curve used for an EC key
  896. :raises:
  897. ValueError - when the key is not an EC key
  898. :return:
  899. A two-element tuple, with the first element being a unicode string
  900. of "implicit_ca", "specified" or "named". If the first element is
  901. "implicit_ca", the second is None. If "specified", the second is
  902. an OrderedDict that is the native version of SpecifiedECDomain. If
  903. "named", the second is a unicode string of the curve name.
  904. """
  905. if self.algorithm != 'ec':
  906. raise ValueError(unwrap(
  907. '''
  908. Only EC keys have a curve, this key is %s
  909. ''',
  910. self.algorithm.upper()
  911. ))
  912. params = self['algorithm']['parameters']
  913. chosen = params.chosen
  914. if params.name == 'implicit_ca':
  915. value = None
  916. else:
  917. value = chosen.native
  918. return (params.name, value)
  919. @property
  920. def hash_algo(self):
  921. """
  922. Returns the name of the family of hash algorithms used to generate a
  923. DSA key
  924. :raises:
  925. ValueError - when the key is not a DSA key
  926. :return:
  927. A unicode string of "sha1" or "sha2" or None if no parameters are
  928. present
  929. """
  930. if self.algorithm != 'dsa':
  931. raise ValueError(unwrap(
  932. '''
  933. Only DSA keys are generated using a hash algorithm, this key is
  934. %s
  935. ''',
  936. self.algorithm.upper()
  937. ))
  938. parameters = self['algorithm']['parameters']
  939. if parameters.native is None:
  940. return None
  941. byte_len = math.log(parameters['q'].native, 2) / 8
  942. return 'sha1' if byte_len <= 20 else 'sha2'
  943. @property
  944. def algorithm(self):
  945. """
  946. :return:
  947. A unicode string of "rsa", "dsa" or "ec"
  948. """
  949. if self._algorithm is None:
  950. self._algorithm = self['algorithm']['algorithm'].native
  951. return self._algorithm
  952. @property
  953. def bit_size(self):
  954. """
  955. :return:
  956. The bit size of the public key, as an integer
  957. """
  958. if self._bit_size is None:
  959. if self.algorithm == 'ec':
  960. self._bit_size = ((len(self['public_key'].native) - 1) / 2) * 8
  961. else:
  962. if self.algorithm == 'rsa':
  963. prime = self['public_key'].parsed['modulus'].native
  964. elif self.algorithm == 'dsa':
  965. prime = self['algorithm']['parameters']['p'].native
  966. self._bit_size = int(math.ceil(math.log(prime, 2)))
  967. modulus = self._bit_size % 8
  968. if modulus != 0:
  969. self._bit_size += 8 - modulus
  970. return self._bit_size
  971. @property
  972. def byte_size(self):
  973. """
  974. :return:
  975. The byte size of the public key, as an integer
  976. """
  977. return int(math.ceil(self.bit_size / 8))
  978. @property
  979. def sha1(self):
  980. """
  981. :return:
  982. The SHA1 hash of the DER-encoded bytes of this public key info
  983. """
  984. if self._sha1 is None:
  985. self._sha1 = hashlib.sha1(byte_cls(self['public_key'])).digest()
  986. return self._sha1
  987. @property
  988. def sha256(self):
  989. """
  990. :return:
  991. The SHA-256 hash of the DER-encoded bytes of this public key info
  992. """
  993. if self._sha256 is None:
  994. self._sha256 = hashlib.sha256(byte_cls(self['public_key'])).digest()
  995. return self._sha256
  996. @property
  997. def fingerprint(self):
  998. """
  999. Creates a fingerprint that can be compared with a private key to see if
  1000. the two form a pair.
  1001. This fingerprint is not compatible with fingerprints generated by any
  1002. other software.
  1003. :return:
  1004. A byte string that is a sha256 hash of selected components (based
  1005. on the key type)
  1006. """
  1007. raise APIException(
  1008. 'asn1crypto.keys.PublicKeyInfo().fingerprint has been removed, '
  1009. 'please use oscrypto.asymmetric.PublicKey().fingerprint instead')