Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/asn1crypto/x509.py: 46%

1007 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-06-07 06:25 +0000

1# coding: utf-8 

2 

3""" 

4ASN.1 type classes for X.509 certificates. Exports the following items: 

5 

6 - Attributes() 

7 - Certificate() 

8 - Extensions() 

9 - GeneralName() 

10 - GeneralNames() 

11 - Name() 

12 

13Other type classes are defined that help compose the types listed above. 

14""" 

15 

16from __future__ import unicode_literals, division, absolute_import, print_function 

17 

18from contextlib import contextmanager 

19from encodings import idna # noqa 

20import hashlib 

21import re 

22import socket 

23import stringprep 

24import sys 

25import unicodedata 

26 

27from ._errors import unwrap 

28from ._iri import iri_to_uri, uri_to_iri 

29from ._ordereddict import OrderedDict 

30from ._types import type_name, str_cls, bytes_to_list 

31from .algos import AlgorithmIdentifier, AnyAlgorithmIdentifier, DigestAlgorithm, SignedDigestAlgorithm 

32from .core import ( 

33 Any, 

34 BitString, 

35 BMPString, 

36 Boolean, 

37 Choice, 

38 Concat, 

39 Enumerated, 

40 GeneralizedTime, 

41 GeneralString, 

42 IA5String, 

43 Integer, 

44 Null, 

45 NumericString, 

46 ObjectIdentifier, 

47 OctetBitString, 

48 OctetString, 

49 ParsableOctetString, 

50 PrintableString, 

51 Sequence, 

52 SequenceOf, 

53 Set, 

54 SetOf, 

55 TeletexString, 

56 UniversalString, 

57 UTCTime, 

58 UTF8String, 

59 VisibleString, 

60 VOID, 

61) 

62from .keys import PublicKeyInfo 

63from .util import int_to_bytes, int_from_bytes, inet_ntop, inet_pton 

64 

65 

66# The structures in this file are taken from https://tools.ietf.org/html/rfc5280 

67# and a few other supplementary sources, mostly due to extra supported 

68# extension and name OIDs 

69 

70 

71class DNSName(IA5String): 

72 

73 _encoding = 'idna' 

74 _bad_tag = (12, 19) 

75 

76 def __ne__(self, other): 

77 return not self == other 

78 

79 def __eq__(self, other): 

80 """ 

81 Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.2 

82 

83 :param other: 

84 Another DNSName object 

85 

86 :return: 

87 A boolean 

88 """ 

89 

90 if not isinstance(other, DNSName): 

91 return False 

92 

93 return self.__unicode__().lower() == other.__unicode__().lower() 

94 

95 def set(self, value): 

96 """ 

97 Sets the value of the DNS name 

98 

99 :param value: 

100 A unicode string 

101 """ 

102 

103 if not isinstance(value, str_cls): 

104 raise TypeError(unwrap( 

105 ''' 

106 %s value must be a unicode string, not %s 

107 ''', 

108 type_name(self), 

109 type_name(value) 

110 )) 

111 

112 if value.startswith('.'): 

113 encoded_value = b'.' + value[1:].encode(self._encoding) 

114 else: 

115 encoded_value = value.encode(self._encoding) 

116 

117 self._unicode = value 

118 self.contents = encoded_value 

119 self._header = None 

120 if self._trailer != b'': 

121 self._trailer = b'' 

122 

123 

124class URI(IA5String): 

125 

126 def set(self, value): 

127 """ 

128 Sets the value of the string 

129 

130 :param value: 

131 A unicode string 

132 """ 

133 

134 if not isinstance(value, str_cls): 

135 raise TypeError(unwrap( 

136 ''' 

137 %s value must be a unicode string, not %s 

138 ''', 

139 type_name(self), 

140 type_name(value) 

141 )) 

142 

143 self._unicode = value 

144 self.contents = iri_to_uri(value) 

145 self._header = None 

146 if self._trailer != b'': 

147 self._trailer = b'' 

148 

149 def __ne__(self, other): 

150 return not self == other 

151 

152 def __eq__(self, other): 

153 """ 

154 Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.4 

155 

156 :param other: 

157 Another URI object 

158 

159 :return: 

160 A boolean 

161 """ 

162 

163 if not isinstance(other, URI): 

164 return False 

165 

166 return iri_to_uri(self.native, True) == iri_to_uri(other.native, True) 

167 

168 def __unicode__(self): 

169 """ 

170 :return: 

171 A unicode string 

172 """ 

173 

174 if self.contents is None: 

175 return '' 

176 if self._unicode is None: 

177 self._unicode = uri_to_iri(self._merge_chunks()) 

178 return self._unicode 

179 

180 

181class EmailAddress(IA5String): 

182 

183 _contents = None 

184 

185 # If the value has gone through the .set() method, thus normalizing it 

186 _normalized = False 

187 

188 # In the wild we've seen this encoded as a UTF8String and PrintableString 

189 _bad_tag = (12, 19) 

190 

191 @property 

192 def contents(self): 

193 """ 

194 :return: 

195 A byte string of the DER-encoded contents of the sequence 

196 """ 

197 

198 return self._contents 

199 

200 @contents.setter 

201 def contents(self, value): 

202 """ 

203 :param value: 

204 A byte string of the DER-encoded contents of the sequence 

205 """ 

206 

207 self._normalized = False 

208 self._contents = value 

209 

210 def set(self, value): 

211 """ 

212 Sets the value of the string 

213 

214 :param value: 

215 A unicode string 

216 """ 

217 

218 if not isinstance(value, str_cls): 

219 raise TypeError(unwrap( 

220 ''' 

221 %s value must be a unicode string, not %s 

222 ''', 

223 type_name(self), 

224 type_name(value) 

225 )) 

226 

227 if value.find('@') != -1: 

228 mailbox, hostname = value.rsplit('@', 1) 

229 encoded_value = mailbox.encode('ascii') + b'@' + hostname.encode('idna') 

230 else: 

231 encoded_value = value.encode('ascii') 

232 

233 self._normalized = True 

234 self._unicode = value 

235 self.contents = encoded_value 

236 self._header = None 

237 if self._trailer != b'': 

238 self._trailer = b'' 

239 

240 def __unicode__(self): 

241 """ 

242 :return: 

243 A unicode string 

244 """ 

245 

246 # We've seen this in the wild as a PrintableString, and since ascii is a 

247 # subset of cp1252, we use the later for decoding to be more user friendly 

248 if self._unicode is None: 

249 contents = self._merge_chunks() 

250 if contents.find(b'@') == -1: 

251 self._unicode = contents.decode('cp1252') 

252 else: 

253 mailbox, hostname = contents.rsplit(b'@', 1) 

254 self._unicode = mailbox.decode('cp1252') + '@' + hostname.decode('idna') 

255 return self._unicode 

256 

257 def __ne__(self, other): 

258 return not self == other 

259 

260 def __eq__(self, other): 

261 """ 

262 Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.5 

263 

264 :param other: 

265 Another EmailAddress object 

266 

267 :return: 

268 A boolean 

269 """ 

270 

271 if not isinstance(other, EmailAddress): 

272 return False 

273 

274 if not self._normalized: 

275 self.set(self.native) 

276 if not other._normalized: 

277 other.set(other.native) 

278 

279 if self._contents.find(b'@') == -1 or other._contents.find(b'@') == -1: 

280 return self._contents == other._contents 

281 

282 other_mailbox, other_hostname = other._contents.rsplit(b'@', 1) 

283 mailbox, hostname = self._contents.rsplit(b'@', 1) 

284 

285 if mailbox != other_mailbox: 

286 return False 

287 

288 if hostname.lower() != other_hostname.lower(): 

289 return False 

290 

291 return True 

292 

293 

294class IPAddress(OctetString): 

295 def parse(self, spec=None, spec_params=None): 

296 """ 

297 This method is not applicable to IP addresses 

298 """ 

299 

300 raise ValueError(unwrap( 

301 ''' 

302 IP address values can not be parsed 

303 ''' 

304 )) 

305 

306 def set(self, value): 

307 """ 

308 Sets the value of the object 

309 

310 :param value: 

311 A unicode string containing an IPv4 address, IPv4 address with CIDR, 

312 an IPv6 address or IPv6 address with CIDR 

313 """ 

314 

315 if not isinstance(value, str_cls): 

316 raise TypeError(unwrap( 

317 ''' 

318 %s value must be a unicode string, not %s 

319 ''', 

320 type_name(self), 

321 type_name(value) 

322 )) 

323 

324 original_value = value 

325 

326 has_cidr = value.find('/') != -1 

327 cidr = 0 

328 if has_cidr: 

329 parts = value.split('/', 1) 

330 value = parts[0] 

331 cidr = int(parts[1]) 

332 if cidr < 0: 

333 raise ValueError(unwrap( 

334 ''' 

335 %s value contains a CIDR range less than 0 

336 ''', 

337 type_name(self) 

338 )) 

339 

340 if value.find(':') != -1: 

341 family = socket.AF_INET6 

342 if cidr > 128: 

343 raise ValueError(unwrap( 

344 ''' 

345 %s value contains a CIDR range bigger than 128, the maximum 

346 value for an IPv6 address 

347 ''', 

348 type_name(self) 

349 )) 

350 cidr_size = 128 

351 else: 

352 family = socket.AF_INET 

353 if cidr > 32: 

354 raise ValueError(unwrap( 

355 ''' 

356 %s value contains a CIDR range bigger than 32, the maximum 

357 value for an IPv4 address 

358 ''', 

359 type_name(self) 

360 )) 

361 cidr_size = 32 

362 

363 cidr_bytes = b'' 

364 if has_cidr: 

365 cidr_mask = '1' * cidr 

366 cidr_mask += '0' * (cidr_size - len(cidr_mask)) 

367 cidr_bytes = int_to_bytes(int(cidr_mask, 2)) 

368 cidr_bytes = (b'\x00' * ((cidr_size // 8) - len(cidr_bytes))) + cidr_bytes 

369 

370 self._native = original_value 

371 self.contents = inet_pton(family, value) + cidr_bytes 

372 self._bytes = self.contents 

373 self._header = None 

374 if self._trailer != b'': 

375 self._trailer = b'' 

376 

377 @property 

378 def native(self): 

379 """ 

380 The native Python datatype representation of this value 

381 

382 :return: 

383 A unicode string or None 

384 """ 

385 

386 if self.contents is None: 

387 return None 

388 

389 if self._native is None: 

390 byte_string = self.__bytes__() 

391 byte_len = len(byte_string) 

392 value = None 

393 cidr_int = None 

394 if byte_len in set([32, 16]): 

395 value = inet_ntop(socket.AF_INET6, byte_string[0:16]) 

396 if byte_len > 16: 

397 cidr_int = int_from_bytes(byte_string[16:]) 

398 elif byte_len in set([8, 4]): 

399 value = inet_ntop(socket.AF_INET, byte_string[0:4]) 

400 if byte_len > 4: 

401 cidr_int = int_from_bytes(byte_string[4:]) 

402 if cidr_int is not None: 

403 cidr_bits = '{0:b}'.format(cidr_int) 

404 cidr = len(cidr_bits.rstrip('0')) 

405 value = value + '/' + str_cls(cidr) 

406 self._native = value 

407 return self._native 

408 

409 def __ne__(self, other): 

410 return not self == other 

411 

412 def __eq__(self, other): 

413 """ 

414 :param other: 

415 Another IPAddress object 

416 

417 :return: 

418 A boolean 

419 """ 

420 

421 if not isinstance(other, IPAddress): 

422 return False 

423 

424 return self.__bytes__() == other.__bytes__() 

425 

426 

427class Attribute(Sequence): 

428 _fields = [ 

429 ('type', ObjectIdentifier), 

430 ('values', SetOf, {'spec': Any}), 

431 ] 

432 

433 

434class Attributes(SequenceOf): 

435 _child_spec = Attribute 

436 

437 

438class KeyUsage(BitString): 

439 _map = { 

440 0: 'digital_signature', 

441 1: 'non_repudiation', 

442 2: 'key_encipherment', 

443 3: 'data_encipherment', 

444 4: 'key_agreement', 

445 5: 'key_cert_sign', 

446 6: 'crl_sign', 

447 7: 'encipher_only', 

448 8: 'decipher_only', 

449 } 

450 

451 

452class PrivateKeyUsagePeriod(Sequence): 

453 _fields = [ 

454 ('not_before', GeneralizedTime, {'implicit': 0, 'optional': True}), 

455 ('not_after', GeneralizedTime, {'implicit': 1, 'optional': True}), 

456 ] 

457 

458 

459class NotReallyTeletexString(TeletexString): 

460 """ 

461 OpenSSL (and probably some other libraries) puts ISO-8859-1 

462 into TeletexString instead of ITU T.61. We use Windows-1252 when 

463 decoding since it is a superset of ISO-8859-1, and less likely to 

464 cause encoding issues, but we stay strict with encoding to prevent 

465 us from creating bad data. 

466 """ 

467 

468 _decoding_encoding = 'cp1252' 

469 

470 def __unicode__(self): 

471 """ 

472 :return: 

473 A unicode string 

474 """ 

475 

476 if self.contents is None: 

477 return '' 

478 if self._unicode is None: 

479 self._unicode = self._merge_chunks().decode(self._decoding_encoding) 

480 return self._unicode 

481 

482 

483@contextmanager 

484def strict_teletex(): 

485 try: 

486 NotReallyTeletexString._decoding_encoding = 'teletex' 

487 yield 

488 finally: 

489 NotReallyTeletexString._decoding_encoding = 'cp1252' 

490 

491 

492class DirectoryString(Choice): 

493 _alternatives = [ 

494 ('teletex_string', NotReallyTeletexString), 

495 ('printable_string', PrintableString), 

496 ('universal_string', UniversalString), 

497 ('utf8_string', UTF8String), 

498 ('bmp_string', BMPString), 

499 # This is an invalid/bad alternative, but some broken certs use it 

500 ('ia5_string', IA5String), 

501 ] 

502 

503 

504class NameType(ObjectIdentifier): 

505 _map = { 

506 '2.5.4.3': 'common_name', 

507 '2.5.4.4': 'surname', 

508 '2.5.4.5': 'serial_number', 

509 '2.5.4.6': 'country_name', 

510 '2.5.4.7': 'locality_name', 

511 '2.5.4.8': 'state_or_province_name', 

512 '2.5.4.9': 'street_address', 

513 '2.5.4.10': 'organization_name', 

514 '2.5.4.11': 'organizational_unit_name', 

515 '2.5.4.12': 'title', 

516 '2.5.4.15': 'business_category', 

517 '2.5.4.17': 'postal_code', 

518 '2.5.4.20': 'telephone_number', 

519 '2.5.4.41': 'name', 

520 '2.5.4.42': 'given_name', 

521 '2.5.4.43': 'initials', 

522 '2.5.4.44': 'generation_qualifier', 

523 '2.5.4.45': 'unique_identifier', 

524 '2.5.4.46': 'dn_qualifier', 

525 '2.5.4.65': 'pseudonym', 

526 '2.5.4.97': 'organization_identifier', 

527 # https://www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf 

528 '2.23.133.2.1': 'tpm_manufacturer', 

529 '2.23.133.2.2': 'tpm_model', 

530 '2.23.133.2.3': 'tpm_version', 

531 '2.23.133.2.4': 'platform_manufacturer', 

532 '2.23.133.2.5': 'platform_model', 

533 '2.23.133.2.6': 'platform_version', 

534 # https://tools.ietf.org/html/rfc2985#page-26 

535 '1.2.840.113549.1.9.1': 'email_address', 

536 # Page 10 of https://cabforum.org/wp-content/uploads/EV-V1_5_5.pdf 

537 '1.3.6.1.4.1.311.60.2.1.1': 'incorporation_locality', 

538 '1.3.6.1.4.1.311.60.2.1.2': 'incorporation_state_or_province', 

539 '1.3.6.1.4.1.311.60.2.1.3': 'incorporation_country', 

540 # https://tools.ietf.org/html/rfc4519#section-2.39 

541 '0.9.2342.19200300.100.1.1': 'user_id', 

542 # https://tools.ietf.org/html/rfc2247#section-4 

543 '0.9.2342.19200300.100.1.25': 'domain_component', 

544 # http://www.alvestrand.no/objectid/0.2.262.1.10.7.20.html 

545 '0.2.262.1.10.7.20': 'name_distinguisher', 

546 } 

547 

548 # This order is largely based on observed order seen in EV certs from 

549 # Symantec and DigiCert. Some of the uncommon name-related fields are 

550 # just placed in what seems like a reasonable order. 

551 preferred_order = [ 

552 'incorporation_country', 

553 'incorporation_state_or_province', 

554 'incorporation_locality', 

555 'business_category', 

556 'serial_number', 

557 'country_name', 

558 'postal_code', 

559 'state_or_province_name', 

560 'locality_name', 

561 'street_address', 

562 'organization_name', 

563 'organizational_unit_name', 

564 'title', 

565 'common_name', 

566 'user_id', 

567 'initials', 

568 'generation_qualifier', 

569 'surname', 

570 'given_name', 

571 'name', 

572 'pseudonym', 

573 'dn_qualifier', 

574 'telephone_number', 

575 'email_address', 

576 'domain_component', 

577 'name_distinguisher', 

578 'organization_identifier', 

579 'tpm_manufacturer', 

580 'tpm_model', 

581 'tpm_version', 

582 'platform_manufacturer', 

583 'platform_model', 

584 'platform_version', 

585 ] 

586 

587 @classmethod 

588 def preferred_ordinal(cls, attr_name): 

589 """ 

590 Returns an ordering value for a particular attribute key. 

591 

592 Unrecognized attributes and OIDs will be sorted lexically at the end. 

593 

594 :return: 

595 An orderable value. 

596 

597 """ 

598 

599 attr_name = cls.map(attr_name) 

600 if attr_name in cls.preferred_order: 

601 ordinal = cls.preferred_order.index(attr_name) 

602 else: 

603 ordinal = len(cls.preferred_order) 

604 

605 return (ordinal, attr_name) 

606 

607 @property 

608 def human_friendly(self): 

609 """ 

610 :return: 

611 A human-friendly unicode string to display to users 

612 """ 

613 

614 return { 

615 'common_name': 'Common Name', 

616 'surname': 'Surname', 

617 'serial_number': 'Serial Number', 

618 'country_name': 'Country', 

619 'locality_name': 'Locality', 

620 'state_or_province_name': 'State/Province', 

621 'street_address': 'Street Address', 

622 'organization_name': 'Organization', 

623 'organizational_unit_name': 'Organizational Unit', 

624 'title': 'Title', 

625 'business_category': 'Business Category', 

626 'postal_code': 'Postal Code', 

627 'telephone_number': 'Telephone Number', 

628 'name': 'Name', 

629 'given_name': 'Given Name', 

630 'initials': 'Initials', 

631 'generation_qualifier': 'Generation Qualifier', 

632 'unique_identifier': 'Unique Identifier', 

633 'dn_qualifier': 'DN Qualifier', 

634 'pseudonym': 'Pseudonym', 

635 'email_address': 'Email Address', 

636 'incorporation_locality': 'Incorporation Locality', 

637 'incorporation_state_or_province': 'Incorporation State/Province', 

638 'incorporation_country': 'Incorporation Country', 

639 'domain_component': 'Domain Component', 

640 'name_distinguisher': 'Name Distinguisher', 

641 'organization_identifier': 'Organization Identifier', 

642 'tpm_manufacturer': 'TPM Manufacturer', 

643 'tpm_model': 'TPM Model', 

644 'tpm_version': 'TPM Version', 

645 'platform_manufacturer': 'Platform Manufacturer', 

646 'platform_model': 'Platform Model', 

647 'platform_version': 'Platform Version', 

648 'user_id': 'User ID', 

649 }.get(self.native, self.native) 

650 

651 

652class NameTypeAndValue(Sequence): 

653 _fields = [ 

654 ('type', NameType), 

655 ('value', Any), 

656 ] 

657 

658 _oid_pair = ('type', 'value') 

659 _oid_specs = { 

660 'common_name': DirectoryString, 

661 'surname': DirectoryString, 

662 'serial_number': DirectoryString, 

663 'country_name': DirectoryString, 

664 'locality_name': DirectoryString, 

665 'state_or_province_name': DirectoryString, 

666 'street_address': DirectoryString, 

667 'organization_name': DirectoryString, 

668 'organizational_unit_name': DirectoryString, 

669 'title': DirectoryString, 

670 'business_category': DirectoryString, 

671 'postal_code': DirectoryString, 

672 'telephone_number': PrintableString, 

673 'name': DirectoryString, 

674 'given_name': DirectoryString, 

675 'initials': DirectoryString, 

676 'generation_qualifier': DirectoryString, 

677 'unique_identifier': OctetBitString, 

678 'dn_qualifier': DirectoryString, 

679 'pseudonym': DirectoryString, 

680 # https://tools.ietf.org/html/rfc2985#page-26 

681 'email_address': EmailAddress, 

682 # Page 10 of https://cabforum.org/wp-content/uploads/EV-V1_5_5.pdf 

683 'incorporation_locality': DirectoryString, 

684 'incorporation_state_or_province': DirectoryString, 

685 'incorporation_country': DirectoryString, 

686 'domain_component': DNSName, 

687 'name_distinguisher': DirectoryString, 

688 'organization_identifier': DirectoryString, 

689 'tpm_manufacturer': UTF8String, 

690 'tpm_model': UTF8String, 

691 'tpm_version': UTF8String, 

692 'platform_manufacturer': UTF8String, 

693 'platform_model': UTF8String, 

694 'platform_version': UTF8String, 

695 'user_id': DirectoryString, 

696 } 

697 

698 _prepped = None 

699 

700 @property 

701 def prepped_value(self): 

702 """ 

703 Returns the value after being processed by the internationalized string 

704 preparation as specified by RFC 5280 

705 

706 :return: 

707 A unicode string 

708 """ 

709 

710 if self._prepped is None: 

711 self._prepped = self._ldap_string_prep(self['value'].native) 

712 return self._prepped 

713 

714 def __ne__(self, other): 

715 return not self == other 

716 

717 def __eq__(self, other): 

718 """ 

719 Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1 

720 

721 :param other: 

722 Another NameTypeAndValue object 

723 

724 :return: 

725 A boolean 

726 """ 

727 

728 if not isinstance(other, NameTypeAndValue): 

729 return False 

730 

731 if other['type'].native != self['type'].native: 

732 return False 

733 

734 return other.prepped_value == self.prepped_value 

735 

736 def _ldap_string_prep(self, string): 

737 """ 

738 Implements the internationalized string preparation algorithm from 

739 RFC 4518. https://tools.ietf.org/html/rfc4518#section-2 

740 

741 :param string: 

742 A unicode string to prepare 

743 

744 :return: 

745 A prepared unicode string, ready for comparison 

746 """ 

747 

748 # Map step 

749 string = re.sub('[\u00ad\u1806\u034f\u180b-\u180d\ufe0f-\uff00\ufffc]+', '', string) 

750 string = re.sub('[\u0009\u000a\u000b\u000c\u000d\u0085]', ' ', string) 

751 if sys.maxunicode == 0xffff: 

752 # Some installs of Python 2.7 don't support 8-digit unicode escape 

753 # ranges, so we have to break them into pieces 

754 # Original was: \U0001D173-\U0001D17A and \U000E0020-\U000E007F 

755 string = re.sub('\ud834[\udd73-\udd7a]|\udb40[\udc20-\udc7f]|\U000e0001', '', string) 

756 else: 

757 string = re.sub('[\U0001D173-\U0001D17A\U000E0020-\U000E007F\U000e0001]', '', string) 

758 string = re.sub( 

759 '[\u0000-\u0008\u000e-\u001f\u007f-\u0084\u0086-\u009f\u06dd\u070f\u180e\u200c-\u200f' 

760 '\u202a-\u202e\u2060-\u2063\u206a-\u206f\ufeff\ufff9-\ufffb]+', 

761 '', 

762 string 

763 ) 

764 string = string.replace('\u200b', '') 

765 string = re.sub('[\u00a0\u1680\u2000-\u200a\u2028-\u2029\u202f\u205f\u3000]', ' ', string) 

766 

767 string = ''.join(map(stringprep.map_table_b2, string)) 

768 

769 # Normalize step 

770 string = unicodedata.normalize('NFKC', string) 

771 

772 # Prohibit step 

773 for char in string: 

774 if stringprep.in_table_a1(char): 

775 raise ValueError(unwrap( 

776 ''' 

777 X.509 Name objects may not contain unassigned code points 

778 ''' 

779 )) 

780 

781 if stringprep.in_table_c8(char): 

782 raise ValueError(unwrap( 

783 ''' 

784 X.509 Name objects may not contain change display or 

785 zzzzdeprecated characters 

786 ''' 

787 )) 

788 

789 if stringprep.in_table_c3(char): 

790 raise ValueError(unwrap( 

791 ''' 

792 X.509 Name objects may not contain private use characters 

793 ''' 

794 )) 

795 

796 if stringprep.in_table_c4(char): 

797 raise ValueError(unwrap( 

798 ''' 

799 X.509 Name objects may not contain non-character code points 

800 ''' 

801 )) 

802 

803 if stringprep.in_table_c5(char): 

804 raise ValueError(unwrap( 

805 ''' 

806 X.509 Name objects may not contain surrogate code points 

807 ''' 

808 )) 

809 

810 if char == '\ufffd': 

811 raise ValueError(unwrap( 

812 ''' 

813 X.509 Name objects may not contain the replacement character 

814 ''' 

815 )) 

816 

817 # Check bidirectional step - here we ensure that we are not mixing 

818 # left-to-right and right-to-left text in the string 

819 has_r_and_al_cat = False 

820 has_l_cat = False 

821 for char in string: 

822 if stringprep.in_table_d1(char): 

823 has_r_and_al_cat = True 

824 elif stringprep.in_table_d2(char): 

825 has_l_cat = True 

826 

827 if has_r_and_al_cat: 

828 first_is_r_and_al = stringprep.in_table_d1(string[0]) 

829 last_is_r_and_al = stringprep.in_table_d1(string[-1]) 

830 

831 if has_l_cat or not first_is_r_and_al or not last_is_r_and_al: 

832 raise ValueError(unwrap( 

833 ''' 

834 X.509 Name object contains a malformed bidirectional 

835 sequence 

836 ''' 

837 )) 

838 

839 # Insignificant space handling step 

840 string = ' ' + re.sub(' +', ' ', string).strip() + ' ' 

841 

842 return string 

843 

844 

845class RelativeDistinguishedName(SetOf): 

846 _child_spec = NameTypeAndValue 

847 

848 @property 

849 def hashable(self): 

850 """ 

851 :return: 

852 A unicode string that can be used as a dict key or in a set 

853 """ 

854 

855 output = [] 

856 values = self._get_values(self) 

857 for key in sorted(values.keys()): 

858 output.append('%s: %s' % (key, values[key])) 

859 # Unit separator is used here since the normalization process for 

860 # values moves any such character, and the keys are all dotted integers 

861 # or under_score_words 

862 return '\x1F'.join(output) 

863 

864 def __ne__(self, other): 

865 return not self == other 

866 

867 def __eq__(self, other): 

868 """ 

869 Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1 

870 

871 :param other: 

872 Another RelativeDistinguishedName object 

873 

874 :return: 

875 A boolean 

876 """ 

877 

878 if not isinstance(other, RelativeDistinguishedName): 

879 return False 

880 

881 if len(self) != len(other): 

882 return False 

883 

884 self_types = self._get_types(self) 

885 other_types = self._get_types(other) 

886 

887 if self_types != other_types: 

888 return False 

889 

890 self_values = self._get_values(self) 

891 other_values = self._get_values(other) 

892 

893 for type_name_ in self_types: 

894 if self_values[type_name_] != other_values[type_name_]: 

895 return False 

896 

897 return True 

898 

899 def _get_types(self, rdn): 

900 """ 

901 Returns a set of types contained in an RDN 

902 

903 :param rdn: 

904 A RelativeDistinguishedName object 

905 

906 :return: 

907 A set object with unicode strings of NameTypeAndValue type field 

908 values 

909 """ 

910 

911 return set([ntv['type'].native for ntv in rdn]) 

912 

913 def _get_values(self, rdn): 

914 """ 

915 Returns a dict of prepped values contained in an RDN 

916 

917 :param rdn: 

918 A RelativeDistinguishedName object 

919 

920 :return: 

921 A dict object with unicode strings of NameTypeAndValue value field 

922 values that have been prepped for comparison 

923 """ 

924 

925 output = {} 

926 [output.update([(ntv['type'].native, ntv.prepped_value)]) for ntv in rdn] 

927 return output 

928 

929 

930class RDNSequence(SequenceOf): 

931 _child_spec = RelativeDistinguishedName 

932 

933 @property 

934 def hashable(self): 

935 """ 

936 :return: 

937 A unicode string that can be used as a dict key or in a set 

938 """ 

939 

940 # Record separator is used here since the normalization process for 

941 # values moves any such character, and the keys are all dotted integers 

942 # or under_score_words 

943 return '\x1E'.join(rdn.hashable for rdn in self) 

944 

945 def __ne__(self, other): 

946 return not self == other 

947 

948 def __eq__(self, other): 

949 """ 

950 Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1 

951 

952 :param other: 

953 Another RDNSequence object 

954 

955 :return: 

956 A boolean 

957 """ 

958 

959 if not isinstance(other, RDNSequence): 

960 return False 

961 

962 if len(self) != len(other): 

963 return False 

964 

965 for index, self_rdn in enumerate(self): 

966 if other[index] != self_rdn: 

967 return False 

968 

969 return True 

970 

971 

972class Name(Choice): 

973 _alternatives = [ 

974 ('', RDNSequence), 

975 ] 

976 

977 _human_friendly = None 

978 _sha1 = None 

979 _sha256 = None 

980 

981 @classmethod 

982 def build(cls, name_dict, use_printable=False): 

983 """ 

984 Creates a Name object from a dict of unicode string keys and values. 

985 The keys should be from NameType._map, or a dotted-integer OID unicode 

986 string. 

987 

988 :param name_dict: 

989 A dict of name information, e.g. {"common_name": "Will Bond", 

990 "country_name": "US", "organization_name": "Codex Non Sufficit LC"} 

991 

992 :param use_printable: 

993 A bool - if PrintableString should be used for encoding instead of 

994 UTF8String. This is for backwards compatibility with old software. 

995 

996 :return: 

997 An x509.Name object 

998 """ 

999 

1000 rdns = [] 

1001 if not use_printable: 

1002 encoding_name = 'utf8_string' 

1003 encoding_class = UTF8String 

1004 else: 

1005 encoding_name = 'printable_string' 

1006 encoding_class = PrintableString 

1007 

1008 # Sort the attributes according to NameType.preferred_order 

1009 name_dict = OrderedDict( 

1010 sorted( 

1011 name_dict.items(), 

1012 key=lambda item: NameType.preferred_ordinal(item[0]) 

1013 ) 

1014 ) 

1015 

1016 for attribute_name, attribute_value in name_dict.items(): 

1017 attribute_name = NameType.map(attribute_name) 

1018 if attribute_name == 'email_address': 

1019 value = EmailAddress(attribute_value) 

1020 elif attribute_name == 'domain_component': 

1021 value = DNSName(attribute_value) 

1022 elif attribute_name in set(['dn_qualifier', 'country_name', 'serial_number']): 

1023 value = DirectoryString( 

1024 name='printable_string', 

1025 value=PrintableString(attribute_value) 

1026 ) 

1027 else: 

1028 value = DirectoryString( 

1029 name=encoding_name, 

1030 value=encoding_class(attribute_value) 

1031 ) 

1032 

1033 rdns.append(RelativeDistinguishedName([ 

1034 NameTypeAndValue({ 

1035 'type': attribute_name, 

1036 'value': value 

1037 }) 

1038 ])) 

1039 

1040 return cls(name='', value=RDNSequence(rdns)) 

1041 

1042 @property 

1043 def hashable(self): 

1044 """ 

1045 :return: 

1046 A unicode string that can be used as a dict key or in a set 

1047 """ 

1048 

1049 return self.chosen.hashable 

1050 

1051 def __len__(self): 

1052 return len(self.chosen) 

1053 

1054 def __ne__(self, other): 

1055 return not self == other 

1056 

1057 def __eq__(self, other): 

1058 """ 

1059 Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1 

1060 

1061 :param other: 

1062 Another Name object 

1063 

1064 :return: 

1065 A boolean 

1066 """ 

1067 

1068 if not isinstance(other, Name): 

1069 return False 

1070 return self.chosen == other.chosen 

1071 

1072 @property 

1073 def native(self): 

1074 if self._native is None: 

1075 self._native = OrderedDict() 

1076 for rdn in self.chosen.native: 

1077 for type_val in rdn: 

1078 field_name = type_val['type'] 

1079 if field_name in self._native: 

1080 existing = self._native[field_name] 

1081 if not isinstance(existing, list): 

1082 existing = self._native[field_name] = [existing] 

1083 existing.append(type_val['value']) 

1084 else: 

1085 self._native[field_name] = type_val['value'] 

1086 return self._native 

1087 

1088 @property 

1089 def human_friendly(self): 

1090 """ 

1091 :return: 

1092 A human-friendly unicode string containing the parts of the name 

1093 """ 

1094 

1095 if self._human_friendly is None: 

1096 data = OrderedDict() 

1097 last_field = None 

1098 for rdn in self.chosen: 

1099 for type_val in rdn: 

1100 field_name = type_val['type'].human_friendly 

1101 last_field = field_name 

1102 if field_name in data: 

1103 data[field_name] = [data[field_name]] 

1104 data[field_name].append(type_val['value']) 

1105 else: 

1106 data[field_name] = type_val['value'] 

1107 to_join = [] 

1108 keys = data.keys() 

1109 if last_field == 'Country': 

1110 keys = reversed(list(keys)) 

1111 for key in keys: 

1112 value = data[key] 

1113 native_value = self._recursive_humanize(value) 

1114 to_join.append('%s: %s' % (key, native_value)) 

1115 

1116 has_comma = False 

1117 for element in to_join: 

1118 if element.find(',') != -1: 

1119 has_comma = True 

1120 break 

1121 

1122 separator = ', ' if not has_comma else '; ' 

1123 self._human_friendly = separator.join(to_join[::-1]) 

1124 

1125 return self._human_friendly 

1126 

1127 def _recursive_humanize(self, value): 

1128 """ 

1129 Recursively serializes data compiled from the RDNSequence 

1130 

1131 :param value: 

1132 An Asn1Value object, or a list of Asn1Value objects 

1133 

1134 :return: 

1135 A unicode string 

1136 """ 

1137 

1138 if isinstance(value, list): 

1139 return ', '.join( 

1140 reversed([self._recursive_humanize(sub_value) for sub_value in value]) 

1141 ) 

1142 return value.native 

1143 

1144 @property 

1145 def sha1(self): 

1146 """ 

1147 :return: 

1148 The SHA1 hash of the DER-encoded bytes of this name 

1149 """ 

1150 

1151 if self._sha1 is None: 

1152 self._sha1 = hashlib.sha1(self.dump()).digest() 

1153 return self._sha1 

1154 

1155 @property 

1156 def sha256(self): 

1157 """ 

1158 :return: 

1159 The SHA-256 hash of the DER-encoded bytes of this name 

1160 """ 

1161 

1162 if self._sha256 is None: 

1163 self._sha256 = hashlib.sha256(self.dump()).digest() 

1164 return self._sha256 

1165 

1166 

1167class AnotherName(Sequence): 

1168 _fields = [ 

1169 ('type_id', ObjectIdentifier), 

1170 ('value', Any, {'explicit': 0}), 

1171 ] 

1172 

1173 

1174class CountryName(Choice): 

1175 class_ = 1 

1176 tag = 1 

1177 

1178 _alternatives = [ 

1179 ('x121_dcc_code', NumericString), 

1180 ('iso_3166_alpha2_code', PrintableString), 

1181 ] 

1182 

1183 

1184class AdministrationDomainName(Choice): 

1185 class_ = 1 

1186 tag = 2 

1187 

1188 _alternatives = [ 

1189 ('numeric', NumericString), 

1190 ('printable', PrintableString), 

1191 ] 

1192 

1193 

1194class PrivateDomainName(Choice): 

1195 _alternatives = [ 

1196 ('numeric', NumericString), 

1197 ('printable', PrintableString), 

1198 ] 

1199 

1200 

1201class PersonalName(Set): 

1202 _fields = [ 

1203 ('surname', PrintableString, {'implicit': 0}), 

1204 ('given_name', PrintableString, {'implicit': 1, 'optional': True}), 

1205 ('initials', PrintableString, {'implicit': 2, 'optional': True}), 

1206 ('generation_qualifier', PrintableString, {'implicit': 3, 'optional': True}), 

1207 ] 

1208 

1209 

1210class TeletexPersonalName(Set): 

1211 _fields = [ 

1212 ('surname', TeletexString, {'implicit': 0}), 

1213 ('given_name', TeletexString, {'implicit': 1, 'optional': True}), 

1214 ('initials', TeletexString, {'implicit': 2, 'optional': True}), 

1215 ('generation_qualifier', TeletexString, {'implicit': 3, 'optional': True}), 

1216 ] 

1217 

1218 

1219class OrganizationalUnitNames(SequenceOf): 

1220 _child_spec = PrintableString 

1221 

1222 

1223class TeletexOrganizationalUnitNames(SequenceOf): 

1224 _child_spec = TeletexString 

1225 

1226 

1227class BuiltInStandardAttributes(Sequence): 

1228 _fields = [ 

1229 ('country_name', CountryName, {'optional': True}), 

1230 ('administration_domain_name', AdministrationDomainName, {'optional': True}), 

1231 ('network_address', NumericString, {'implicit': 0, 'optional': True}), 

1232 ('terminal_identifier', PrintableString, {'implicit': 1, 'optional': True}), 

1233 ('private_domain_name', PrivateDomainName, {'explicit': 2, 'optional': True}), 

1234 ('organization_name', PrintableString, {'implicit': 3, 'optional': True}), 

1235 ('numeric_user_identifier', NumericString, {'implicit': 4, 'optional': True}), 

1236 ('personal_name', PersonalName, {'implicit': 5, 'optional': True}), 

1237 ('organizational_unit_names', OrganizationalUnitNames, {'implicit': 6, 'optional': True}), 

1238 ] 

1239 

1240 

1241class BuiltInDomainDefinedAttribute(Sequence): 

1242 _fields = [ 

1243 ('type', PrintableString), 

1244 ('value', PrintableString), 

1245 ] 

1246 

1247 

1248class BuiltInDomainDefinedAttributes(SequenceOf): 

1249 _child_spec = BuiltInDomainDefinedAttribute 

1250 

1251 

1252class TeletexDomainDefinedAttribute(Sequence): 

1253 _fields = [ 

1254 ('type', TeletexString), 

1255 ('value', TeletexString), 

1256 ] 

1257 

1258 

1259class TeletexDomainDefinedAttributes(SequenceOf): 

1260 _child_spec = TeletexDomainDefinedAttribute 

1261 

1262 

1263class PhysicalDeliveryCountryName(Choice): 

1264 _alternatives = [ 

1265 ('x121_dcc_code', NumericString), 

1266 ('iso_3166_alpha2_code', PrintableString), 

1267 ] 

1268 

1269 

1270class PostalCode(Choice): 

1271 _alternatives = [ 

1272 ('numeric_code', NumericString), 

1273 ('printable_code', PrintableString), 

1274 ] 

1275 

1276 

1277class PDSParameter(Set): 

1278 _fields = [ 

1279 ('printable_string', PrintableString, {'optional': True}), 

1280 ('teletex_string', TeletexString, {'optional': True}), 

1281 ] 

1282 

1283 

1284class PrintableAddress(SequenceOf): 

1285 _child_spec = PrintableString 

1286 

1287 

1288class UnformattedPostalAddress(Set): 

1289 _fields = [ 

1290 ('printable_address', PrintableAddress, {'optional': True}), 

1291 ('teletex_string', TeletexString, {'optional': True}), 

1292 ] 

1293 

1294 

1295class E1634Address(Sequence): 

1296 _fields = [ 

1297 ('number', NumericString, {'implicit': 0}), 

1298 ('sub_address', NumericString, {'implicit': 1, 'optional': True}), 

1299 ] 

1300 

1301 

1302class NAddresses(SetOf): 

1303 _child_spec = OctetString 

1304 

1305 

1306class PresentationAddress(Sequence): 

1307 _fields = [ 

1308 ('p_selector', OctetString, {'explicit': 0, 'optional': True}), 

1309 ('s_selector', OctetString, {'explicit': 1, 'optional': True}), 

1310 ('t_selector', OctetString, {'explicit': 2, 'optional': True}), 

1311 ('n_addresses', NAddresses, {'explicit': 3}), 

1312 ] 

1313 

1314 

1315class ExtendedNetworkAddress(Choice): 

1316 _alternatives = [ 

1317 ('e163_4_address', E1634Address), 

1318 ('psap_address', PresentationAddress, {'implicit': 0}) 

1319 ] 

1320 

1321 

1322class TerminalType(Integer): 

1323 _map = { 

1324 3: 'telex', 

1325 4: 'teletex', 

1326 5: 'g3_facsimile', 

1327 6: 'g4_facsimile', 

1328 7: 'ia5_terminal', 

1329 8: 'videotex', 

1330 } 

1331 

1332 

1333class ExtensionAttributeType(Integer): 

1334 _map = { 

1335 1: 'common_name', 

1336 2: 'teletex_common_name', 

1337 3: 'teletex_organization_name', 

1338 4: 'teletex_personal_name', 

1339 5: 'teletex_organization_unit_names', 

1340 6: 'teletex_domain_defined_attributes', 

1341 7: 'pds_name', 

1342 8: 'physical_delivery_country_name', 

1343 9: 'postal_code', 

1344 10: 'physical_delivery_office_name', 

1345 11: 'physical_delivery_office_number', 

1346 12: 'extension_of_address_components', 

1347 13: 'physical_delivery_personal_name', 

1348 14: 'physical_delivery_organization_name', 

1349 15: 'extension_physical_delivery_address_components', 

1350 16: 'unformatted_postal_address', 

1351 17: 'street_address', 

1352 18: 'post_office_box_address', 

1353 19: 'poste_restante_address', 

1354 20: 'unique_postal_name', 

1355 21: 'local_postal_attributes', 

1356 22: 'extended_network_address', 

1357 23: 'terminal_type', 

1358 } 

1359 

1360 

1361class ExtensionAttribute(Sequence): 

1362 _fields = [ 

1363 ('extension_attribute_type', ExtensionAttributeType, {'implicit': 0}), 

1364 ('extension_attribute_value', Any, {'explicit': 1}), 

1365 ] 

1366 

1367 _oid_pair = ('extension_attribute_type', 'extension_attribute_value') 

1368 _oid_specs = { 

1369 'common_name': PrintableString, 

1370 'teletex_common_name': TeletexString, 

1371 'teletex_organization_name': TeletexString, 

1372 'teletex_personal_name': TeletexPersonalName, 

1373 'teletex_organization_unit_names': TeletexOrganizationalUnitNames, 

1374 'teletex_domain_defined_attributes': TeletexDomainDefinedAttributes, 

1375 'pds_name': PrintableString, 

1376 'physical_delivery_country_name': PhysicalDeliveryCountryName, 

1377 'postal_code': PostalCode, 

1378 'physical_delivery_office_name': PDSParameter, 

1379 'physical_delivery_office_number': PDSParameter, 

1380 'extension_of_address_components': PDSParameter, 

1381 'physical_delivery_personal_name': PDSParameter, 

1382 'physical_delivery_organization_name': PDSParameter, 

1383 'extension_physical_delivery_address_components': PDSParameter, 

1384 'unformatted_postal_address': UnformattedPostalAddress, 

1385 'street_address': PDSParameter, 

1386 'post_office_box_address': PDSParameter, 

1387 'poste_restante_address': PDSParameter, 

1388 'unique_postal_name': PDSParameter, 

1389 'local_postal_attributes': PDSParameter, 

1390 'extended_network_address': ExtendedNetworkAddress, 

1391 'terminal_type': TerminalType, 

1392 } 

1393 

1394 

1395class ExtensionAttributes(SequenceOf): 

1396 _child_spec = ExtensionAttribute 

1397 

1398 

1399class ORAddress(Sequence): 

1400 _fields = [ 

1401 ('built_in_standard_attributes', BuiltInStandardAttributes), 

1402 ('built_in_domain_defined_attributes', BuiltInDomainDefinedAttributes, {'optional': True}), 

1403 ('extension_attributes', ExtensionAttributes, {'optional': True}), 

1404 ] 

1405 

1406 

1407class EDIPartyName(Sequence): 

1408 _fields = [ 

1409 ('name_assigner', DirectoryString, {'implicit': 0, 'optional': True}), 

1410 ('party_name', DirectoryString, {'implicit': 1}), 

1411 ] 

1412 

1413 

1414class GeneralName(Choice): 

1415 _alternatives = [ 

1416 ('other_name', AnotherName, {'implicit': 0}), 

1417 ('rfc822_name', EmailAddress, {'implicit': 1}), 

1418 ('dns_name', DNSName, {'implicit': 2}), 

1419 ('x400_address', ORAddress, {'implicit': 3}), 

1420 ('directory_name', Name, {'explicit': 4}), 

1421 ('edi_party_name', EDIPartyName, {'implicit': 5}), 

1422 ('uniform_resource_identifier', URI, {'implicit': 6}), 

1423 ('ip_address', IPAddress, {'implicit': 7}), 

1424 ('registered_id', ObjectIdentifier, {'implicit': 8}), 

1425 ] 

1426 

1427 def __ne__(self, other): 

1428 return not self == other 

1429 

1430 def __eq__(self, other): 

1431 """ 

1432 Does not support other_name, x400_address or edi_party_name 

1433 

1434 :param other: 

1435 The other GeneralName to compare to 

1436 

1437 :return: 

1438 A boolean 

1439 """ 

1440 

1441 if self.name in ('other_name', 'x400_address', 'edi_party_name'): 

1442 raise ValueError(unwrap( 

1443 ''' 

1444 Comparison is not supported for GeneralName objects of 

1445 choice %s 

1446 ''', 

1447 self.name 

1448 )) 

1449 

1450 if other.name in ('other_name', 'x400_address', 'edi_party_name'): 

1451 raise ValueError(unwrap( 

1452 ''' 

1453 Comparison is not supported for GeneralName objects of choice 

1454 %s''', 

1455 other.name 

1456 )) 

1457 

1458 if self.name != other.name: 

1459 return False 

1460 

1461 return self.chosen == other.chosen 

1462 

1463 

1464class GeneralNames(SequenceOf): 

1465 _child_spec = GeneralName 

1466 

1467 

1468class Time(Choice): 

1469 _alternatives = [ 

1470 ('utc_time', UTCTime), 

1471 ('general_time', GeneralizedTime), 

1472 ] 

1473 

1474 

1475class Validity(Sequence): 

1476 _fields = [ 

1477 ('not_before', Time), 

1478 ('not_after', Time), 

1479 ] 

1480 

1481 

1482class BasicConstraints(Sequence): 

1483 _fields = [ 

1484 ('ca', Boolean, {'default': False}), 

1485 ('path_len_constraint', Integer, {'optional': True}), 

1486 ] 

1487 

1488 

1489class AuthorityKeyIdentifier(Sequence): 

1490 _fields = [ 

1491 ('key_identifier', OctetString, {'implicit': 0, 'optional': True}), 

1492 ('authority_cert_issuer', GeneralNames, {'implicit': 1, 'optional': True}), 

1493 ('authority_cert_serial_number', Integer, {'implicit': 2, 'optional': True}), 

1494 ] 

1495 

1496 

1497class DistributionPointName(Choice): 

1498 _alternatives = [ 

1499 ('full_name', GeneralNames, {'implicit': 0}), 

1500 ('name_relative_to_crl_issuer', RelativeDistinguishedName, {'implicit': 1}), 

1501 ] 

1502 

1503 

1504class ReasonFlags(BitString): 

1505 _map = { 

1506 0: 'unused', 

1507 1: 'key_compromise', 

1508 2: 'ca_compromise', 

1509 3: 'affiliation_changed', 

1510 4: 'superseded', 

1511 5: 'cessation_of_operation', 

1512 6: 'certificate_hold', 

1513 7: 'privilege_withdrawn', 

1514 8: 'aa_compromise', 

1515 } 

1516 

1517 

1518class GeneralSubtree(Sequence): 

1519 _fields = [ 

1520 ('base', GeneralName), 

1521 ('minimum', Integer, {'implicit': 0, 'default': 0}), 

1522 ('maximum', Integer, {'implicit': 1, 'optional': True}), 

1523 ] 

1524 

1525 

1526class GeneralSubtrees(SequenceOf): 

1527 _child_spec = GeneralSubtree 

1528 

1529 

1530class NameConstraints(Sequence): 

1531 _fields = [ 

1532 ('permitted_subtrees', GeneralSubtrees, {'implicit': 0, 'optional': True}), 

1533 ('excluded_subtrees', GeneralSubtrees, {'implicit': 1, 'optional': True}), 

1534 ] 

1535 

1536 

1537class DistributionPoint(Sequence): 

1538 _fields = [ 

1539 ('distribution_point', DistributionPointName, {'explicit': 0, 'optional': True}), 

1540 ('reasons', ReasonFlags, {'implicit': 1, 'optional': True}), 

1541 ('crl_issuer', GeneralNames, {'implicit': 2, 'optional': True}), 

1542 ] 

1543 

1544 _url = False 

1545 

1546 @property 

1547 def url(self): 

1548 """ 

1549 :return: 

1550 None or a unicode string of the distribution point's URL 

1551 """ 

1552 

1553 if self._url is False: 

1554 self._url = None 

1555 name = self['distribution_point'] 

1556 if name.name != 'full_name': 

1557 raise ValueError(unwrap( 

1558 ''' 

1559 CRL distribution points that are relative to the issuer are 

1560 not supported 

1561 ''' 

1562 )) 

1563 

1564 for general_name in name.chosen: 

1565 if general_name.name == 'uniform_resource_identifier': 

1566 url = general_name.native 

1567 if url.lower().startswith(('http://', 'https://', 'ldap://', 'ldaps://')): 

1568 self._url = url 

1569 break 

1570 

1571 return self._url 

1572 

1573 

1574class CRLDistributionPoints(SequenceOf): 

1575 _child_spec = DistributionPoint 

1576 

1577 

1578class DisplayText(Choice): 

1579 _alternatives = [ 

1580 ('ia5_string', IA5String), 

1581 ('visible_string', VisibleString), 

1582 ('bmp_string', BMPString), 

1583 ('utf8_string', UTF8String), 

1584 ] 

1585 

1586 

1587class NoticeNumbers(SequenceOf): 

1588 _child_spec = Integer 

1589 

1590 

1591class NoticeReference(Sequence): 

1592 _fields = [ 

1593 ('organization', DisplayText), 

1594 ('notice_numbers', NoticeNumbers), 

1595 ] 

1596 

1597 

1598class UserNotice(Sequence): 

1599 _fields = [ 

1600 ('notice_ref', NoticeReference, {'optional': True}), 

1601 ('explicit_text', DisplayText, {'optional': True}), 

1602 ] 

1603 

1604 

1605class PolicyQualifierId(ObjectIdentifier): 

1606 _map = { 

1607 '1.3.6.1.5.5.7.2.1': 'certification_practice_statement', 

1608 '1.3.6.1.5.5.7.2.2': 'user_notice', 

1609 } 

1610 

1611 

1612class PolicyQualifierInfo(Sequence): 

1613 _fields = [ 

1614 ('policy_qualifier_id', PolicyQualifierId), 

1615 ('qualifier', Any), 

1616 ] 

1617 

1618 _oid_pair = ('policy_qualifier_id', 'qualifier') 

1619 _oid_specs = { 

1620 'certification_practice_statement': IA5String, 

1621 'user_notice': UserNotice, 

1622 } 

1623 

1624 

1625class PolicyQualifierInfos(SequenceOf): 

1626 _child_spec = PolicyQualifierInfo 

1627 

1628 

1629class PolicyIdentifier(ObjectIdentifier): 

1630 _map = { 

1631 '2.5.29.32.0': 'any_policy', 

1632 } 

1633 

1634 

1635class PolicyInformation(Sequence): 

1636 _fields = [ 

1637 ('policy_identifier', PolicyIdentifier), 

1638 ('policy_qualifiers', PolicyQualifierInfos, {'optional': True}) 

1639 ] 

1640 

1641 

1642class CertificatePolicies(SequenceOf): 

1643 _child_spec = PolicyInformation 

1644 

1645 

1646class PolicyMapping(Sequence): 

1647 _fields = [ 

1648 ('issuer_domain_policy', PolicyIdentifier), 

1649 ('subject_domain_policy', PolicyIdentifier), 

1650 ] 

1651 

1652 

1653class PolicyMappings(SequenceOf): 

1654 _child_spec = PolicyMapping 

1655 

1656 

1657class PolicyConstraints(Sequence): 

1658 _fields = [ 

1659 ('require_explicit_policy', Integer, {'implicit': 0, 'optional': True}), 

1660 ('inhibit_policy_mapping', Integer, {'implicit': 1, 'optional': True}), 

1661 ] 

1662 

1663 

1664class KeyPurposeId(ObjectIdentifier): 

1665 _map = { 

1666 # https://tools.ietf.org/html/rfc5280#page-45 

1667 '2.5.29.37.0': 'any_extended_key_usage', 

1668 '1.3.6.1.5.5.7.3.1': 'server_auth', 

1669 '1.3.6.1.5.5.7.3.2': 'client_auth', 

1670 '1.3.6.1.5.5.7.3.3': 'code_signing', 

1671 '1.3.6.1.5.5.7.3.4': 'email_protection', 

1672 '1.3.6.1.5.5.7.3.5': 'ipsec_end_system', 

1673 '1.3.6.1.5.5.7.3.6': 'ipsec_tunnel', 

1674 '1.3.6.1.5.5.7.3.7': 'ipsec_user', 

1675 '1.3.6.1.5.5.7.3.8': 'time_stamping', 

1676 '1.3.6.1.5.5.7.3.9': 'ocsp_signing', 

1677 # http://tools.ietf.org/html/rfc3029.html#page-9 

1678 '1.3.6.1.5.5.7.3.10': 'dvcs', 

1679 # http://tools.ietf.org/html/rfc6268.html#page-16 

1680 '1.3.6.1.5.5.7.3.13': 'eap_over_ppp', 

1681 '1.3.6.1.5.5.7.3.14': 'eap_over_lan', 

1682 # https://tools.ietf.org/html/rfc5055#page-76 

1683 '1.3.6.1.5.5.7.3.15': 'scvp_server', 

1684 '1.3.6.1.5.5.7.3.16': 'scvp_client', 

1685 # https://tools.ietf.org/html/rfc4945#page-31 

1686 '1.3.6.1.5.5.7.3.17': 'ipsec_ike', 

1687 # https://tools.ietf.org/html/rfc5415#page-38 

1688 '1.3.6.1.5.5.7.3.18': 'capwap_ac', 

1689 '1.3.6.1.5.5.7.3.19': 'capwap_wtp', 

1690 # https://tools.ietf.org/html/rfc5924#page-8 

1691 '1.3.6.1.5.5.7.3.20': 'sip_domain', 

1692 # https://tools.ietf.org/html/rfc6187#page-7 

1693 '1.3.6.1.5.5.7.3.21': 'secure_shell_client', 

1694 '1.3.6.1.5.5.7.3.22': 'secure_shell_server', 

1695 # https://tools.ietf.org/html/rfc6494#page-7 

1696 '1.3.6.1.5.5.7.3.23': 'send_router', 

1697 '1.3.6.1.5.5.7.3.24': 'send_proxied_router', 

1698 '1.3.6.1.5.5.7.3.25': 'send_owner', 

1699 '1.3.6.1.5.5.7.3.26': 'send_proxied_owner', 

1700 # https://tools.ietf.org/html/rfc6402#page-10 

1701 '1.3.6.1.5.5.7.3.27': 'cmc_ca', 

1702 '1.3.6.1.5.5.7.3.28': 'cmc_ra', 

1703 '1.3.6.1.5.5.7.3.29': 'cmc_archive', 

1704 # https://tools.ietf.org/html/draft-ietf-sidr-bgpsec-pki-profiles-15#page-6 

1705 '1.3.6.1.5.5.7.3.30': 'bgpspec_router', 

1706 # https://www.ietf.org/proceedings/44/I-D/draft-ietf-ipsec-pki-req-01.txt 

1707 '1.3.6.1.5.5.8.2.2': 'ike_intermediate', 

1708 # https://msdn.microsoft.com/en-us/library/windows/desktop/aa378132(v=vs.85).aspx 

1709 # and https://support.microsoft.com/en-us/kb/287547 

1710 '1.3.6.1.4.1.311.10.3.1': 'microsoft_trust_list_signing', 

1711 '1.3.6.1.4.1.311.10.3.2': 'microsoft_time_stamp_signing', 

1712 '1.3.6.1.4.1.311.10.3.3': 'microsoft_server_gated', 

1713 '1.3.6.1.4.1.311.10.3.3.1': 'microsoft_serialized', 

1714 '1.3.6.1.4.1.311.10.3.4': 'microsoft_efs', 

1715 '1.3.6.1.4.1.311.10.3.4.1': 'microsoft_efs_recovery', 

1716 '1.3.6.1.4.1.311.10.3.5': 'microsoft_whql', 

1717 '1.3.6.1.4.1.311.10.3.6': 'microsoft_nt5', 

1718 '1.3.6.1.4.1.311.10.3.7': 'microsoft_oem_whql', 

1719 '1.3.6.1.4.1.311.10.3.8': 'microsoft_embedded_nt', 

1720 '1.3.6.1.4.1.311.10.3.9': 'microsoft_root_list_signer', 

1721 '1.3.6.1.4.1.311.10.3.10': 'microsoft_qualified_subordination', 

1722 '1.3.6.1.4.1.311.10.3.11': 'microsoft_key_recovery', 

1723 '1.3.6.1.4.1.311.10.3.12': 'microsoft_document_signing', 

1724 '1.3.6.1.4.1.311.10.3.13': 'microsoft_lifetime_signing', 

1725 '1.3.6.1.4.1.311.10.3.14': 'microsoft_mobile_device_software', 

1726 # https://support.microsoft.com/en-us/help/287547/object-ids-associated-with-microsoft-cryptography 

1727 '1.3.6.1.4.1.311.20.2.2': 'microsoft_smart_card_logon', 

1728 # https://opensource.apple.com/source 

1729 # - /Security/Security-57031.40.6/Security/libsecurity_keychain/lib/SecPolicy.cpp 

1730 # - /libsecurity_cssm/libsecurity_cssm-36064/lib/oidsalg.c 

1731 '1.2.840.113635.100.1.2': 'apple_x509_basic', 

1732 '1.2.840.113635.100.1.3': 'apple_ssl', 

1733 '1.2.840.113635.100.1.4': 'apple_local_cert_gen', 

1734 '1.2.840.113635.100.1.5': 'apple_csr_gen', 

1735 '1.2.840.113635.100.1.6': 'apple_revocation_crl', 

1736 '1.2.840.113635.100.1.7': 'apple_revocation_ocsp', 

1737 '1.2.840.113635.100.1.8': 'apple_smime', 

1738 '1.2.840.113635.100.1.9': 'apple_eap', 

1739 '1.2.840.113635.100.1.10': 'apple_software_update_signing', 

1740 '1.2.840.113635.100.1.11': 'apple_ipsec', 

1741 '1.2.840.113635.100.1.12': 'apple_ichat', 

1742 '1.2.840.113635.100.1.13': 'apple_resource_signing', 

1743 '1.2.840.113635.100.1.14': 'apple_pkinit_client', 

1744 '1.2.840.113635.100.1.15': 'apple_pkinit_server', 

1745 '1.2.840.113635.100.1.16': 'apple_code_signing', 

1746 '1.2.840.113635.100.1.17': 'apple_package_signing', 

1747 '1.2.840.113635.100.1.18': 'apple_id_validation', 

1748 '1.2.840.113635.100.1.20': 'apple_time_stamping', 

1749 '1.2.840.113635.100.1.21': 'apple_revocation', 

1750 '1.2.840.113635.100.1.22': 'apple_passbook_signing', 

1751 '1.2.840.113635.100.1.23': 'apple_mobile_store', 

1752 '1.2.840.113635.100.1.24': 'apple_escrow_service', 

1753 '1.2.840.113635.100.1.25': 'apple_profile_signer', 

1754 '1.2.840.113635.100.1.26': 'apple_qa_profile_signer', 

1755 '1.2.840.113635.100.1.27': 'apple_test_mobile_store', 

1756 '1.2.840.113635.100.1.28': 'apple_otapki_signer', 

1757 '1.2.840.113635.100.1.29': 'apple_test_otapki_signer', 

1758 '1.2.840.113625.100.1.30': 'apple_id_validation_record_signing_policy', 

1759 '1.2.840.113625.100.1.31': 'apple_smp_encryption', 

1760 '1.2.840.113625.100.1.32': 'apple_test_smp_encryption', 

1761 '1.2.840.113635.100.1.33': 'apple_server_authentication', 

1762 '1.2.840.113635.100.1.34': 'apple_pcs_escrow_service', 

1763 # http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.201-2.pdf 

1764 '2.16.840.1.101.3.6.8': 'piv_card_authentication', 

1765 '2.16.840.1.101.3.6.7': 'piv_content_signing', 

1766 # https://tools.ietf.org/html/rfc4556.html 

1767 '1.3.6.1.5.2.3.4': 'pkinit_kpclientauth', 

1768 '1.3.6.1.5.2.3.5': 'pkinit_kpkdc', 

1769 # https://www.adobe.com/devnet-docs/acrobatetk/tools/DigSig/changes.html 

1770 '1.2.840.113583.1.1.5': 'adobe_authentic_documents_trust', 

1771 # https://www.idmanagement.gov/wp-content/uploads/sites/1171/uploads/fpki-pivi-cert-profiles.pdf 

1772 '2.16.840.1.101.3.8.7': 'fpki_pivi_content_signing' 

1773 } 

1774 

1775 

1776class ExtKeyUsageSyntax(SequenceOf): 

1777 _child_spec = KeyPurposeId 

1778 

1779 

1780class AccessMethod(ObjectIdentifier): 

1781 _map = { 

1782 '1.3.6.1.5.5.7.48.1': 'ocsp', 

1783 '1.3.6.1.5.5.7.48.2': 'ca_issuers', 

1784 '1.3.6.1.5.5.7.48.3': 'time_stamping', 

1785 '1.3.6.1.5.5.7.48.5': 'ca_repository', 

1786 } 

1787 

1788 

1789class AccessDescription(Sequence): 

1790 _fields = [ 

1791 ('access_method', AccessMethod), 

1792 ('access_location', GeneralName), 

1793 ] 

1794 

1795 

1796class AuthorityInfoAccessSyntax(SequenceOf): 

1797 _child_spec = AccessDescription 

1798 

1799 

1800class SubjectInfoAccessSyntax(SequenceOf): 

1801 _child_spec = AccessDescription 

1802 

1803 

1804# https://tools.ietf.org/html/rfc7633 

1805class Features(SequenceOf): 

1806 _child_spec = Integer 

1807 

1808 

1809class EntrustVersionInfo(Sequence): 

1810 _fields = [ 

1811 ('entrust_vers', GeneralString), 

1812 ('entrust_info_flags', BitString) 

1813 ] 

1814 

1815 

1816class NetscapeCertificateType(BitString): 

1817 _map = { 

1818 0: 'ssl_client', 

1819 1: 'ssl_server', 

1820 2: 'email', 

1821 3: 'object_signing', 

1822 4: 'reserved', 

1823 5: 'ssl_ca', 

1824 6: 'email_ca', 

1825 7: 'object_signing_ca', 

1826 } 

1827 

1828 

1829class Version(Integer): 

1830 _map = { 

1831 0: 'v1', 

1832 1: 'v2', 

1833 2: 'v3', 

1834 } 

1835 

1836 

1837class TPMSpecification(Sequence): 

1838 _fields = [ 

1839 ('family', UTF8String), 

1840 ('level', Integer), 

1841 ('revision', Integer), 

1842 ] 

1843 

1844 

1845class SetOfTPMSpecification(SetOf): 

1846 _child_spec = TPMSpecification 

1847 

1848 

1849class TCGSpecificationVersion(Sequence): 

1850 _fields = [ 

1851 ('major_version', Integer), 

1852 ('minor_version', Integer), 

1853 ('revision', Integer), 

1854 ] 

1855 

1856 

1857class TCGPlatformSpecification(Sequence): 

1858 _fields = [ 

1859 ('version', TCGSpecificationVersion), 

1860 ('platform_class', OctetString), 

1861 ] 

1862 

1863 

1864class SetOfTCGPlatformSpecification(SetOf): 

1865 _child_spec = TCGPlatformSpecification 

1866 

1867 

1868class EKGenerationType(Enumerated): 

1869 _map = { 

1870 0: 'internal', 

1871 1: 'injected', 

1872 2: 'internal_revocable', 

1873 3: 'injected_revocable', 

1874 } 

1875 

1876 

1877class EKGenerationLocation(Enumerated): 

1878 _map = { 

1879 0: 'tpm_manufacturer', 

1880 1: 'platform_manufacturer', 

1881 2: 'ek_cert_signer', 

1882 } 

1883 

1884 

1885class EKCertificateGenerationLocation(Enumerated): 

1886 _map = { 

1887 0: 'tpm_manufacturer', 

1888 1: 'platform_manufacturer', 

1889 2: 'ek_cert_signer', 

1890 } 

1891 

1892 

1893class EvaluationAssuranceLevel(Enumerated): 

1894 _map = { 

1895 1: 'level1', 

1896 2: 'level2', 

1897 3: 'level3', 

1898 4: 'level4', 

1899 5: 'level5', 

1900 6: 'level6', 

1901 7: 'level7', 

1902 } 

1903 

1904 

1905class EvaluationStatus(Enumerated): 

1906 _map = { 

1907 0: 'designed_to_meet', 

1908 1: 'evaluation_in_progress', 

1909 2: 'evaluation_completed', 

1910 } 

1911 

1912 

1913class StrengthOfFunction(Enumerated): 

1914 _map = { 

1915 0: 'basic', 

1916 1: 'medium', 

1917 2: 'high', 

1918 } 

1919 

1920 

1921class URIReference(Sequence): 

1922 _fields = [ 

1923 ('uniform_resource_identifier', IA5String), 

1924 ('hash_algorithm', DigestAlgorithm, {'optional': True}), 

1925 ('hash_value', BitString, {'optional': True}), 

1926 ] 

1927 

1928 

1929class CommonCriteriaMeasures(Sequence): 

1930 _fields = [ 

1931 ('version', IA5String), 

1932 ('assurance_level', EvaluationAssuranceLevel), 

1933 ('evaluation_status', EvaluationStatus), 

1934 ('plus', Boolean, {'default': False}), 

1935 ('strengh_of_function', StrengthOfFunction, {'implicit': 0, 'optional': True}), 

1936 ('profile_oid', ObjectIdentifier, {'implicit': 1, 'optional': True}), 

1937 ('profile_url', URIReference, {'implicit': 2, 'optional': True}), 

1938 ('target_oid', ObjectIdentifier, {'implicit': 3, 'optional': True}), 

1939 ('target_uri', URIReference, {'implicit': 4, 'optional': True}), 

1940 ] 

1941 

1942 

1943class SecurityLevel(Enumerated): 

1944 _map = { 

1945 1: 'level1', 

1946 2: 'level2', 

1947 3: 'level3', 

1948 4: 'level4', 

1949 } 

1950 

1951 

1952class FIPSLevel(Sequence): 

1953 _fields = [ 

1954 ('version', IA5String), 

1955 ('level', SecurityLevel), 

1956 ('plus', Boolean, {'default': False}), 

1957 ] 

1958 

1959 

1960class TPMSecurityAssertions(Sequence): 

1961 _fields = [ 

1962 ('version', Version, {'default': 'v1'}), 

1963 ('field_upgradable', Boolean, {'default': False}), 

1964 ('ek_generation_type', EKGenerationType, {'implicit': 0, 'optional': True}), 

1965 ('ek_generation_location', EKGenerationLocation, {'implicit': 1, 'optional': True}), 

1966 ('ek_certificate_generation_location', EKCertificateGenerationLocation, {'implicit': 2, 'optional': True}), 

1967 ('cc_info', CommonCriteriaMeasures, {'implicit': 3, 'optional': True}), 

1968 ('fips_level', FIPSLevel, {'implicit': 4, 'optional': True}), 

1969 ('iso_9000_certified', Boolean, {'implicit': 5, 'default': False}), 

1970 ('iso_9000_uri', IA5String, {'optional': True}), 

1971 ] 

1972 

1973 

1974class SetOfTPMSecurityAssertions(SetOf): 

1975 _child_spec = TPMSecurityAssertions 

1976 

1977 

1978class SubjectDirectoryAttributeId(ObjectIdentifier): 

1979 _map = { 

1980 # https://tools.ietf.org/html/rfc2256#page-11 

1981 '2.5.4.52': 'supported_algorithms', 

1982 # https://www.trustedcomputinggroup.org/wp-content/uploads/Credential_Profile_EK_V2.0_R14_published.pdf 

1983 '2.23.133.2.16': 'tpm_specification', 

1984 '2.23.133.2.17': 'tcg_platform_specification', 

1985 '2.23.133.2.18': 'tpm_security_assertions', 

1986 # https://tools.ietf.org/html/rfc3739#page-18 

1987 '1.3.6.1.5.5.7.9.1': 'pda_date_of_birth', 

1988 '1.3.6.1.5.5.7.9.2': 'pda_place_of_birth', 

1989 '1.3.6.1.5.5.7.9.3': 'pda_gender', 

1990 '1.3.6.1.5.5.7.9.4': 'pda_country_of_citizenship', 

1991 '1.3.6.1.5.5.7.9.5': 'pda_country_of_residence', 

1992 # https://holtstrom.com/michael/tools/asn1decoder.php 

1993 '1.2.840.113533.7.68.29': 'entrust_user_role', 

1994 } 

1995 

1996 

1997class SetOfGeneralizedTime(SetOf): 

1998 _child_spec = GeneralizedTime 

1999 

2000 

2001class SetOfDirectoryString(SetOf): 

2002 _child_spec = DirectoryString 

2003 

2004 

2005class SetOfPrintableString(SetOf): 

2006 _child_spec = PrintableString 

2007 

2008 

2009class SupportedAlgorithm(Sequence): 

2010 _fields = [ 

2011 ('algorithm_identifier', AnyAlgorithmIdentifier), 

2012 ('intended_usage', KeyUsage, {'explicit': 0, 'optional': True}), 

2013 ('intended_certificate_policies', CertificatePolicies, {'explicit': 1, 'optional': True}), 

2014 ] 

2015 

2016 

2017class SetOfSupportedAlgorithm(SetOf): 

2018 _child_spec = SupportedAlgorithm 

2019 

2020 

2021class SubjectDirectoryAttribute(Sequence): 

2022 _fields = [ 

2023 ('type', SubjectDirectoryAttributeId), 

2024 ('values', Any), 

2025 ] 

2026 

2027 _oid_pair = ('type', 'values') 

2028 _oid_specs = { 

2029 'supported_algorithms': SetOfSupportedAlgorithm, 

2030 'tpm_specification': SetOfTPMSpecification, 

2031 'tcg_platform_specification': SetOfTCGPlatformSpecification, 

2032 'tpm_security_assertions': SetOfTPMSecurityAssertions, 

2033 'pda_date_of_birth': SetOfGeneralizedTime, 

2034 'pda_place_of_birth': SetOfDirectoryString, 

2035 'pda_gender': SetOfPrintableString, 

2036 'pda_country_of_citizenship': SetOfPrintableString, 

2037 'pda_country_of_residence': SetOfPrintableString, 

2038 } 

2039 

2040 def _values_spec(self): 

2041 type_ = self['type'].native 

2042 if type_ in self._oid_specs: 

2043 return self._oid_specs[type_] 

2044 return SetOf 

2045 

2046 _spec_callbacks = { 

2047 'values': _values_spec 

2048 } 

2049 

2050 

2051class SubjectDirectoryAttributes(SequenceOf): 

2052 _child_spec = SubjectDirectoryAttribute 

2053 

2054 

2055class ExtensionId(ObjectIdentifier): 

2056 _map = { 

2057 '2.5.29.9': 'subject_directory_attributes', 

2058 '2.5.29.14': 'key_identifier', 

2059 '2.5.29.15': 'key_usage', 

2060 '2.5.29.16': 'private_key_usage_period', 

2061 '2.5.29.17': 'subject_alt_name', 

2062 '2.5.29.18': 'issuer_alt_name', 

2063 '2.5.29.19': 'basic_constraints', 

2064 '2.5.29.30': 'name_constraints', 

2065 '2.5.29.31': 'crl_distribution_points', 

2066 '2.5.29.32': 'certificate_policies', 

2067 '2.5.29.33': 'policy_mappings', 

2068 '2.5.29.35': 'authority_key_identifier', 

2069 '2.5.29.36': 'policy_constraints', 

2070 '2.5.29.37': 'extended_key_usage', 

2071 '2.5.29.46': 'freshest_crl', 

2072 '2.5.29.54': 'inhibit_any_policy', 

2073 '1.3.6.1.5.5.7.1.1': 'authority_information_access', 

2074 '1.3.6.1.5.5.7.1.11': 'subject_information_access', 

2075 # https://tools.ietf.org/html/rfc7633 

2076 '1.3.6.1.5.5.7.1.24': 'tls_feature', 

2077 '1.3.6.1.5.5.7.48.1.5': 'ocsp_no_check', 

2078 '1.2.840.113533.7.65.0': 'entrust_version_extension', 

2079 '2.16.840.1.113730.1.1': 'netscape_certificate_type', 

2080 # https://tools.ietf.org/html/rfc6962.html#page-14 

2081 '1.3.6.1.4.1.11129.2.4.2': 'signed_certificate_timestamp_list', 

2082 # https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/3aec3e50-511a-42f9-a5d5-240af503e470 

2083 '1.3.6.1.4.1.311.20.2': 'microsoft_enroll_certtype', 

2084 } 

2085 

2086 

2087class Extension(Sequence): 

2088 _fields = [ 

2089 ('extn_id', ExtensionId), 

2090 ('critical', Boolean, {'default': False}), 

2091 ('extn_value', ParsableOctetString), 

2092 ] 

2093 

2094 _oid_pair = ('extn_id', 'extn_value') 

2095 _oid_specs = { 

2096 'subject_directory_attributes': SubjectDirectoryAttributes, 

2097 'key_identifier': OctetString, 

2098 'key_usage': KeyUsage, 

2099 'private_key_usage_period': PrivateKeyUsagePeriod, 

2100 'subject_alt_name': GeneralNames, 

2101 'issuer_alt_name': GeneralNames, 

2102 'basic_constraints': BasicConstraints, 

2103 'name_constraints': NameConstraints, 

2104 'crl_distribution_points': CRLDistributionPoints, 

2105 'certificate_policies': CertificatePolicies, 

2106 'policy_mappings': PolicyMappings, 

2107 'authority_key_identifier': AuthorityKeyIdentifier, 

2108 'policy_constraints': PolicyConstraints, 

2109 'extended_key_usage': ExtKeyUsageSyntax, 

2110 'freshest_crl': CRLDistributionPoints, 

2111 'inhibit_any_policy': Integer, 

2112 'authority_information_access': AuthorityInfoAccessSyntax, 

2113 'subject_information_access': SubjectInfoAccessSyntax, 

2114 'tls_feature': Features, 

2115 'ocsp_no_check': Null, 

2116 'entrust_version_extension': EntrustVersionInfo, 

2117 'netscape_certificate_type': NetscapeCertificateType, 

2118 'signed_certificate_timestamp_list': OctetString, 

2119 # Not UTF8String as Microsofts docs claim, see: 

2120 # https://www.alvestrand.no/objectid/1.3.6.1.4.1.311.20.2.html 

2121 'microsoft_enroll_certtype': BMPString, 

2122 } 

2123 

2124 

2125class Extensions(SequenceOf): 

2126 _child_spec = Extension 

2127 

2128 

2129class TbsCertificate(Sequence): 

2130 _fields = [ 

2131 ('version', Version, {'explicit': 0, 'default': 'v1'}), 

2132 ('serial_number', Integer), 

2133 ('signature', SignedDigestAlgorithm), 

2134 ('issuer', Name), 

2135 ('validity', Validity), 

2136 ('subject', Name), 

2137 ('subject_public_key_info', PublicKeyInfo), 

2138 ('issuer_unique_id', OctetBitString, {'implicit': 1, 'optional': True}), 

2139 ('subject_unique_id', OctetBitString, {'implicit': 2, 'optional': True}), 

2140 ('extensions', Extensions, {'explicit': 3, 'optional': True}), 

2141 ] 

2142 

2143 

2144class Certificate(Sequence): 

2145 _fields = [ 

2146 ('tbs_certificate', TbsCertificate), 

2147 ('signature_algorithm', SignedDigestAlgorithm), 

2148 ('signature_value', OctetBitString), 

2149 ] 

2150 

2151 _processed_extensions = False 

2152 _critical_extensions = None 

2153 _subject_directory_attributes_value = None 

2154 _key_identifier_value = None 

2155 _key_usage_value = None 

2156 _subject_alt_name_value = None 

2157 _issuer_alt_name_value = None 

2158 _basic_constraints_value = None 

2159 _name_constraints_value = None 

2160 _crl_distribution_points_value = None 

2161 _certificate_policies_value = None 

2162 _policy_mappings_value = None 

2163 _authority_key_identifier_value = None 

2164 _policy_constraints_value = None 

2165 _freshest_crl_value = None 

2166 _inhibit_any_policy_value = None 

2167 _extended_key_usage_value = None 

2168 _authority_information_access_value = None 

2169 _subject_information_access_value = None 

2170 _private_key_usage_period_value = None 

2171 _tls_feature_value = None 

2172 _ocsp_no_check_value = None 

2173 _issuer_serial = None 

2174 _authority_issuer_serial = False 

2175 _crl_distribution_points = None 

2176 _delta_crl_distribution_points = None 

2177 _valid_domains = None 

2178 _valid_ips = None 

2179 _self_issued = None 

2180 _self_signed = None 

2181 _sha1 = None 

2182 _sha256 = None 

2183 

2184 def _set_extensions(self): 

2185 """ 

2186 Sets common named extensions to private attributes and creates a list 

2187 of critical extensions 

2188 """ 

2189 

2190 self._critical_extensions = set() 

2191 

2192 for extension in self['tbs_certificate']['extensions']: 

2193 name = extension['extn_id'].native 

2194 attribute_name = '_%s_value' % name 

2195 if hasattr(self, attribute_name): 

2196 setattr(self, attribute_name, extension['extn_value'].parsed) 

2197 if extension['critical'].native: 

2198 self._critical_extensions.add(name) 

2199 

2200 self._processed_extensions = True 

2201 

2202 @property 

2203 def critical_extensions(self): 

2204 """ 

2205 Returns a set of the names (or OID if not a known extension) of the 

2206 extensions marked as critical 

2207 

2208 :return: 

2209 A set of unicode strings 

2210 """ 

2211 

2212 if not self._processed_extensions: 

2213 self._set_extensions() 

2214 return self._critical_extensions 

2215 

2216 @property 

2217 def private_key_usage_period_value(self): 

2218 """ 

2219 This extension is used to constrain the period over which the subject 

2220 private key may be used 

2221 

2222 :return: 

2223 None or a PrivateKeyUsagePeriod object 

2224 """ 

2225 

2226 if not self._processed_extensions: 

2227 self._set_extensions() 

2228 return self._private_key_usage_period_value 

2229 

2230 @property 

2231 def subject_directory_attributes_value(self): 

2232 """ 

2233 This extension is used to contain additional identification attributes 

2234 about the subject. 

2235 

2236 :return: 

2237 None or a SubjectDirectoryAttributes object 

2238 """ 

2239 

2240 if not self._processed_extensions: 

2241 self._set_extensions() 

2242 return self._subject_directory_attributes_value 

2243 

2244 @property 

2245 def key_identifier_value(self): 

2246 """ 

2247 This extension is used to help in creating certificate validation paths. 

2248 It contains an identifier that should generally, but is not guaranteed 

2249 to, be unique. 

2250 

2251 :return: 

2252 None or an OctetString object 

2253 """ 

2254 

2255 if not self._processed_extensions: 

2256 self._set_extensions() 

2257 return self._key_identifier_value 

2258 

2259 @property 

2260 def key_usage_value(self): 

2261 """ 

2262 This extension is used to define the purpose of the public key 

2263 contained within the certificate. 

2264 

2265 :return: 

2266 None or a KeyUsage 

2267 """ 

2268 

2269 if not self._processed_extensions: 

2270 self._set_extensions() 

2271 return self._key_usage_value 

2272 

2273 @property 

2274 def subject_alt_name_value(self): 

2275 """ 

2276 This extension allows for additional names to be associate with the 

2277 subject of the certificate. While it may contain a whole host of 

2278 possible names, it is usually used to allow certificates to be used 

2279 with multiple different domain names. 

2280 

2281 :return: 

2282 None or a GeneralNames object 

2283 """ 

2284 

2285 if not self._processed_extensions: 

2286 self._set_extensions() 

2287 return self._subject_alt_name_value 

2288 

2289 @property 

2290 def issuer_alt_name_value(self): 

2291 """ 

2292 This extension allows associating one or more alternative names with 

2293 the issuer of the certificate. 

2294 

2295 :return: 

2296 None or an x509.GeneralNames object 

2297 """ 

2298 

2299 if not self._processed_extensions: 

2300 self._set_extensions() 

2301 return self._issuer_alt_name_value 

2302 

2303 @property 

2304 def basic_constraints_value(self): 

2305 """ 

2306 This extension is used to determine if the subject of the certificate 

2307 is a CA, and if so, what the maximum number of intermediate CA certs 

2308 after this are, before an end-entity certificate is found. 

2309 

2310 :return: 

2311 None or a BasicConstraints object 

2312 """ 

2313 

2314 if not self._processed_extensions: 

2315 self._set_extensions() 

2316 return self._basic_constraints_value 

2317 

2318 @property 

2319 def name_constraints_value(self): 

2320 """ 

2321 This extension is used in CA certificates, and is used to limit the 

2322 possible names of certificates issued. 

2323 

2324 :return: 

2325 None or a NameConstraints object 

2326 """ 

2327 

2328 if not self._processed_extensions: 

2329 self._set_extensions() 

2330 return self._name_constraints_value 

2331 

2332 @property 

2333 def crl_distribution_points_value(self): 

2334 """ 

2335 This extension is used to help in locating the CRL for this certificate. 

2336 

2337 :return: 

2338 None or a CRLDistributionPoints object 

2339 extension 

2340 """ 

2341 

2342 if not self._processed_extensions: 

2343 self._set_extensions() 

2344 return self._crl_distribution_points_value 

2345 

2346 @property 

2347 def certificate_policies_value(self): 

2348 """ 

2349 This extension defines policies in CA certificates under which 

2350 certificates may be issued. In end-entity certificates, the inclusion 

2351 of a policy indicates the issuance of the certificate follows the 

2352 policy. 

2353 

2354 :return: 

2355 None or a CertificatePolicies object 

2356 """ 

2357 

2358 if not self._processed_extensions: 

2359 self._set_extensions() 

2360 return self._certificate_policies_value 

2361 

2362 @property 

2363 def policy_mappings_value(self): 

2364 """ 

2365 This extension allows mapping policy OIDs to other OIDs. This is used 

2366 to allow different policies to be treated as equivalent in the process 

2367 of validation. 

2368 

2369 :return: 

2370 None or a PolicyMappings object 

2371 """ 

2372 

2373 if not self._processed_extensions: 

2374 self._set_extensions() 

2375 return self._policy_mappings_value 

2376 

2377 @property 

2378 def authority_key_identifier_value(self): 

2379 """ 

2380 This extension helps in identifying the public key with which to 

2381 validate the authenticity of the certificate. 

2382 

2383 :return: 

2384 None or an AuthorityKeyIdentifier object 

2385 """ 

2386 

2387 if not self._processed_extensions: 

2388 self._set_extensions() 

2389 return self._authority_key_identifier_value 

2390 

2391 @property 

2392 def policy_constraints_value(self): 

2393 """ 

2394 This extension is used to control if policy mapping is allowed and 

2395 when policies are required. 

2396 

2397 :return: 

2398 None or a PolicyConstraints object 

2399 """ 

2400 

2401 if not self._processed_extensions: 

2402 self._set_extensions() 

2403 return self._policy_constraints_value 

2404 

2405 @property 

2406 def freshest_crl_value(self): 

2407 """ 

2408 This extension is used to help locate any available delta CRLs 

2409 

2410 :return: 

2411 None or an CRLDistributionPoints object 

2412 """ 

2413 

2414 if not self._processed_extensions: 

2415 self._set_extensions() 

2416 return self._freshest_crl_value 

2417 

2418 @property 

2419 def inhibit_any_policy_value(self): 

2420 """ 

2421 This extension is used to prevent mapping of the any policy to 

2422 specific requirements 

2423 

2424 :return: 

2425 None or a Integer object 

2426 """ 

2427 

2428 if not self._processed_extensions: 

2429 self._set_extensions() 

2430 return self._inhibit_any_policy_value 

2431 

2432 @property 

2433 def extended_key_usage_value(self): 

2434 """ 

2435 This extension is used to define additional purposes for the public key 

2436 beyond what is contained in the basic constraints. 

2437 

2438 :return: 

2439 None or an ExtKeyUsageSyntax object 

2440 """ 

2441 

2442 if not self._processed_extensions: 

2443 self._set_extensions() 

2444 return self._extended_key_usage_value 

2445 

2446 @property 

2447 def authority_information_access_value(self): 

2448 """ 

2449 This extension is used to locate the CA certificate used to sign this 

2450 certificate, or the OCSP responder for this certificate. 

2451 

2452 :return: 

2453 None or an AuthorityInfoAccessSyntax object 

2454 """ 

2455 

2456 if not self._processed_extensions: 

2457 self._set_extensions() 

2458 return self._authority_information_access_value 

2459 

2460 @property 

2461 def subject_information_access_value(self): 

2462 """ 

2463 This extension is used to access information about the subject of this 

2464 certificate. 

2465 

2466 :return: 

2467 None or a SubjectInfoAccessSyntax object 

2468 """ 

2469 

2470 if not self._processed_extensions: 

2471 self._set_extensions() 

2472 return self._subject_information_access_value 

2473 

2474 @property 

2475 def tls_feature_value(self): 

2476 """ 

2477 This extension is used to list the TLS features a server must respond 

2478 with if a client initiates a request supporting them. 

2479 

2480 :return: 

2481 None or a Features object 

2482 """ 

2483 

2484 if not self._processed_extensions: 

2485 self._set_extensions() 

2486 return self._tls_feature_value 

2487 

2488 @property 

2489 def ocsp_no_check_value(self): 

2490 """ 

2491 This extension is used on certificates of OCSP responders, indicating 

2492 that revocation information for the certificate should never need to 

2493 be verified, thus preventing possible loops in path validation. 

2494 

2495 :return: 

2496 None or a Null object (if present) 

2497 """ 

2498 

2499 if not self._processed_extensions: 

2500 self._set_extensions() 

2501 return self._ocsp_no_check_value 

2502 

2503 @property 

2504 def signature(self): 

2505 """ 

2506 :return: 

2507 A byte string of the signature 

2508 """ 

2509 

2510 return self['signature_value'].native 

2511 

2512 @property 

2513 def signature_algo(self): 

2514 """ 

2515 :return: 

2516 A unicode string of "rsassa_pkcs1v15", "rsassa_pss", "dsa", "ecdsa" 

2517 """ 

2518 

2519 return self['signature_algorithm'].signature_algo 

2520 

2521 @property 

2522 def hash_algo(self): 

2523 """ 

2524 :return: 

2525 A unicode string of "md2", "md5", "sha1", "sha224", "sha256", 

2526 "sha384", "sha512", "sha512_224", "sha512_256" 

2527 """ 

2528 

2529 return self['signature_algorithm'].hash_algo 

2530 

2531 @property 

2532 def public_key(self): 

2533 """ 

2534 :return: 

2535 The PublicKeyInfo object for this certificate 

2536 """ 

2537 

2538 return self['tbs_certificate']['subject_public_key_info'] 

2539 

2540 @property 

2541 def subject(self): 

2542 """ 

2543 :return: 

2544 The Name object for the subject of this certificate 

2545 """ 

2546 

2547 return self['tbs_certificate']['subject'] 

2548 

2549 @property 

2550 def issuer(self): 

2551 """ 

2552 :return: 

2553 The Name object for the issuer of this certificate 

2554 """ 

2555 

2556 return self['tbs_certificate']['issuer'] 

2557 

2558 @property 

2559 def serial_number(self): 

2560 """ 

2561 :return: 

2562 An integer of the certificate's serial number 

2563 """ 

2564 

2565 return self['tbs_certificate']['serial_number'].native 

2566 

2567 @property 

2568 def key_identifier(self): 

2569 """ 

2570 :return: 

2571 None or a byte string of the certificate's key identifier from the 

2572 key identifier extension 

2573 """ 

2574 

2575 if not self.key_identifier_value: 

2576 return None 

2577 

2578 return self.key_identifier_value.native 

2579 

2580 @property 

2581 def issuer_serial(self): 

2582 """ 

2583 :return: 

2584 A byte string of the SHA-256 hash of the issuer concatenated with 

2585 the ascii character ":", concatenated with the serial number as 

2586 an ascii string 

2587 """ 

2588 

2589 if self._issuer_serial is None: 

2590 self._issuer_serial = self.issuer.sha256 + b':' + str_cls(self.serial_number).encode('ascii') 

2591 return self._issuer_serial 

2592 

2593 @property 

2594 def not_valid_after(self): 

2595 """ 

2596 :return: 

2597 A datetime of latest time when the certificate is still valid 

2598 """ 

2599 return self['tbs_certificate']['validity']['not_after'].native 

2600 

2601 @property 

2602 def not_valid_before(self): 

2603 """ 

2604 :return: 

2605 A datetime of the earliest time when the certificate is valid 

2606 """ 

2607 return self['tbs_certificate']['validity']['not_before'].native 

2608 

2609 @property 

2610 def authority_key_identifier(self): 

2611 """ 

2612 :return: 

2613 None or a byte string of the key_identifier from the authority key 

2614 identifier extension 

2615 """ 

2616 

2617 if not self.authority_key_identifier_value: 

2618 return None 

2619 

2620 return self.authority_key_identifier_value['key_identifier'].native 

2621 

2622 @property 

2623 def authority_issuer_serial(self): 

2624 """ 

2625 :return: 

2626 None or a byte string of the SHA-256 hash of the isser from the 

2627 authority key identifier extension concatenated with the ascii 

2628 character ":", concatenated with the serial number from the 

2629 authority key identifier extension as an ascii string 

2630 """ 

2631 

2632 if self._authority_issuer_serial is False: 

2633 akiv = self.authority_key_identifier_value 

2634 if akiv and akiv['authority_cert_issuer'].native: 

2635 issuer = self.authority_key_identifier_value['authority_cert_issuer'][0].chosen 

2636 # We untag the element since it is tagged via being a choice from GeneralName 

2637 issuer = issuer.untag() 

2638 authority_serial = self.authority_key_identifier_value['authority_cert_serial_number'].native 

2639 self._authority_issuer_serial = issuer.sha256 + b':' + str_cls(authority_serial).encode('ascii') 

2640 else: 

2641 self._authority_issuer_serial = None 

2642 return self._authority_issuer_serial 

2643 

2644 @property 

2645 def crl_distribution_points(self): 

2646 """ 

2647 Returns complete CRL URLs - does not include delta CRLs 

2648 

2649 :return: 

2650 A list of zero or more DistributionPoint objects 

2651 """ 

2652 

2653 if self._crl_distribution_points is None: 

2654 self._crl_distribution_points = self._get_http_crl_distribution_points(self.crl_distribution_points_value) 

2655 return self._crl_distribution_points 

2656 

2657 @property 

2658 def delta_crl_distribution_points(self): 

2659 """ 

2660 Returns delta CRL URLs - does not include complete CRLs 

2661 

2662 :return: 

2663 A list of zero or more DistributionPoint objects 

2664 """ 

2665 

2666 if self._delta_crl_distribution_points is None: 

2667 self._delta_crl_distribution_points = self._get_http_crl_distribution_points(self.freshest_crl_value) 

2668 return self._delta_crl_distribution_points 

2669 

2670 def _get_http_crl_distribution_points(self, crl_distribution_points): 

2671 """ 

2672 Fetches the DistributionPoint object for non-relative, HTTP CRLs 

2673 referenced by the certificate 

2674 

2675 :param crl_distribution_points: 

2676 A CRLDistributionPoints object to grab the DistributionPoints from 

2677 

2678 :return: 

2679 A list of zero or more DistributionPoint objects 

2680 """ 

2681 

2682 output = [] 

2683 

2684 if crl_distribution_points is None: 

2685 return [] 

2686 

2687 for distribution_point in crl_distribution_points: 

2688 distribution_point_name = distribution_point['distribution_point'] 

2689 if distribution_point_name is VOID: 

2690 continue 

2691 # RFC 5280 indicates conforming CA should not use the relative form 

2692 if distribution_point_name.name == 'name_relative_to_crl_issuer': 

2693 continue 

2694 # This library is currently only concerned with HTTP-based CRLs 

2695 for general_name in distribution_point_name.chosen: 

2696 if general_name.name == 'uniform_resource_identifier': 

2697 output.append(distribution_point) 

2698 

2699 return output 

2700 

2701 @property 

2702 def ocsp_urls(self): 

2703 """ 

2704 :return: 

2705 A list of zero or more unicode strings of the OCSP URLs for this 

2706 cert 

2707 """ 

2708 

2709 if not self.authority_information_access_value: 

2710 return [] 

2711 

2712 output = [] 

2713 for entry in self.authority_information_access_value: 

2714 if entry['access_method'].native == 'ocsp': 

2715 location = entry['access_location'] 

2716 if location.name != 'uniform_resource_identifier': 

2717 continue 

2718 url = location.native 

2719 if url.lower().startswith(('http://', 'https://', 'ldap://', 'ldaps://')): 

2720 output.append(url) 

2721 return output 

2722 

2723 @property 

2724 def valid_domains(self): 

2725 """ 

2726 :return: 

2727 A list of unicode strings of valid domain names for the certificate. 

2728 Wildcard certificates will have a domain in the form: *.example.com 

2729 """ 

2730 

2731 if self._valid_domains is None: 

2732 self._valid_domains = [] 

2733 

2734 # For the subject alt name extension, we can look at the name of 

2735 # the choice selected since it distinguishes between domain names, 

2736 # email addresses, IPs, etc 

2737 if self.subject_alt_name_value: 

2738 for general_name in self.subject_alt_name_value: 

2739 if general_name.name == 'dns_name' and general_name.native not in self._valid_domains: 

2740 self._valid_domains.append(general_name.native) 

2741 

2742 # If there was no subject alt name extension, and the common name 

2743 # in the subject looks like a domain, that is considered the valid 

2744 # list. This is done because according to 

2745 # https://tools.ietf.org/html/rfc6125#section-6.4.4, the common 

2746 # name should not be used if the subject alt name is present. 

2747 else: 

2748 pattern = re.compile('^(\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]*[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$') 

2749 for rdn in self.subject.chosen: 

2750 for name_type_value in rdn: 

2751 if name_type_value['type'].native == 'common_name': 

2752 value = name_type_value['value'].native 

2753 if pattern.match(value): 

2754 self._valid_domains.append(value) 

2755 

2756 return self._valid_domains 

2757 

2758 @property 

2759 def valid_ips(self): 

2760 """ 

2761 :return: 

2762 A list of unicode strings of valid IP addresses for the certificate 

2763 """ 

2764 

2765 if self._valid_ips is None: 

2766 self._valid_ips = [] 

2767 

2768 if self.subject_alt_name_value: 

2769 for general_name in self.subject_alt_name_value: 

2770 if general_name.name == 'ip_address': 

2771 self._valid_ips.append(general_name.native) 

2772 

2773 return self._valid_ips 

2774 

2775 @property 

2776 def ca(self): 

2777 """ 

2778 :return; 

2779 A boolean - if the certificate is marked as a CA 

2780 """ 

2781 

2782 return self.basic_constraints_value and self.basic_constraints_value['ca'].native 

2783 

2784 @property 

2785 def max_path_length(self): 

2786 """ 

2787 :return; 

2788 None or an integer of the maximum path length 

2789 """ 

2790 

2791 if not self.ca: 

2792 return None 

2793 return self.basic_constraints_value['path_len_constraint'].native 

2794 

2795 @property 

2796 def self_issued(self): 

2797 """ 

2798 :return: 

2799 A boolean - if the certificate is self-issued, as defined by RFC 

2800 5280 

2801 """ 

2802 

2803 if self._self_issued is None: 

2804 self._self_issued = self.subject == self.issuer 

2805 return self._self_issued 

2806 

2807 @property 

2808 def self_signed(self): 

2809 """ 

2810 :return: 

2811 A unicode string of "no" or "maybe". The "maybe" result will 

2812 be returned if the certificate issuer and subject are the same. 

2813 If a key identifier and authority key identifier are present, 

2814 they will need to match otherwise "no" will be returned. 

2815 

2816 To verify is a certificate is truly self-signed, the signature 

2817 will need to be verified. See the certvalidator package for 

2818 one possible solution. 

2819 """ 

2820 

2821 if self._self_signed is None: 

2822 self._self_signed = 'no' 

2823 if self.self_issued: 

2824 if self.key_identifier: 

2825 if not self.authority_key_identifier: 

2826 self._self_signed = 'maybe' 

2827 elif self.authority_key_identifier == self.key_identifier: 

2828 self._self_signed = 'maybe' 

2829 else: 

2830 self._self_signed = 'maybe' 

2831 return self._self_signed 

2832 

2833 @property 

2834 def sha1(self): 

2835 """ 

2836 :return: 

2837 The SHA-1 hash of the DER-encoded bytes of this complete certificate 

2838 """ 

2839 

2840 if self._sha1 is None: 

2841 self._sha1 = hashlib.sha1(self.dump()).digest() 

2842 return self._sha1 

2843 

2844 @property 

2845 def sha1_fingerprint(self): 

2846 """ 

2847 :return: 

2848 A unicode string of the SHA-1 hash, formatted using hex encoding 

2849 with a space between each pair of characters, all uppercase 

2850 """ 

2851 

2852 return ' '.join('%02X' % c for c in bytes_to_list(self.sha1)) 

2853 

2854 @property 

2855 def sha256(self): 

2856 """ 

2857 :return: 

2858 The SHA-256 hash of the DER-encoded bytes of this complete 

2859 certificate 

2860 """ 

2861 

2862 if self._sha256 is None: 

2863 self._sha256 = hashlib.sha256(self.dump()).digest() 

2864 return self._sha256 

2865 

2866 @property 

2867 def sha256_fingerprint(self): 

2868 """ 

2869 :return: 

2870 A unicode string of the SHA-256 hash, formatted using hex encoding 

2871 with a space between each pair of characters, all uppercase 

2872 """ 

2873 

2874 return ' '.join('%02X' % c for c in bytes_to_list(self.sha256)) 

2875 

2876 def is_valid_domain_ip(self, domain_ip): 

2877 """ 

2878 Check if a domain name or IP address is valid according to the 

2879 certificate 

2880 

2881 :param domain_ip: 

2882 A unicode string of a domain name or IP address 

2883 

2884 :return: 

2885 A boolean - if the domain or IP is valid for the certificate 

2886 """ 

2887 

2888 if not isinstance(domain_ip, str_cls): 

2889 raise TypeError(unwrap( 

2890 ''' 

2891 domain_ip must be a unicode string, not %s 

2892 ''', 

2893 type_name(domain_ip) 

2894 )) 

2895 

2896 encoded_domain_ip = domain_ip.encode('idna').decode('ascii').lower() 

2897 

2898 is_ipv6 = encoded_domain_ip.find(':') != -1 

2899 is_ipv4 = not is_ipv6 and re.match('^\\d+\\.\\d+\\.\\d+\\.\\d+$', encoded_domain_ip) 

2900 is_domain = not is_ipv6 and not is_ipv4 

2901 

2902 # Handle domain name checks 

2903 if is_domain: 

2904 if not self.valid_domains: 

2905 return False 

2906 

2907 domain_labels = encoded_domain_ip.split('.') 

2908 

2909 for valid_domain in self.valid_domains: 

2910 encoded_valid_domain = valid_domain.encode('idna').decode('ascii').lower() 

2911 valid_domain_labels = encoded_valid_domain.split('.') 

2912 

2913 # The domain must be equal in label length to match 

2914 if len(valid_domain_labels) != len(domain_labels): 

2915 continue 

2916 

2917 if valid_domain_labels == domain_labels: 

2918 return True 

2919 

2920 is_wildcard = self._is_wildcard_domain(encoded_valid_domain) 

2921 if is_wildcard and self._is_wildcard_match(domain_labels, valid_domain_labels): 

2922 return True 

2923 

2924 return False 

2925 

2926 # Handle IP address checks 

2927 if not self.valid_ips: 

2928 return False 

2929 

2930 family = socket.AF_INET if is_ipv4 else socket.AF_INET6 

2931 normalized_ip = inet_pton(family, encoded_domain_ip) 

2932 

2933 for valid_ip in self.valid_ips: 

2934 valid_family = socket.AF_INET if valid_ip.find('.') != -1 else socket.AF_INET6 

2935 normalized_valid_ip = inet_pton(valid_family, valid_ip) 

2936 

2937 if normalized_valid_ip == normalized_ip: 

2938 return True 

2939 

2940 return False 

2941 

2942 def _is_wildcard_domain(self, domain): 

2943 """ 

2944 Checks if a domain is a valid wildcard according to 

2945 https://tools.ietf.org/html/rfc6125#section-6.4.3 

2946 

2947 :param domain: 

2948 A unicode string of the domain name, where any U-labels from an IDN 

2949 have been converted to A-labels 

2950 

2951 :return: 

2952 A boolean - if the domain is a valid wildcard domain 

2953 """ 

2954 

2955 # The * character must be present for a wildcard match, and if there is 

2956 # most than one, it is an invalid wildcard specification 

2957 if domain.count('*') != 1: 

2958 return False 

2959 

2960 labels = domain.lower().split('.') 

2961 

2962 if not labels: 

2963 return False 

2964 

2965 # Wildcards may only appear in the left-most label 

2966 if labels[0].find('*') == -1: 

2967 return False 

2968 

2969 # Wildcards may not be embedded in an A-label from an IDN 

2970 if labels[0][0:4] == 'xn--': 

2971 return False 

2972 

2973 return True 

2974 

2975 def _is_wildcard_match(self, domain_labels, valid_domain_labels): 

2976 """ 

2977 Determines if the labels in a domain are a match for labels from a 

2978 wildcard valid domain name 

2979 

2980 :param domain_labels: 

2981 A list of unicode strings, with A-label form for IDNs, of the labels 

2982 in the domain name to check 

2983 

2984 :param valid_domain_labels: 

2985 A list of unicode strings, with A-label form for IDNs, of the labels 

2986 in a wildcard domain pattern 

2987 

2988 :return: 

2989 A boolean - if the domain matches the valid domain 

2990 """ 

2991 

2992 first_domain_label = domain_labels[0] 

2993 other_domain_labels = domain_labels[1:] 

2994 

2995 wildcard_label = valid_domain_labels[0] 

2996 other_valid_domain_labels = valid_domain_labels[1:] 

2997 

2998 # The wildcard is only allowed in the first label, so if 

2999 # The subsequent labels are not equal, there is no match 

3000 if other_domain_labels != other_valid_domain_labels: 

3001 return False 

3002 

3003 if wildcard_label == '*': 

3004 return True 

3005 

3006 wildcard_regex = re.compile('^' + wildcard_label.replace('*', '.*') + '$') 

3007 if wildcard_regex.match(first_domain_label): 

3008 return True 

3009 

3010 return False 

3011 

3012 

3013# The structures are taken from the OpenSSL source file x_x509a.c, and specify 

3014# extra information that is added to X.509 certificates to store trust 

3015# information about the certificate. 

3016 

3017class KeyPurposeIdentifiers(SequenceOf): 

3018 _child_spec = KeyPurposeId 

3019 

3020 

3021class SequenceOfAlgorithmIdentifiers(SequenceOf): 

3022 _child_spec = AlgorithmIdentifier 

3023 

3024 

3025class CertificateAux(Sequence): 

3026 _fields = [ 

3027 ('trust', KeyPurposeIdentifiers, {'optional': True}), 

3028 ('reject', KeyPurposeIdentifiers, {'implicit': 0, 'optional': True}), 

3029 ('alias', UTF8String, {'optional': True}), 

3030 ('keyid', OctetString, {'optional': True}), 

3031 ('other', SequenceOfAlgorithmIdentifiers, {'implicit': 1, 'optional': True}), 

3032 ] 

3033 

3034 

3035class TrustedCertificate(Concat): 

3036 _child_specs = [Certificate, CertificateAux]