extensions.py 74 KB

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