You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2728 lines
82 KiB

7 years ago
  1. # coding: utf-8
  2. """
  3. ASN.1 type classes for X.509 certificates. Exports the following items:
  4. - Attributes()
  5. - Certificate()
  6. - Extensions()
  7. - GeneralName()
  8. - GeneralNames()
  9. - Name()
  10. Other type classes are defined that help compose the types listed above.
  11. """
  12. from __future__ import unicode_literals, division, absolute_import, print_function
  13. from contextlib import contextmanager
  14. from encodings import idna # noqa
  15. import hashlib
  16. import re
  17. import socket
  18. import stringprep
  19. import sys
  20. import unicodedata
  21. from ._errors import unwrap
  22. from ._iri import iri_to_uri, uri_to_iri
  23. from ._ordereddict import OrderedDict
  24. from ._types import type_name, str_cls, bytes_to_list
  25. from .algos import AlgorithmIdentifier, SignedDigestAlgorithm
  26. from .core import (
  27. Any,
  28. BitString,
  29. BMPString,
  30. Boolean,
  31. Choice,
  32. Concat,
  33. GeneralizedTime,
  34. GeneralString,
  35. IA5String,
  36. Integer,
  37. Null,
  38. NumericString,
  39. ObjectIdentifier,
  40. OctetBitString,
  41. OctetString,
  42. ParsableOctetString,
  43. PrintableString,
  44. Sequence,
  45. SequenceOf,
  46. Set,
  47. SetOf,
  48. TeletexString,
  49. UniversalString,
  50. UTCTime,
  51. UTF8String,
  52. VisibleString,
  53. VOID,
  54. )
  55. from .keys import PublicKeyInfo
  56. from .util import int_to_bytes, int_from_bytes, inet_ntop, inet_pton
  57. # The structures in this file are taken from https://tools.ietf.org/html/rfc5280
  58. # and a few other supplementary sources, mostly due to extra supported
  59. # extension and name OIDs
  60. class DNSName(IA5String):
  61. _encoding = 'idna'
  62. _bad_tag = 19
  63. def __ne__(self, other):
  64. return not self == other
  65. def __eq__(self, other):
  66. """
  67. Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.2
  68. :param other:
  69. Another DNSName object
  70. :return:
  71. A boolean
  72. """
  73. if not isinstance(other, DNSName):
  74. return False
  75. return self.__unicode__().lower() == other.__unicode__().lower()
  76. def set(self, value):
  77. """
  78. Sets the value of the DNS name
  79. :param value:
  80. A unicode string
  81. """
  82. if not isinstance(value, str_cls):
  83. raise TypeError(unwrap(
  84. '''
  85. %s value must be a unicode string, not %s
  86. ''',
  87. type_name(self),
  88. type_name(value)
  89. ))
  90. if value.startswith('.'):
  91. encoded_value = b'.' + value[1:].encode(self._encoding)
  92. else:
  93. encoded_value = value.encode(self._encoding)
  94. self._unicode = value
  95. self.contents = encoded_value
  96. self._header = None
  97. if self._trailer != b'':
  98. self._trailer = b''
  99. class URI(IA5String):
  100. def set(self, value):
  101. """
  102. Sets the value of the string
  103. :param value:
  104. A unicode string
  105. """
  106. if not isinstance(value, str_cls):
  107. raise TypeError(unwrap(
  108. '''
  109. %s value must be a unicode string, not %s
  110. ''',
  111. type_name(self),
  112. type_name(value)
  113. ))
  114. self._unicode = value
  115. self.contents = iri_to_uri(value)
  116. self._header = None
  117. if self._trailer != b'':
  118. self._trailer = b''
  119. def __ne__(self, other):
  120. return not self == other
  121. def __eq__(self, other):
  122. """
  123. Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.4
  124. :param other:
  125. Another URI object
  126. :return:
  127. A boolean
  128. """
  129. if not isinstance(other, URI):
  130. return False
  131. return iri_to_uri(self.native) == iri_to_uri(other.native)
  132. def __unicode__(self):
  133. """
  134. :return:
  135. A unicode string
  136. """
  137. if self.contents is None:
  138. return ''
  139. if self._unicode is None:
  140. self._unicode = uri_to_iri(self._merge_chunks())
  141. return self._unicode
  142. class EmailAddress(IA5String):
  143. _contents = None
  144. # If the value has gone through the .set() method, thus normalizing it
  145. _normalized = False
  146. @property
  147. def contents(self):
  148. """
  149. :return:
  150. A byte string of the DER-encoded contents of the sequence
  151. """
  152. return self._contents
  153. @contents.setter
  154. def contents(self, value):
  155. """
  156. :param value:
  157. A byte string of the DER-encoded contents of the sequence
  158. """
  159. self._normalized = False
  160. self._contents = value
  161. def set(self, value):
  162. """
  163. Sets the value of the string
  164. :param value:
  165. A unicode string
  166. """
  167. if not isinstance(value, str_cls):
  168. raise TypeError(unwrap(
  169. '''
  170. %s value must be a unicode string, not %s
  171. ''',
  172. type_name(self),
  173. type_name(value)
  174. ))
  175. if value.find('@') != -1:
  176. mailbox, hostname = value.rsplit('@', 1)
  177. encoded_value = mailbox.encode('ascii') + b'@' + hostname.encode('idna')
  178. else:
  179. encoded_value = value.encode('ascii')
  180. self._normalized = True
  181. self._unicode = value
  182. self.contents = encoded_value
  183. self._header = None
  184. if self._trailer != b'':
  185. self._trailer = b''
  186. def __unicode__(self):
  187. """
  188. :return:
  189. A unicode string
  190. """
  191. if self._unicode is None:
  192. contents = self._merge_chunks()
  193. if contents.find(b'@') == -1:
  194. self._unicode = contents.decode('ascii')
  195. else:
  196. mailbox, hostname = contents.rsplit(b'@', 1)
  197. self._unicode = mailbox.decode('ascii') + '@' + hostname.decode('idna')
  198. return self._unicode
  199. def __ne__(self, other):
  200. return not self == other
  201. def __eq__(self, other):
  202. """
  203. Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.5
  204. :param other:
  205. Another EmailAddress object
  206. :return:
  207. A boolean
  208. """
  209. if not isinstance(other, EmailAddress):
  210. return False
  211. if not self._normalized:
  212. self.set(self.native)
  213. if not other._normalized:
  214. other.set(other.native)
  215. if self._contents.find(b'@') == -1 or other._contents.find(b'@') == -1:
  216. return self._contents == other._contents
  217. other_mailbox, other_hostname = other._contents.rsplit(b'@', 1)
  218. mailbox, hostname = self._contents.rsplit(b'@', 1)
  219. if mailbox != other_mailbox:
  220. return False
  221. if hostname.lower() != other_hostname.lower():
  222. return False
  223. return True
  224. class IPAddress(OctetString):
  225. def parse(self, spec=None, spec_params=None):
  226. """
  227. This method is not applicable to IP addresses
  228. """
  229. raise ValueError(unwrap(
  230. '''
  231. IP address values can not be parsed
  232. '''
  233. ))
  234. def set(self, value):
  235. """
  236. Sets the value of the object
  237. :param value:
  238. A unicode string containing an IPv4 address, IPv4 address with CIDR,
  239. an IPv6 address or IPv6 address with CIDR
  240. """
  241. if not isinstance(value, str_cls):
  242. raise TypeError(unwrap(
  243. '''
  244. %s value must be a unicode string, not %s
  245. ''',
  246. type_name(self),
  247. type_name(value)
  248. ))
  249. original_value = value
  250. has_cidr = value.find('/') != -1
  251. cidr = 0
  252. if has_cidr:
  253. parts = value.split('/', 1)
  254. value = parts[0]
  255. cidr = int(parts[1])
  256. if cidr < 0:
  257. raise ValueError(unwrap(
  258. '''
  259. %s value contains a CIDR range less than 0
  260. ''',
  261. type_name(self)
  262. ))
  263. if value.find(':') != -1:
  264. family = socket.AF_INET6
  265. if cidr > 128:
  266. raise ValueError(unwrap(
  267. '''
  268. %s value contains a CIDR range bigger than 128, the maximum
  269. value for an IPv6 address
  270. ''',
  271. type_name(self)
  272. ))
  273. cidr_size = 128
  274. else:
  275. family = socket.AF_INET
  276. if cidr > 32:
  277. raise ValueError(unwrap(
  278. '''
  279. %s value contains a CIDR range bigger than 32, the maximum
  280. value for an IPv4 address
  281. ''',
  282. type_name(self)
  283. ))
  284. cidr_size = 32
  285. cidr_bytes = b''
  286. if has_cidr:
  287. cidr_mask = '1' * cidr
  288. cidr_mask += '0' * (cidr_size - len(cidr_mask))
  289. cidr_bytes = int_to_bytes(int(cidr_mask, 2))
  290. cidr_bytes = (b'\x00' * ((cidr_size // 8) - len(cidr_bytes))) + cidr_bytes
  291. self._native = original_value
  292. self.contents = inet_pton(family, value) + cidr_bytes
  293. self._bytes = self.contents
  294. self._header = None
  295. if self._trailer != b'':
  296. self._trailer = b''
  297. @property
  298. def native(self):
  299. """
  300. The a native Python datatype representation of this value
  301. :return:
  302. A unicode string or None
  303. """
  304. if self.contents is None:
  305. return None
  306. if self._native is None:
  307. byte_string = self.__bytes__()
  308. byte_len = len(byte_string)
  309. cidr_int = None
  310. if byte_len in set([32, 16]):
  311. value = inet_ntop(socket.AF_INET6, byte_string[0:16])
  312. if byte_len > 16:
  313. cidr_int = int_from_bytes(byte_string[16:])
  314. elif byte_len in set([8, 4]):
  315. value = inet_ntop(socket.AF_INET, byte_string[0:4])
  316. if byte_len > 4:
  317. cidr_int = int_from_bytes(byte_string[4:])
  318. if cidr_int is not None:
  319. cidr_bits = '{0:b}'.format(cidr_int)
  320. cidr = len(cidr_bits.rstrip('0'))
  321. value = value + '/' + str_cls(cidr)
  322. self._native = value
  323. return self._native
  324. def __ne__(self, other):
  325. return not self == other
  326. def __eq__(self, other):
  327. """
  328. :param other:
  329. Another IPAddress object
  330. :return:
  331. A boolean
  332. """
  333. if not isinstance(other, IPAddress):
  334. return False
  335. return self.__bytes__() == other.__bytes__()
  336. class Attribute(Sequence):
  337. _fields = [
  338. ('type', ObjectIdentifier),
  339. ('values', SetOf, {'spec': Any}),
  340. ]
  341. class Attributes(SequenceOf):
  342. _child_spec = Attribute
  343. class KeyUsage(BitString):
  344. _map = {
  345. 0: 'digital_signature',
  346. 1: 'non_repudiation',
  347. 2: 'key_encipherment',
  348. 3: 'data_encipherment',
  349. 4: 'key_agreement',
  350. 5: 'key_cert_sign',
  351. 6: 'crl_sign',
  352. 7: 'encipher_only',
  353. 8: 'decipher_only',
  354. }
  355. class PrivateKeyUsagePeriod(Sequence):
  356. _fields = [
  357. ('not_before', GeneralizedTime, {'implicit': 0, 'optional': True}),
  358. ('not_after', GeneralizedTime, {'implicit': 1, 'optional': True}),
  359. ]
  360. class NotReallyTeletexString(TeletexString):
  361. """
  362. OpenSSL (and probably some other libraries) puts ISO-8859-1
  363. into TeletexString instead of ITU T.61. We use Windows-1252 when
  364. decoding since it is a superset of ISO-8859-1, and less likely to
  365. cause encoding issues, but we stay strict with encoding to prevent
  366. us from creating bad data.
  367. """
  368. _decoding_encoding = 'cp1252'
  369. def __unicode__(self):
  370. """
  371. :return:
  372. A unicode string
  373. """
  374. if self.contents is None:
  375. return ''
  376. if self._unicode is None:
  377. self._unicode = self._merge_chunks().decode(self._decoding_encoding)
  378. return self._unicode
  379. @contextmanager
  380. def strict_teletex():
  381. try:
  382. NotReallyTeletexString._decoding_encoding = 'teletex'
  383. yield
  384. finally:
  385. NotReallyTeletexString._decoding_encoding = 'cp1252'
  386. class DirectoryString(Choice):
  387. _alternatives = [
  388. ('teletex_string', NotReallyTeletexString),
  389. ('printable_string', PrintableString),
  390. ('universal_string', UniversalString),
  391. ('utf8_string', UTF8String),
  392. ('bmp_string', BMPString),
  393. # This is an invalid/bad alternative, but some broken certs use it
  394. ('ia5_string', IA5String),
  395. ]
  396. class NameType(ObjectIdentifier):
  397. _map = {
  398. '2.5.4.3': 'common_name',
  399. '2.5.4.4': 'surname',
  400. '2.5.4.5': 'serial_number',
  401. '2.5.4.6': 'country_name',
  402. '2.5.4.7': 'locality_name',
  403. '2.5.4.8': 'state_or_province_name',
  404. '2.5.4.9': 'street_address',
  405. '2.5.4.10': 'organization_name',
  406. '2.5.4.11': 'organizational_unit_name',
  407. '2.5.4.12': 'title',
  408. '2.5.4.15': 'business_category',
  409. '2.5.4.17': 'postal_code',
  410. '2.5.4.20': 'telephone_number',
  411. '2.5.4.41': 'name',
  412. '2.5.4.42': 'given_name',
  413. '2.5.4.43': 'initials',
  414. '2.5.4.44': 'generation_qualifier',
  415. '2.5.4.45': 'unique_identifier',
  416. '2.5.4.46': 'dn_qualifier',
  417. '2.5.4.65': 'pseudonym',
  418. '2.5.4.97': 'organization_identifier',
  419. # https://tools.ietf.org/html/rfc2985#page-26
  420. '1.2.840.113549.1.9.1': 'email_address',
  421. # Page 10 of https://cabforum.org/wp-content/uploads/EV-V1_5_5.pdf
  422. '1.3.6.1.4.1.311.60.2.1.1': 'incorporation_locality',
  423. '1.3.6.1.4.1.311.60.2.1.2': 'incorporation_state_or_province',
  424. '1.3.6.1.4.1.311.60.2.1.3': 'incorporation_country',
  425. # https://tools.ietf.org/html/rfc2247#section-4
  426. '0.9.2342.19200300.100.1.25': 'domain_component',
  427. # http://www.alvestrand.no/objectid/0.2.262.1.10.7.20.html
  428. '0.2.262.1.10.7.20': 'name_distinguisher',
  429. }
  430. # This order is largely based on observed order seen in EV certs from
  431. # Symantec and DigiCert. Some of the uncommon name-related fields are
  432. # just placed in what seems like a reasonable order.
  433. preferred_order = [
  434. 'incorporation_country',
  435. 'incorporation_state_or_province',
  436. 'incorporation_locality',
  437. 'business_category',
  438. 'serial_number',
  439. 'country_name',
  440. 'postal_code',
  441. 'state_or_province_name',
  442. 'locality_name',
  443. 'street_address',
  444. 'organization_name',
  445. 'organizational_unit_name',
  446. 'title',
  447. 'common_name',
  448. 'initials',
  449. 'generation_qualifier',
  450. 'surname',
  451. 'given_name',
  452. 'name',
  453. 'pseudonym',
  454. 'dn_qualifier',
  455. 'telephone_number',
  456. 'email_address',
  457. 'domain_component',
  458. 'name_distinguisher',
  459. 'organization_identifier',
  460. ]
  461. @classmethod
  462. def preferred_ordinal(cls, attr_name):
  463. """
  464. Returns an ordering value for a particular attribute key.
  465. Unrecognized attributes and OIDs will be sorted lexically at the end.
  466. :return:
  467. An orderable value.
  468. """
  469. attr_name = cls.map(attr_name)
  470. if attr_name in cls.preferred_order:
  471. ordinal = cls.preferred_order.index(attr_name)
  472. else:
  473. ordinal = len(cls.preferred_order)
  474. return (ordinal, attr_name)
  475. @property
  476. def human_friendly(self):
  477. """
  478. :return:
  479. A human-friendly unicode string to display to users
  480. """
  481. return {
  482. 'common_name': 'Common Name',
  483. 'surname': 'Surname',
  484. 'serial_number': 'Serial Number',
  485. 'country_name': 'Country',
  486. 'locality_name': 'Locality',
  487. 'state_or_province_name': 'State/Province',
  488. 'street_address': 'Street Address',
  489. 'organization_name': 'Organization',
  490. 'organizational_unit_name': 'Organizational Unit',
  491. 'title': 'Title',
  492. 'business_category': 'Business Category',
  493. 'postal_code': 'Postal Code',
  494. 'telephone_number': 'Telephone Number',
  495. 'name': 'Name',
  496. 'given_name': 'Given Name',
  497. 'initials': 'Initials',
  498. 'generation_qualifier': 'Generation Qualifier',
  499. 'unique_identifier': 'Unique Identifier',
  500. 'dn_qualifier': 'DN Qualifier',
  501. 'pseudonym': 'Pseudonym',
  502. 'email_address': 'Email Address',
  503. 'incorporation_locality': 'Incorporation Locality',
  504. 'incorporation_state_or_province': 'Incorporation State/Province',
  505. 'incorporation_country': 'Incorporation Country',
  506. 'domain_component': 'Domain Component',
  507. 'name_distinguisher': 'Name Distinguisher',
  508. 'organization_identifier': 'Organization Identifier',
  509. }.get(self.native, self.native)
  510. class NameTypeAndValue(Sequence):
  511. _fields = [
  512. ('type', NameType),
  513. ('value', Any),
  514. ]
  515. _oid_pair = ('type', 'value')
  516. _oid_specs = {
  517. 'common_name': DirectoryString,
  518. 'surname': DirectoryString,
  519. 'serial_number': DirectoryString,
  520. 'country_name': DirectoryString,
  521. 'locality_name': DirectoryString,
  522. 'state_or_province_name': DirectoryString,
  523. 'street_address': DirectoryString,
  524. 'organization_name': DirectoryString,
  525. 'organizational_unit_name': DirectoryString,
  526. 'title': DirectoryString,
  527. 'business_category': DirectoryString,
  528. 'postal_code': DirectoryString,
  529. 'telephone_number': PrintableString,
  530. 'name': DirectoryString,
  531. 'given_name': DirectoryString,
  532. 'initials': DirectoryString,
  533. 'generation_qualifier': DirectoryString,
  534. 'unique_identifier': OctetBitString,
  535. 'dn_qualifier': DirectoryString,
  536. 'pseudonym': DirectoryString,
  537. # https://tools.ietf.org/html/rfc2985#page-26
  538. 'email_address': EmailAddress,
  539. # Page 10 of https://cabforum.org/wp-content/uploads/EV-V1_5_5.pdf
  540. 'incorporation_locality': DirectoryString,
  541. 'incorporation_state_or_province': DirectoryString,
  542. 'incorporation_country': DirectoryString,
  543. 'domain_component': DNSName,
  544. 'name_distinguisher': DirectoryString,
  545. 'organization_identifier': DirectoryString,
  546. }
  547. _prepped = None
  548. @property
  549. def prepped_value(self):
  550. """
  551. Returns the value after being processed by the internationalized string
  552. preparation as specified by RFC 5280
  553. :return:
  554. A unicode string
  555. """
  556. if self._prepped is None:
  557. self._prepped = self._ldap_string_prep(self['value'].native)
  558. return self._prepped
  559. def __ne__(self, other):
  560. return not self == other
  561. def __eq__(self, other):
  562. """
  563. Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1
  564. :param other:
  565. Another NameTypeAndValue object
  566. :return:
  567. A boolean
  568. """
  569. if not isinstance(other, NameTypeAndValue):
  570. return False
  571. if other['type'].native != self['type'].native:
  572. return False
  573. return other.prepped_value == self.prepped_value
  574. def _ldap_string_prep(self, string):
  575. """
  576. Implements the internationalized string preparation algorithm from
  577. RFC 4518. https://tools.ietf.org/html/rfc4518#section-2
  578. :param string:
  579. A unicode string to prepare
  580. :return:
  581. A prepared unicode string, ready for comparison
  582. """
  583. # Map step
  584. string = re.sub('[\u00ad\u1806\u034f\u180b-\u180d\ufe0f-\uff00\ufffc]+', '', string)
  585. string = re.sub('[\u0009\u000a\u000b\u000c\u000d\u0085]', ' ', string)
  586. if sys.maxunicode == 0xffff:
  587. # Some installs of Python 2.7 don't support 8-digit unicode escape
  588. # ranges, so we have to break them into pieces
  589. # Original was: \U0001D173-\U0001D17A and \U000E0020-\U000E007F
  590. string = re.sub('\ud834[\udd73-\udd7a]|\udb40[\udc20-\udc7f]|\U000e0001', '', string)
  591. else:
  592. string = re.sub('[\U0001D173-\U0001D17A\U000E0020-\U000E007F\U000e0001]', '', string)
  593. string = re.sub(
  594. '[\u0000-\u0008\u000e-\u001f\u007f-\u0084\u0086-\u009f\u06dd\u070f\u180e\u200c-\u200f'
  595. '\u202a-\u202e\u2060-\u2063\u206a-\u206f\ufeff\ufff9-\ufffb]+',
  596. '',
  597. string
  598. )
  599. string = string.replace('\u200b', '')
  600. string = re.sub('[\u00a0\u1680\u2000-\u200a\u2028-\u2029\u202f\u205f\u3000]', ' ', string)
  601. string = ''.join(map(stringprep.map_table_b2, string))
  602. # Normalize step
  603. string = unicodedata.normalize('NFKC', string)
  604. # Prohibit step
  605. for char in string:
  606. if stringprep.in_table_a1(char):
  607. raise ValueError(unwrap(
  608. '''
  609. X.509 Name objects may not contain unassigned code points
  610. '''
  611. ))
  612. if stringprep.in_table_c8(char):
  613. raise ValueError(unwrap(
  614. '''
  615. X.509 Name objects may not contain change display or
  616. zzzzdeprecated characters
  617. '''
  618. ))
  619. if stringprep.in_table_c3(char):
  620. raise ValueError(unwrap(
  621. '''
  622. X.509 Name objects may not contain private use characters
  623. '''
  624. ))
  625. if stringprep.in_table_c4(char):
  626. raise ValueError(unwrap(
  627. '''
  628. X.509 Name objects may not contain non-character code points
  629. '''
  630. ))
  631. if stringprep.in_table_c5(char):
  632. raise ValueError(unwrap(
  633. '''
  634. X.509 Name objects may not contain surrogate code points
  635. '''
  636. ))
  637. if char == '\ufffd':
  638. raise ValueError(unwrap(
  639. '''
  640. X.509 Name objects may not contain the replacement character
  641. '''
  642. ))
  643. # Check bidirectional step - here we ensure that we are not mixing
  644. # left-to-right and right-to-left text in the string
  645. has_r_and_al_cat = False
  646. has_l_cat = False
  647. for char in string:
  648. if stringprep.in_table_d1(char):
  649. has_r_and_al_cat = True
  650. elif stringprep.in_table_d2(char):
  651. has_l_cat = True
  652. if has_r_and_al_cat:
  653. first_is_r_and_al = stringprep.in_table_d1(string[0])
  654. last_is_r_and_al = stringprep.in_table_d1(string[-1])
  655. if has_l_cat or not first_is_r_and_al or not last_is_r_and_al:
  656. raise ValueError(unwrap(
  657. '''
  658. X.509 Name object contains a malformed bidirectional
  659. sequence
  660. '''
  661. ))
  662. # Insignificant space handling step
  663. string = ' ' + re.sub(' +', ' ', string).strip() + ' '
  664. return string
  665. class RelativeDistinguishedName(SetOf):
  666. _child_spec = NameTypeAndValue
  667. @property
  668. def hashable(self):
  669. """
  670. :return:
  671. A unicode string that can be used as a dict key or in a set
  672. """
  673. output = []
  674. values = self._get_values(self)
  675. for key in sorted(values.keys()):
  676. output.append('%s: %s' % (key, values[key]))
  677. # Unit separator is used here since the normalization process for
  678. # values moves any such character, and the keys are all dotted integers
  679. # or under_score_words
  680. return '\x1F'.join(output)
  681. def __ne__(self, other):
  682. return not self == other
  683. def __eq__(self, other):
  684. """
  685. Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1
  686. :param other:
  687. Another RelativeDistinguishedName object
  688. :return:
  689. A boolean
  690. """
  691. if not isinstance(other, RelativeDistinguishedName):
  692. return False
  693. if len(self) != len(other):
  694. return False
  695. self_types = self._get_types(self)
  696. other_types = self._get_types(other)
  697. if self_types != other_types:
  698. return False
  699. self_values = self._get_values(self)
  700. other_values = self._get_values(other)
  701. for type_name_ in self_types:
  702. if self_values[type_name_] != other_values[type_name_]:
  703. return False
  704. return True
  705. def _get_types(self, rdn):
  706. """
  707. Returns a set of types contained in an RDN
  708. :param rdn:
  709. A RelativeDistinguishedName object
  710. :return:
  711. A set object with unicode strings of NameTypeAndValue type field
  712. values
  713. """
  714. return set([ntv['type'].native for ntv in rdn])
  715. def _get_values(self, rdn):
  716. """
  717. Returns a dict of prepped values contained in an RDN
  718. :param rdn:
  719. A RelativeDistinguishedName object
  720. :return:
  721. A dict object with unicode strings of NameTypeAndValue value field
  722. values that have been prepped for comparison
  723. """
  724. output = {}
  725. [output.update([(ntv['type'].native, ntv.prepped_value)]) for ntv in rdn]
  726. return output
  727. class RDNSequence(SequenceOf):
  728. _child_spec = RelativeDistinguishedName
  729. @property
  730. def hashable(self):
  731. """
  732. :return:
  733. A unicode string that can be used as a dict key or in a set
  734. """
  735. # Record separator is used here since the normalization process for
  736. # values moves any such character, and the keys are all dotted integers
  737. # or under_score_words
  738. return '\x1E'.join(rdn.hashable for rdn in self)
  739. def __ne__(self, other):
  740. return not self == other
  741. def __eq__(self, other):
  742. """
  743. Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1
  744. :param other:
  745. Another RDNSequence object
  746. :return:
  747. A boolean
  748. """
  749. if not isinstance(other, RDNSequence):
  750. return False
  751. if len(self) != len(other):
  752. return False
  753. for index, self_rdn in enumerate(self):
  754. if other[index] != self_rdn:
  755. return False
  756. return True
  757. class Name(Choice):
  758. _alternatives = [
  759. ('', RDNSequence),
  760. ]
  761. _human_friendly = None
  762. _sha1 = None
  763. _sha256 = None
  764. @classmethod
  765. def build(cls, name_dict, use_printable=False):
  766. """
  767. Creates a Name object from a dict of unicode string keys and values.
  768. The keys should be from NameType._map, or a dotted-integer OID unicode
  769. string.
  770. :param name_dict:
  771. A dict of name information, e.g. {"common_name": "Will Bond",
  772. "country_name": "US", "organization": "Codex Non Sufficit LC"}
  773. :param use_printable:
  774. A bool - if PrintableString should be used for encoding instead of
  775. UTF8String. This is for backwards compatibility with old software.
  776. :return:
  777. An x509.Name object
  778. """
  779. rdns = []
  780. if not use_printable:
  781. encoding_name = 'utf8_string'
  782. encoding_class = UTF8String
  783. else:
  784. encoding_name = 'printable_string'
  785. encoding_class = PrintableString
  786. # Sort the attributes according to NameType.preferred_order
  787. name_dict = OrderedDict(
  788. sorted(
  789. name_dict.items(),
  790. key=lambda item: NameType.preferred_ordinal(item[0])
  791. )
  792. )
  793. for attribute_name, attribute_value in name_dict.items():
  794. attribute_name = NameType.map(attribute_name)
  795. if attribute_name == 'email_address':
  796. value = EmailAddress(attribute_value)
  797. elif attribute_name == 'domain_component':
  798. value = DNSName(attribute_value)
  799. elif attribute_name in set(['dn_qualifier', 'country_name', 'serial_number']):
  800. value = DirectoryString(
  801. name='printable_string',
  802. value=PrintableString(attribute_value)
  803. )
  804. else:
  805. value = DirectoryString(
  806. name=encoding_name,
  807. value=encoding_class(attribute_value)
  808. )
  809. rdns.append(RelativeDistinguishedName([
  810. NameTypeAndValue({
  811. 'type': attribute_name,
  812. 'value': value
  813. })
  814. ]))
  815. return cls(name='', value=RDNSequence(rdns))
  816. @property
  817. def hashable(self):
  818. """
  819. :return:
  820. A unicode string that can be used as a dict key or in a set
  821. """
  822. return self.chosen.hashable
  823. def __len__(self):
  824. return len(self.chosen)
  825. def __ne__(self, other):
  826. return not self == other
  827. def __eq__(self, other):
  828. """
  829. Equality as defined by https://tools.ietf.org/html/rfc5280#section-7.1
  830. :param other:
  831. Another Name object
  832. :return:
  833. A boolean
  834. """
  835. if not isinstance(other, Name):
  836. return False
  837. return self.chosen == other.chosen
  838. @property
  839. def native(self):
  840. if self._native is None:
  841. self._native = OrderedDict()
  842. for rdn in self.chosen.native:
  843. for type_val in rdn:
  844. field_name = type_val['type']
  845. if field_name in self._native:
  846. existing = self._native[field_name]
  847. if not isinstance(existing, list):
  848. existing = self._native[field_name] = [existing]
  849. existing.append(type_val['value'])
  850. else:
  851. self._native[field_name] = type_val['value']
  852. return self._native
  853. @property
  854. def human_friendly(self):
  855. """
  856. :return:
  857. A human-friendly unicode string containing the parts of the name
  858. """
  859. if self._human_friendly is None:
  860. data = OrderedDict()
  861. last_field = None
  862. for rdn in self.chosen:
  863. for type_val in rdn:
  864. field_name = type_val['type'].human_friendly
  865. last_field = field_name
  866. if field_name in data:
  867. data[field_name] = [data[field_name]]
  868. data[field_name].append(type_val['value'])
  869. else:
  870. data[field_name] = type_val['value']
  871. to_join = []
  872. keys = data.keys()
  873. if last_field == 'Country':
  874. keys = reversed(list(keys))
  875. for key in keys:
  876. value = data[key]
  877. native_value = self._recursive_humanize(value)
  878. to_join.append('%s: %s' % (key, native_value))
  879. has_comma = False
  880. for element in to_join:
  881. if element.find(',') != -1:
  882. has_comma = True
  883. break
  884. separator = ', ' if not has_comma else '; '
  885. self._human_friendly = separator.join(to_join[::-1])
  886. return self._human_friendly
  887. def _recursive_humanize(self, value):
  888. """
  889. Recursively serializes data compiled from the RDNSequence
  890. :param value:
  891. An Asn1Value object, or a list of Asn1Value objects
  892. :return:
  893. A unicode string
  894. """
  895. if isinstance(value, list):
  896. return', '.join(
  897. reversed([self._recursive_humanize(sub_value) for sub_value in value])
  898. )
  899. return value.native
  900. @property
  901. def sha1(self):
  902. """
  903. :return:
  904. The SHA1 hash of the DER-encoded bytes of this name
  905. """
  906. if self._sha1 is None:
  907. self._sha1 = hashlib.sha1(self.dump()).digest()
  908. return self._sha1
  909. @property
  910. def sha256(self):
  911. """
  912. :return:
  913. The SHA-256 hash of the DER-encoded bytes of this name
  914. """
  915. if self._sha256 is None:
  916. self._sha256 = hashlib.sha256(self.dump()).digest()
  917. return self._sha256
  918. class AnotherName(Sequence):
  919. _fields = [
  920. ('type_id', ObjectIdentifier),
  921. ('value', Any, {'explicit': 0}),
  922. ]
  923. class CountryName(Choice):
  924. class_ = 1
  925. tag = 1
  926. _alternatives = [
  927. ('x121_dcc_code', NumericString),
  928. ('iso_3166_alpha2_code', PrintableString),
  929. ]
  930. class AdministrationDomainName(Choice):
  931. class_ = 1
  932. tag = 2
  933. _alternatives = [
  934. ('numeric', NumericString),
  935. ('printable', PrintableString),
  936. ]
  937. class PrivateDomainName(Choice):
  938. _alternatives = [
  939. ('numeric', NumericString),
  940. ('printable', PrintableString),
  941. ]
  942. class PersonalName(Set):
  943. _fields = [
  944. ('surname', PrintableString, {'implicit': 0}),
  945. ('given_name', PrintableString, {'implicit': 1, 'optional': True}),
  946. ('initials', PrintableString, {'implicit': 2, 'optional': True}),
  947. ('generation_qualifier', PrintableString, {'implicit': 3, 'optional': True}),
  948. ]
  949. class TeletexPersonalName(Set):
  950. _fields = [
  951. ('surname', TeletexString, {'implicit': 0}),
  952. ('given_name', TeletexString, {'implicit': 1, 'optional': True}),
  953. ('initials', TeletexString, {'implicit': 2, 'optional': True}),
  954. ('generation_qualifier', TeletexString, {'implicit': 3, 'optional': True}),
  955. ]
  956. class OrganizationalUnitNames(SequenceOf):
  957. _child_spec = PrintableString
  958. class TeletexOrganizationalUnitNames(SequenceOf):
  959. _child_spec = TeletexString
  960. class BuiltInStandardAttributes(Sequence):
  961. _fields = [
  962. ('country_name', CountryName, {'optional': True}),
  963. ('administration_domain_name', AdministrationDomainName, {'optional': True}),
  964. ('network_address', NumericString, {'implicit': 0, 'optional': True}),
  965. ('terminal_identifier', PrintableString, {'implicit': 1, 'optional': True}),
  966. ('private_domain_name', PrivateDomainName, {'explicit': 2, 'optional': True}),
  967. ('organization_name', PrintableString, {'implicit': 3, 'optional': True}),
  968. ('numeric_user_identifier', NumericString, {'implicit': 4, 'optional': True}),
  969. ('personal_name', PersonalName, {'implicit': 5, 'optional': True}),
  970. ('organizational_unit_names', OrganizationalUnitNames, {'implicit': 6, 'optional': True}),
  971. ]
  972. class BuiltInDomainDefinedAttribute(Sequence):
  973. _fields = [
  974. ('type', PrintableString),
  975. ('value', PrintableString),
  976. ]
  977. class BuiltInDomainDefinedAttributes(SequenceOf):
  978. _child_spec = BuiltInDomainDefinedAttribute
  979. class TeletexDomainDefinedAttribute(Sequence):
  980. _fields = [
  981. ('type', TeletexString),
  982. ('value', TeletexString),
  983. ]
  984. class TeletexDomainDefinedAttributes(SequenceOf):
  985. _child_spec = TeletexDomainDefinedAttribute
  986. class PhysicalDeliveryCountryName(Choice):
  987. _alternatives = [
  988. ('x121_dcc_code', NumericString),
  989. ('iso_3166_alpha2_code', PrintableString),
  990. ]
  991. class PostalCode(Choice):
  992. _alternatives = [
  993. ('numeric_code', NumericString),
  994. ('printable_code', PrintableString),
  995. ]
  996. class PDSParameter(Set):
  997. _fields = [
  998. ('printable_string', PrintableString, {'optional': True}),
  999. ('teletex_string', TeletexString, {'optional': True}),
  1000. ]
  1001. class PrintableAddress(SequenceOf):
  1002. _child_spec = PrintableString
  1003. class UnformattedPostalAddress(Set):
  1004. _fields = [
  1005. ('printable_address', PrintableAddress, {'optional': True}),
  1006. ('teletex_string', TeletexString, {'optional': True}),
  1007. ]
  1008. class E1634Address(Sequence):
  1009. _fields = [
  1010. ('number', NumericString, {'implicit': 0}),
  1011. ('sub_address', NumericString, {'implicit': 1, 'optional': True}),
  1012. ]
  1013. class NAddresses(SetOf):
  1014. _child_spec = OctetString
  1015. class PresentationAddress(Sequence):
  1016. _fields = [
  1017. ('p_selector', OctetString, {'explicit': 0, 'optional': True}),
  1018. ('s_selector', OctetString, {'explicit': 1, 'optional': True}),
  1019. ('t_selector', OctetString, {'explicit': 2, 'optional': True}),
  1020. ('n_addresses', NAddresses, {'explicit': 3}),
  1021. ]
  1022. class ExtendedNetworkAddress(Choice):
  1023. _alternatives = [
  1024. ('e163_4_address', E1634Address),
  1025. ('psap_address', PresentationAddress, {'implicit': 0})
  1026. ]
  1027. class TerminalType(Integer):
  1028. _map = {
  1029. 3: 'telex',
  1030. 4: 'teletex',
  1031. 5: 'g3_facsimile',
  1032. 6: 'g4_facsimile',
  1033. 7: 'ia5_terminal',
  1034. 8: 'videotex',
  1035. }
  1036. class ExtensionAttributeType(Integer):
  1037. _map = {
  1038. 1: 'common_name',
  1039. 2: 'teletex_common_name',
  1040. 3: 'teletex_organization_name',
  1041. 4: 'teletex_personal_name',
  1042. 5: 'teletex_organization_unit_names',
  1043. 6: 'teletex_domain_defined_attributes',
  1044. 7: 'pds_name',
  1045. 8: 'physical_delivery_country_name',
  1046. 9: 'postal_code',
  1047. 10: 'physical_delivery_office_name',
  1048. 11: 'physical_delivery_office_number',
  1049. 12: 'extension_of_address_components',
  1050. 13: 'physical_delivery_personal_name',
  1051. 14: 'physical_delivery_organization_name',
  1052. 15: 'extension_physical_delivery_address_components',
  1053. 16: 'unformatted_postal_address',
  1054. 17: 'street_address',
  1055. 18: 'post_office_box_address',
  1056. 19: 'poste_restante_address',
  1057. 20: 'unique_postal_name',
  1058. 21: 'local_postal_attributes',
  1059. 22: 'extended_network_address',
  1060. 23: 'terminal_type',
  1061. }
  1062. class ExtensionAttribute(Sequence):
  1063. _fields = [
  1064. ('extension_attribute_type', ExtensionAttributeType, {'implicit': 0}),
  1065. ('extension_attribute_value', Any, {'explicit': 1}),
  1066. ]
  1067. _oid_pair = ('extension_attribute_type', 'extension_attribute_value')
  1068. _oid_specs = {
  1069. 'common_name': PrintableString,
  1070. 'teletex_common_name': TeletexString,
  1071. 'teletex_organization_name': TeletexString,
  1072. 'teletex_personal_name': TeletexPersonalName,
  1073. 'teletex_organization_unit_names': TeletexOrganizationalUnitNames,
  1074. 'teletex_domain_defined_attributes': TeletexDomainDefinedAttributes,
  1075. 'pds_name': PrintableString,
  1076. 'physical_delivery_country_name': PhysicalDeliveryCountryName,
  1077. 'postal_code': PostalCode,
  1078. 'physical_delivery_office_name': PDSParameter,
  1079. 'physical_delivery_office_number': PDSParameter,
  1080. 'extension_of_address_components': PDSParameter,
  1081. 'physical_delivery_personal_name': PDSParameter,
  1082. 'physical_delivery_organization_name': PDSParameter,
  1083. 'extension_physical_delivery_address_components': PDSParameter,
  1084. 'unformatted_postal_address': UnformattedPostalAddress,
  1085. 'street_address': PDSParameter,
  1086. 'post_office_box_address': PDSParameter,
  1087. 'poste_restante_address': PDSParameter,
  1088. 'unique_postal_name': PDSParameter,
  1089. 'local_postal_attributes': PDSParameter,
  1090. 'extended_network_address': ExtendedNetworkAddress,
  1091. 'terminal_type': TerminalType,
  1092. }
  1093. class ExtensionAttributes(SequenceOf):
  1094. _child_spec = ExtensionAttribute
  1095. class ORAddress(Sequence):
  1096. _fields = [
  1097. ('built_in_standard_attributes', BuiltInStandardAttributes),
  1098. ('built_in_domain_defined_attributes', BuiltInDomainDefinedAttributes, {'optional': True}),
  1099. ('extension_attributes', ExtensionAttributes, {'optional': True}),
  1100. ]
  1101. class EDIPartyName(Sequence):
  1102. _fields = [
  1103. ('name_assigner', DirectoryString, {'implicit': 0, 'optional': True}),
  1104. ('party_name', DirectoryString, {'implicit': 1}),
  1105. ]
  1106. class GeneralName(Choice):
  1107. _alternatives = [
  1108. ('other_name', AnotherName, {'implicit': 0}),
  1109. ('rfc822_name', EmailAddress, {'implicit': 1}),
  1110. ('dns_name', DNSName, {'implicit': 2}),
  1111. ('x400_address', ORAddress, {'implicit': 3}),
  1112. ('directory_name', Name, {'explicit': 4}),
  1113. ('edi_party_name', EDIPartyName, {'implicit': 5}),
  1114. ('uniform_resource_identifier', URI, {'implicit': 6}),
  1115. ('ip_address', IPAddress, {'implicit': 7}),
  1116. ('registered_id', ObjectIdentifier, {'implicit': 8}),
  1117. ]
  1118. def __ne__(self, other):
  1119. return not self == other
  1120. def __eq__(self, other):
  1121. """
  1122. Does not support other_name, x400_address or edi_party_name
  1123. :param other:
  1124. The other GeneralName to compare to
  1125. :return:
  1126. A boolean
  1127. """
  1128. if self.name in ('other_name', 'x400_address', 'edi_party_name'):
  1129. raise ValueError(unwrap(
  1130. '''
  1131. Comparison is not supported for GeneralName objects of
  1132. choice %s
  1133. ''',
  1134. self.name
  1135. ))
  1136. if other.name in ('other_name', 'x400_address', 'edi_party_name'):
  1137. raise ValueError(unwrap(
  1138. '''
  1139. Comparison is not supported for GeneralName objects of choice
  1140. %s''',
  1141. other.name
  1142. ))
  1143. if self.name != other.name:
  1144. return False
  1145. return self.chosen == other.chosen
  1146. class GeneralNames(SequenceOf):
  1147. _child_spec = GeneralName
  1148. class Time(Choice):
  1149. _alternatives = [
  1150. ('utc_time', UTCTime),
  1151. ('general_time', GeneralizedTime),
  1152. ]
  1153. class Validity(Sequence):
  1154. _fields = [
  1155. ('not_before', Time),
  1156. ('not_after', Time),
  1157. ]
  1158. class BasicConstraints(Sequence):
  1159. _fields = [
  1160. ('ca', Boolean, {'default': False}),
  1161. ('path_len_constraint', Integer, {'optional': True}),
  1162. ]
  1163. class AuthorityKeyIdentifier(Sequence):
  1164. _fields = [
  1165. ('key_identifier', OctetString, {'implicit': 0, 'optional': True}),
  1166. ('authority_cert_issuer', GeneralNames, {'implicit': 1, 'optional': True}),
  1167. ('authority_cert_serial_number', Integer, {'implicit': 2, 'optional': True}),
  1168. ]
  1169. class DistributionPointName(Choice):
  1170. _alternatives = [
  1171. ('full_name', GeneralNames, {'implicit': 0}),
  1172. ('name_relative_to_crl_issuer', RelativeDistinguishedName, {'implicit': 1}),
  1173. ]
  1174. class ReasonFlags(BitString):
  1175. _map = {
  1176. 0: 'unused',
  1177. 1: 'key_compromise',
  1178. 2: 'ca_compromise',
  1179. 3: 'affiliation_changed',
  1180. 4: 'superseded',
  1181. 5: 'cessation_of_operation',
  1182. 6: 'certificate_hold',
  1183. 7: 'privilege_withdrawn',
  1184. 8: 'aa_compromise',
  1185. }
  1186. class GeneralSubtree(Sequence):
  1187. _fields = [
  1188. ('base', GeneralName),
  1189. ('minimum', Integer, {'implicit': 0, 'default': 0}),
  1190. ('maximum', Integer, {'implicit': 1, 'optional': True}),
  1191. ]
  1192. class GeneralSubtrees(SequenceOf):
  1193. _child_spec = GeneralSubtree
  1194. class NameConstraints(Sequence):
  1195. _fields = [
  1196. ('permitted_subtrees', GeneralSubtrees, {'implicit': 0, 'optional': True}),
  1197. ('excluded_subtrees', GeneralSubtrees, {'implicit': 1, 'optional': True}),
  1198. ]
  1199. class DistributionPoint(Sequence):
  1200. _fields = [
  1201. ('distribution_point', DistributionPointName, {'explicit': 0, 'optional': True}),
  1202. ('reasons', ReasonFlags, {'implicit': 1, 'optional': True}),
  1203. ('crl_issuer', GeneralNames, {'implicit': 2, 'optional': True}),
  1204. ]
  1205. _url = False
  1206. @property
  1207. def url(self):
  1208. """
  1209. :return:
  1210. None or a unicode string of the distribution point's URL
  1211. """
  1212. if self._url is False:
  1213. self._url = None
  1214. name = self['distribution_point']
  1215. if name.name != 'full_name':
  1216. raise ValueError(unwrap(
  1217. '''
  1218. CRL distribution points that are relative to the issuer are
  1219. not supported
  1220. '''
  1221. ))
  1222. for general_name in name.chosen:
  1223. if general_name.name == 'uniform_resource_identifier':
  1224. url = general_name.native
  1225. if url.lower().startswith(('http://', 'https://', 'ldap://', 'ldaps://')):
  1226. self._url = url
  1227. break
  1228. return self._url
  1229. class CRLDistributionPoints(SequenceOf):
  1230. _child_spec = DistributionPoint
  1231. class DisplayText(Choice):
  1232. _alternatives = [
  1233. ('ia5_string', IA5String),
  1234. ('visible_string', VisibleString),
  1235. ('bmp_string', BMPString),
  1236. ('utf8_string', UTF8String),
  1237. ]
  1238. class NoticeNumbers(SequenceOf):
  1239. _child_spec = Integer
  1240. class NoticeReference(Sequence):
  1241. _fields = [
  1242. ('organization', DisplayText),
  1243. ('notice_numbers', NoticeNumbers),
  1244. ]
  1245. class UserNotice(Sequence):
  1246. _fields = [
  1247. ('notice_ref', NoticeReference, {'optional': True}),
  1248. ('explicit_text', DisplayText, {'optional': True}),
  1249. ]
  1250. class PolicyQualifierId(ObjectIdentifier):
  1251. _map = {
  1252. '1.3.6.1.5.5.7.2.1': 'certification_practice_statement',
  1253. '1.3.6.1.5.5.7.2.2': 'user_notice',
  1254. }
  1255. class PolicyQualifierInfo(Sequence):
  1256. _fields = [
  1257. ('policy_qualifier_id', PolicyQualifierId),
  1258. ('qualifier', Any),
  1259. ]
  1260. _oid_pair = ('policy_qualifier_id', 'qualifier')
  1261. _oid_specs = {
  1262. 'certification_practice_statement': IA5String,
  1263. 'user_notice': UserNotice,
  1264. }
  1265. class PolicyQualifierInfos(SequenceOf):
  1266. _child_spec = PolicyQualifierInfo
  1267. class PolicyIdentifier(ObjectIdentifier):
  1268. _map = {
  1269. '2.5.29.32.0': 'any_policy',
  1270. }
  1271. class PolicyInformation(Sequence):
  1272. _fields = [
  1273. ('policy_identifier', PolicyIdentifier),
  1274. ('policy_qualifiers', PolicyQualifierInfos, {'optional': True})
  1275. ]
  1276. class CertificatePolicies(SequenceOf):
  1277. _child_spec = PolicyInformation
  1278. class PolicyMapping(Sequence):
  1279. _fields = [
  1280. ('issuer_domain_policy', PolicyIdentifier),
  1281. ('subject_domain_policy', PolicyIdentifier),
  1282. ]
  1283. class PolicyMappings(SequenceOf):
  1284. _child_spec = PolicyMapping
  1285. class PolicyConstraints(Sequence):
  1286. _fields = [
  1287. ('require_explicit_policy', Integer, {'implicit': 0, 'optional': True}),
  1288. ('inhibit_policy_mapping', Integer, {'implicit': 1, 'optional': True}),
  1289. ]
  1290. class KeyPurposeId(ObjectIdentifier):
  1291. _map = {
  1292. # https://tools.ietf.org/html/rfc5280#page-45
  1293. '2.5.29.37.0': 'any_extended_key_usage',
  1294. '1.3.6.1.5.5.7.3.1': 'server_auth',
  1295. '1.3.6.1.5.5.7.3.2': 'client_auth',
  1296. '1.3.6.1.5.5.7.3.3': 'code_signing',
  1297. '1.3.6.1.5.5.7.3.4': 'email_protection',
  1298. '1.3.6.1.5.5.7.3.5': 'ipsec_end_system',
  1299. '1.3.6.1.5.5.7.3.6': 'ipsec_tunnel',
  1300. '1.3.6.1.5.5.7.3.7': 'ipsec_user',
  1301. '1.3.6.1.5.5.7.3.8': 'time_stamping',
  1302. '1.3.6.1.5.5.7.3.9': 'ocsp_signing',
  1303. # http://tools.ietf.org/html/rfc3029.html#page-9
  1304. '1.3.6.1.5.5.7.3.10': 'dvcs',
  1305. # http://tools.ietf.org/html/rfc6268.html#page-16
  1306. '1.3.6.1.5.5.7.3.13': 'eap_over_ppp',
  1307. '1.3.6.1.5.5.7.3.14': 'eap_over_lan',
  1308. # https://tools.ietf.org/html/rfc5055#page-76
  1309. '1.3.6.1.5.5.7.3.15': 'scvp_server',
  1310. '1.3.6.1.5.5.7.3.16': 'scvp_client',
  1311. # https://tools.ietf.org/html/rfc4945#page-31
  1312. '1.3.6.1.5.5.7.3.17': 'ipsec_ike',
  1313. # https://tools.ietf.org/html/rfc5415#page-38
  1314. '1.3.6.1.5.5.7.3.18': 'capwap_ac',
  1315. '1.3.6.1.5.5.7.3.19': 'capwap_wtp',
  1316. # https://tools.ietf.org/html/rfc5924#page-8
  1317. '1.3.6.1.5.5.7.3.20': 'sip_domain',
  1318. # https://tools.ietf.org/html/rfc6187#page-7
  1319. '1.3.6.1.5.5.7.3.21': 'secure_shell_client',
  1320. '1.3.6.1.5.5.7.3.22': 'secure_shell_server',
  1321. # https://tools.ietf.org/html/rfc6494#page-7
  1322. '1.3.6.1.5.5.7.3.23': 'send_router',
  1323. '1.3.6.1.5.5.7.3.24': 'send_proxied_router',
  1324. '1.3.6.1.5.5.7.3.25': 'send_owner',
  1325. '1.3.6.1.5.5.7.3.26': 'send_proxied_owner',
  1326. # https://tools.ietf.org/html/rfc6402#page-10
  1327. '1.3.6.1.5.5.7.3.27': 'cmc_ca',
  1328. '1.3.6.1.5.5.7.3.28': 'cmc_ra',
  1329. '1.3.6.1.5.5.7.3.29': 'cmc_archive',
  1330. # https://tools.ietf.org/html/draft-ietf-sidr-bgpsec-pki-profiles-15#page-6
  1331. '1.3.6.1.5.5.7.3.30': 'bgpspec_router',
  1332. # https://msdn.microsoft.com/en-us/library/windows/desktop/aa378132(v=vs.85).aspx
  1333. # and https://support.microsoft.com/en-us/kb/287547
  1334. '1.3.6.1.4.1.311.10.3.1': 'microsoft_trust_list_signing',
  1335. '1.3.6.1.4.1.311.10.3.2': 'microsoft_time_stamp_signing',
  1336. '1.3.6.1.4.1.311.10.3.3': 'microsoft_server_gated',
  1337. '1.3.6.1.4.1.311.10.3.3.1': 'microsoft_serialized',
  1338. '1.3.6.1.4.1.311.10.3.4': 'microsoft_efs',
  1339. '1.3.6.1.4.1.311.10.3.4.1': 'microsoft_efs_recovery',
  1340. '1.3.6.1.4.1.311.10.3.5': 'microsoft_whql',
  1341. '1.3.6.1.4.1.311.10.3.6': 'microsoft_nt5',
  1342. '1.3.6.1.4.1.311.10.3.7': 'microsoft_oem_whql',
  1343. '1.3.6.1.4.1.311.10.3.8': 'microsoft_embedded_nt',
  1344. '1.3.6.1.4.1.311.10.3.9': 'microsoft_root_list_signer',
  1345. '1.3.6.1.4.1.311.10.3.10': 'microsoft_qualified_subordination',
  1346. '1.3.6.1.4.1.311.10.3.11': 'microsoft_key_recovery',
  1347. '1.3.6.1.4.1.311.10.3.12': 'microsoft_document_signing',
  1348. '1.3.6.1.4.1.311.10.3.13': 'microsoft_lifetime_signing',
  1349. '1.3.6.1.4.1.311.10.3.14': 'microsoft_mobile_device_software',
  1350. # https://opensource.apple.com/source
  1351. # - /Security/Security-57031.40.6/Security/libsecurity_keychain/lib/SecPolicy.cpp
  1352. # - /libsecurity_cssm/libsecurity_cssm-36064/lib/oidsalg.c
  1353. '1.2.840.113635.100.1.2': 'apple_x509_basic',
  1354. '1.2.840.113635.100.1.3': 'apple_ssl',
  1355. '1.2.840.113635.100.1.4': 'apple_local_cert_gen',
  1356. '1.2.840.113635.100.1.5': 'apple_csr_gen',
  1357. '1.2.840.113635.100.1.6': 'apple_revocation_crl',
  1358. '1.2.840.113635.100.1.7': 'apple_revocation_ocsp',
  1359. '1.2.840.113635.100.1.8': 'apple_smime',
  1360. '1.2.840.113635.100.1.9': 'apple_eap',
  1361. '1.2.840.113635.100.1.10': 'apple_software_update_signing',
  1362. '1.2.840.113635.100.1.11': 'apple_ipsec',
  1363. '1.2.840.113635.100.1.12': 'apple_ichat',
  1364. '1.2.840.113635.100.1.13': 'apple_resource_signing',
  1365. '1.2.840.113635.100.1.14': 'apple_pkinit_client',
  1366. '1.2.840.113635.100.1.15': 'apple_pkinit_server',
  1367. '1.2.840.113635.100.1.16': 'apple_code_signing',
  1368. '1.2.840.113635.100.1.17': 'apple_package_signing',
  1369. '1.2.840.113635.100.1.18': 'apple_id_validation',
  1370. '1.2.840.113635.100.1.20': 'apple_time_stamping',
  1371. '1.2.840.113635.100.1.21': 'apple_revocation',
  1372. '1.2.840.113635.100.1.22': 'apple_passbook_signing',
  1373. '1.2.840.113635.100.1.23': 'apple_mobile_store',
  1374. '1.2.840.113635.100.1.24': 'apple_escrow_service',
  1375. '1.2.840.113635.100.1.25': 'apple_profile_signer',
  1376. '1.2.840.113635.100.1.26': 'apple_qa_profile_signer',
  1377. '1.2.840.113635.100.1.27': 'apple_test_mobile_store',
  1378. '1.2.840.113635.100.1.28': 'apple_otapki_signer',
  1379. '1.2.840.113635.100.1.29': 'apple_test_otapki_signer',
  1380. '1.2.840.113625.100.1.30': 'apple_id_validation_record_signing_policy',
  1381. '1.2.840.113625.100.1.31': 'apple_smp_encryption',
  1382. '1.2.840.113625.100.1.32': 'apple_test_smp_encryption',
  1383. '1.2.840.113635.100.1.33': 'apple_server_authentication',
  1384. '1.2.840.113635.100.1.34': 'apple_pcs_escrow_service',
  1385. }
  1386. class ExtKeyUsageSyntax(SequenceOf):
  1387. _child_spec = KeyPurposeId
  1388. class AccessMethod(ObjectIdentifier):
  1389. _map = {
  1390. '1.3.6.1.5.5.7.48.1': 'ocsp',
  1391. '1.3.6.1.5.5.7.48.2': 'ca_issuers',
  1392. '1.3.6.1.5.5.7.48.3': 'time_stamping',
  1393. '1.3.6.1.5.5.7.48.5': 'ca_repository',
  1394. }
  1395. class AccessDescription(Sequence):
  1396. _fields = [
  1397. ('access_method', AccessMethod),
  1398. ('access_location', GeneralName),
  1399. ]
  1400. class AuthorityInfoAccessSyntax(SequenceOf):
  1401. _child_spec = AccessDescription
  1402. class SubjectInfoAccessSyntax(SequenceOf):
  1403. _child_spec = AccessDescription
  1404. # https://tools.ietf.org/html/rfc7633
  1405. class Features(SequenceOf):
  1406. _child_spec = Integer
  1407. class EntrustVersionInfo(Sequence):
  1408. _fields = [
  1409. ('entrust_vers', GeneralString),
  1410. ('entrust_info_flags', BitString)
  1411. ]
  1412. class NetscapeCertificateType(BitString):
  1413. _map = {
  1414. 0: 'ssl_client',
  1415. 1: 'ssl_server',
  1416. 2: 'email',
  1417. 3: 'object_signing',
  1418. 4: 'reserved',
  1419. 5: 'ssl_ca',
  1420. 6: 'email_ca',
  1421. 7: 'object_signing_ca',
  1422. }
  1423. class ExtensionId(ObjectIdentifier):
  1424. _map = {
  1425. '2.5.29.9': 'subject_directory_attributes',
  1426. '2.5.29.14': 'key_identifier',
  1427. '2.5.29.15': 'key_usage',
  1428. '2.5.29.16': 'private_key_usage_period',
  1429. '2.5.29.17': 'subject_alt_name',
  1430. '2.5.29.18': 'issuer_alt_name',
  1431. '2.5.29.19': 'basic_constraints',
  1432. '2.5.29.30': 'name_constraints',
  1433. '2.5.29.31': 'crl_distribution_points',
  1434. '2.5.29.32': 'certificate_policies',
  1435. '2.5.29.33': 'policy_mappings',
  1436. '2.5.29.35': 'authority_key_identifier',
  1437. '2.5.29.36': 'policy_constraints',
  1438. '2.5.29.37': 'extended_key_usage',
  1439. '2.5.29.46': 'freshest_crl',
  1440. '2.5.29.54': 'inhibit_any_policy',
  1441. '1.3.6.1.5.5.7.1.1': 'authority_information_access',
  1442. '1.3.6.1.5.5.7.1.11': 'subject_information_access',
  1443. # https://tools.ietf.org/html/rfc7633
  1444. '1.3.6.1.5.5.7.1.24': 'tls_feature',
  1445. '1.3.6.1.5.5.7.48.1.5': 'ocsp_no_check',
  1446. '1.2.840.113533.7.65.0': 'entrust_version_extension',
  1447. '2.16.840.1.113730.1.1': 'netscape_certificate_type',
  1448. # https://tools.ietf.org/html/rfc6962.html#page-14
  1449. '1.3.6.1.4.1.11129.2.4.2': 'signed_certificate_timestamp_list',
  1450. }
  1451. class Extension(Sequence):
  1452. _fields = [
  1453. ('extn_id', ExtensionId),
  1454. ('critical', Boolean, {'default': False}),
  1455. ('extn_value', ParsableOctetString),
  1456. ]
  1457. _oid_pair = ('extn_id', 'extn_value')
  1458. _oid_specs = {
  1459. 'subject_directory_attributes': Attributes,
  1460. 'key_identifier': OctetString,
  1461. 'key_usage': KeyUsage,
  1462. 'private_key_usage_period': PrivateKeyUsagePeriod,
  1463. 'subject_alt_name': GeneralNames,
  1464. 'issuer_alt_name': GeneralNames,
  1465. 'basic_constraints': BasicConstraints,
  1466. 'name_constraints': NameConstraints,
  1467. 'crl_distribution_points': CRLDistributionPoints,
  1468. 'certificate_policies': CertificatePolicies,
  1469. 'policy_mappings': PolicyMappings,
  1470. 'authority_key_identifier': AuthorityKeyIdentifier,
  1471. 'policy_constraints': PolicyConstraints,
  1472. 'extended_key_usage': ExtKeyUsageSyntax,
  1473. 'freshest_crl': CRLDistributionPoints,
  1474. 'inhibit_any_policy': Integer,
  1475. 'authority_information_access': AuthorityInfoAccessSyntax,
  1476. 'subject_information_access': SubjectInfoAccessSyntax,
  1477. 'tls_feature': Features,
  1478. 'ocsp_no_check': Null,
  1479. 'entrust_version_extension': EntrustVersionInfo,
  1480. 'netscape_certificate_type': NetscapeCertificateType,
  1481. 'signed_certificate_timestamp_list': OctetString,
  1482. }
  1483. class Extensions(SequenceOf):
  1484. _child_spec = Extension
  1485. class Version(Integer):
  1486. _map = {
  1487. 0: 'v1',
  1488. 1: 'v2',
  1489. 2: 'v3',
  1490. }
  1491. class TbsCertificate(Sequence):
  1492. _fields = [
  1493. ('version', Version, {'explicit': 0, 'default': 'v1'}),
  1494. ('serial_number', Integer),
  1495. ('signature', SignedDigestAlgorithm),
  1496. ('issuer', Name),
  1497. ('validity', Validity),
  1498. ('subject', Name),
  1499. ('subject_public_key_info', PublicKeyInfo),
  1500. ('issuer_unique_id', OctetBitString, {'implicit': 1, 'optional': True}),
  1501. ('subject_unique_id', OctetBitString, {'implicit': 2, 'optional': True}),
  1502. ('extensions', Extensions, {'explicit': 3, 'optional': True}),
  1503. ]
  1504. class Certificate(Sequence):
  1505. _fields = [
  1506. ('tbs_certificate', TbsCertificate),
  1507. ('signature_algorithm', SignedDigestAlgorithm),
  1508. ('signature_value', OctetBitString),
  1509. ]
  1510. _processed_extensions = False
  1511. _critical_extensions = None
  1512. _subject_directory_attributes = None
  1513. _key_identifier_value = None
  1514. _key_usage_value = None
  1515. _subject_alt_name_value = None
  1516. _issuer_alt_name_value = None
  1517. _basic_constraints_value = None
  1518. _name_constraints_value = None
  1519. _crl_distribution_points_value = None
  1520. _certificate_policies_value = None
  1521. _policy_mappings_value = None
  1522. _authority_key_identifier_value = None
  1523. _policy_constraints_value = None
  1524. _freshest_crl_value = None
  1525. _inhibit_any_policy_value = None
  1526. _extended_key_usage_value = None
  1527. _authority_information_access_value = None
  1528. _subject_information_access_value = None
  1529. _tls_feature_value = None
  1530. _ocsp_no_check_value = None
  1531. _issuer_serial = None
  1532. _authority_issuer_serial = False
  1533. _crl_distribution_points = None
  1534. _delta_crl_distribution_points = None
  1535. _valid_domains = None
  1536. _valid_ips = None
  1537. _self_issued = None
  1538. _self_signed = None
  1539. _sha1 = None
  1540. _sha256 = None
  1541. def _set_extensions(self):
  1542. """
  1543. Sets common named extensions to private attributes and creates a list
  1544. of critical extensions
  1545. """
  1546. self._critical_extensions = set()
  1547. for extension in self['tbs_certificate']['extensions']:
  1548. name = extension['extn_id'].native
  1549. attribute_name = '_%s_value' % name
  1550. if hasattr(self, attribute_name):
  1551. setattr(self, attribute_name, extension['extn_value'].parsed)
  1552. if extension['critical'].native:
  1553. self._critical_extensions.add(name)
  1554. self._processed_extensions = True
  1555. @property
  1556. def critical_extensions(self):
  1557. """
  1558. Returns a set of the names (or OID if not a known extension) of the
  1559. extensions marked as critical
  1560. :return:
  1561. A set of unicode strings
  1562. """
  1563. if not self._processed_extensions:
  1564. self._set_extensions()
  1565. return self._critical_extensions
  1566. @property
  1567. def subject_directory_attributes_value(self):
  1568. """
  1569. This extension is used to contain additional identification attributes
  1570. about the subject.
  1571. :return:
  1572. None or an Attributes object
  1573. """
  1574. if not self._processed_extensions:
  1575. self._set_extensions()
  1576. return self._key_identifier_value
  1577. @property
  1578. def key_identifier_value(self):
  1579. """
  1580. This extension is used to help in creating certificate validation paths.
  1581. It contains an identifier that should generally, but is not guaranteed
  1582. to, be unique.
  1583. :return:
  1584. None or an OctetString object
  1585. """
  1586. if not self._processed_extensions:
  1587. self._set_extensions()
  1588. return self._key_identifier_value
  1589. @property
  1590. def key_usage_value(self):
  1591. """
  1592. This extension is used to define the purpose of the public key
  1593. contained within the certificate.
  1594. :return:
  1595. None or a KeyUsage
  1596. """
  1597. if not self._processed_extensions:
  1598. self._set_extensions()
  1599. return self._key_usage_value
  1600. @property
  1601. def subject_alt_name_value(self):
  1602. """
  1603. This extension allows for additional names to be associate with the
  1604. subject of the certificate. While it may contain a whole host of
  1605. possible names, it is usually used to allow certificates to be used
  1606. with multiple different domain names.
  1607. :return:
  1608. None or a GeneralNames object
  1609. """
  1610. if not self._processed_extensions:
  1611. self._set_extensions()
  1612. return self._subject_alt_name_value
  1613. @property
  1614. def issuer_alt_name_value(self):
  1615. """
  1616. This extension allows associating one or more alternative names with
  1617. the issuer of the certificate.
  1618. :return:
  1619. None or an x509.GeneralNames object
  1620. """
  1621. if not self._processed_extensions:
  1622. self._set_extensions()
  1623. return self._issuer_alt_name_value
  1624. @property
  1625. def basic_constraints_value(self):
  1626. """
  1627. This extension is used to determine if the subject of the certificate
  1628. is a CA, and if so, what the maximum number of intermediate CA certs
  1629. after this are, before an end-entity certificate is found.
  1630. :return:
  1631. None or a BasicConstraints object
  1632. """
  1633. if not self._processed_extensions:
  1634. self._set_extensions()
  1635. return self._basic_constraints_value
  1636. @property
  1637. def name_constraints_value(self):
  1638. """
  1639. This extension is used in CA certificates, and is used to limit the
  1640. possible names of certificates issued.
  1641. :return:
  1642. None or a NameConstraints object
  1643. """
  1644. if not self._processed_extensions:
  1645. self._set_extensions()
  1646. return self._name_constraints_value
  1647. @property
  1648. def crl_distribution_points_value(self):
  1649. """
  1650. This extension is used to help in locating the CRL for this certificate.
  1651. :return:
  1652. None or a CRLDistributionPoints object
  1653. extension
  1654. """
  1655. if not self._processed_extensions:
  1656. self._set_extensions()
  1657. return self._crl_distribution_points_value
  1658. @property
  1659. def certificate_policies_value(self):
  1660. """
  1661. This extension defines policies in CA certificates under which
  1662. certificates may be issued. In end-entity certificates, the inclusion
  1663. of a policy indicates the issuance of the certificate follows the
  1664. policy.
  1665. :return:
  1666. None or a CertificatePolicies object
  1667. """
  1668. if not self._processed_extensions:
  1669. self._set_extensions()
  1670. return self._certificate_policies_value
  1671. @property
  1672. def policy_mappings_value(self):
  1673. """
  1674. This extension allows mapping policy OIDs to other OIDs. This is used
  1675. to allow different policies to be treated as equivalent in the process
  1676. of validation.
  1677. :return:
  1678. None or a PolicyMappings object
  1679. """
  1680. if not self._processed_extensions:
  1681. self._set_extensions()
  1682. return self._policy_mappings_value
  1683. @property
  1684. def authority_key_identifier_value(self):
  1685. """
  1686. This extension helps in identifying the public key with which to
  1687. validate the authenticity of the certificate.
  1688. :return:
  1689. None or an AuthorityKeyIdentifier object
  1690. """
  1691. if not self._processed_extensions:
  1692. self._set_extensions()
  1693. return self._authority_key_identifier_value
  1694. @property
  1695. def policy_constraints_value(self):
  1696. """
  1697. This extension is used to control if policy mapping is allowed and
  1698. when policies are required.
  1699. :return:
  1700. None or a PolicyConstraints object
  1701. """
  1702. if not self._processed_extensions:
  1703. self._set_extensions()
  1704. return self._policy_constraints_value
  1705. @property
  1706. def freshest_crl_value(self):
  1707. """
  1708. This extension is used to help locate any available delta CRLs
  1709. :return:
  1710. None or an CRLDistributionPoints object
  1711. """
  1712. if not self._processed_extensions:
  1713. self._set_extensions()
  1714. return self._freshest_crl_value
  1715. @property
  1716. def inhibit_any_policy_value(self):
  1717. """
  1718. This extension is used to prevent mapping of the any policy to
  1719. specific requirements
  1720. :return:
  1721. None or a Integer object
  1722. """
  1723. if not self._processed_extensions:
  1724. self._set_extensions()
  1725. return self._inhibit_any_policy_value
  1726. @property
  1727. def extended_key_usage_value(self):
  1728. """
  1729. This extension is used to define additional purposes for the public key
  1730. beyond what is contained in the basic constraints.
  1731. :return:
  1732. None or an ExtKeyUsageSyntax object
  1733. """
  1734. if not self._processed_extensions:
  1735. self._set_extensions()
  1736. return self._extended_key_usage_value
  1737. @property
  1738. def authority_information_access_value(self):
  1739. """
  1740. This extension is used to locate the CA certificate used to sign this
  1741. certificate, or the OCSP responder for this certificate.
  1742. :return:
  1743. None or an AuthorityInfoAccessSyntax object
  1744. """
  1745. if not self._processed_extensions:
  1746. self._set_extensions()
  1747. return self._authority_information_access_value
  1748. @property
  1749. def subject_information_access_value(self):
  1750. """
  1751. This extension is used to access information about the subject of this
  1752. certificate.
  1753. :return:
  1754. None or a SubjectInfoAccessSyntax object
  1755. """
  1756. if not self._processed_extensions:
  1757. self._set_extensions()
  1758. return self._subject_information_access_value
  1759. @property
  1760. def tls_feature_value(self):
  1761. """
  1762. This extension is used to list the TLS features a server must respond
  1763. with if a client initiates a request supporting them.
  1764. :return:
  1765. None or a Features object
  1766. """
  1767. if not self._processed_extensions:
  1768. self._set_extensions()
  1769. return self._tls_feature_value
  1770. @property
  1771. def ocsp_no_check_value(self):
  1772. """
  1773. This extension is used on certificates of OCSP responders, indicating
  1774. that revocation information for the certificate should never need to
  1775. be verified, thus preventing possible loops in path validation.
  1776. :return:
  1777. None or a Null object (if present)
  1778. """
  1779. if not self._processed_extensions:
  1780. self._set_extensions()
  1781. return self._ocsp_no_check_value
  1782. @property
  1783. def signature(self):
  1784. """
  1785. :return:
  1786. A byte string of the signature
  1787. """
  1788. return self['signature_value'].native
  1789. @property
  1790. def signature_algo(self):
  1791. """
  1792. :return:
  1793. A unicode string of "rsassa_pkcs1v15", "rsassa_pss", "dsa", "ecdsa"
  1794. """
  1795. return self['signature_algorithm'].signature_algo
  1796. @property
  1797. def hash_algo(self):
  1798. """
  1799. :return:
  1800. A unicode string of "md2", "md5", "sha1", "sha224", "sha256",
  1801. "sha384", "sha512", "sha512_224", "sha512_256"
  1802. """
  1803. return self['signature_algorithm'].hash_algo
  1804. @property
  1805. def public_key(self):
  1806. """
  1807. :return:
  1808. The PublicKeyInfo object for this certificate
  1809. """
  1810. return self['tbs_certificate']['subject_public_key_info']
  1811. @property
  1812. def subject(self):
  1813. """
  1814. :return:
  1815. The Name object for the subject of this certificate
  1816. """
  1817. return self['tbs_certificate']['subject']
  1818. @property
  1819. def issuer(self):
  1820. """
  1821. :return:
  1822. The Name object for the issuer of this certificate
  1823. """
  1824. return self['tbs_certificate']['issuer']
  1825. @property
  1826. def serial_number(self):
  1827. """
  1828. :return:
  1829. An integer of the certificate's serial number
  1830. """
  1831. return self['tbs_certificate']['serial_number'].native
  1832. @property
  1833. def key_identifier(self):
  1834. """
  1835. :return:
  1836. None or a byte string of the certificate's key identifier from the
  1837. key identifier extension
  1838. """
  1839. if not self.key_identifier_value:
  1840. return None
  1841. return self.key_identifier_value.native
  1842. @property
  1843. def issuer_serial(self):
  1844. """
  1845. :return:
  1846. A byte string of the SHA-256 hash of the issuer concatenated with
  1847. the ascii character ":", concatenated with the serial number as
  1848. an ascii string
  1849. """
  1850. if self._issuer_serial is None:
  1851. self._issuer_serial = self.issuer.sha256 + b':' + str_cls(self.serial_number).encode('ascii')
  1852. return self._issuer_serial
  1853. @property
  1854. def authority_key_identifier(self):
  1855. """
  1856. :return:
  1857. None or a byte string of the key_identifier from the authority key
  1858. identifier extension
  1859. """
  1860. if not self.authority_key_identifier_value:
  1861. return None
  1862. return self.authority_key_identifier_value['key_identifier'].native
  1863. @property
  1864. def authority_issuer_serial(self):
  1865. """
  1866. :return:
  1867. None or a byte string of the SHA-256 hash of the isser from the
  1868. authority key identifier extension concatenated with the ascii
  1869. character ":", concatenated with the serial number from the
  1870. authority key identifier extension as an ascii string
  1871. """
  1872. if self._authority_issuer_serial is False:
  1873. akiv = self.authority_key_identifier_value
  1874. if akiv and akiv['authority_cert_issuer'].native:
  1875. issuer = self.authority_key_identifier_value['authority_cert_issuer'][0].chosen
  1876. # We untag the element since it is tagged via being a choice from GeneralName
  1877. issuer = issuer.untag()
  1878. authority_serial = self.authority_key_identifier_value['authority_cert_serial_number'].native
  1879. self._authority_issuer_serial = issuer.sha256 + b':' + str_cls(authority_serial).encode('ascii')
  1880. else:
  1881. self._authority_issuer_serial = None
  1882. return self._authority_issuer_serial
  1883. @property
  1884. def crl_distribution_points(self):
  1885. """
  1886. Returns complete CRL URLs - does not include delta CRLs
  1887. :return:
  1888. A list of zero or more DistributionPoint objects
  1889. """
  1890. if self._crl_distribution_points is None:
  1891. self._crl_distribution_points = self._get_http_crl_distribution_points(self.crl_distribution_points_value)
  1892. return self._crl_distribution_points
  1893. @property
  1894. def delta_crl_distribution_points(self):
  1895. """
  1896. Returns delta CRL URLs - does not include complete CRLs
  1897. :return:
  1898. A list of zero or more DistributionPoint objects
  1899. """
  1900. if self._delta_crl_distribution_points is None:
  1901. self._delta_crl_distribution_points = self._get_http_crl_distribution_points(self.freshest_crl_value)
  1902. return self._delta_crl_distribution_points
  1903. def _get_http_crl_distribution_points(self, crl_distribution_points):
  1904. """
  1905. Fetches the DistributionPoint object for non-relative, HTTP CRLs
  1906. referenced by the certificate
  1907. :param crl_distribution_points:
  1908. A CRLDistributionPoints object to grab the DistributionPoints from
  1909. :return:
  1910. A list of zero or more DistributionPoint objects
  1911. """
  1912. output = []
  1913. if crl_distribution_points is None:
  1914. return []
  1915. for distribution_point in crl_distribution_points:
  1916. distribution_point_name = distribution_point['distribution_point']
  1917. if distribution_point_name is VOID:
  1918. continue
  1919. # RFC 5280 indicates conforming CA should not use the relative form
  1920. if distribution_point_name.name == 'name_relative_to_crl_issuer':
  1921. continue
  1922. # This library is currently only concerned with HTTP-based CRLs
  1923. for general_name in distribution_point_name.chosen:
  1924. if general_name.name == 'uniform_resource_identifier':
  1925. output.append(distribution_point)
  1926. return output
  1927. @property
  1928. def ocsp_urls(self):
  1929. """
  1930. :return:
  1931. A list of zero or more unicode strings of the OCSP URLs for this
  1932. cert
  1933. """
  1934. if not self.authority_information_access_value:
  1935. return []
  1936. output = []
  1937. for entry in self.authority_information_access_value:
  1938. if entry['access_method'].native == 'ocsp':
  1939. location = entry['access_location']
  1940. if location.name != 'uniform_resource_identifier':
  1941. continue
  1942. url = location.native
  1943. if url.lower().startswith(('http://', 'https://', 'ldap://', 'ldaps://')):
  1944. output.append(url)
  1945. return output
  1946. @property
  1947. def valid_domains(self):
  1948. """
  1949. :return:
  1950. A list of unicode strings of valid domain names for the certificate.
  1951. Wildcard certificates will have a domain in the form: *.example.com
  1952. """
  1953. if self._valid_domains is None:
  1954. self._valid_domains = []
  1955. # For the subject alt name extension, we can look at the name of
  1956. # the choice selected since it distinguishes between domain names,
  1957. # email addresses, IPs, etc
  1958. if self.subject_alt_name_value:
  1959. for general_name in self.subject_alt_name_value:
  1960. if general_name.name == 'dns_name' and general_name.native not in self._valid_domains:
  1961. self._valid_domains.append(general_name.native)
  1962. # If there was no subject alt name extension, and the common name
  1963. # in the subject looks like a domain, that is considered the valid
  1964. # list. This is done because according to
  1965. # https://tools.ietf.org/html/rfc6125#section-6.4.4, the common
  1966. # name should not be used if the subject alt name is present.
  1967. else:
  1968. pattern = re.compile('^(\\*\\.)?(?:[a-zA-Z0-9](?:[a-zA-Z0-9\\-]*[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$')
  1969. for rdn in self.subject.chosen:
  1970. for name_type_value in rdn:
  1971. if name_type_value['type'].native == 'common_name':
  1972. value = name_type_value['value'].native
  1973. if pattern.match(value):
  1974. self._valid_domains.append(value)
  1975. return self._valid_domains
  1976. @property
  1977. def valid_ips(self):
  1978. """
  1979. :return:
  1980. A list of unicode strings of valid IP addresses for the certificate
  1981. """
  1982. if self._valid_ips is None:
  1983. self._valid_ips = []
  1984. if self.subject_alt_name_value:
  1985. for general_name in self.subject_alt_name_value:
  1986. if general_name.name == 'ip_address':
  1987. self._valid_ips.append(general_name.native)
  1988. return self._valid_ips
  1989. @property
  1990. def ca(self):
  1991. """
  1992. :return;
  1993. A boolean - if the certificate is marked as a CA
  1994. """
  1995. return self.basic_constraints_value and self.basic_constraints_value['ca'].native
  1996. @property
  1997. def max_path_length(self):
  1998. """
  1999. :return;
  2000. None or an integer of the maximum path length
  2001. """
  2002. if not self.ca:
  2003. return None
  2004. return self.basic_constraints_value['path_len_constraint'].native
  2005. @property
  2006. def self_issued(self):
  2007. """
  2008. :return:
  2009. A boolean - if the certificate is self-issued, as defined by RFC
  2010. 5280
  2011. """
  2012. if self._self_issued is None:
  2013. self._self_issued = self.subject == self.issuer
  2014. return self._self_issued
  2015. @property
  2016. def self_signed(self):
  2017. """
  2018. :return:
  2019. A unicode string of "yes", "no" or "maybe". The "maybe" result will
  2020. be returned if the certificate does not contain a key identifier
  2021. extension, but is issued by the subject. In this case the
  2022. certificate signature will need to be verified using the subject
  2023. public key to determine a "yes" or "no" answer.
  2024. """
  2025. if self._self_signed is None:
  2026. self._self_signed = 'no'
  2027. if self.self_issued:
  2028. if self.key_identifier:
  2029. if not self.authority_key_identifier:
  2030. self._self_signed = 'yes'
  2031. elif self.authority_key_identifier == self.key_identifier:
  2032. self._self_signed = 'yes'
  2033. else:
  2034. self._self_signed = 'maybe'
  2035. return self._self_signed
  2036. @property
  2037. def sha1(self):
  2038. """
  2039. :return:
  2040. The SHA-1 hash of the DER-encoded bytes of this complete certificate
  2041. """
  2042. if self._sha1 is None:
  2043. self._sha1 = hashlib.sha1(self.dump()).digest()
  2044. return self._sha1
  2045. @property
  2046. def sha1_fingerprint(self):
  2047. """
  2048. :return:
  2049. A unicode string of the SHA-1 hash, formatted using hex encoding
  2050. with a space between each pair of characters, all uppercase
  2051. """
  2052. return ' '.join('%02X' % c for c in bytes_to_list(self.sha1))
  2053. @property
  2054. def sha256(self):
  2055. """
  2056. :return:
  2057. The SHA-256 hash of the DER-encoded bytes of this complete
  2058. certificate
  2059. """
  2060. if self._sha256 is None:
  2061. self._sha256 = hashlib.sha256(self.dump()).digest()
  2062. return self._sha256
  2063. @property
  2064. def sha256_fingerprint(self):
  2065. """
  2066. :return:
  2067. A unicode string of the SHA-256 hash, formatted using hex encoding
  2068. with a space between each pair of characters, all uppercase
  2069. """
  2070. return ' '.join('%02X' % c for c in bytes_to_list(self.sha256))
  2071. def is_valid_domain_ip(self, domain_ip):
  2072. """
  2073. Check if a domain name or IP address is valid according to the
  2074. certificate
  2075. :param domain_ip:
  2076. A unicode string of a domain name or IP address
  2077. :return:
  2078. A boolean - if the domain or IP is valid for the certificate
  2079. """
  2080. if not isinstance(domain_ip, str_cls):
  2081. raise TypeError(unwrap(
  2082. '''
  2083. domain_ip must be a unicode string, not %s
  2084. ''',
  2085. type_name(domain_ip)
  2086. ))
  2087. encoded_domain_ip = domain_ip.encode('idna').decode('ascii').lower()
  2088. is_ipv6 = encoded_domain_ip.find(':') != -1
  2089. is_ipv4 = not is_ipv6 and re.match('^\\d+\\.\\d+\\.\\d+\\.\\d+$', encoded_domain_ip)
  2090. is_domain = not is_ipv6 and not is_ipv4
  2091. # Handle domain name checks
  2092. if is_domain:
  2093. if not self.valid_domains:
  2094. return False
  2095. domain_labels = encoded_domain_ip.split('.')
  2096. for valid_domain in self.valid_domains:
  2097. encoded_valid_domain = valid_domain.encode('idna').decode('ascii').lower()
  2098. valid_domain_labels = encoded_valid_domain.split('.')
  2099. # The domain must be equal in label length to match
  2100. if len(valid_domain_labels) != len(domain_labels):
  2101. continue
  2102. if valid_domain_labels == domain_labels:
  2103. return True
  2104. is_wildcard = self._is_wildcard_domain(encoded_valid_domain)
  2105. if is_wildcard and self._is_wildcard_match(domain_labels, valid_domain_labels):
  2106. return True
  2107. return False
  2108. # Handle IP address checks
  2109. if not self.valid_ips:
  2110. return False
  2111. family = socket.AF_INET if is_ipv4 else socket.AF_INET6
  2112. normalized_ip = inet_pton(family, encoded_domain_ip)
  2113. for valid_ip in self.valid_ips:
  2114. valid_family = socket.AF_INET if valid_ip.find('.') != -1 else socket.AF_INET6
  2115. normalized_valid_ip = inet_pton(valid_family, valid_ip)
  2116. if normalized_valid_ip == normalized_ip:
  2117. return True
  2118. return False
  2119. def _is_wildcard_domain(self, domain):
  2120. """
  2121. Checks if a domain is a valid wildcard according to
  2122. https://tools.ietf.org/html/rfc6125#section-6.4.3
  2123. :param domain:
  2124. A unicode string of the domain name, where any U-labels from an IDN
  2125. have been converted to A-labels
  2126. :return:
  2127. A boolean - if the domain is a valid wildcard domain
  2128. """
  2129. # The * character must be present for a wildcard match, and if there is
  2130. # most than one, it is an invalid wildcard specification
  2131. if domain.count('*') != 1:
  2132. return False
  2133. labels = domain.lower().split('.')
  2134. if not labels:
  2135. return False
  2136. # Wildcards may only appear in the left-most label
  2137. if labels[0].find('*') == -1:
  2138. return False
  2139. # Wildcards may not be embedded in an A-label from an IDN
  2140. if labels[0][0:4] == 'xn--':
  2141. return False
  2142. return True
  2143. def _is_wildcard_match(self, domain_labels, valid_domain_labels):
  2144. """
  2145. Determines if the labels in a domain are a match for labels from a
  2146. wildcard valid domain name
  2147. :param domain_labels:
  2148. A list of unicode strings, with A-label form for IDNs, of the labels
  2149. in the domain name to check
  2150. :param valid_domain_labels:
  2151. A list of unicode strings, with A-label form for IDNs, of the labels
  2152. in a wildcard domain pattern
  2153. :return:
  2154. A boolean - if the domain matches the valid domain
  2155. """
  2156. first_domain_label = domain_labels[0]
  2157. other_domain_labels = domain_labels[1:]
  2158. wildcard_label = valid_domain_labels[0]
  2159. other_valid_domain_labels = valid_domain_labels[1:]
  2160. # The wildcard is only allowed in the first label, so if
  2161. # The subsequent labels are not equal, there is no match
  2162. if other_domain_labels != other_valid_domain_labels:
  2163. return False
  2164. if wildcard_label == '*':
  2165. return True
  2166. wildcard_regex = re.compile('^' + wildcard_label.replace('*', '.*') + '$')
  2167. if wildcard_regex.match(first_domain_label):
  2168. return True
  2169. return False
  2170. # The structures are taken from the OpenSSL source file x_x509a.c, and specify
  2171. # extra information that is added to X.509 certificates to store trust
  2172. # information about the certificate.
  2173. class KeyPurposeIdentifiers(SequenceOf):
  2174. _child_spec = KeyPurposeId
  2175. class SequenceOfAlgorithmIdentifiers(SequenceOf):
  2176. _child_spec = AlgorithmIdentifier
  2177. class CertificateAux(Sequence):
  2178. _fields = [
  2179. ('trust', KeyPurposeIdentifiers, {'optional': True}),
  2180. ('reject', KeyPurposeIdentifiers, {'implicit': 0, 'optional': True}),
  2181. ('alias', UTF8String, {'optional': True}),
  2182. ('keyid', OctetString, {'optional': True}),
  2183. ('other', SequenceOfAlgorithmIdentifiers, {'implicit': 1, 'optional': True}),
  2184. ]
  2185. class TrustedCertificate(Concat):
  2186. _child_specs = [Certificate, CertificateAux]

Powered by TurnKey Linux.