Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/asn1crypto/keys.py: 70%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

319 statements  

1# coding: utf-8 

2 

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 

17from __future__ import unicode_literals, division, absolute_import, print_function 

18 

19import hashlib 

20import math 

21 

22from ._errors import unwrap, APIException 

23from ._types import type_name, byte_cls 

24from .algos import _ForceNullParameters, DigestAlgorithm, EncryptionAlgorithm, RSAESOAEPParams, RSASSAPSSParams 

25from .core import ( 

26 Any, 

27 Asn1Value, 

28 BitString, 

29 Choice, 

30 Integer, 

31 IntegerOctetString, 

32 Null, 

33 ObjectIdentifier, 

34 OctetBitString, 

35 OctetString, 

36 ParsableOctetString, 

37 ParsableOctetBitString, 

38 Sequence, 

39 SequenceOf, 

40 SetOf, 

41) 

42from .util import int_from_bytes, int_to_bytes 

43 

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 """ 

109 The ASN.1 structure that OpenSSL uses to store a DSA private key that is 

110 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 

127class _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 

182 if first_byte not in set([b'\x02', b'\x03']): 

183 raise ValueError(unwrap( 

184 ''' 

185 Invalid EC public key - first byte is incorrect 

186 ''' 

187 )) 

188 

189 raise ValueError(unwrap( 

190 ''' 

191 Compressed representations of EC public keys are not supported due 

192 to patent US6252960 

193 ''' 

194 )) 

195 

196 

197class ECPoint(OctetString, _ECPoint): 

198 

199 pass 

200 

201 

202class ECPointBitString(OctetBitString, _ECPoint): 

203 

204 pass 

205 

206 

207class 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), 

313 ('base', ECPoint), 

314 ('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', 

351 '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', 

356 # https://tools.ietf.org/html/rfc5480#page-5 

357 # 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', 

360 '1.3.132.0.1': 'sect163k1', 

361 '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', 

369 '1.3.132.0.10': 'secp256k1', 

370 '1.3.132.0.15': 'sect163r2', 

371 '1.3.132.0.16': 'sect283k1', 

372 '1.3.132.0.17': 'sect283r1', 

373 '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', 

385 '1.3.132.0.34': 'secp384r1', 

386 '1.3.132.0.35': 'secp521r1', 

387 '1.3.132.0.36': 'sect409k1', 

388 '1.3.132.0.37': 'sect409r1', 

389 '1.3.132.0.38': 'sect571k1', 

390 '1.3.132.0.39': 'sect571r1', 

391 # 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', 

406 } 

407 

408 _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 

438 # ceil(n.bit_length() / 8) 

439 '1.2.840.10045.3.1.1': 24, 

440 '1.2.840.10045.3.1.7': 32, 

441 '1.3.132.0.1': 21, 

442 '1.3.132.0.2': 21, 

443 '1.3.132.0.3': 30, 

444 '1.3.132.0.4': 15, 

445 '1.3.132.0.5': 15, 

446 '1.3.132.0.6': 14, 

447 '1.3.132.0.7': 14, 

448 '1.3.132.0.8': 21, 

449 '1.3.132.0.9': 21, 

450 '1.3.132.0.10': 32, 

451 '1.3.132.0.15': 21, 

452 '1.3.132.0.16': 36, 

453 '1.3.132.0.17': 36, 

454 '1.3.132.0.22': 17, 

455 '1.3.132.0.23': 17, 

456 '1.3.132.0.24': 25, 

457 '1.3.132.0.25': 25, 

458 '1.3.132.0.26': 29, 

459 '1.3.132.0.27': 30, 

460 '1.3.132.0.28': 16, 

461 '1.3.132.0.29': 16, 

462 '1.3.132.0.30': 21, 

463 '1.3.132.0.31': 24, 

464 '1.3.132.0.32': 29, 

465 '1.3.132.0.33': 28, 

466 '1.3.132.0.34': 48, 

467 '1.3.132.0.35': 66, 

468 '1.3.132.0.36': 51, 

469 '1.3.132.0.37': 52, 

470 '1.3.132.0.38': 72, 

471 '1.3.132.0.39': 72, 

472 # 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, 

489 } 

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 

509 if cls._reverse_map is not None: 

510 cls._reverse_map[name] = oid 

511 cls._key_sizes[oid] = key_size 

512 

513 

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 

525 @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 

550 

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), 

570 ('parameters', ECDomainParameters, {'explicit': 0, 'optional': True}), 

571 ('public_key', ECPointBitString, {'explicit': 1, 'optional': True}), 

572 ] 

573 

574 # 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 

616 

617class 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', 

663 # https://tools.ietf.org/html/rfc4055#page-8 

664 '1.2.840.113549.1.1.10': 'rsassa_pss', 

665 # 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 

668 '1.2.840.10045.2.1': 'ec', 

669 # https://tools.ietf.org/html/rfc8410#section-9 

670 '1.3.101.110': 'x25519', 

671 '1.3.101.111': 'x448', 

672 '1.3.101.112': 'ed25519', 

673 '1.3.101.113': 'ed448', 

674 } 

675 

676 

677class PrivateKeyAlgorithm(_ForceNullParameters, Sequence): 

678 """ 

679 Original Name: PrivateKeyAlgorithmIdentifier 

680 Source: https://tools.ietf.org/html/rfc5208#page-3 

681 """ 

682 

683 _fields = [ 

684 ('algorithm', PrivateKeyAlgorithmId), 

685 ('parameters', Any, {'optional': True}), 

686 ] 

687 

688 _oid_pair = ('algorithm', 'parameters') 

689 _oid_specs = { 

690 'dsa': DSAParams, 

691 'ec': ECDomainParameters, 

692 'rsassa_pss': RSASSAPSSParams, 

693 } 

694 

695 

696class PrivateKeyInfo(Sequence): 

697 """ 

698 Source: https://tools.ietf.org/html/rfc5208#page-3 

699 """ 

700 

701 _fields = [ 

702 ('version', Integer), 

703 ('private_key_algorithm', PrivateKeyAlgorithm), 

704 ('private_key', ParsableOctetString), 

705 ('attributes', Attributes, {'implicit': 0, 'optional': True}), 

706 ] 

707 

708 def _private_key_spec(self): 

709 algorithm = self['private_key_algorithm']['algorithm'].native 

710 return { 

711 'rsa': RSAPrivateKey, 

712 'rsassa_pss': RSAPrivateKey, 

713 'dsa': Integer, 

714 'ec': ECPrivateKey, 

715 # These should be treated as opaque octet strings according 

716 # to RFC 8410 

717 'x25519': OctetString, 

718 'x448': OctetString, 

719 'ed25519': OctetString, 

720 'ed448': OctetString, 

721 }[algorithm] 

722 

723 _spec_callbacks = { 

724 'private_key': _private_key_spec 

725 } 

726 

727 _algorithm = None 

728 _bit_size = None 

729 _public_key = None 

730 _fingerprint = None 

731 

732 @classmethod 

733 def wrap(cls, private_key, algorithm): 

734 """ 

735 Wraps a private key in a PrivateKeyInfo structure 

736 

737 :param private_key: 

738 A byte string or Asn1Value object of the private key 

739 

740 :param algorithm: 

741 A unicode string of "rsa", "dsa" or "ec" 

742 

743 :return: 

744 A PrivateKeyInfo object 

745 """ 

746 

747 if not isinstance(private_key, byte_cls) and not isinstance(private_key, Asn1Value): 

748 raise TypeError(unwrap( 

749 ''' 

750 private_key must be a byte string or Asn1Value, not %s 

751 ''', 

752 type_name(private_key) 

753 )) 

754 

755 if algorithm == 'rsa' or algorithm == 'rsassa_pss': 

756 if not isinstance(private_key, RSAPrivateKey): 

757 private_key = RSAPrivateKey.load(private_key) 

758 params = Null() 

759 elif algorithm == 'dsa': 

760 if not isinstance(private_key, DSAPrivateKey): 

761 private_key = DSAPrivateKey.load(private_key) 

762 params = DSAParams() 

763 params['p'] = private_key['p'] 

764 params['q'] = private_key['q'] 

765 params['g'] = private_key['g'] 

766 public_key = private_key['public_key'] 

767 private_key = private_key['private_key'] 

768 elif algorithm == 'ec': 

769 if not isinstance(private_key, ECPrivateKey): 

770 private_key = ECPrivateKey.load(private_key) 

771 else: 

772 private_key = private_key.copy() 

773 params = private_key['parameters'] 

774 del private_key['parameters'] 

775 else: 

776 raise ValueError(unwrap( 

777 ''' 

778 algorithm must be one of "rsa", "dsa", "ec", not %s 

779 ''', 

780 repr(algorithm) 

781 )) 

782 

783 private_key_algo = PrivateKeyAlgorithm() 

784 private_key_algo['algorithm'] = PrivateKeyAlgorithmId(algorithm) 

785 private_key_algo['parameters'] = params 

786 

787 container = cls() 

788 container._algorithm = algorithm 

789 container['version'] = Integer(0) 

790 container['private_key_algorithm'] = private_key_algo 

791 container['private_key'] = private_key 

792 

793 # Here we save the DSA public key if possible since it is not contained 

794 # within the PKCS#8 structure for a DSA key 

795 if algorithm == 'dsa': 

796 container._public_key = public_key 

797 

798 return container 

799 

800 # This is necessary to ensure any contained ECPrivateKey is the 

801 # correct size 

802 def __setitem__(self, key, value): 

803 res = super(PrivateKeyInfo, self).__setitem__(key, value) 

804 

805 algorithm = self['private_key_algorithm'] 

806 

807 # When possible, use the parameter info to make sure the private key encoding 

808 # retains any necessary leading bytes, instead of them being dropped 

809 if (key == 'private_key_algorithm' or key == 'private_key') and \ 

810 algorithm['algorithm'].native == 'ec' and \ 

811 isinstance(algorithm['parameters'], ECDomainParameters) and \ 

812 algorithm['parameters'].name != 'implicit_ca' and \ 

813 isinstance(self['private_key'], ParsableOctetString) and \ 

814 isinstance(self['private_key'].parsed, ECPrivateKey): 

815 self['private_key'].parsed.set_key_size(algorithm['parameters'].key_size) 

816 

817 return res 

818 

819 def unwrap(self): 

820 """ 

821 Unwraps the private key into an RSAPrivateKey, DSAPrivateKey or 

822 ECPrivateKey object 

823 

824 :return: 

825 An RSAPrivateKey, DSAPrivateKey or ECPrivateKey object 

826 """ 

827 

828 raise APIException( 

829 'asn1crypto.keys.PrivateKeyInfo().unwrap() has been removed, ' 

830 'please use oscrypto.asymmetric.PrivateKey().unwrap() instead') 

831 

832 @property 

833 def curve(self): 

834 """ 

835 Returns information about the curve used for an EC key 

836 

837 :raises: 

838 ValueError - when the key is not an EC key 

839 

840 :return: 

841 A two-element tuple, with the first element being a unicode string 

842 of "implicit_ca", "specified" or "named". If the first element is 

843 "implicit_ca", the second is None. If "specified", the second is 

844 an OrderedDict that is the native version of SpecifiedECDomain. If 

845 "named", the second is a unicode string of the curve name. 

846 """ 

847 

848 if self.algorithm != 'ec': 

849 raise ValueError(unwrap( 

850 ''' 

851 Only EC keys have a curve, this key is %s 

852 ''', 

853 self.algorithm.upper() 

854 )) 

855 

856 params = self['private_key_algorithm']['parameters'] 

857 chosen = params.chosen 

858 

859 if params.name == 'implicit_ca': 

860 value = None 

861 else: 

862 value = chosen.native 

863 

864 return (params.name, value) 

865 

866 @property 

867 def hash_algo(self): 

868 """ 

869 Returns the name of the family of hash algorithms used to generate a 

870 DSA key 

871 

872 :raises: 

873 ValueError - when the key is not a DSA key 

874 

875 :return: 

876 A unicode string of "sha1" or "sha2" 

877 """ 

878 

879 if self.algorithm != 'dsa': 

880 raise ValueError(unwrap( 

881 ''' 

882 Only DSA keys are generated using a hash algorithm, this key is 

883 %s 

884 ''', 

885 self.algorithm.upper() 

886 )) 

887 

888 byte_len = math.log(self['private_key_algorithm']['parameters']['q'].native, 2) / 8 

889 

890 return 'sha1' if byte_len <= 20 else 'sha2' 

891 

892 @property 

893 def algorithm(self): 

894 """ 

895 :return: 

896 A unicode string of "rsa", "rsassa_pss", "dsa" or "ec" 

897 """ 

898 

899 if self._algorithm is None: 

900 self._algorithm = self['private_key_algorithm']['algorithm'].native 

901 return self._algorithm 

902 

903 @property 

904 def bit_size(self): 

905 """ 

906 :return: 

907 The bit size of the private key, as an integer 

908 """ 

909 

910 if self._bit_size is None: 

911 if self.algorithm == 'rsa' or self.algorithm == 'rsassa_pss': 

912 prime = self['private_key'].parsed['modulus'].native 

913 elif self.algorithm == 'dsa': 

914 prime = self['private_key_algorithm']['parameters']['p'].native 

915 elif self.algorithm == 'ec': 

916 prime = self['private_key'].parsed['private_key'].native 

917 self._bit_size = int(math.ceil(math.log(prime, 2))) 

918 modulus = self._bit_size % 8 

919 if modulus != 0: 

920 self._bit_size += 8 - modulus 

921 return self._bit_size 

922 

923 @property 

924 def byte_size(self): 

925 """ 

926 :return: 

927 The byte size of the private key, as an integer 

928 """ 

929 

930 return int(math.ceil(self.bit_size / 8)) 

931 

932 @property 

933 def public_key(self): 

934 """ 

935 :return: 

936 If an RSA key, an RSAPublicKey object. If a DSA key, an Integer 

937 object. If an EC key, an ECPointBitString object. 

938 """ 

939 

940 raise APIException( 

941 'asn1crypto.keys.PrivateKeyInfo().public_key has been removed, ' 

942 'please use oscrypto.asymmetric.PrivateKey().public_key.unwrap() instead') 

943 

944 @property 

945 def public_key_info(self): 

946 """ 

947 :return: 

948 A PublicKeyInfo object derived from this private key. 

949 """ 

950 

951 raise APIException( 

952 'asn1crypto.keys.PrivateKeyInfo().public_key_info has been removed, ' 

953 'please use oscrypto.asymmetric.PrivateKey().public_key.asn1 instead') 

954 

955 @property 

956 def fingerprint(self): 

957 """ 

958 Creates a fingerprint that can be compared with a public key to see if 

959 the two form a pair. 

960 

961 This fingerprint is not compatible with fingerprints generated by any 

962 other software. 

963 

964 :return: 

965 A byte string that is a sha256 hash of selected components (based 

966 on the key type) 

967 """ 

968 

969 raise APIException( 

970 'asn1crypto.keys.PrivateKeyInfo().fingerprint has been removed, ' 

971 'please use oscrypto.asymmetric.PrivateKey().fingerprint instead') 

972 

973 

974class EncryptedPrivateKeyInfo(Sequence): 

975 """ 

976 Source: https://tools.ietf.org/html/rfc5208#page-4 

977 """ 

978 

979 _fields = [ 

980 ('encryption_algorithm', EncryptionAlgorithm), 

981 ('encrypted_data', OctetString), 

982 ] 

983 

984 

985# These structures are from https://tools.ietf.org/html/rfc3279 

986 

987class ValidationParms(Sequence): 

988 """ 

989 Source: https://tools.ietf.org/html/rfc3279#page-10 

990 """ 

991 

992 _fields = [ 

993 ('seed', BitString), 

994 ('pgen_counter', Integer), 

995 ] 

996 

997 

998class DomainParameters(Sequence): 

999 """ 

1000 Source: https://tools.ietf.org/html/rfc3279#page-10 

1001 """ 

1002 

1003 _fields = [ 

1004 ('p', Integer), 

1005 ('g', Integer), 

1006 ('q', Integer), 

1007 ('j', Integer, {'optional': True}), 

1008 ('validation_params', ValidationParms, {'optional': True}), 

1009 ] 

1010 

1011 

1012class PublicKeyAlgorithmId(ObjectIdentifier): 

1013 """ 

1014 Original Name: None 

1015 Source: https://tools.ietf.org/html/rfc3279 

1016 """ 

1017 

1018 _map = { 

1019 # https://tools.ietf.org/html/rfc3279#page-19 

1020 '1.2.840.113549.1.1.1': 'rsa', 

1021 # https://tools.ietf.org/html/rfc3447#page-47 

1022 '1.2.840.113549.1.1.7': 'rsaes_oaep', 

1023 # https://tools.ietf.org/html/rfc4055#page-8 

1024 '1.2.840.113549.1.1.10': 'rsassa_pss', 

1025 # https://tools.ietf.org/html/rfc3279#page-18 

1026 '1.2.840.10040.4.1': 'dsa', 

1027 # https://tools.ietf.org/html/rfc3279#page-13 

1028 '1.2.840.10045.2.1': 'ec', 

1029 # https://tools.ietf.org/html/rfc3279#page-10 

1030 '1.2.840.10046.2.1': 'dh', 

1031 # https://tools.ietf.org/html/rfc8410#section-9 

1032 '1.3.101.110': 'x25519', 

1033 '1.3.101.111': 'x448', 

1034 '1.3.101.112': 'ed25519', 

1035 '1.3.101.113': 'ed448', 

1036 } 

1037 

1038 

1039class PublicKeyAlgorithm(_ForceNullParameters, Sequence): 

1040 """ 

1041 Original Name: AlgorithmIdentifier 

1042 Source: https://tools.ietf.org/html/rfc5280#page-18 

1043 """ 

1044 

1045 _fields = [ 

1046 ('algorithm', PublicKeyAlgorithmId), 

1047 ('parameters', Any, {'optional': True}), 

1048 ] 

1049 

1050 _oid_pair = ('algorithm', 'parameters') 

1051 _oid_specs = { 

1052 'dsa': DSAParams, 

1053 'ec': ECDomainParameters, 

1054 'dh': DomainParameters, 

1055 'rsaes_oaep': RSAESOAEPParams, 

1056 'rsassa_pss': RSASSAPSSParams, 

1057 } 

1058 

1059 

1060class PublicKeyInfo(Sequence): 

1061 """ 

1062 Original Name: SubjectPublicKeyInfo 

1063 Source: https://tools.ietf.org/html/rfc5280#page-17 

1064 """ 

1065 

1066 _fields = [ 

1067 ('algorithm', PublicKeyAlgorithm), 

1068 ('public_key', ParsableOctetBitString), 

1069 ] 

1070 

1071 def _public_key_spec(self): 

1072 algorithm = self['algorithm']['algorithm'].native 

1073 return { 

1074 'rsa': RSAPublicKey, 

1075 'rsaes_oaep': RSAPublicKey, 

1076 'rsassa_pss': RSAPublicKey, 

1077 'dsa': Integer, 

1078 # We override the field spec with ECPoint so that users can easily 

1079 # decompose the byte string into the constituent X and Y coords 

1080 'ec': (ECPointBitString, None), 

1081 'dh': Integer, 

1082 # These should be treated as opaque bit strings according 

1083 # to RFC 8410, and need not even be valid ASN.1 

1084 'x25519': (OctetBitString, None), 

1085 'x448': (OctetBitString, None), 

1086 'ed25519': (OctetBitString, None), 

1087 'ed448': (OctetBitString, None), 

1088 }[algorithm] 

1089 

1090 _spec_callbacks = { 

1091 'public_key': _public_key_spec 

1092 } 

1093 

1094 _algorithm = None 

1095 _bit_size = None 

1096 _fingerprint = None 

1097 _sha1 = None 

1098 _sha256 = None 

1099 

1100 @classmethod 

1101 def wrap(cls, public_key, algorithm): 

1102 """ 

1103 Wraps a public key in a PublicKeyInfo structure 

1104 

1105 :param public_key: 

1106 A byte string or Asn1Value object of the public key 

1107 

1108 :param algorithm: 

1109 A unicode string of "rsa" 

1110 

1111 :return: 

1112 A PublicKeyInfo object 

1113 """ 

1114 

1115 if not isinstance(public_key, byte_cls) and not isinstance(public_key, Asn1Value): 

1116 raise TypeError(unwrap( 

1117 ''' 

1118 public_key must be a byte string or Asn1Value, not %s 

1119 ''', 

1120 type_name(public_key) 

1121 )) 

1122 

1123 if algorithm != 'rsa' and algorithm != 'rsassa_pss': 

1124 raise ValueError(unwrap( 

1125 ''' 

1126 algorithm must "rsa", not %s 

1127 ''', 

1128 repr(algorithm) 

1129 )) 

1130 

1131 algo = PublicKeyAlgorithm() 

1132 algo['algorithm'] = PublicKeyAlgorithmId(algorithm) 

1133 algo['parameters'] = Null() 

1134 

1135 container = cls() 

1136 container['algorithm'] = algo 

1137 if isinstance(public_key, Asn1Value): 

1138 public_key = public_key.untag().dump() 

1139 container['public_key'] = ParsableOctetBitString(public_key) 

1140 

1141 return container 

1142 

1143 def unwrap(self): 

1144 """ 

1145 Unwraps an RSA public key into an RSAPublicKey object. Does not support 

1146 DSA or EC public keys since they do not have an unwrapped form. 

1147 

1148 :return: 

1149 An RSAPublicKey object 

1150 """ 

1151 

1152 raise APIException( 

1153 'asn1crypto.keys.PublicKeyInfo().unwrap() has been removed, ' 

1154 'please use oscrypto.asymmetric.PublicKey().unwrap() instead') 

1155 

1156 @property 

1157 def curve(self): 

1158 """ 

1159 Returns information about the curve used for an EC key 

1160 

1161 :raises: 

1162 ValueError - when the key is not an EC key 

1163 

1164 :return: 

1165 A two-element tuple, with the first element being a unicode string 

1166 of "implicit_ca", "specified" or "named". If the first element is 

1167 "implicit_ca", the second is None. If "specified", the second is 

1168 an OrderedDict that is the native version of SpecifiedECDomain. If 

1169 "named", the second is a unicode string of the curve name. 

1170 """ 

1171 

1172 if self.algorithm != 'ec': 

1173 raise ValueError(unwrap( 

1174 ''' 

1175 Only EC keys have a curve, this key is %s 

1176 ''', 

1177 self.algorithm.upper() 

1178 )) 

1179 

1180 params = self['algorithm']['parameters'] 

1181 chosen = params.chosen 

1182 

1183 if params.name == 'implicit_ca': 

1184 value = None 

1185 else: 

1186 value = chosen.native 

1187 

1188 return (params.name, value) 

1189 

1190 @property 

1191 def hash_algo(self): 

1192 """ 

1193 Returns the name of the family of hash algorithms used to generate a 

1194 DSA key 

1195 

1196 :raises: 

1197 ValueError - when the key is not a DSA key 

1198 

1199 :return: 

1200 A unicode string of "sha1" or "sha2" or None if no parameters are 

1201 present 

1202 """ 

1203 

1204 if self.algorithm != 'dsa': 

1205 raise ValueError(unwrap( 

1206 ''' 

1207 Only DSA keys are generated using a hash algorithm, this key is 

1208 %s 

1209 ''', 

1210 self.algorithm.upper() 

1211 )) 

1212 

1213 parameters = self['algorithm']['parameters'] 

1214 if parameters.native is None: 

1215 return None 

1216 

1217 byte_len = math.log(parameters['q'].native, 2) / 8 

1218 

1219 return 'sha1' if byte_len <= 20 else 'sha2' 

1220 

1221 @property 

1222 def algorithm(self): 

1223 """ 

1224 :return: 

1225 A unicode string of "rsa", "rsassa_pss", "dsa" or "ec" 

1226 """ 

1227 

1228 if self._algorithm is None: 

1229 self._algorithm = self['algorithm']['algorithm'].native 

1230 return self._algorithm 

1231 

1232 @property 

1233 def bit_size(self): 

1234 """ 

1235 :return: 

1236 The bit size of the public key, as an integer 

1237 """ 

1238 

1239 if self._bit_size is None: 

1240 if self.algorithm == 'ec': 

1241 self._bit_size = int(((len(self['public_key'].native) - 1) / 2) * 8) 

1242 else: 

1243 if self.algorithm == 'rsa' or self.algorithm == 'rsassa_pss': 

1244 prime = self['public_key'].parsed['modulus'].native 

1245 elif self.algorithm == 'dsa': 

1246 prime = self['algorithm']['parameters']['p'].native 

1247 self._bit_size = int(math.ceil(math.log(prime, 2))) 

1248 modulus = self._bit_size % 8 

1249 if modulus != 0: 

1250 self._bit_size += 8 - modulus 

1251 

1252 return self._bit_size 

1253 

1254 @property 

1255 def byte_size(self): 

1256 """ 

1257 :return: 

1258 The byte size of the public key, as an integer 

1259 """ 

1260 

1261 return int(math.ceil(self.bit_size / 8)) 

1262 

1263 @property 

1264 def sha1(self): 

1265 """ 

1266 :return: 

1267 The SHA1 hash of the DER-encoded bytes of this public key info 

1268 """ 

1269 

1270 if self._sha1 is None: 

1271 self._sha1 = hashlib.sha1(byte_cls(self['public_key'])).digest() 

1272 return self._sha1 

1273 

1274 @property 

1275 def sha256(self): 

1276 """ 

1277 :return: 

1278 The SHA-256 hash of the DER-encoded bytes of this public key info 

1279 """ 

1280 

1281 if self._sha256 is None: 

1282 self._sha256 = hashlib.sha256(byte_cls(self['public_key'])).digest() 

1283 return self._sha256 

1284 

1285 @property 

1286 def fingerprint(self): 

1287 """ 

1288 Creates a fingerprint that can be compared with a private key to see if 

1289 the two form a pair. 

1290 

1291 This fingerprint is not compatible with fingerprints generated by any 

1292 other software. 

1293 

1294 :return: 

1295 A byte string that is a sha256 hash of selected components (based 

1296 on the key type) 

1297 """ 

1298 

1299 raise APIException( 

1300 'asn1crypto.keys.PublicKeyInfo().fingerprint has been removed, ' 

1301 'please use oscrypto.asymmetric.PublicKey().fingerprint instead')