您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

2529 行
76 KiB

  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. from __future__ import annotations
  5. import abc
  6. import datetime
  7. import hashlib
  8. import ipaddress
  9. import typing
  10. from collections.abc import Iterable, Iterator
  11. from cryptography import utils
  12. from cryptography.hazmat.bindings._rust import asn1
  13. from cryptography.hazmat.bindings._rust import x509 as rust_x509
  14. from cryptography.hazmat.primitives import constant_time, serialization
  15. from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
  16. from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
  17. from cryptography.hazmat.primitives.asymmetric.types import (
  18. CertificateIssuerPublicKeyTypes,
  19. CertificatePublicKeyTypes,
  20. )
  21. from cryptography.x509.certificate_transparency import (
  22. SignedCertificateTimestamp,
  23. )
  24. from cryptography.x509.general_name import (
  25. DirectoryName,
  26. DNSName,
  27. GeneralName,
  28. IPAddress,
  29. OtherName,
  30. RegisteredID,
  31. RFC822Name,
  32. UniformResourceIdentifier,
  33. _IPAddressTypes,
  34. )
  35. from cryptography.x509.name import Name, RelativeDistinguishedName
  36. from cryptography.x509.oid import (
  37. CRLEntryExtensionOID,
  38. ExtensionOID,
  39. ObjectIdentifier,
  40. OCSPExtensionOID,
  41. )
  42. ExtensionTypeVar = typing.TypeVar(
  43. "ExtensionTypeVar", bound="ExtensionType", covariant=True
  44. )
  45. def _key_identifier_from_public_key(
  46. public_key: CertificatePublicKeyTypes,
  47. ) -> bytes:
  48. if isinstance(public_key, RSAPublicKey):
  49. data = public_key.public_bytes(
  50. serialization.Encoding.DER,
  51. serialization.PublicFormat.PKCS1,
  52. )
  53. elif isinstance(public_key, EllipticCurvePublicKey):
  54. data = public_key.public_bytes(
  55. serialization.Encoding.X962,
  56. serialization.PublicFormat.UncompressedPoint,
  57. )
  58. else:
  59. # This is a very slow way to do this.
  60. serialized = public_key.public_bytes(
  61. serialization.Encoding.DER,
  62. serialization.PublicFormat.SubjectPublicKeyInfo,
  63. )
  64. data = asn1.parse_spki_for_data(serialized)
  65. return hashlib.sha1(data).digest()
  66. def _make_sequence_methods(field_name: str):
  67. def len_method(self) -> int:
  68. return len(getattr(self, field_name))
  69. def iter_method(self):
  70. return iter(getattr(self, field_name))
  71. def getitem_method(self, idx):
  72. return getattr(self, field_name)[idx]
  73. return len_method, iter_method, getitem_method
  74. class DuplicateExtension(Exception):
  75. def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
  76. super().__init__(msg)
  77. self.oid = oid
  78. class ExtensionNotFound(Exception):
  79. def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
  80. super().__init__(msg)
  81. self.oid = oid
  82. class ExtensionType(metaclass=abc.ABCMeta):
  83. oid: typing.ClassVar[ObjectIdentifier]
  84. def public_bytes(self) -> bytes:
  85. """
  86. Serializes the extension type to DER.
  87. """
  88. raise NotImplementedError(
  89. f"public_bytes is not implemented for extension type {self!r}"
  90. )
  91. class Extensions:
  92. def __init__(self, extensions: Iterable[Extension[ExtensionType]]) -> None:
  93. self._extensions = list(extensions)
  94. def get_extension_for_oid(
  95. self, oid: ObjectIdentifier
  96. ) -> Extension[ExtensionType]:
  97. for ext in self:
  98. if ext.oid == oid:
  99. return ext
  100. raise ExtensionNotFound(f"No {oid} extension was found", oid)
  101. def get_extension_for_class(
  102. self, extclass: type[ExtensionTypeVar]
  103. ) -> Extension[ExtensionTypeVar]:
  104. if extclass is UnrecognizedExtension:
  105. raise TypeError(
  106. "UnrecognizedExtension can't be used with "
  107. "get_extension_for_class because more than one instance of the"
  108. " class may be present."
  109. )
  110. for ext in self:
  111. if isinstance(ext.value, extclass):
  112. return ext
  113. raise ExtensionNotFound(
  114. f"No {extclass} extension was found", extclass.oid
  115. )
  116. __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
  117. def __repr__(self) -> str:
  118. return f"<Extensions({self._extensions})>"
  119. class CRLNumber(ExtensionType):
  120. oid = ExtensionOID.CRL_NUMBER
  121. def __init__(self, crl_number: int) -> None:
  122. if not isinstance(crl_number, int):
  123. raise TypeError("crl_number must be an integer")
  124. self._crl_number = crl_number
  125. def __eq__(self, other: object) -> bool:
  126. if not isinstance(other, CRLNumber):
  127. return NotImplemented
  128. return self.crl_number == other.crl_number
  129. def __hash__(self) -> int:
  130. return hash(self.crl_number)
  131. def __repr__(self) -> str:
  132. return f"<CRLNumber({self.crl_number})>"
  133. @property
  134. def crl_number(self) -> int:
  135. return self._crl_number
  136. def public_bytes(self) -> bytes:
  137. return rust_x509.encode_extension_value(self)
  138. class AuthorityKeyIdentifier(ExtensionType):
  139. oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
  140. def __init__(
  141. self,
  142. key_identifier: bytes | None,
  143. authority_cert_issuer: Iterable[GeneralName] | None,
  144. authority_cert_serial_number: int | None,
  145. ) -> None:
  146. if (authority_cert_issuer is None) != (
  147. authority_cert_serial_number is None
  148. ):
  149. raise ValueError(
  150. "authority_cert_issuer and authority_cert_serial_number "
  151. "must both be present or both None"
  152. )
  153. if authority_cert_issuer is not None:
  154. authority_cert_issuer = list(authority_cert_issuer)
  155. if not all(
  156. isinstance(x, GeneralName) for x in authority_cert_issuer
  157. ):
  158. raise TypeError(
  159. "authority_cert_issuer must be a list of GeneralName "
  160. "objects"
  161. )
  162. if authority_cert_serial_number is not None and not isinstance(
  163. authority_cert_serial_number, int
  164. ):
  165. raise TypeError("authority_cert_serial_number must be an integer")
  166. self._key_identifier = key_identifier
  167. self._authority_cert_issuer = authority_cert_issuer
  168. self._authority_cert_serial_number = authority_cert_serial_number
  169. # This takes a subset of CertificatePublicKeyTypes because an issuer
  170. # cannot have an X25519/X448 key. This introduces some unfortunate
  171. # asymmetry that requires typing users to explicitly
  172. # narrow their type, but we should make this accurate and not just
  173. # convenient.
  174. @classmethod
  175. def from_issuer_public_key(
  176. cls, public_key: CertificateIssuerPublicKeyTypes
  177. ) -> AuthorityKeyIdentifier:
  178. digest = _key_identifier_from_public_key(public_key)
  179. return cls(
  180. key_identifier=digest,
  181. authority_cert_issuer=None,
  182. authority_cert_serial_number=None,
  183. )
  184. @classmethod
  185. def from_issuer_subject_key_identifier(
  186. cls, ski: SubjectKeyIdentifier
  187. ) -> AuthorityKeyIdentifier:
  188. return cls(
  189. key_identifier=ski.digest,
  190. authority_cert_issuer=None,
  191. authority_cert_serial_number=None,
  192. )
  193. def __repr__(self) -> str:
  194. return (
  195. f"<AuthorityKeyIdentifier(key_identifier={self.key_identifier!r}, "
  196. f"authority_cert_issuer={self.authority_cert_issuer}, "
  197. f"authority_cert_serial_number={self.authority_cert_serial_number}"
  198. ")>"
  199. )
  200. def __eq__(self, other: object) -> bool:
  201. if not isinstance(other, AuthorityKeyIdentifier):
  202. return NotImplemented
  203. return (
  204. self.key_identifier == other.key_identifier
  205. and self.authority_cert_issuer == other.authority_cert_issuer
  206. and self.authority_cert_serial_number
  207. == other.authority_cert_serial_number
  208. )
  209. def __hash__(self) -> int:
  210. if self.authority_cert_issuer is None:
  211. aci = None
  212. else:
  213. aci = tuple(self.authority_cert_issuer)
  214. return hash(
  215. (self.key_identifier, aci, self.authority_cert_serial_number)
  216. )
  217. @property
  218. def key_identifier(self) -> bytes | None:
  219. return self._key_identifier
  220. @property
  221. def authority_cert_issuer(
  222. self,
  223. ) -> list[GeneralName] | None:
  224. return self._authority_cert_issuer
  225. @property
  226. def authority_cert_serial_number(self) -> int | None:
  227. return self._authority_cert_serial_number
  228. def public_bytes(self) -> bytes:
  229. return rust_x509.encode_extension_value(self)
  230. class SubjectKeyIdentifier(ExtensionType):
  231. oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
  232. def __init__(self, digest: bytes) -> None:
  233. self._digest = digest
  234. @classmethod
  235. def from_public_key(
  236. cls, public_key: CertificatePublicKeyTypes
  237. ) -> SubjectKeyIdentifier:
  238. return cls(_key_identifier_from_public_key(public_key))
  239. @property
  240. def digest(self) -> bytes:
  241. return self._digest
  242. @property
  243. def key_identifier(self) -> bytes:
  244. return self._digest
  245. def __repr__(self) -> str:
  246. return f"<SubjectKeyIdentifier(digest={self.digest!r})>"
  247. def __eq__(self, other: object) -> bool:
  248. if not isinstance(other, SubjectKeyIdentifier):
  249. return NotImplemented
  250. return constant_time.bytes_eq(self.digest, other.digest)
  251. def __hash__(self) -> int:
  252. return hash(self.digest)
  253. def public_bytes(self) -> bytes:
  254. return rust_x509.encode_extension_value(self)
  255. class AuthorityInformationAccess(ExtensionType):
  256. oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
  257. def __init__(self, descriptions: Iterable[AccessDescription]) -> None:
  258. descriptions = list(descriptions)
  259. if not all(isinstance(x, AccessDescription) for x in descriptions):
  260. raise TypeError(
  261. "Every item in the descriptions list must be an "
  262. "AccessDescription"
  263. )
  264. self._descriptions = descriptions
  265. __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
  266. def __repr__(self) -> str:
  267. return f"<AuthorityInformationAccess({self._descriptions})>"
  268. def __eq__(self, other: object) -> bool:
  269. if not isinstance(other, AuthorityInformationAccess):
  270. return NotImplemented
  271. return self._descriptions == other._descriptions
  272. def __hash__(self) -> int:
  273. return hash(tuple(self._descriptions))
  274. def public_bytes(self) -> bytes:
  275. return rust_x509.encode_extension_value(self)
  276. class SubjectInformationAccess(ExtensionType):
  277. oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS
  278. def __init__(self, descriptions: Iterable[AccessDescription]) -> None:
  279. descriptions = list(descriptions)
  280. if not all(isinstance(x, AccessDescription) for x in descriptions):
  281. raise TypeError(
  282. "Every item in the descriptions list must be an "
  283. "AccessDescription"
  284. )
  285. self._descriptions = descriptions
  286. __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
  287. def __repr__(self) -> str:
  288. return f"<SubjectInformationAccess({self._descriptions})>"
  289. def __eq__(self, other: object) -> bool:
  290. if not isinstance(other, SubjectInformationAccess):
  291. return NotImplemented
  292. return self._descriptions == other._descriptions
  293. def __hash__(self) -> int:
  294. return hash(tuple(self._descriptions))
  295. def public_bytes(self) -> bytes:
  296. return rust_x509.encode_extension_value(self)
  297. class AccessDescription:
  298. def __init__(
  299. self, access_method: ObjectIdentifier, access_location: GeneralName
  300. ) -> None:
  301. if not isinstance(access_method, ObjectIdentifier):
  302. raise TypeError("access_method must be an ObjectIdentifier")
  303. if not isinstance(access_location, GeneralName):
  304. raise TypeError("access_location must be a GeneralName")
  305. self._access_method = access_method
  306. self._access_location = access_location
  307. def __repr__(self) -> str:
  308. return (
  309. f"<AccessDescription(access_method={self.access_method}, "
  310. f"access_location={self.access_location})>"
  311. )
  312. def __eq__(self, other: object) -> bool:
  313. if not isinstance(other, AccessDescription):
  314. return NotImplemented
  315. return (
  316. self.access_method == other.access_method
  317. and self.access_location == other.access_location
  318. )
  319. def __hash__(self) -> int:
  320. return hash((self.access_method, self.access_location))
  321. @property
  322. def access_method(self) -> ObjectIdentifier:
  323. return self._access_method
  324. @property
  325. def access_location(self) -> GeneralName:
  326. return self._access_location
  327. class BasicConstraints(ExtensionType):
  328. oid = ExtensionOID.BASIC_CONSTRAINTS
  329. def __init__(self, ca: bool, path_length: int | None) -> None:
  330. if not isinstance(ca, bool):
  331. raise TypeError("ca must be a boolean value")
  332. if path_length is not None and not ca:
  333. raise ValueError("path_length must be None when ca is False")
  334. if path_length is not None and (
  335. not isinstance(path_length, int) or path_length < 0
  336. ):
  337. raise TypeError(
  338. "path_length must be a non-negative integer or None"
  339. )
  340. self._ca = ca
  341. self._path_length = path_length
  342. @property
  343. def ca(self) -> bool:
  344. return self._ca
  345. @property
  346. def path_length(self) -> int | None:
  347. return self._path_length
  348. def __repr__(self) -> str:
  349. return (
  350. f"<BasicConstraints(ca={self.ca}, path_length={self.path_length})>"
  351. )
  352. def __eq__(self, other: object) -> bool:
  353. if not isinstance(other, BasicConstraints):
  354. return NotImplemented
  355. return self.ca == other.ca and self.path_length == other.path_length
  356. def __hash__(self) -> int:
  357. return hash((self.ca, self.path_length))
  358. def public_bytes(self) -> bytes:
  359. return rust_x509.encode_extension_value(self)
  360. class DeltaCRLIndicator(ExtensionType):
  361. oid = ExtensionOID.DELTA_CRL_INDICATOR
  362. def __init__(self, crl_number: int) -> None:
  363. if not isinstance(crl_number, int):
  364. raise TypeError("crl_number must be an integer")
  365. self._crl_number = crl_number
  366. @property
  367. def crl_number(self) -> int:
  368. return self._crl_number
  369. def __eq__(self, other: object) -> bool:
  370. if not isinstance(other, DeltaCRLIndicator):
  371. return NotImplemented
  372. return self.crl_number == other.crl_number
  373. def __hash__(self) -> int:
  374. return hash(self.crl_number)
  375. def __repr__(self) -> str:
  376. return f"<DeltaCRLIndicator(crl_number={self.crl_number})>"
  377. def public_bytes(self) -> bytes:
  378. return rust_x509.encode_extension_value(self)
  379. class CRLDistributionPoints(ExtensionType):
  380. oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
  381. def __init__(
  382. self, distribution_points: Iterable[DistributionPoint]
  383. ) -> None:
  384. distribution_points = list(distribution_points)
  385. if not all(
  386. isinstance(x, DistributionPoint) for x in distribution_points
  387. ):
  388. raise TypeError(
  389. "distribution_points must be a list of DistributionPoint "
  390. "objects"
  391. )
  392. self._distribution_points = distribution_points
  393. __len__, __iter__, __getitem__ = _make_sequence_methods(
  394. "_distribution_points"
  395. )
  396. def __repr__(self) -> str:
  397. return f"<CRLDistributionPoints({self._distribution_points})>"
  398. def __eq__(self, other: object) -> bool:
  399. if not isinstance(other, CRLDistributionPoints):
  400. return NotImplemented
  401. return self._distribution_points == other._distribution_points
  402. def __hash__(self) -> int:
  403. return hash(tuple(self._distribution_points))
  404. def public_bytes(self) -> bytes:
  405. return rust_x509.encode_extension_value(self)
  406. class FreshestCRL(ExtensionType):
  407. oid = ExtensionOID.FRESHEST_CRL
  408. def __init__(
  409. self, distribution_points: Iterable[DistributionPoint]
  410. ) -> None:
  411. distribution_points = list(distribution_points)
  412. if not all(
  413. isinstance(x, DistributionPoint) for x in distribution_points
  414. ):
  415. raise TypeError(
  416. "distribution_points must be a list of DistributionPoint "
  417. "objects"
  418. )
  419. self._distribution_points = distribution_points
  420. __len__, __iter__, __getitem__ = _make_sequence_methods(
  421. "_distribution_points"
  422. )
  423. def __repr__(self) -> str:
  424. return f"<FreshestCRL({self._distribution_points})>"
  425. def __eq__(self, other: object) -> bool:
  426. if not isinstance(other, FreshestCRL):
  427. return NotImplemented
  428. return self._distribution_points == other._distribution_points
  429. def __hash__(self) -> int:
  430. return hash(tuple(self._distribution_points))
  431. def public_bytes(self) -> bytes:
  432. return rust_x509.encode_extension_value(self)
  433. class DistributionPoint:
  434. def __init__(
  435. self,
  436. full_name: Iterable[GeneralName] | None,
  437. relative_name: RelativeDistinguishedName | None,
  438. reasons: frozenset[ReasonFlags] | None,
  439. crl_issuer: Iterable[GeneralName] | None,
  440. ) -> None:
  441. if full_name and relative_name:
  442. raise ValueError(
  443. "You cannot provide both full_name and relative_name, at "
  444. "least one must be None."
  445. )
  446. if not full_name and not relative_name and not crl_issuer:
  447. raise ValueError(
  448. "Either full_name, relative_name or crl_issuer must be "
  449. "provided."
  450. )
  451. if full_name is not None:
  452. full_name = list(full_name)
  453. if not all(isinstance(x, GeneralName) for x in full_name):
  454. raise TypeError(
  455. "full_name must be a list of GeneralName objects"
  456. )
  457. if relative_name:
  458. if not isinstance(relative_name, RelativeDistinguishedName):
  459. raise TypeError(
  460. "relative_name must be a RelativeDistinguishedName"
  461. )
  462. if crl_issuer is not None:
  463. crl_issuer = list(crl_issuer)
  464. if not all(isinstance(x, GeneralName) for x in crl_issuer):
  465. raise TypeError(
  466. "crl_issuer must be None or a list of general names"
  467. )
  468. if reasons and (
  469. not isinstance(reasons, frozenset)
  470. or not all(isinstance(x, ReasonFlags) for x in reasons)
  471. ):
  472. raise TypeError("reasons must be None or frozenset of ReasonFlags")
  473. if reasons and (
  474. ReasonFlags.unspecified in reasons
  475. or ReasonFlags.remove_from_crl in reasons
  476. ):
  477. raise ValueError(
  478. "unspecified and remove_from_crl are not valid reasons in a "
  479. "DistributionPoint"
  480. )
  481. self._full_name = full_name
  482. self._relative_name = relative_name
  483. self._reasons = reasons
  484. self._crl_issuer = crl_issuer
  485. def __repr__(self) -> str:
  486. return (
  487. "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
  488. "tive_name}, reasons={0.reasons}, "
  489. "crl_issuer={0.crl_issuer})>".format(self)
  490. )
  491. def __eq__(self, other: object) -> bool:
  492. if not isinstance(other, DistributionPoint):
  493. return NotImplemented
  494. return (
  495. self.full_name == other.full_name
  496. and self.relative_name == other.relative_name
  497. and self.reasons == other.reasons
  498. and self.crl_issuer == other.crl_issuer
  499. )
  500. def __hash__(self) -> int:
  501. if self.full_name is not None:
  502. fn: tuple[GeneralName, ...] | None = tuple(self.full_name)
  503. else:
  504. fn = None
  505. if self.crl_issuer is not None:
  506. crl_issuer: tuple[GeneralName, ...] | None = tuple(self.crl_issuer)
  507. else:
  508. crl_issuer = None
  509. return hash((fn, self.relative_name, self.reasons, crl_issuer))
  510. @property
  511. def full_name(self) -> list[GeneralName] | None:
  512. return self._full_name
  513. @property
  514. def relative_name(self) -> RelativeDistinguishedName | None:
  515. return self._relative_name
  516. @property
  517. def reasons(self) -> frozenset[ReasonFlags] | None:
  518. return self._reasons
  519. @property
  520. def crl_issuer(self) -> list[GeneralName] | None:
  521. return self._crl_issuer
  522. class ReasonFlags(utils.Enum):
  523. unspecified = "unspecified"
  524. key_compromise = "keyCompromise"
  525. ca_compromise = "cACompromise"
  526. affiliation_changed = "affiliationChanged"
  527. superseded = "superseded"
  528. cessation_of_operation = "cessationOfOperation"
  529. certificate_hold = "certificateHold"
  530. privilege_withdrawn = "privilegeWithdrawn"
  531. aa_compromise = "aACompromise"
  532. remove_from_crl = "removeFromCRL"
  533. # These are distribution point bit string mappings. Not to be confused with
  534. # CRLReason reason flags bit string mappings.
  535. # ReasonFlags ::= BIT STRING {
  536. # unused (0),
  537. # keyCompromise (1),
  538. # cACompromise (2),
  539. # affiliationChanged (3),
  540. # superseded (4),
  541. # cessationOfOperation (5),
  542. # certificateHold (6),
  543. # privilegeWithdrawn (7),
  544. # aACompromise (8) }
  545. _REASON_BIT_MAPPING = {
  546. 1: ReasonFlags.key_compromise,
  547. 2: ReasonFlags.ca_compromise,
  548. 3: ReasonFlags.affiliation_changed,
  549. 4: ReasonFlags.superseded,
  550. 5: ReasonFlags.cessation_of_operation,
  551. 6: ReasonFlags.certificate_hold,
  552. 7: ReasonFlags.privilege_withdrawn,
  553. 8: ReasonFlags.aa_compromise,
  554. }
  555. _CRLREASONFLAGS = {
  556. ReasonFlags.key_compromise: 1,
  557. ReasonFlags.ca_compromise: 2,
  558. ReasonFlags.affiliation_changed: 3,
  559. ReasonFlags.superseded: 4,
  560. ReasonFlags.cessation_of_operation: 5,
  561. ReasonFlags.certificate_hold: 6,
  562. ReasonFlags.privilege_withdrawn: 7,
  563. ReasonFlags.aa_compromise: 8,
  564. }
  565. # CRLReason ::= ENUMERATED {
  566. # unspecified (0),
  567. # keyCompromise (1),
  568. # cACompromise (2),
  569. # affiliationChanged (3),
  570. # superseded (4),
  571. # cessationOfOperation (5),
  572. # certificateHold (6),
  573. # -- value 7 is not used
  574. # removeFromCRL (8),
  575. # privilegeWithdrawn (9),
  576. # aACompromise (10) }
  577. _CRL_ENTRY_REASON_ENUM_TO_CODE = {
  578. ReasonFlags.unspecified: 0,
  579. ReasonFlags.key_compromise: 1,
  580. ReasonFlags.ca_compromise: 2,
  581. ReasonFlags.affiliation_changed: 3,
  582. ReasonFlags.superseded: 4,
  583. ReasonFlags.cessation_of_operation: 5,
  584. ReasonFlags.certificate_hold: 6,
  585. ReasonFlags.remove_from_crl: 8,
  586. ReasonFlags.privilege_withdrawn: 9,
  587. ReasonFlags.aa_compromise: 10,
  588. }
  589. class PolicyConstraints(ExtensionType):
  590. oid = ExtensionOID.POLICY_CONSTRAINTS
  591. def __init__(
  592. self,
  593. require_explicit_policy: int | None,
  594. inhibit_policy_mapping: int | None,
  595. ) -> None:
  596. if require_explicit_policy is not None and not isinstance(
  597. require_explicit_policy, int
  598. ):
  599. raise TypeError(
  600. "require_explicit_policy must be a non-negative integer or "
  601. "None"
  602. )
  603. if inhibit_policy_mapping is not None and not isinstance(
  604. inhibit_policy_mapping, int
  605. ):
  606. raise TypeError(
  607. "inhibit_policy_mapping must be a non-negative integer or None"
  608. )
  609. if inhibit_policy_mapping is None and require_explicit_policy is None:
  610. raise ValueError(
  611. "At least one of require_explicit_policy and "
  612. "inhibit_policy_mapping must not be None"
  613. )
  614. self._require_explicit_policy = require_explicit_policy
  615. self._inhibit_policy_mapping = inhibit_policy_mapping
  616. def __repr__(self) -> str:
  617. return (
  618. "<PolicyConstraints(require_explicit_policy={0.require_explicit"
  619. "_policy}, inhibit_policy_mapping={0.inhibit_policy_"
  620. "mapping})>".format(self)
  621. )
  622. def __eq__(self, other: object) -> bool:
  623. if not isinstance(other, PolicyConstraints):
  624. return NotImplemented
  625. return (
  626. self.require_explicit_policy == other.require_explicit_policy
  627. and self.inhibit_policy_mapping == other.inhibit_policy_mapping
  628. )
  629. def __hash__(self) -> int:
  630. return hash(
  631. (self.require_explicit_policy, self.inhibit_policy_mapping)
  632. )
  633. @property
  634. def require_explicit_policy(self) -> int | None:
  635. return self._require_explicit_policy
  636. @property
  637. def inhibit_policy_mapping(self) -> int | None:
  638. return self._inhibit_policy_mapping
  639. def public_bytes(self) -> bytes:
  640. return rust_x509.encode_extension_value(self)
  641. class CertificatePolicies(ExtensionType):
  642. oid = ExtensionOID.CERTIFICATE_POLICIES
  643. def __init__(self, policies: Iterable[PolicyInformation]) -> None:
  644. policies = list(policies)
  645. if not all(isinstance(x, PolicyInformation) for x in policies):
  646. raise TypeError(
  647. "Every item in the policies list must be a PolicyInformation"
  648. )
  649. self._policies = policies
  650. __len__, __iter__, __getitem__ = _make_sequence_methods("_policies")
  651. def __repr__(self) -> str:
  652. return f"<CertificatePolicies({self._policies})>"
  653. def __eq__(self, other: object) -> bool:
  654. if not isinstance(other, CertificatePolicies):
  655. return NotImplemented
  656. return self._policies == other._policies
  657. def __hash__(self) -> int:
  658. return hash(tuple(self._policies))
  659. def public_bytes(self) -> bytes:
  660. return rust_x509.encode_extension_value(self)
  661. class PolicyInformation:
  662. def __init__(
  663. self,
  664. policy_identifier: ObjectIdentifier,
  665. policy_qualifiers: Iterable[str | UserNotice] | None,
  666. ) -> None:
  667. if not isinstance(policy_identifier, ObjectIdentifier):
  668. raise TypeError("policy_identifier must be an ObjectIdentifier")
  669. self._policy_identifier = policy_identifier
  670. if policy_qualifiers is not None:
  671. policy_qualifiers = list(policy_qualifiers)
  672. if not all(
  673. isinstance(x, (str, UserNotice)) for x in policy_qualifiers
  674. ):
  675. raise TypeError(
  676. "policy_qualifiers must be a list of strings and/or "
  677. "UserNotice objects or None"
  678. )
  679. self._policy_qualifiers = policy_qualifiers
  680. def __repr__(self) -> str:
  681. return (
  682. f"<PolicyInformation(policy_identifier={self.policy_identifier}, "
  683. f"policy_qualifiers={self.policy_qualifiers})>"
  684. )
  685. def __eq__(self, other: object) -> bool:
  686. if not isinstance(other, PolicyInformation):
  687. return NotImplemented
  688. return (
  689. self.policy_identifier == other.policy_identifier
  690. and self.policy_qualifiers == other.policy_qualifiers
  691. )
  692. def __hash__(self) -> int:
  693. if self.policy_qualifiers is not None:
  694. pq = tuple(self.policy_qualifiers)
  695. else:
  696. pq = None
  697. return hash((self.policy_identifier, pq))
  698. @property
  699. def policy_identifier(self) -> ObjectIdentifier:
  700. return self._policy_identifier
  701. @property
  702. def policy_qualifiers(
  703. self,
  704. ) -> list[str | UserNotice] | None:
  705. return self._policy_qualifiers
  706. class UserNotice:
  707. def __init__(
  708. self,
  709. notice_reference: NoticeReference | None,
  710. explicit_text: str | None,
  711. ) -> None:
  712. if notice_reference and not isinstance(
  713. notice_reference, NoticeReference
  714. ):
  715. raise TypeError(
  716. "notice_reference must be None or a NoticeReference"
  717. )
  718. self._notice_reference = notice_reference
  719. self._explicit_text = explicit_text
  720. def __repr__(self) -> str:
  721. return (
  722. f"<UserNotice(notice_reference={self.notice_reference}, "
  723. f"explicit_text={self.explicit_text!r})>"
  724. )
  725. def __eq__(self, other: object) -> bool:
  726. if not isinstance(other, UserNotice):
  727. return NotImplemented
  728. return (
  729. self.notice_reference == other.notice_reference
  730. and self.explicit_text == other.explicit_text
  731. )
  732. def __hash__(self) -> int:
  733. return hash((self.notice_reference, self.explicit_text))
  734. @property
  735. def notice_reference(self) -> NoticeReference | None:
  736. return self._notice_reference
  737. @property
  738. def explicit_text(self) -> str | None:
  739. return self._explicit_text
  740. class NoticeReference:
  741. def __init__(
  742. self,
  743. organization: str | None,
  744. notice_numbers: Iterable[int],
  745. ) -> None:
  746. self._organization = organization
  747. notice_numbers = list(notice_numbers)
  748. if not all(isinstance(x, int) for x in notice_numbers):
  749. raise TypeError("notice_numbers must be a list of integers")
  750. self._notice_numbers = notice_numbers
  751. def __repr__(self) -> str:
  752. return (
  753. f"<NoticeReference(organization={self.organization!r}, "
  754. f"notice_numbers={self.notice_numbers})>"
  755. )
  756. def __eq__(self, other: object) -> bool:
  757. if not isinstance(other, NoticeReference):
  758. return NotImplemented
  759. return (
  760. self.organization == other.organization
  761. and self.notice_numbers == other.notice_numbers
  762. )
  763. def __hash__(self) -> int:
  764. return hash((self.organization, tuple(self.notice_numbers)))
  765. @property
  766. def organization(self) -> str | None:
  767. return self._organization
  768. @property
  769. def notice_numbers(self) -> list[int]:
  770. return self._notice_numbers
  771. class ExtendedKeyUsage(ExtensionType):
  772. oid = ExtensionOID.EXTENDED_KEY_USAGE
  773. def __init__(self, usages: Iterable[ObjectIdentifier]) -> None:
  774. usages = list(usages)
  775. if not all(isinstance(x, ObjectIdentifier) for x in usages):
  776. raise TypeError(
  777. "Every item in the usages list must be an ObjectIdentifier"
  778. )
  779. self._usages = usages
  780. __len__, __iter__, __getitem__ = _make_sequence_methods("_usages")
  781. def __repr__(self) -> str:
  782. return f"<ExtendedKeyUsage({self._usages})>"
  783. def __eq__(self, other: object) -> bool:
  784. if not isinstance(other, ExtendedKeyUsage):
  785. return NotImplemented
  786. return self._usages == other._usages
  787. def __hash__(self) -> int:
  788. return hash(tuple(self._usages))
  789. def public_bytes(self) -> bytes:
  790. return rust_x509.encode_extension_value(self)
  791. class OCSPNoCheck(ExtensionType):
  792. oid = ExtensionOID.OCSP_NO_CHECK
  793. def __eq__(self, other: object) -> bool:
  794. if not isinstance(other, OCSPNoCheck):
  795. return NotImplemented
  796. return True
  797. def __hash__(self) -> int:
  798. return hash(OCSPNoCheck)
  799. def __repr__(self) -> str:
  800. return "<OCSPNoCheck()>"
  801. def public_bytes(self) -> bytes:
  802. return rust_x509.encode_extension_value(self)
  803. class PrecertPoison(ExtensionType):
  804. oid = ExtensionOID.PRECERT_POISON
  805. def __eq__(self, other: object) -> bool:
  806. if not isinstance(other, PrecertPoison):
  807. return NotImplemented
  808. return True
  809. def __hash__(self) -> int:
  810. return hash(PrecertPoison)
  811. def __repr__(self) -> str:
  812. return "<PrecertPoison()>"
  813. def public_bytes(self) -> bytes:
  814. return rust_x509.encode_extension_value(self)
  815. class TLSFeature(ExtensionType):
  816. oid = ExtensionOID.TLS_FEATURE
  817. def __init__(self, features: Iterable[TLSFeatureType]) -> None:
  818. features = list(features)
  819. if (
  820. not all(isinstance(x, TLSFeatureType) for x in features)
  821. or len(features) == 0
  822. ):
  823. raise TypeError(
  824. "features must be a list of elements from the TLSFeatureType "
  825. "enum"
  826. )
  827. self._features = features
  828. __len__, __iter__, __getitem__ = _make_sequence_methods("_features")
  829. def __repr__(self) -> str:
  830. return f"<TLSFeature(features={self._features})>"
  831. def __eq__(self, other: object) -> bool:
  832. if not isinstance(other, TLSFeature):
  833. return NotImplemented
  834. return self._features == other._features
  835. def __hash__(self) -> int:
  836. return hash(tuple(self._features))
  837. def public_bytes(self) -> bytes:
  838. return rust_x509.encode_extension_value(self)
  839. class TLSFeatureType(utils.Enum):
  840. # status_request is defined in RFC 6066 and is used for what is commonly
  841. # called OCSP Must-Staple when present in the TLS Feature extension in an
  842. # X.509 certificate.
  843. status_request = 5
  844. # status_request_v2 is defined in RFC 6961 and allows multiple OCSP
  845. # responses to be provided. It is not currently in use by clients or
  846. # servers.
  847. status_request_v2 = 17
  848. _TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType}
  849. class InhibitAnyPolicy(ExtensionType):
  850. oid = ExtensionOID.INHIBIT_ANY_POLICY
  851. def __init__(self, skip_certs: int) -> None:
  852. if not isinstance(skip_certs, int):
  853. raise TypeError("skip_certs must be an integer")
  854. if skip_certs < 0:
  855. raise ValueError("skip_certs must be a non-negative integer")
  856. self._skip_certs = skip_certs
  857. def __repr__(self) -> str:
  858. return f"<InhibitAnyPolicy(skip_certs={self.skip_certs})>"
  859. def __eq__(self, other: object) -> bool:
  860. if not isinstance(other, InhibitAnyPolicy):
  861. return NotImplemented
  862. return self.skip_certs == other.skip_certs
  863. def __hash__(self) -> int:
  864. return hash(self.skip_certs)
  865. @property
  866. def skip_certs(self) -> int:
  867. return self._skip_certs
  868. def public_bytes(self) -> bytes:
  869. return rust_x509.encode_extension_value(self)
  870. class KeyUsage(ExtensionType):
  871. oid = ExtensionOID.KEY_USAGE
  872. def __init__(
  873. self,
  874. digital_signature: bool,
  875. content_commitment: bool,
  876. key_encipherment: bool,
  877. data_encipherment: bool,
  878. key_agreement: bool,
  879. key_cert_sign: bool,
  880. crl_sign: bool,
  881. encipher_only: bool,
  882. decipher_only: bool,
  883. ) -> None:
  884. if not key_agreement and (encipher_only or decipher_only):
  885. raise ValueError(
  886. "encipher_only and decipher_only can only be true when "
  887. "key_agreement is true"
  888. )
  889. self._digital_signature = digital_signature
  890. self._content_commitment = content_commitment
  891. self._key_encipherment = key_encipherment
  892. self._data_encipherment = data_encipherment
  893. self._key_agreement = key_agreement
  894. self._key_cert_sign = key_cert_sign
  895. self._crl_sign = crl_sign
  896. self._encipher_only = encipher_only
  897. self._decipher_only = decipher_only
  898. @property
  899. def digital_signature(self) -> bool:
  900. return self._digital_signature
  901. @property
  902. def content_commitment(self) -> bool:
  903. return self._content_commitment
  904. @property
  905. def key_encipherment(self) -> bool:
  906. return self._key_encipherment
  907. @property
  908. def data_encipherment(self) -> bool:
  909. return self._data_encipherment
  910. @property
  911. def key_agreement(self) -> bool:
  912. return self._key_agreement
  913. @property
  914. def key_cert_sign(self) -> bool:
  915. return self._key_cert_sign
  916. @property
  917. def crl_sign(self) -> bool:
  918. return self._crl_sign
  919. @property
  920. def encipher_only(self) -> bool:
  921. if not self.key_agreement:
  922. raise ValueError(
  923. "encipher_only is undefined unless key_agreement is true"
  924. )
  925. else:
  926. return self._encipher_only
  927. @property
  928. def decipher_only(self) -> bool:
  929. if not self.key_agreement:
  930. raise ValueError(
  931. "decipher_only is undefined unless key_agreement is true"
  932. )
  933. else:
  934. return self._decipher_only
  935. def __repr__(self) -> str:
  936. try:
  937. encipher_only = self.encipher_only
  938. decipher_only = self.decipher_only
  939. except ValueError:
  940. # Users found None confusing because even though encipher/decipher
  941. # have no meaning unless key_agreement is true, to construct an
  942. # instance of the class you still need to pass False.
  943. encipher_only = False
  944. decipher_only = False
  945. return (
  946. f"<KeyUsage(digital_signature={self.digital_signature}, "
  947. f"content_commitment={self.content_commitment}, "
  948. f"key_encipherment={self.key_encipherment}, "
  949. f"data_encipherment={self.data_encipherment}, "
  950. f"key_agreement={self.key_agreement}, "
  951. f"key_cert_sign={self.key_cert_sign}, crl_sign={self.crl_sign}, "
  952. f"encipher_only={encipher_only}, decipher_only={decipher_only})>"
  953. )
  954. def __eq__(self, other: object) -> bool:
  955. if not isinstance(other, KeyUsage):
  956. return NotImplemented
  957. return (
  958. self.digital_signature == other.digital_signature
  959. and self.content_commitment == other.content_commitment
  960. and self.key_encipherment == other.key_encipherment
  961. and self.data_encipherment == other.data_encipherment
  962. and self.key_agreement == other.key_agreement
  963. and self.key_cert_sign == other.key_cert_sign
  964. and self.crl_sign == other.crl_sign
  965. and self._encipher_only == other._encipher_only
  966. and self._decipher_only == other._decipher_only
  967. )
  968. def __hash__(self) -> int:
  969. return hash(
  970. (
  971. self.digital_signature,
  972. self.content_commitment,
  973. self.key_encipherment,
  974. self.data_encipherment,
  975. self.key_agreement,
  976. self.key_cert_sign,
  977. self.crl_sign,
  978. self._encipher_only,
  979. self._decipher_only,
  980. )
  981. )
  982. def public_bytes(self) -> bytes:
  983. return rust_x509.encode_extension_value(self)
  984. class PrivateKeyUsagePeriod(ExtensionType):
  985. oid = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD
  986. def __init__(
  987. self,
  988. not_before: datetime.datetime | None,
  989. not_after: datetime.datetime | None,
  990. ) -> None:
  991. if (
  992. not isinstance(not_before, datetime.datetime)
  993. and not_before is not None
  994. ):
  995. raise TypeError("not_before must be a datetime.datetime or None")
  996. if (
  997. not isinstance(not_after, datetime.datetime)
  998. and not_after is not None
  999. ):
  1000. raise TypeError("not_after must be a datetime.datetime or None")
  1001. if not_before is None and not_after is None:
  1002. raise ValueError(
  1003. "At least one of not_before and not_after must not be None"
  1004. )
  1005. if (
  1006. not_before is not None
  1007. and not_after is not None
  1008. and not_before > not_after
  1009. ):
  1010. raise ValueError("not_before must be before not_after")
  1011. self._not_before = not_before
  1012. self._not_after = not_after
  1013. @property
  1014. def not_before(self) -> datetime.datetime | None:
  1015. return self._not_before
  1016. @property
  1017. def not_after(self) -> datetime.datetime | None:
  1018. return self._not_after
  1019. def __repr__(self) -> str:
  1020. return (
  1021. f"<PrivateKeyUsagePeriod(not_before={self.not_before}, "
  1022. f"not_after={self.not_after})>"
  1023. )
  1024. def __eq__(self, other: object) -> bool:
  1025. if not isinstance(other, PrivateKeyUsagePeriod):
  1026. return NotImplemented
  1027. return (
  1028. self.not_before == other.not_before
  1029. and self.not_after == other.not_after
  1030. )
  1031. def __hash__(self) -> int:
  1032. return hash((self.not_before, self.not_after))
  1033. def public_bytes(self) -> bytes:
  1034. return rust_x509.encode_extension_value(self)
  1035. class NameConstraints(ExtensionType):
  1036. oid = ExtensionOID.NAME_CONSTRAINTS
  1037. def __init__(
  1038. self,
  1039. permitted_subtrees: Iterable[GeneralName] | None,
  1040. excluded_subtrees: Iterable[GeneralName] | None,
  1041. ) -> None:
  1042. if permitted_subtrees is not None:
  1043. permitted_subtrees = list(permitted_subtrees)
  1044. if not permitted_subtrees:
  1045. raise ValueError(
  1046. "permitted_subtrees must be a non-empty list or None"
  1047. )
  1048. if not all(isinstance(x, GeneralName) for x in permitted_subtrees):
  1049. raise TypeError(
  1050. "permitted_subtrees must be a list of GeneralName objects "
  1051. "or None"
  1052. )
  1053. self._validate_tree(permitted_subtrees)
  1054. if excluded_subtrees is not None:
  1055. excluded_subtrees = list(excluded_subtrees)
  1056. if not excluded_subtrees:
  1057. raise ValueError(
  1058. "excluded_subtrees must be a non-empty list or None"
  1059. )
  1060. if not all(isinstance(x, GeneralName) for x in excluded_subtrees):
  1061. raise TypeError(
  1062. "excluded_subtrees must be a list of GeneralName objects "
  1063. "or None"
  1064. )
  1065. self._validate_tree(excluded_subtrees)
  1066. if permitted_subtrees is None and excluded_subtrees is None:
  1067. raise ValueError(
  1068. "At least one of permitted_subtrees and excluded_subtrees "
  1069. "must not be None"
  1070. )
  1071. self._permitted_subtrees = permitted_subtrees
  1072. self._excluded_subtrees = excluded_subtrees
  1073. def __eq__(self, other: object) -> bool:
  1074. if not isinstance(other, NameConstraints):
  1075. return NotImplemented
  1076. return (
  1077. self.excluded_subtrees == other.excluded_subtrees
  1078. and self.permitted_subtrees == other.permitted_subtrees
  1079. )
  1080. def _validate_tree(self, tree: Iterable[GeneralName]) -> None:
  1081. self._validate_ip_name(tree)
  1082. self._validate_dns_name(tree)
  1083. def _validate_ip_name(self, tree: Iterable[GeneralName]) -> None:
  1084. if any(
  1085. isinstance(name, IPAddress)
  1086. and not isinstance(
  1087. name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
  1088. )
  1089. for name in tree
  1090. ):
  1091. raise TypeError(
  1092. "IPAddress name constraints must be an IPv4Network or"
  1093. " IPv6Network object"
  1094. )
  1095. def _validate_dns_name(self, tree: Iterable[GeneralName]) -> None:
  1096. if any(
  1097. isinstance(name, DNSName) and "*" in name.value for name in tree
  1098. ):
  1099. raise ValueError(
  1100. "DNSName name constraints must not contain the '*' wildcard"
  1101. " character"
  1102. )
  1103. def __repr__(self) -> str:
  1104. return (
  1105. f"<NameConstraints(permitted_subtrees={self.permitted_subtrees}, "
  1106. f"excluded_subtrees={self.excluded_subtrees})>"
  1107. )
  1108. def __hash__(self) -> int:
  1109. if self.permitted_subtrees is not None:
  1110. ps: tuple[GeneralName, ...] | None = tuple(self.permitted_subtrees)
  1111. else:
  1112. ps = None
  1113. if self.excluded_subtrees is not None:
  1114. es: tuple[GeneralName, ...] | None = tuple(self.excluded_subtrees)
  1115. else:
  1116. es = None
  1117. return hash((ps, es))
  1118. @property
  1119. def permitted_subtrees(
  1120. self,
  1121. ) -> list[GeneralName] | None:
  1122. return self._permitted_subtrees
  1123. @property
  1124. def excluded_subtrees(
  1125. self,
  1126. ) -> list[GeneralName] | None:
  1127. return self._excluded_subtrees
  1128. def public_bytes(self) -> bytes:
  1129. return rust_x509.encode_extension_value(self)
  1130. class Extension(typing.Generic[ExtensionTypeVar]):
  1131. def __init__(
  1132. self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar
  1133. ) -> None:
  1134. if not isinstance(oid, ObjectIdentifier):
  1135. raise TypeError(
  1136. "oid argument must be an ObjectIdentifier instance."
  1137. )
  1138. if not isinstance(critical, bool):
  1139. raise TypeError("critical must be a boolean value")
  1140. self._oid = oid
  1141. self._critical = critical
  1142. self._value = value
  1143. @property
  1144. def oid(self) -> ObjectIdentifier:
  1145. return self._oid
  1146. @property
  1147. def critical(self) -> bool:
  1148. return self._critical
  1149. @property
  1150. def value(self) -> ExtensionTypeVar:
  1151. return self._value
  1152. def __repr__(self) -> str:
  1153. return (
  1154. f"<Extension(oid={self.oid}, critical={self.critical}, "
  1155. f"value={self.value})>"
  1156. )
  1157. def __eq__(self, other: object) -> bool:
  1158. if not isinstance(other, Extension):
  1159. return NotImplemented
  1160. return (
  1161. self.oid == other.oid
  1162. and self.critical == other.critical
  1163. and self.value == other.value
  1164. )
  1165. def __hash__(self) -> int:
  1166. return hash((self.oid, self.critical, self.value))
  1167. class GeneralNames:
  1168. def __init__(self, general_names: Iterable[GeneralName]) -> None:
  1169. general_names = list(general_names)
  1170. if not all(isinstance(x, GeneralName) for x in general_names):
  1171. raise TypeError(
  1172. "Every item in the general_names list must be an "
  1173. "object conforming to the GeneralName interface"
  1174. )
  1175. self._general_names = general_names
  1176. __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
  1177. @typing.overload
  1178. def get_values_for_type(
  1179. self,
  1180. type: type[DNSName]
  1181. | type[UniformResourceIdentifier]
  1182. | type[RFC822Name],
  1183. ) -> list[str]: ...
  1184. @typing.overload
  1185. def get_values_for_type(
  1186. self,
  1187. type: type[DirectoryName],
  1188. ) -> list[Name]: ...
  1189. @typing.overload
  1190. def get_values_for_type(
  1191. self,
  1192. type: type[RegisteredID],
  1193. ) -> list[ObjectIdentifier]: ...
  1194. @typing.overload
  1195. def get_values_for_type(
  1196. self, type: type[IPAddress]
  1197. ) -> list[_IPAddressTypes]: ...
  1198. @typing.overload
  1199. def get_values_for_type(
  1200. self, type: type[OtherName]
  1201. ) -> list[OtherName]: ...
  1202. def get_values_for_type(
  1203. self,
  1204. type: type[DNSName]
  1205. | type[DirectoryName]
  1206. | type[IPAddress]
  1207. | type[OtherName]
  1208. | type[RFC822Name]
  1209. | type[RegisteredID]
  1210. | type[UniformResourceIdentifier],
  1211. ) -> (
  1212. list[_IPAddressTypes]
  1213. | list[str]
  1214. | list[OtherName]
  1215. | list[Name]
  1216. | list[ObjectIdentifier]
  1217. ):
  1218. # Return the value of each GeneralName, except for OtherName instances
  1219. # which we return directly because it has two important properties not
  1220. # just one value.
  1221. objs = (i for i in self if isinstance(i, type))
  1222. if type != OtherName:
  1223. return [i.value for i in objs]
  1224. return list(objs)
  1225. def __repr__(self) -> str:
  1226. return f"<GeneralNames({self._general_names})>"
  1227. def __eq__(self, other: object) -> bool:
  1228. if not isinstance(other, GeneralNames):
  1229. return NotImplemented
  1230. return self._general_names == other._general_names
  1231. def __hash__(self) -> int:
  1232. return hash(tuple(self._general_names))
  1233. class SubjectAlternativeName(ExtensionType):
  1234. oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
  1235. def __init__(self, general_names: Iterable[GeneralName]) -> None:
  1236. self._general_names = GeneralNames(general_names)
  1237. __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
  1238. @typing.overload
  1239. def get_values_for_type(
  1240. self,
  1241. type: type[DNSName]
  1242. | type[UniformResourceIdentifier]
  1243. | type[RFC822Name],
  1244. ) -> list[str]: ...
  1245. @typing.overload
  1246. def get_values_for_type(
  1247. self,
  1248. type: type[DirectoryName],
  1249. ) -> list[Name]: ...
  1250. @typing.overload
  1251. def get_values_for_type(
  1252. self,
  1253. type: type[RegisteredID],
  1254. ) -> list[ObjectIdentifier]: ...
  1255. @typing.overload
  1256. def get_values_for_type(
  1257. self, type: type[IPAddress]
  1258. ) -> list[_IPAddressTypes]: ...
  1259. @typing.overload
  1260. def get_values_for_type(
  1261. self, type: type[OtherName]
  1262. ) -> list[OtherName]: ...
  1263. def get_values_for_type(
  1264. self,
  1265. type: type[DNSName]
  1266. | type[DirectoryName]
  1267. | type[IPAddress]
  1268. | type[OtherName]
  1269. | type[RFC822Name]
  1270. | type[RegisteredID]
  1271. | type[UniformResourceIdentifier],
  1272. ) -> (
  1273. list[_IPAddressTypes]
  1274. | list[str]
  1275. | list[OtherName]
  1276. | list[Name]
  1277. | list[ObjectIdentifier]
  1278. ):
  1279. return self._general_names.get_values_for_type(type)
  1280. def __repr__(self) -> str:
  1281. return f"<SubjectAlternativeName({self._general_names})>"
  1282. def __eq__(self, other: object) -> bool:
  1283. if not isinstance(other, SubjectAlternativeName):
  1284. return NotImplemented
  1285. return self._general_names == other._general_names
  1286. def __hash__(self) -> int:
  1287. return hash(self._general_names)
  1288. def public_bytes(self) -> bytes:
  1289. return rust_x509.encode_extension_value(self)
  1290. class IssuerAlternativeName(ExtensionType):
  1291. oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
  1292. def __init__(self, general_names: Iterable[GeneralName]) -> None:
  1293. self._general_names = GeneralNames(general_names)
  1294. __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
  1295. @typing.overload
  1296. def get_values_for_type(
  1297. self,
  1298. type: type[DNSName]
  1299. | type[UniformResourceIdentifier]
  1300. | type[RFC822Name],
  1301. ) -> list[str]: ...
  1302. @typing.overload
  1303. def get_values_for_type(
  1304. self,
  1305. type: type[DirectoryName],
  1306. ) -> list[Name]: ...
  1307. @typing.overload
  1308. def get_values_for_type(
  1309. self,
  1310. type: type[RegisteredID],
  1311. ) -> list[ObjectIdentifier]: ...
  1312. @typing.overload
  1313. def get_values_for_type(
  1314. self, type: type[IPAddress]
  1315. ) -> list[_IPAddressTypes]: ...
  1316. @typing.overload
  1317. def get_values_for_type(
  1318. self, type: type[OtherName]
  1319. ) -> list[OtherName]: ...
  1320. def get_values_for_type(
  1321. self,
  1322. type: type[DNSName]
  1323. | type[DirectoryName]
  1324. | type[IPAddress]
  1325. | type[OtherName]
  1326. | type[RFC822Name]
  1327. | type[RegisteredID]
  1328. | type[UniformResourceIdentifier],
  1329. ) -> (
  1330. list[_IPAddressTypes]
  1331. | list[str]
  1332. | list[OtherName]
  1333. | list[Name]
  1334. | list[ObjectIdentifier]
  1335. ):
  1336. return self._general_names.get_values_for_type(type)
  1337. def __repr__(self) -> str:
  1338. return f"<IssuerAlternativeName({self._general_names})>"
  1339. def __eq__(self, other: object) -> bool:
  1340. if not isinstance(other, IssuerAlternativeName):
  1341. return NotImplemented
  1342. return self._general_names == other._general_names
  1343. def __hash__(self) -> int:
  1344. return hash(self._general_names)
  1345. def public_bytes(self) -> bytes:
  1346. return rust_x509.encode_extension_value(self)
  1347. class CertificateIssuer(ExtensionType):
  1348. oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
  1349. def __init__(self, general_names: Iterable[GeneralName]) -> None:
  1350. self._general_names = GeneralNames(general_names)
  1351. __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
  1352. @typing.overload
  1353. def get_values_for_type(
  1354. self,
  1355. type: type[DNSName]
  1356. | type[UniformResourceIdentifier]
  1357. | type[RFC822Name],
  1358. ) -> list[str]: ...
  1359. @typing.overload
  1360. def get_values_for_type(
  1361. self,
  1362. type: type[DirectoryName],
  1363. ) -> list[Name]: ...
  1364. @typing.overload
  1365. def get_values_for_type(
  1366. self,
  1367. type: type[RegisteredID],
  1368. ) -> list[ObjectIdentifier]: ...
  1369. @typing.overload
  1370. def get_values_for_type(
  1371. self, type: type[IPAddress]
  1372. ) -> list[_IPAddressTypes]: ...
  1373. @typing.overload
  1374. def get_values_for_type(
  1375. self, type: type[OtherName]
  1376. ) -> list[OtherName]: ...
  1377. def get_values_for_type(
  1378. self,
  1379. type: type[DNSName]
  1380. | type[DirectoryName]
  1381. | type[IPAddress]
  1382. | type[OtherName]
  1383. | type[RFC822Name]
  1384. | type[RegisteredID]
  1385. | type[UniformResourceIdentifier],
  1386. ) -> (
  1387. list[_IPAddressTypes]
  1388. | list[str]
  1389. | list[OtherName]
  1390. | list[Name]
  1391. | list[ObjectIdentifier]
  1392. ):
  1393. return self._general_names.get_values_for_type(type)
  1394. def __repr__(self) -> str:
  1395. return f"<CertificateIssuer({self._general_names})>"
  1396. def __eq__(self, other: object) -> bool:
  1397. if not isinstance(other, CertificateIssuer):
  1398. return NotImplemented
  1399. return self._general_names == other._general_names
  1400. def __hash__(self) -> int:
  1401. return hash(self._general_names)
  1402. def public_bytes(self) -> bytes:
  1403. return rust_x509.encode_extension_value(self)
  1404. class CRLReason(ExtensionType):
  1405. oid = CRLEntryExtensionOID.CRL_REASON
  1406. def __init__(self, reason: ReasonFlags) -> None:
  1407. if not isinstance(reason, ReasonFlags):
  1408. raise TypeError("reason must be an element from ReasonFlags")
  1409. self._reason = reason
  1410. def __repr__(self) -> str:
  1411. return f"<CRLReason(reason={self._reason})>"
  1412. def __eq__(self, other: object) -> bool:
  1413. if not isinstance(other, CRLReason):
  1414. return NotImplemented
  1415. return self.reason == other.reason
  1416. def __hash__(self) -> int:
  1417. return hash(self.reason)
  1418. @property
  1419. def reason(self) -> ReasonFlags:
  1420. return self._reason
  1421. def public_bytes(self) -> bytes:
  1422. return rust_x509.encode_extension_value(self)
  1423. class InvalidityDate(ExtensionType):
  1424. oid = CRLEntryExtensionOID.INVALIDITY_DATE
  1425. def __init__(self, invalidity_date: datetime.datetime) -> None:
  1426. if not isinstance(invalidity_date, datetime.datetime):
  1427. raise TypeError("invalidity_date must be a datetime.datetime")
  1428. self._invalidity_date = invalidity_date
  1429. def __repr__(self) -> str:
  1430. return f"<InvalidityDate(invalidity_date={self._invalidity_date})>"
  1431. def __eq__(self, other: object) -> bool:
  1432. if not isinstance(other, InvalidityDate):
  1433. return NotImplemented
  1434. return self.invalidity_date == other.invalidity_date
  1435. def __hash__(self) -> int:
  1436. return hash(self.invalidity_date)
  1437. @property
  1438. def invalidity_date(self) -> datetime.datetime:
  1439. return self._invalidity_date
  1440. @property
  1441. def invalidity_date_utc(self) -> datetime.datetime:
  1442. if self._invalidity_date.tzinfo is None:
  1443. return self._invalidity_date.replace(tzinfo=datetime.timezone.utc)
  1444. else:
  1445. return self._invalidity_date.astimezone(tz=datetime.timezone.utc)
  1446. def public_bytes(self) -> bytes:
  1447. return rust_x509.encode_extension_value(self)
  1448. class PrecertificateSignedCertificateTimestamps(ExtensionType):
  1449. oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
  1450. def __init__(
  1451. self,
  1452. signed_certificate_timestamps: Iterable[SignedCertificateTimestamp],
  1453. ) -> None:
  1454. signed_certificate_timestamps = list(signed_certificate_timestamps)
  1455. if not all(
  1456. isinstance(sct, SignedCertificateTimestamp)
  1457. for sct in signed_certificate_timestamps
  1458. ):
  1459. raise TypeError(
  1460. "Every item in the signed_certificate_timestamps list must be "
  1461. "a SignedCertificateTimestamp"
  1462. )
  1463. self._signed_certificate_timestamps = signed_certificate_timestamps
  1464. __len__, __iter__, __getitem__ = _make_sequence_methods(
  1465. "_signed_certificate_timestamps"
  1466. )
  1467. def __repr__(self) -> str:
  1468. return f"<PrecertificateSignedCertificateTimestamps({list(self)})>"
  1469. def __hash__(self) -> int:
  1470. return hash(tuple(self._signed_certificate_timestamps))
  1471. def __eq__(self, other: object) -> bool:
  1472. if not isinstance(other, PrecertificateSignedCertificateTimestamps):
  1473. return NotImplemented
  1474. return (
  1475. self._signed_certificate_timestamps
  1476. == other._signed_certificate_timestamps
  1477. )
  1478. def public_bytes(self) -> bytes:
  1479. return rust_x509.encode_extension_value(self)
  1480. class SignedCertificateTimestamps(ExtensionType):
  1481. oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS
  1482. def __init__(
  1483. self,
  1484. signed_certificate_timestamps: Iterable[SignedCertificateTimestamp],
  1485. ) -> None:
  1486. signed_certificate_timestamps = list(signed_certificate_timestamps)
  1487. if not all(
  1488. isinstance(sct, SignedCertificateTimestamp)
  1489. for sct in signed_certificate_timestamps
  1490. ):
  1491. raise TypeError(
  1492. "Every item in the signed_certificate_timestamps list must be "
  1493. "a SignedCertificateTimestamp"
  1494. )
  1495. self._signed_certificate_timestamps = signed_certificate_timestamps
  1496. __len__, __iter__, __getitem__ = _make_sequence_methods(
  1497. "_signed_certificate_timestamps"
  1498. )
  1499. def __repr__(self) -> str:
  1500. return f"<SignedCertificateTimestamps({list(self)})>"
  1501. def __hash__(self) -> int:
  1502. return hash(tuple(self._signed_certificate_timestamps))
  1503. def __eq__(self, other: object) -> bool:
  1504. if not isinstance(other, SignedCertificateTimestamps):
  1505. return NotImplemented
  1506. return (
  1507. self._signed_certificate_timestamps
  1508. == other._signed_certificate_timestamps
  1509. )
  1510. def public_bytes(self) -> bytes:
  1511. return rust_x509.encode_extension_value(self)
  1512. class OCSPNonce(ExtensionType):
  1513. oid = OCSPExtensionOID.NONCE
  1514. def __init__(self, nonce: bytes) -> None:
  1515. if not isinstance(nonce, bytes):
  1516. raise TypeError("nonce must be bytes")
  1517. self._nonce = nonce
  1518. def __eq__(self, other: object) -> bool:
  1519. if not isinstance(other, OCSPNonce):
  1520. return NotImplemented
  1521. return self.nonce == other.nonce
  1522. def __hash__(self) -> int:
  1523. return hash(self.nonce)
  1524. def __repr__(self) -> str:
  1525. return f"<OCSPNonce(nonce={self.nonce!r})>"
  1526. @property
  1527. def nonce(self) -> bytes:
  1528. return self._nonce
  1529. def public_bytes(self) -> bytes:
  1530. return rust_x509.encode_extension_value(self)
  1531. class OCSPAcceptableResponses(ExtensionType):
  1532. oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES
  1533. def __init__(self, responses: Iterable[ObjectIdentifier]) -> None:
  1534. responses = list(responses)
  1535. if any(not isinstance(r, ObjectIdentifier) for r in responses):
  1536. raise TypeError("All responses must be ObjectIdentifiers")
  1537. self._responses = responses
  1538. def __eq__(self, other: object) -> bool:
  1539. if not isinstance(other, OCSPAcceptableResponses):
  1540. return NotImplemented
  1541. return self._responses == other._responses
  1542. def __hash__(self) -> int:
  1543. return hash(tuple(self._responses))
  1544. def __repr__(self) -> str:
  1545. return f"<OCSPAcceptableResponses(responses={self._responses})>"
  1546. def __iter__(self) -> Iterator[ObjectIdentifier]:
  1547. return iter(self._responses)
  1548. def public_bytes(self) -> bytes:
  1549. return rust_x509.encode_extension_value(self)
  1550. class IssuingDistributionPoint(ExtensionType):
  1551. oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT
  1552. def __init__(
  1553. self,
  1554. full_name: Iterable[GeneralName] | None,
  1555. relative_name: RelativeDistinguishedName | None,
  1556. only_contains_user_certs: bool,
  1557. only_contains_ca_certs: bool,
  1558. only_some_reasons: frozenset[ReasonFlags] | None,
  1559. indirect_crl: bool,
  1560. only_contains_attribute_certs: bool,
  1561. ) -> None:
  1562. if full_name is not None:
  1563. full_name = list(full_name)
  1564. if only_some_reasons and (
  1565. not isinstance(only_some_reasons, frozenset)
  1566. or not all(isinstance(x, ReasonFlags) for x in only_some_reasons)
  1567. ):
  1568. raise TypeError(
  1569. "only_some_reasons must be None or frozenset of ReasonFlags"
  1570. )
  1571. if only_some_reasons and (
  1572. ReasonFlags.unspecified in only_some_reasons
  1573. or ReasonFlags.remove_from_crl in only_some_reasons
  1574. ):
  1575. raise ValueError(
  1576. "unspecified and remove_from_crl are not valid reasons in an "
  1577. "IssuingDistributionPoint"
  1578. )
  1579. if not (
  1580. isinstance(only_contains_user_certs, bool)
  1581. and isinstance(only_contains_ca_certs, bool)
  1582. and isinstance(indirect_crl, bool)
  1583. and isinstance(only_contains_attribute_certs, bool)
  1584. ):
  1585. raise TypeError(
  1586. "only_contains_user_certs, only_contains_ca_certs, "
  1587. "indirect_crl and only_contains_attribute_certs "
  1588. "must all be boolean."
  1589. )
  1590. # Per RFC5280 Section 5.2.5, the Issuing Distribution Point extension
  1591. # in a CRL can have only one of onlyContainsUserCerts,
  1592. # onlyContainsCACerts, onlyContainsAttributeCerts set to TRUE.
  1593. crl_constraints = [
  1594. only_contains_user_certs,
  1595. only_contains_ca_certs,
  1596. only_contains_attribute_certs,
  1597. ]
  1598. if len([x for x in crl_constraints if x]) > 1:
  1599. raise ValueError(
  1600. "Only one of the following can be set to True: "
  1601. "only_contains_user_certs, only_contains_ca_certs, "
  1602. "only_contains_attribute_certs"
  1603. )
  1604. if not any(
  1605. [
  1606. only_contains_user_certs,
  1607. only_contains_ca_certs,
  1608. indirect_crl,
  1609. only_contains_attribute_certs,
  1610. full_name,
  1611. relative_name,
  1612. only_some_reasons,
  1613. ]
  1614. ):
  1615. raise ValueError(
  1616. "Cannot create empty extension: "
  1617. "if only_contains_user_certs, only_contains_ca_certs, "
  1618. "indirect_crl, and only_contains_attribute_certs are all False"
  1619. ", then either full_name, relative_name, or only_some_reasons "
  1620. "must have a value."
  1621. )
  1622. self._only_contains_user_certs = only_contains_user_certs
  1623. self._only_contains_ca_certs = only_contains_ca_certs
  1624. self._indirect_crl = indirect_crl
  1625. self._only_contains_attribute_certs = only_contains_attribute_certs
  1626. self._only_some_reasons = only_some_reasons
  1627. self._full_name = full_name
  1628. self._relative_name = relative_name
  1629. def __repr__(self) -> str:
  1630. return (
  1631. f"<IssuingDistributionPoint(full_name={self.full_name}, "
  1632. f"relative_name={self.relative_name}, "
  1633. f"only_contains_user_certs={self.only_contains_user_certs}, "
  1634. f"only_contains_ca_certs={self.only_contains_ca_certs}, "
  1635. f"only_some_reasons={self.only_some_reasons}, "
  1636. f"indirect_crl={self.indirect_crl}, "
  1637. "only_contains_attribute_certs="
  1638. f"{self.only_contains_attribute_certs})>"
  1639. )
  1640. def __eq__(self, other: object) -> bool:
  1641. if not isinstance(other, IssuingDistributionPoint):
  1642. return NotImplemented
  1643. return (
  1644. self.full_name == other.full_name
  1645. and self.relative_name == other.relative_name
  1646. and self.only_contains_user_certs == other.only_contains_user_certs
  1647. and self.only_contains_ca_certs == other.only_contains_ca_certs
  1648. and self.only_some_reasons == other.only_some_reasons
  1649. and self.indirect_crl == other.indirect_crl
  1650. and self.only_contains_attribute_certs
  1651. == other.only_contains_attribute_certs
  1652. )
  1653. def __hash__(self) -> int:
  1654. return hash(
  1655. (
  1656. self.full_name,
  1657. self.relative_name,
  1658. self.only_contains_user_certs,
  1659. self.only_contains_ca_certs,
  1660. self.only_some_reasons,
  1661. self.indirect_crl,
  1662. self.only_contains_attribute_certs,
  1663. )
  1664. )
  1665. @property
  1666. def full_name(self) -> list[GeneralName] | None:
  1667. return self._full_name
  1668. @property
  1669. def relative_name(self) -> RelativeDistinguishedName | None:
  1670. return self._relative_name
  1671. @property
  1672. def only_contains_user_certs(self) -> bool:
  1673. return self._only_contains_user_certs
  1674. @property
  1675. def only_contains_ca_certs(self) -> bool:
  1676. return self._only_contains_ca_certs
  1677. @property
  1678. def only_some_reasons(
  1679. self,
  1680. ) -> frozenset[ReasonFlags] | None:
  1681. return self._only_some_reasons
  1682. @property
  1683. def indirect_crl(self) -> bool:
  1684. return self._indirect_crl
  1685. @property
  1686. def only_contains_attribute_certs(self) -> bool:
  1687. return self._only_contains_attribute_certs
  1688. def public_bytes(self) -> bytes:
  1689. return rust_x509.encode_extension_value(self)
  1690. class MSCertificateTemplate(ExtensionType):
  1691. oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE
  1692. def __init__(
  1693. self,
  1694. template_id: ObjectIdentifier,
  1695. major_version: int | None,
  1696. minor_version: int | None,
  1697. ) -> None:
  1698. if not isinstance(template_id, ObjectIdentifier):
  1699. raise TypeError("oid must be an ObjectIdentifier")
  1700. self._template_id = template_id
  1701. if (
  1702. major_version is not None and not isinstance(major_version, int)
  1703. ) or (
  1704. minor_version is not None and not isinstance(minor_version, int)
  1705. ):
  1706. raise TypeError(
  1707. "major_version and minor_version must be integers or None"
  1708. )
  1709. self._major_version = major_version
  1710. self._minor_version = minor_version
  1711. @property
  1712. def template_id(self) -> ObjectIdentifier:
  1713. return self._template_id
  1714. @property
  1715. def major_version(self) -> int | None:
  1716. return self._major_version
  1717. @property
  1718. def minor_version(self) -> int | None:
  1719. return self._minor_version
  1720. def __repr__(self) -> str:
  1721. return (
  1722. f"<MSCertificateTemplate(template_id={self.template_id}, "
  1723. f"major_version={self.major_version}, "
  1724. f"minor_version={self.minor_version})>"
  1725. )
  1726. def __eq__(self, other: object) -> bool:
  1727. if not isinstance(other, MSCertificateTemplate):
  1728. return NotImplemented
  1729. return (
  1730. self.template_id == other.template_id
  1731. and self.major_version == other.major_version
  1732. and self.minor_version == other.minor_version
  1733. )
  1734. def __hash__(self) -> int:
  1735. return hash((self.template_id, self.major_version, self.minor_version))
  1736. def public_bytes(self) -> bytes:
  1737. return rust_x509.encode_extension_value(self)
  1738. class NamingAuthority:
  1739. def __init__(
  1740. self,
  1741. id: ObjectIdentifier | None,
  1742. url: str | None,
  1743. text: str | None,
  1744. ) -> None:
  1745. if id is not None and not isinstance(id, ObjectIdentifier):
  1746. raise TypeError("id must be an ObjectIdentifier")
  1747. if url is not None and not isinstance(url, str):
  1748. raise TypeError("url must be a str")
  1749. if text is not None and not isinstance(text, str):
  1750. raise TypeError("text must be a str")
  1751. self._id = id
  1752. self._url = url
  1753. self._text = text
  1754. @property
  1755. def id(self) -> ObjectIdentifier | None:
  1756. return self._id
  1757. @property
  1758. def url(self) -> str | None:
  1759. return self._url
  1760. @property
  1761. def text(self) -> str | None:
  1762. return self._text
  1763. def __repr__(self) -> str:
  1764. return (
  1765. f"<NamingAuthority("
  1766. f"id={self.id}, url={self.url}, text={self.text})>"
  1767. )
  1768. def __eq__(self, other: object) -> bool:
  1769. if not isinstance(other, NamingAuthority):
  1770. return NotImplemented
  1771. return (
  1772. self.id == other.id
  1773. and self.url == other.url
  1774. and self.text == other.text
  1775. )
  1776. def __hash__(self) -> int:
  1777. return hash(
  1778. (
  1779. self.id,
  1780. self.url,
  1781. self.text,
  1782. )
  1783. )
  1784. class ProfessionInfo:
  1785. def __init__(
  1786. self,
  1787. naming_authority: NamingAuthority | None,
  1788. profession_items: Iterable[str],
  1789. profession_oids: Iterable[ObjectIdentifier] | None,
  1790. registration_number: str | None,
  1791. add_profession_info: bytes | None,
  1792. ) -> None:
  1793. if naming_authority is not None and not isinstance(
  1794. naming_authority, NamingAuthority
  1795. ):
  1796. raise TypeError("naming_authority must be a NamingAuthority")
  1797. profession_items = list(profession_items)
  1798. if not all(isinstance(item, str) for item in profession_items):
  1799. raise TypeError(
  1800. "Every item in the profession_items list must be a str"
  1801. )
  1802. if profession_oids is not None:
  1803. profession_oids = list(profession_oids)
  1804. if not all(
  1805. isinstance(oid, ObjectIdentifier) for oid in profession_oids
  1806. ):
  1807. raise TypeError(
  1808. "Every item in the profession_oids list must be an "
  1809. "ObjectIdentifier"
  1810. )
  1811. if registration_number is not None and not isinstance(
  1812. registration_number, str
  1813. ):
  1814. raise TypeError("registration_number must be a str")
  1815. if add_profession_info is not None and not isinstance(
  1816. add_profession_info, bytes
  1817. ):
  1818. raise TypeError("add_profession_info must be bytes")
  1819. self._naming_authority = naming_authority
  1820. self._profession_items = profession_items
  1821. self._profession_oids = profession_oids
  1822. self._registration_number = registration_number
  1823. self._add_profession_info = add_profession_info
  1824. @property
  1825. def naming_authority(self) -> NamingAuthority | None:
  1826. return self._naming_authority
  1827. @property
  1828. def profession_items(self) -> list[str]:
  1829. return self._profession_items
  1830. @property
  1831. def profession_oids(self) -> list[ObjectIdentifier] | None:
  1832. return self._profession_oids
  1833. @property
  1834. def registration_number(self) -> str | None:
  1835. return self._registration_number
  1836. @property
  1837. def add_profession_info(self) -> bytes | None:
  1838. return self._add_profession_info
  1839. def __repr__(self) -> str:
  1840. return (
  1841. f"<ProfessionInfo(naming_authority={self.naming_authority}, "
  1842. f"profession_items={self.profession_items}, "
  1843. f"profession_oids={self.profession_oids}, "
  1844. f"registration_number={self.registration_number}, "
  1845. f"add_profession_info={self.add_profession_info!r})>"
  1846. )
  1847. def __eq__(self, other: object) -> bool:
  1848. if not isinstance(other, ProfessionInfo):
  1849. return NotImplemented
  1850. return (
  1851. self.naming_authority == other.naming_authority
  1852. and self.profession_items == other.profession_items
  1853. and self.profession_oids == other.profession_oids
  1854. and self.registration_number == other.registration_number
  1855. and self.add_profession_info == other.add_profession_info
  1856. )
  1857. def __hash__(self) -> int:
  1858. if self.profession_oids is not None:
  1859. profession_oids = tuple(self.profession_oids)
  1860. else:
  1861. profession_oids = None
  1862. return hash(
  1863. (
  1864. self.naming_authority,
  1865. tuple(self.profession_items),
  1866. profession_oids,
  1867. self.registration_number,
  1868. self.add_profession_info,
  1869. )
  1870. )
  1871. class Admission:
  1872. def __init__(
  1873. self,
  1874. admission_authority: GeneralName | None,
  1875. naming_authority: NamingAuthority | None,
  1876. profession_infos: Iterable[ProfessionInfo],
  1877. ) -> None:
  1878. if admission_authority is not None and not isinstance(
  1879. admission_authority, GeneralName
  1880. ):
  1881. raise TypeError("admission_authority must be a GeneralName")
  1882. if naming_authority is not None and not isinstance(
  1883. naming_authority, NamingAuthority
  1884. ):
  1885. raise TypeError("naming_authority must be a NamingAuthority")
  1886. profession_infos = list(profession_infos)
  1887. if not all(
  1888. isinstance(info, ProfessionInfo) for info in profession_infos
  1889. ):
  1890. raise TypeError(
  1891. "Every item in the profession_infos list must be a "
  1892. "ProfessionInfo"
  1893. )
  1894. self._admission_authority = admission_authority
  1895. self._naming_authority = naming_authority
  1896. self._profession_infos = profession_infos
  1897. @property
  1898. def admission_authority(self) -> GeneralName | None:
  1899. return self._admission_authority
  1900. @property
  1901. def naming_authority(self) -> NamingAuthority | None:
  1902. return self._naming_authority
  1903. @property
  1904. def profession_infos(self) -> list[ProfessionInfo]:
  1905. return self._profession_infos
  1906. def __repr__(self) -> str:
  1907. return (
  1908. f"<Admission(admission_authority={self.admission_authority}, "
  1909. f"naming_authority={self.naming_authority}, "
  1910. f"profession_infos={self.profession_infos})>"
  1911. )
  1912. def __eq__(self, other: object) -> bool:
  1913. if not isinstance(other, Admission):
  1914. return NotImplemented
  1915. return (
  1916. self.admission_authority == other.admission_authority
  1917. and self.naming_authority == other.naming_authority
  1918. and self.profession_infos == other.profession_infos
  1919. )
  1920. def __hash__(self) -> int:
  1921. return hash(
  1922. (
  1923. self.admission_authority,
  1924. self.naming_authority,
  1925. tuple(self.profession_infos),
  1926. )
  1927. )
  1928. class Admissions(ExtensionType):
  1929. oid = ExtensionOID.ADMISSIONS
  1930. def __init__(
  1931. self,
  1932. authority: GeneralName | None,
  1933. admissions: Iterable[Admission],
  1934. ) -> None:
  1935. if authority is not None and not isinstance(authority, GeneralName):
  1936. raise TypeError("authority must be a GeneralName")
  1937. admissions = list(admissions)
  1938. if not all(
  1939. isinstance(admission, Admission) for admission in admissions
  1940. ):
  1941. raise TypeError(
  1942. "Every item in the contents_of_admissions list must be an "
  1943. "Admission"
  1944. )
  1945. self._authority = authority
  1946. self._admissions = admissions
  1947. __len__, __iter__, __getitem__ = _make_sequence_methods("_admissions")
  1948. @property
  1949. def authority(self) -> GeneralName | None:
  1950. return self._authority
  1951. def __repr__(self) -> str:
  1952. return (
  1953. f"<Admissions(authority={self._authority}, "
  1954. f"admissions={self._admissions})>"
  1955. )
  1956. def __eq__(self, other: object) -> bool:
  1957. if not isinstance(other, Admissions):
  1958. return NotImplemented
  1959. return (
  1960. self.authority == other.authority
  1961. and self._admissions == other._admissions
  1962. )
  1963. def __hash__(self) -> int:
  1964. return hash((self.authority, tuple(self._admissions)))
  1965. def public_bytes(self) -> bytes:
  1966. return rust_x509.encode_extension_value(self)
  1967. class UnrecognizedExtension(ExtensionType):
  1968. def __init__(self, oid: ObjectIdentifier, value: bytes) -> None:
  1969. if not isinstance(oid, ObjectIdentifier):
  1970. raise TypeError("oid must be an ObjectIdentifier")
  1971. self._oid = oid
  1972. self._value = value
  1973. @property
  1974. def oid(self) -> ObjectIdentifier: # type: ignore[override]
  1975. return self._oid
  1976. @property
  1977. def value(self) -> bytes:
  1978. return self._value
  1979. def __repr__(self) -> str:
  1980. return f"<UnrecognizedExtension(oid={self.oid}, value={self.value!r})>"
  1981. def __eq__(self, other: object) -> bool:
  1982. if not isinstance(other, UnrecognizedExtension):
  1983. return NotImplemented
  1984. return self.oid == other.oid and self.value == other.value
  1985. def __hash__(self) -> int:
  1986. return hash((self.oid, self.value))
  1987. def public_bytes(self) -> bytes:
  1988. return self.value