No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

704 líneas
19 KiB

  1. # coding: utf-8
  2. """
  3. ASN.1 type classes for the online certificate status protocol (OCSP). Exports
  4. the following items:
  5. - OCSPRequest()
  6. - OCSPResponse()
  7. Other type classes are defined that help compose the types listed above.
  8. """
  9. from __future__ import unicode_literals, division, absolute_import, print_function
  10. from ._errors import unwrap
  11. from .algos import DigestAlgorithm, SignedDigestAlgorithm
  12. from .core import (
  13. Boolean,
  14. Choice,
  15. Enumerated,
  16. GeneralizedTime,
  17. IA5String,
  18. Integer,
  19. Null,
  20. ObjectIdentifier,
  21. OctetBitString,
  22. OctetString,
  23. ParsableOctetString,
  24. Sequence,
  25. SequenceOf,
  26. )
  27. from .crl import AuthorityInfoAccessSyntax, CRLReason
  28. from .keys import PublicKeyAlgorithm
  29. from .x509 import Certificate, GeneralName, GeneralNames, Name
  30. # The structures in this file are taken from https://tools.ietf.org/html/rfc6960
  31. class Version(Integer):
  32. _map = {
  33. 0: 'v1'
  34. }
  35. class CertId(Sequence):
  36. _fields = [
  37. ('hash_algorithm', DigestAlgorithm),
  38. ('issuer_name_hash', OctetString),
  39. ('issuer_key_hash', OctetString),
  40. ('serial_number', Integer),
  41. ]
  42. class ServiceLocator(Sequence):
  43. _fields = [
  44. ('issuer', Name),
  45. ('locator', AuthorityInfoAccessSyntax),
  46. ]
  47. class RequestExtensionId(ObjectIdentifier):
  48. _map = {
  49. '1.3.6.1.5.5.7.48.1.7': 'service_locator',
  50. }
  51. class RequestExtension(Sequence):
  52. _fields = [
  53. ('extn_id', RequestExtensionId),
  54. ('critical', Boolean, {'default': False}),
  55. ('extn_value', ParsableOctetString),
  56. ]
  57. _oid_pair = ('extn_id', 'extn_value')
  58. _oid_specs = {
  59. 'service_locator': ServiceLocator,
  60. }
  61. class RequestExtensions(SequenceOf):
  62. _child_spec = RequestExtension
  63. class Request(Sequence):
  64. _fields = [
  65. ('req_cert', CertId),
  66. ('single_request_extensions', RequestExtensions, {'explicit': 0, 'optional': True}),
  67. ]
  68. _processed_extensions = False
  69. _critical_extensions = None
  70. _service_locator_value = None
  71. def _set_extensions(self):
  72. """
  73. Sets common named extensions to private attributes and creates a list
  74. of critical extensions
  75. """
  76. self._critical_extensions = set()
  77. for extension in self['single_request_extensions']:
  78. name = extension['extn_id'].native
  79. attribute_name = '_%s_value' % name
  80. if hasattr(self, attribute_name):
  81. setattr(self, attribute_name, extension['extn_value'].parsed)
  82. if extension['critical'].native:
  83. self._critical_extensions.add(name)
  84. self._processed_extensions = True
  85. @property
  86. def critical_extensions(self):
  87. """
  88. Returns a set of the names (or OID if not a known extension) of the
  89. extensions marked as critical
  90. :return:
  91. A set of unicode strings
  92. """
  93. if not self._processed_extensions:
  94. self._set_extensions()
  95. return self._critical_extensions
  96. @property
  97. def service_locator_value(self):
  98. """
  99. This extension is used when communicating with an OCSP responder that
  100. acts as a proxy for OCSP requests
  101. :return:
  102. None or a ServiceLocator object
  103. """
  104. if self._processed_extensions is False:
  105. self._set_extensions()
  106. return self._service_locator_value
  107. class Requests(SequenceOf):
  108. _child_spec = Request
  109. class ResponseType(ObjectIdentifier):
  110. _map = {
  111. '1.3.6.1.5.5.7.48.1.1': 'basic_ocsp_response',
  112. }
  113. class AcceptableResponses(SequenceOf):
  114. _child_spec = ResponseType
  115. class PreferredSignatureAlgorithm(Sequence):
  116. _fields = [
  117. ('sig_identifier', SignedDigestAlgorithm),
  118. ('cert_identifier', PublicKeyAlgorithm, {'optional': True}),
  119. ]
  120. class PreferredSignatureAlgorithms(SequenceOf):
  121. _child_spec = PreferredSignatureAlgorithm
  122. class TBSRequestExtensionId(ObjectIdentifier):
  123. _map = {
  124. '1.3.6.1.5.5.7.48.1.2': 'nonce',
  125. '1.3.6.1.5.5.7.48.1.4': 'acceptable_responses',
  126. '1.3.6.1.5.5.7.48.1.8': 'preferred_signature_algorithms',
  127. }
  128. class TBSRequestExtension(Sequence):
  129. _fields = [
  130. ('extn_id', TBSRequestExtensionId),
  131. ('critical', Boolean, {'default': False}),
  132. ('extn_value', ParsableOctetString),
  133. ]
  134. _oid_pair = ('extn_id', 'extn_value')
  135. _oid_specs = {
  136. 'nonce': OctetString,
  137. 'acceptable_responses': AcceptableResponses,
  138. 'preferred_signature_algorithms': PreferredSignatureAlgorithms,
  139. }
  140. class TBSRequestExtensions(SequenceOf):
  141. _child_spec = TBSRequestExtension
  142. class TBSRequest(Sequence):
  143. _fields = [
  144. ('version', Version, {'explicit': 0, 'default': 'v1'}),
  145. ('requestor_name', GeneralName, {'explicit': 1, 'optional': True}),
  146. ('request_list', Requests),
  147. ('request_extensions', TBSRequestExtensions, {'explicit': 2, 'optional': True}),
  148. ]
  149. class Certificates(SequenceOf):
  150. _child_spec = Certificate
  151. class Signature(Sequence):
  152. _fields = [
  153. ('signature_algorithm', SignedDigestAlgorithm),
  154. ('signature', OctetBitString),
  155. ('certs', Certificates, {'explicit': 0, 'optional': True}),
  156. ]
  157. class OCSPRequest(Sequence):
  158. _fields = [
  159. ('tbs_request', TBSRequest),
  160. ('optional_signature', Signature, {'explicit': 0, 'optional': True}),
  161. ]
  162. _processed_extensions = False
  163. _critical_extensions = None
  164. _nonce_value = None
  165. _acceptable_responses_value = None
  166. _preferred_signature_algorithms_value = None
  167. def _set_extensions(self):
  168. """
  169. Sets common named extensions to private attributes and creates a list
  170. of critical extensions
  171. """
  172. self._critical_extensions = set()
  173. for extension in self['tbs_request']['request_extensions']:
  174. name = extension['extn_id'].native
  175. attribute_name = '_%s_value' % name
  176. if hasattr(self, attribute_name):
  177. setattr(self, attribute_name, extension['extn_value'].parsed)
  178. if extension['critical'].native:
  179. self._critical_extensions.add(name)
  180. self._processed_extensions = True
  181. @property
  182. def critical_extensions(self):
  183. """
  184. Returns a set of the names (or OID if not a known extension) of the
  185. extensions marked as critical
  186. :return:
  187. A set of unicode strings
  188. """
  189. if not self._processed_extensions:
  190. self._set_extensions()
  191. return self._critical_extensions
  192. @property
  193. def nonce_value(self):
  194. """
  195. This extension is used to prevent replay attacks by including a unique,
  196. random value with each request/response pair
  197. :return:
  198. None or an OctetString object
  199. """
  200. if self._processed_extensions is False:
  201. self._set_extensions()
  202. return self._nonce_value
  203. @property
  204. def acceptable_responses_value(self):
  205. """
  206. This extension is used to allow the client and server to communicate
  207. with alternative response formats other than just basic_ocsp_response,
  208. although no other formats are defined in the standard.
  209. :return:
  210. None or an AcceptableResponses object
  211. """
  212. if self._processed_extensions is False:
  213. self._set_extensions()
  214. return self._acceptable_responses_value
  215. @property
  216. def preferred_signature_algorithms_value(self):
  217. """
  218. This extension is used by the client to define what signature algorithms
  219. are preferred, including both the hash algorithm and the public key
  220. algorithm, with a level of detail down to even the public key algorithm
  221. parameters, such as curve name.
  222. :return:
  223. None or a PreferredSignatureAlgorithms object
  224. """
  225. if self._processed_extensions is False:
  226. self._set_extensions()
  227. return self._preferred_signature_algorithms_value
  228. class OCSPResponseStatus(Enumerated):
  229. _map = {
  230. 0: 'successful',
  231. 1: 'malformed_request',
  232. 2: 'internal_error',
  233. 3: 'try_later',
  234. 5: 'sign_required',
  235. 6: 'unauthorized',
  236. }
  237. class ResponderId(Choice):
  238. _alternatives = [
  239. ('by_name', Name, {'explicit': 1}),
  240. ('by_key', OctetString, {'explicit': 2}),
  241. ]
  242. # Custom class to return a meaningful .native attribute from CertStatus()
  243. class StatusGood(Null):
  244. def set(self, value):
  245. """
  246. Sets the value of the object
  247. :param value:
  248. None or 'good'
  249. """
  250. if value is not None and value != 'good' and not isinstance(value, Null):
  251. raise ValueError(unwrap(
  252. '''
  253. value must be one of None, "good", not %s
  254. ''',
  255. repr(value)
  256. ))
  257. self.contents = b''
  258. @property
  259. def native(self):
  260. return 'good'
  261. # Custom class to return a meaningful .native attribute from CertStatus()
  262. class StatusUnknown(Null):
  263. def set(self, value):
  264. """
  265. Sets the value of the object
  266. :param value:
  267. None or 'unknown'
  268. """
  269. if value is not None and value != 'unknown' and not isinstance(value, Null):
  270. raise ValueError(unwrap(
  271. '''
  272. value must be one of None, "unknown", not %s
  273. ''',
  274. repr(value)
  275. ))
  276. self.contents = b''
  277. @property
  278. def native(self):
  279. return 'unknown'
  280. class RevokedInfo(Sequence):
  281. _fields = [
  282. ('revocation_time', GeneralizedTime),
  283. ('revocation_reason', CRLReason, {'explicit': 0, 'optional': True}),
  284. ]
  285. class CertStatus(Choice):
  286. _alternatives = [
  287. ('good', StatusGood, {'implicit': 0}),
  288. ('revoked', RevokedInfo, {'implicit': 1}),
  289. ('unknown', StatusUnknown, {'implicit': 2}),
  290. ]
  291. class CrlId(Sequence):
  292. _fields = [
  293. ('crl_url', IA5String, {'explicit': 0, 'optional': True}),
  294. ('crl_num', Integer, {'explicit': 1, 'optional': True}),
  295. ('crl_time', GeneralizedTime, {'explicit': 2, 'optional': True}),
  296. ]
  297. class SingleResponseExtensionId(ObjectIdentifier):
  298. _map = {
  299. '1.3.6.1.5.5.7.48.1.3': 'crl',
  300. '1.3.6.1.5.5.7.48.1.6': 'archive_cutoff',
  301. # These are CRLEntryExtension values from
  302. # https://tools.ietf.org/html/rfc5280
  303. '2.5.29.21': 'crl_reason',
  304. '2.5.29.24': 'invalidity_date',
  305. '2.5.29.29': 'certificate_issuer',
  306. # https://tools.ietf.org/html/rfc6962.html#page-13
  307. '1.3.6.1.4.1.11129.2.4.5': 'signed_certificate_timestamp_list',
  308. }
  309. class SingleResponseExtension(Sequence):
  310. _fields = [
  311. ('extn_id', SingleResponseExtensionId),
  312. ('critical', Boolean, {'default': False}),
  313. ('extn_value', ParsableOctetString),
  314. ]
  315. _oid_pair = ('extn_id', 'extn_value')
  316. _oid_specs = {
  317. 'crl': CrlId,
  318. 'archive_cutoff': GeneralizedTime,
  319. 'crl_reason': CRLReason,
  320. 'invalidity_date': GeneralizedTime,
  321. 'certificate_issuer': GeneralNames,
  322. 'signed_certificate_timestamp_list': OctetString,
  323. }
  324. class SingleResponseExtensions(SequenceOf):
  325. _child_spec = SingleResponseExtension
  326. class SingleResponse(Sequence):
  327. _fields = [
  328. ('cert_id', CertId),
  329. ('cert_status', CertStatus),
  330. ('this_update', GeneralizedTime),
  331. ('next_update', GeneralizedTime, {'explicit': 0, 'optional': True}),
  332. ('single_extensions', SingleResponseExtensions, {'explicit': 1, 'optional': True}),
  333. ]
  334. _processed_extensions = False
  335. _critical_extensions = None
  336. _crl_value = None
  337. _archive_cutoff_value = None
  338. _crl_reason_value = None
  339. _invalidity_date_value = None
  340. _certificate_issuer_value = None
  341. def _set_extensions(self):
  342. """
  343. Sets common named extensions to private attributes and creates a list
  344. of critical extensions
  345. """
  346. self._critical_extensions = set()
  347. for extension in self['single_extensions']:
  348. name = extension['extn_id'].native
  349. attribute_name = '_%s_value' % name
  350. if hasattr(self, attribute_name):
  351. setattr(self, attribute_name, extension['extn_value'].parsed)
  352. if extension['critical'].native:
  353. self._critical_extensions.add(name)
  354. self._processed_extensions = True
  355. @property
  356. def critical_extensions(self):
  357. """
  358. Returns a set of the names (or OID if not a known extension) of the
  359. extensions marked as critical
  360. :return:
  361. A set of unicode strings
  362. """
  363. if not self._processed_extensions:
  364. self._set_extensions()
  365. return self._critical_extensions
  366. @property
  367. def crl_value(self):
  368. """
  369. This extension is used to locate the CRL that a certificate's revocation
  370. is contained within.
  371. :return:
  372. None or a CrlId object
  373. """
  374. if self._processed_extensions is False:
  375. self._set_extensions()
  376. return self._crl_value
  377. @property
  378. def archive_cutoff_value(self):
  379. """
  380. This extension is used to indicate the date at which an archived
  381. (historical) certificate status entry will no longer be available.
  382. :return:
  383. None or a GeneralizedTime object
  384. """
  385. if self._processed_extensions is False:
  386. self._set_extensions()
  387. return self._archive_cutoff_value
  388. @property
  389. def crl_reason_value(self):
  390. """
  391. This extension indicates the reason that a certificate was revoked.
  392. :return:
  393. None or a CRLReason object
  394. """
  395. if self._processed_extensions is False:
  396. self._set_extensions()
  397. return self._crl_reason_value
  398. @property
  399. def invalidity_date_value(self):
  400. """
  401. This extension indicates the suspected date/time the private key was
  402. compromised or the certificate became invalid. This would usually be
  403. before the revocation date, which is when the CA processed the
  404. revocation.
  405. :return:
  406. None or a GeneralizedTime object
  407. """
  408. if self._processed_extensions is False:
  409. self._set_extensions()
  410. return self._invalidity_date_value
  411. @property
  412. def certificate_issuer_value(self):
  413. """
  414. This extension indicates the issuer of the certificate in question.
  415. :return:
  416. None or an x509.GeneralNames object
  417. """
  418. if self._processed_extensions is False:
  419. self._set_extensions()
  420. return self._certificate_issuer_value
  421. class Responses(SequenceOf):
  422. _child_spec = SingleResponse
  423. class ResponseDataExtensionId(ObjectIdentifier):
  424. _map = {
  425. '1.3.6.1.5.5.7.48.1.2': 'nonce',
  426. '1.3.6.1.5.5.7.48.1.9': 'extended_revoke',
  427. }
  428. class ResponseDataExtension(Sequence):
  429. _fields = [
  430. ('extn_id', ResponseDataExtensionId),
  431. ('critical', Boolean, {'default': False}),
  432. ('extn_value', ParsableOctetString),
  433. ]
  434. _oid_pair = ('extn_id', 'extn_value')
  435. _oid_specs = {
  436. 'nonce': OctetString,
  437. 'extended_revoke': Null,
  438. }
  439. class ResponseDataExtensions(SequenceOf):
  440. _child_spec = ResponseDataExtension
  441. class ResponseData(Sequence):
  442. _fields = [
  443. ('version', Version, {'explicit': 0, 'default': 'v1'}),
  444. ('responder_id', ResponderId),
  445. ('produced_at', GeneralizedTime),
  446. ('responses', Responses),
  447. ('response_extensions', ResponseDataExtensions, {'explicit': 1, 'optional': True}),
  448. ]
  449. class BasicOCSPResponse(Sequence):
  450. _fields = [
  451. ('tbs_response_data', ResponseData),
  452. ('signature_algorithm', SignedDigestAlgorithm),
  453. ('signature', OctetBitString),
  454. ('certs', Certificates, {'explicit': 0, 'optional': True}),
  455. ]
  456. class ResponseBytes(Sequence):
  457. _fields = [
  458. ('response_type', ResponseType),
  459. ('response', ParsableOctetString),
  460. ]
  461. _oid_pair = ('response_type', 'response')
  462. _oid_specs = {
  463. 'basic_ocsp_response': BasicOCSPResponse,
  464. }
  465. class OCSPResponse(Sequence):
  466. _fields = [
  467. ('response_status', OCSPResponseStatus),
  468. ('response_bytes', ResponseBytes, {'explicit': 0, 'optional': True}),
  469. ]
  470. _processed_extensions = False
  471. _critical_extensions = None
  472. _nonce_value = None
  473. _extended_revoke_value = None
  474. def _set_extensions(self):
  475. """
  476. Sets common named extensions to private attributes and creates a list
  477. of critical extensions
  478. """
  479. self._critical_extensions = set()
  480. for extension in self['response_bytes']['response'].parsed['tbs_response_data']['response_extensions']:
  481. name = extension['extn_id'].native
  482. attribute_name = '_%s_value' % name
  483. if hasattr(self, attribute_name):
  484. setattr(self, attribute_name, extension['extn_value'].parsed)
  485. if extension['critical'].native:
  486. self._critical_extensions.add(name)
  487. self._processed_extensions = True
  488. @property
  489. def critical_extensions(self):
  490. """
  491. Returns a set of the names (or OID if not a known extension) of the
  492. extensions marked as critical
  493. :return:
  494. A set of unicode strings
  495. """
  496. if not self._processed_extensions:
  497. self._set_extensions()
  498. return self._critical_extensions
  499. @property
  500. def nonce_value(self):
  501. """
  502. This extension is used to prevent replay attacks on the request/response
  503. exchange
  504. :return:
  505. None or an OctetString object
  506. """
  507. if self._processed_extensions is False:
  508. self._set_extensions()
  509. return self._nonce_value
  510. @property
  511. def extended_revoke_value(self):
  512. """
  513. This extension is used to signal that the responder will return a
  514. "revoked" status for non-issued certificates.
  515. :return:
  516. None or a Null object (if present)
  517. """
  518. if self._processed_extensions is False:
  519. self._set_extensions()
  520. return self._extended_revoke_value
  521. @property
  522. def basic_ocsp_response(self):
  523. """
  524. A shortcut into the BasicOCSPResponse sequence
  525. :return:
  526. None or an asn1crypto.ocsp.BasicOCSPResponse object
  527. """
  528. return self['response_bytes']['response'].parsed
  529. @property
  530. def response_data(self):
  531. """
  532. A shortcut into the parsed, ResponseData sequence
  533. :return:
  534. None or an asn1crypto.ocsp.ResponseData object
  535. """
  536. return self['response_bytes']['response'].parsed['tbs_response_data']