@pairling/runtime-darwin-x64 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/README.md +1 -1
  2. package/bin/pairling-connectd +0 -0
  3. package/manifest.json +4 -4
  4. package/package.json +3 -3
  5. package/python/bin/python3 +0 -0
  6. package/python/bin/python3.12 +0 -0
  7. package/python/lib/libpython3.12.dylib +0 -0
  8. package/python/lib/python3.12/lib-dynload/_crypt.cpython-312-darwin.so +0 -0
  9. package/python/lib/python3.12/lib-dynload/_dbm.cpython-312-darwin.so +0 -0
  10. package/python/lib/python3.12/site-packages/_cffi_backend.cpython-312-darwin.so +0 -0
  11. package/python/lib/python3.12/site-packages/cffi/__init__.py +14 -0
  12. package/python/lib/python3.12/site-packages/cffi/_cffi_errors.h +149 -0
  13. package/python/lib/python3.12/site-packages/cffi/_cffi_include.h +389 -0
  14. package/python/lib/python3.12/site-packages/cffi/_embedding.h +550 -0
  15. package/python/lib/python3.12/site-packages/cffi/_imp_emulation.py +83 -0
  16. package/python/lib/python3.12/site-packages/cffi/_shimmed_dist_utils.py +45 -0
  17. package/python/lib/python3.12/site-packages/cffi/api.py +967 -0
  18. package/python/lib/python3.12/site-packages/cffi/backend_ctypes.py +1121 -0
  19. package/python/lib/python3.12/site-packages/cffi/cffi_opcode.py +187 -0
  20. package/python/lib/python3.12/site-packages/cffi/commontypes.py +82 -0
  21. package/python/lib/python3.12/site-packages/cffi/cparser.py +1015 -0
  22. package/python/lib/python3.12/site-packages/cffi/error.py +31 -0
  23. package/python/lib/python3.12/site-packages/cffi/ffiplatform.py +113 -0
  24. package/python/lib/python3.12/site-packages/cffi/lock.py +30 -0
  25. package/python/lib/python3.12/site-packages/cffi/model.py +618 -0
  26. package/python/lib/python3.12/site-packages/cffi/parse_c_type.h +181 -0
  27. package/python/lib/python3.12/site-packages/cffi/pkgconfig.py +121 -0
  28. package/python/lib/python3.12/site-packages/cffi/recompiler.py +1598 -0
  29. package/python/lib/python3.12/site-packages/cffi/setuptools_ext.py +216 -0
  30. package/python/lib/python3.12/site-packages/cffi/vengine_cpy.py +1084 -0
  31. package/python/lib/python3.12/site-packages/cffi/vengine_gen.py +679 -0
  32. package/python/lib/python3.12/site-packages/cffi/verifier.py +306 -0
  33. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/INSTALLER +1 -0
  34. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/LICENSE +26 -0
  35. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/METADATA +40 -0
  36. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/RECORD +30 -0
  37. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/WHEEL +5 -0
  38. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/entry_points.txt +2 -0
  39. package/python/lib/python3.12/site-packages/cffi-1.17.1.dist-info/top_level.txt +2 -0
  40. package/python/lib/python3.12/site-packages/cryptography/__about__.py +17 -0
  41. package/python/lib/python3.12/site-packages/cryptography/__init__.py +26 -0
  42. package/python/lib/python3.12/site-packages/cryptography/exceptions.py +52 -0
  43. package/python/lib/python3.12/site-packages/cryptography/fernet.py +224 -0
  44. package/python/lib/python3.12/site-packages/cryptography/hazmat/__init__.py +13 -0
  45. package/python/lib/python3.12/site-packages/cryptography/hazmat/_oid.py +348 -0
  46. package/python/lib/python3.12/site-packages/cryptography/hazmat/backends/__init__.py +13 -0
  47. package/python/lib/python3.12/site-packages/cryptography/hazmat/backends/openssl/__init__.py +9 -0
  48. package/python/lib/python3.12/site-packages/cryptography/hazmat/backends/openssl/backend.py +308 -0
  49. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/__init__.py +3 -0
  50. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/__init__.pyi +37 -0
  51. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/_openssl.pyi +8 -0
  52. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/asn1.pyi +7 -0
  53. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/exceptions.pyi +17 -0
  54. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/ocsp.pyi +117 -0
  55. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi +75 -0
  56. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/aead.pyi +107 -0
  57. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi +38 -0
  58. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/cmac.pyi +18 -0
  59. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/dh.pyi +51 -0
  60. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/dsa.pyi +41 -0
  61. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/ec.pyi +52 -0
  62. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi +13 -0
  63. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/ed448.pyi +13 -0
  64. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/hashes.pyi +28 -0
  65. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/hmac.pyi +22 -0
  66. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/kdf.pyi +49 -0
  67. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/keys.pyi +34 -0
  68. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi +15 -0
  69. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/rsa.pyi +55 -0
  70. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/x25519.pyi +13 -0
  71. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/openssl/x448.pyi +13 -0
  72. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/pkcs12.pyi +52 -0
  73. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/pkcs7.pyi +50 -0
  74. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/test_support.pyi +23 -0
  75. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust/x509.pyi +313 -0
  76. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/_rust.abi3.so +0 -0
  77. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/openssl/__init__.py +3 -0
  78. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py +191 -0
  79. package/python/lib/python3.12/site-packages/cryptography/hazmat/bindings/openssl/binding.py +122 -0
  80. package/python/lib/python3.12/site-packages/cryptography/hazmat/decrepit/__init__.py +5 -0
  81. package/python/lib/python3.12/site-packages/cryptography/hazmat/decrepit/ciphers/__init__.py +5 -0
  82. package/python/lib/python3.12/site-packages/cryptography/hazmat/decrepit/ciphers/algorithms.py +112 -0
  83. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/__init__.py +3 -0
  84. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/_asymmetric.py +19 -0
  85. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/_cipheralgorithm.py +60 -0
  86. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/_serialization.py +168 -0
  87. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py +3 -0
  88. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py +147 -0
  89. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py +167 -0
  90. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py +447 -0
  91. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py +129 -0
  92. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py +131 -0
  93. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py +113 -0
  94. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py +277 -0
  95. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/types.py +111 -0
  96. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py +24 -0
  97. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py +122 -0
  98. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py +125 -0
  99. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py +27 -0
  100. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/aead.py +23 -0
  101. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py +183 -0
  102. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/base.py +146 -0
  103. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/ciphers/modes.py +268 -0
  104. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/cmac.py +10 -0
  105. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/constant_time.py +14 -0
  106. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/hashes.py +246 -0
  107. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/hmac.py +13 -0
  108. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/__init__.py +23 -0
  109. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/argon2.py +13 -0
  110. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py +125 -0
  111. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py +101 -0
  112. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py +305 -0
  113. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py +62 -0
  114. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py +19 -0
  115. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py +61 -0
  116. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/keywrap.py +177 -0
  117. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/padding.py +69 -0
  118. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/poly1305.py +11 -0
  119. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/__init__.py +65 -0
  120. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/base.py +14 -0
  121. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py +176 -0
  122. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py +411 -0
  123. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/serialization/ssh.py +1619 -0
  124. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py +9 -0
  125. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py +101 -0
  126. package/python/lib/python3.12/site-packages/cryptography/hazmat/primitives/twofactor/totp.py +56 -0
  127. package/python/lib/python3.12/site-packages/cryptography/py.typed +0 -0
  128. package/python/lib/python3.12/site-packages/cryptography/utils.py +139 -0
  129. package/python/lib/python3.12/site-packages/cryptography/x509/__init__.py +270 -0
  130. package/python/lib/python3.12/site-packages/cryptography/x509/base.py +848 -0
  131. package/python/lib/python3.12/site-packages/cryptography/x509/certificate_transparency.py +35 -0
  132. package/python/lib/python3.12/site-packages/cryptography/x509/extensions.py +2528 -0
  133. package/python/lib/python3.12/site-packages/cryptography/x509/general_name.py +281 -0
  134. package/python/lib/python3.12/site-packages/cryptography/x509/name.py +477 -0
  135. package/python/lib/python3.12/site-packages/cryptography/x509/ocsp.py +379 -0
  136. package/python/lib/python3.12/site-packages/cryptography/x509/oid.py +37 -0
  137. package/python/lib/python3.12/site-packages/cryptography/x509/verification.py +34 -0
  138. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/INSTALLER +1 -0
  139. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/METADATA +139 -0
  140. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/RECORD +106 -0
  141. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/REQUESTED +0 -0
  142. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/WHEEL +4 -0
  143. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/licenses/LICENSE +3 -0
  144. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/licenses/LICENSE.APACHE +202 -0
  145. package/python/lib/python3.12/site-packages/cryptography-45.0.7.dist-info/licenses/LICENSE.BSD +27 -0
  146. package/python/lib/python3.12/site-packages/pycparser/__init__.py +99 -0
  147. package/python/lib/python3.12/site-packages/pycparser/_ast_gen.py +355 -0
  148. package/python/lib/python3.12/site-packages/pycparser/_c_ast.cfg +195 -0
  149. package/python/lib/python3.12/site-packages/pycparser/ast_transforms.py +174 -0
  150. package/python/lib/python3.12/site-packages/pycparser/c_ast.py +1341 -0
  151. package/python/lib/python3.12/site-packages/pycparser/c_generator.py +573 -0
  152. package/python/lib/python3.12/site-packages/pycparser/c_lexer.py +706 -0
  153. package/python/lib/python3.12/site-packages/pycparser/c_parser.py +2376 -0
  154. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/INSTALLER +1 -0
  155. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/METADATA +244 -0
  156. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/RECORD +14 -0
  157. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/WHEEL +5 -0
  158. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/licenses/LICENSE +27 -0
  159. package/python/lib/python3.12/site-packages/pycparser-3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2528 @@
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
+
5
+ from __future__ import annotations
6
+
7
+ import abc
8
+ import datetime
9
+ import hashlib
10
+ import ipaddress
11
+ import typing
12
+ from collections.abc import Iterable, Iterator
13
+
14
+ from cryptography import utils
15
+ from cryptography.hazmat.bindings._rust import asn1
16
+ from cryptography.hazmat.bindings._rust import x509 as rust_x509
17
+ from cryptography.hazmat.primitives import constant_time, serialization
18
+ from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
19
+ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
20
+ from cryptography.hazmat.primitives.asymmetric.types import (
21
+ CertificateIssuerPublicKeyTypes,
22
+ CertificatePublicKeyTypes,
23
+ )
24
+ from cryptography.x509.certificate_transparency import (
25
+ SignedCertificateTimestamp,
26
+ )
27
+ from cryptography.x509.general_name import (
28
+ DirectoryName,
29
+ DNSName,
30
+ GeneralName,
31
+ IPAddress,
32
+ OtherName,
33
+ RegisteredID,
34
+ RFC822Name,
35
+ UniformResourceIdentifier,
36
+ _IPAddressTypes,
37
+ )
38
+ from cryptography.x509.name import Name, RelativeDistinguishedName
39
+ from cryptography.x509.oid import (
40
+ CRLEntryExtensionOID,
41
+ ExtensionOID,
42
+ ObjectIdentifier,
43
+ OCSPExtensionOID,
44
+ )
45
+
46
+ ExtensionTypeVar = typing.TypeVar(
47
+ "ExtensionTypeVar", bound="ExtensionType", covariant=True
48
+ )
49
+
50
+
51
+ def _key_identifier_from_public_key(
52
+ public_key: CertificatePublicKeyTypes,
53
+ ) -> bytes:
54
+ if isinstance(public_key, RSAPublicKey):
55
+ data = public_key.public_bytes(
56
+ serialization.Encoding.DER,
57
+ serialization.PublicFormat.PKCS1,
58
+ )
59
+ elif isinstance(public_key, EllipticCurvePublicKey):
60
+ data = public_key.public_bytes(
61
+ serialization.Encoding.X962,
62
+ serialization.PublicFormat.UncompressedPoint,
63
+ )
64
+ else:
65
+ # This is a very slow way to do this.
66
+ serialized = public_key.public_bytes(
67
+ serialization.Encoding.DER,
68
+ serialization.PublicFormat.SubjectPublicKeyInfo,
69
+ )
70
+ data = asn1.parse_spki_for_data(serialized)
71
+
72
+ return hashlib.sha1(data).digest()
73
+
74
+
75
+ def _make_sequence_methods(field_name: str):
76
+ def len_method(self) -> int:
77
+ return len(getattr(self, field_name))
78
+
79
+ def iter_method(self):
80
+ return iter(getattr(self, field_name))
81
+
82
+ def getitem_method(self, idx):
83
+ return getattr(self, field_name)[idx]
84
+
85
+ return len_method, iter_method, getitem_method
86
+
87
+
88
+ class DuplicateExtension(Exception):
89
+ def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
90
+ super().__init__(msg)
91
+ self.oid = oid
92
+
93
+
94
+ class ExtensionNotFound(Exception):
95
+ def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
96
+ super().__init__(msg)
97
+ self.oid = oid
98
+
99
+
100
+ class ExtensionType(metaclass=abc.ABCMeta):
101
+ oid: typing.ClassVar[ObjectIdentifier]
102
+
103
+ def public_bytes(self) -> bytes:
104
+ """
105
+ Serializes the extension type to DER.
106
+ """
107
+ raise NotImplementedError(
108
+ f"public_bytes is not implemented for extension type {self!r}"
109
+ )
110
+
111
+
112
+ class Extensions:
113
+ def __init__(self, extensions: Iterable[Extension[ExtensionType]]) -> None:
114
+ self._extensions = list(extensions)
115
+
116
+ def get_extension_for_oid(
117
+ self, oid: ObjectIdentifier
118
+ ) -> Extension[ExtensionType]:
119
+ for ext in self:
120
+ if ext.oid == oid:
121
+ return ext
122
+
123
+ raise ExtensionNotFound(f"No {oid} extension was found", oid)
124
+
125
+ def get_extension_for_class(
126
+ self, extclass: type[ExtensionTypeVar]
127
+ ) -> Extension[ExtensionTypeVar]:
128
+ if extclass is UnrecognizedExtension:
129
+ raise TypeError(
130
+ "UnrecognizedExtension can't be used with "
131
+ "get_extension_for_class because more than one instance of the"
132
+ " class may be present."
133
+ )
134
+
135
+ for ext in self:
136
+ if isinstance(ext.value, extclass):
137
+ return ext
138
+
139
+ raise ExtensionNotFound(
140
+ f"No {extclass} extension was found", extclass.oid
141
+ )
142
+
143
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
144
+
145
+ def __repr__(self) -> str:
146
+ return f"<Extensions({self._extensions})>"
147
+
148
+
149
+ class CRLNumber(ExtensionType):
150
+ oid = ExtensionOID.CRL_NUMBER
151
+
152
+ def __init__(self, crl_number: int) -> None:
153
+ if not isinstance(crl_number, int):
154
+ raise TypeError("crl_number must be an integer")
155
+
156
+ self._crl_number = crl_number
157
+
158
+ def __eq__(self, other: object) -> bool:
159
+ if not isinstance(other, CRLNumber):
160
+ return NotImplemented
161
+
162
+ return self.crl_number == other.crl_number
163
+
164
+ def __hash__(self) -> int:
165
+ return hash(self.crl_number)
166
+
167
+ def __repr__(self) -> str:
168
+ return f"<CRLNumber({self.crl_number})>"
169
+
170
+ @property
171
+ def crl_number(self) -> int:
172
+ return self._crl_number
173
+
174
+ def public_bytes(self) -> bytes:
175
+ return rust_x509.encode_extension_value(self)
176
+
177
+
178
+ class AuthorityKeyIdentifier(ExtensionType):
179
+ oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
180
+
181
+ def __init__(
182
+ self,
183
+ key_identifier: bytes | None,
184
+ authority_cert_issuer: Iterable[GeneralName] | None,
185
+ authority_cert_serial_number: int | None,
186
+ ) -> None:
187
+ if (authority_cert_issuer is None) != (
188
+ authority_cert_serial_number is None
189
+ ):
190
+ raise ValueError(
191
+ "authority_cert_issuer and authority_cert_serial_number "
192
+ "must both be present or both None"
193
+ )
194
+
195
+ if authority_cert_issuer is not None:
196
+ authority_cert_issuer = list(authority_cert_issuer)
197
+ if not all(
198
+ isinstance(x, GeneralName) for x in authority_cert_issuer
199
+ ):
200
+ raise TypeError(
201
+ "authority_cert_issuer must be a list of GeneralName "
202
+ "objects"
203
+ )
204
+
205
+ if authority_cert_serial_number is not None and not isinstance(
206
+ authority_cert_serial_number, int
207
+ ):
208
+ raise TypeError("authority_cert_serial_number must be an integer")
209
+
210
+ self._key_identifier = key_identifier
211
+ self._authority_cert_issuer = authority_cert_issuer
212
+ self._authority_cert_serial_number = authority_cert_serial_number
213
+
214
+ # This takes a subset of CertificatePublicKeyTypes because an issuer
215
+ # cannot have an X25519/X448 key. This introduces some unfortunate
216
+ # asymmetry that requires typing users to explicitly
217
+ # narrow their type, but we should make this accurate and not just
218
+ # convenient.
219
+ @classmethod
220
+ def from_issuer_public_key(
221
+ cls, public_key: CertificateIssuerPublicKeyTypes
222
+ ) -> AuthorityKeyIdentifier:
223
+ digest = _key_identifier_from_public_key(public_key)
224
+ return cls(
225
+ key_identifier=digest,
226
+ authority_cert_issuer=None,
227
+ authority_cert_serial_number=None,
228
+ )
229
+
230
+ @classmethod
231
+ def from_issuer_subject_key_identifier(
232
+ cls, ski: SubjectKeyIdentifier
233
+ ) -> AuthorityKeyIdentifier:
234
+ return cls(
235
+ key_identifier=ski.digest,
236
+ authority_cert_issuer=None,
237
+ authority_cert_serial_number=None,
238
+ )
239
+
240
+ def __repr__(self) -> str:
241
+ return (
242
+ f"<AuthorityKeyIdentifier(key_identifier={self.key_identifier!r}, "
243
+ f"authority_cert_issuer={self.authority_cert_issuer}, "
244
+ f"authority_cert_serial_number={self.authority_cert_serial_number}"
245
+ ")>"
246
+ )
247
+
248
+ def __eq__(self, other: object) -> bool:
249
+ if not isinstance(other, AuthorityKeyIdentifier):
250
+ return NotImplemented
251
+
252
+ return (
253
+ self.key_identifier == other.key_identifier
254
+ and self.authority_cert_issuer == other.authority_cert_issuer
255
+ and self.authority_cert_serial_number
256
+ == other.authority_cert_serial_number
257
+ )
258
+
259
+ def __hash__(self) -> int:
260
+ if self.authority_cert_issuer is None:
261
+ aci = None
262
+ else:
263
+ aci = tuple(self.authority_cert_issuer)
264
+ return hash(
265
+ (self.key_identifier, aci, self.authority_cert_serial_number)
266
+ )
267
+
268
+ @property
269
+ def key_identifier(self) -> bytes | None:
270
+ return self._key_identifier
271
+
272
+ @property
273
+ def authority_cert_issuer(
274
+ self,
275
+ ) -> list[GeneralName] | None:
276
+ return self._authority_cert_issuer
277
+
278
+ @property
279
+ def authority_cert_serial_number(self) -> int | None:
280
+ return self._authority_cert_serial_number
281
+
282
+ def public_bytes(self) -> bytes:
283
+ return rust_x509.encode_extension_value(self)
284
+
285
+
286
+ class SubjectKeyIdentifier(ExtensionType):
287
+ oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
288
+
289
+ def __init__(self, digest: bytes) -> None:
290
+ self._digest = digest
291
+
292
+ @classmethod
293
+ def from_public_key(
294
+ cls, public_key: CertificatePublicKeyTypes
295
+ ) -> SubjectKeyIdentifier:
296
+ return cls(_key_identifier_from_public_key(public_key))
297
+
298
+ @property
299
+ def digest(self) -> bytes:
300
+ return self._digest
301
+
302
+ @property
303
+ def key_identifier(self) -> bytes:
304
+ return self._digest
305
+
306
+ def __repr__(self) -> str:
307
+ return f"<SubjectKeyIdentifier(digest={self.digest!r})>"
308
+
309
+ def __eq__(self, other: object) -> bool:
310
+ if not isinstance(other, SubjectKeyIdentifier):
311
+ return NotImplemented
312
+
313
+ return constant_time.bytes_eq(self.digest, other.digest)
314
+
315
+ def __hash__(self) -> int:
316
+ return hash(self.digest)
317
+
318
+ def public_bytes(self) -> bytes:
319
+ return rust_x509.encode_extension_value(self)
320
+
321
+
322
+ class AuthorityInformationAccess(ExtensionType):
323
+ oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
324
+
325
+ def __init__(self, descriptions: Iterable[AccessDescription]) -> None:
326
+ descriptions = list(descriptions)
327
+ if not all(isinstance(x, AccessDescription) for x in descriptions):
328
+ raise TypeError(
329
+ "Every item in the descriptions list must be an "
330
+ "AccessDescription"
331
+ )
332
+
333
+ self._descriptions = descriptions
334
+
335
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
336
+
337
+ def __repr__(self) -> str:
338
+ return f"<AuthorityInformationAccess({self._descriptions})>"
339
+
340
+ def __eq__(self, other: object) -> bool:
341
+ if not isinstance(other, AuthorityInformationAccess):
342
+ return NotImplemented
343
+
344
+ return self._descriptions == other._descriptions
345
+
346
+ def __hash__(self) -> int:
347
+ return hash(tuple(self._descriptions))
348
+
349
+ def public_bytes(self) -> bytes:
350
+ return rust_x509.encode_extension_value(self)
351
+
352
+
353
+ class SubjectInformationAccess(ExtensionType):
354
+ oid = ExtensionOID.SUBJECT_INFORMATION_ACCESS
355
+
356
+ def __init__(self, descriptions: Iterable[AccessDescription]) -> None:
357
+ descriptions = list(descriptions)
358
+ if not all(isinstance(x, AccessDescription) for x in descriptions):
359
+ raise TypeError(
360
+ "Every item in the descriptions list must be an "
361
+ "AccessDescription"
362
+ )
363
+
364
+ self._descriptions = descriptions
365
+
366
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
367
+
368
+ def __repr__(self) -> str:
369
+ return f"<SubjectInformationAccess({self._descriptions})>"
370
+
371
+ def __eq__(self, other: object) -> bool:
372
+ if not isinstance(other, SubjectInformationAccess):
373
+ return NotImplemented
374
+
375
+ return self._descriptions == other._descriptions
376
+
377
+ def __hash__(self) -> int:
378
+ return hash(tuple(self._descriptions))
379
+
380
+ def public_bytes(self) -> bytes:
381
+ return rust_x509.encode_extension_value(self)
382
+
383
+
384
+ class AccessDescription:
385
+ def __init__(
386
+ self, access_method: ObjectIdentifier, access_location: GeneralName
387
+ ) -> None:
388
+ if not isinstance(access_method, ObjectIdentifier):
389
+ raise TypeError("access_method must be an ObjectIdentifier")
390
+
391
+ if not isinstance(access_location, GeneralName):
392
+ raise TypeError("access_location must be a GeneralName")
393
+
394
+ self._access_method = access_method
395
+ self._access_location = access_location
396
+
397
+ def __repr__(self) -> str:
398
+ return (
399
+ f"<AccessDescription(access_method={self.access_method}, "
400
+ f"access_location={self.access_location})>"
401
+ )
402
+
403
+ def __eq__(self, other: object) -> bool:
404
+ if not isinstance(other, AccessDescription):
405
+ return NotImplemented
406
+
407
+ return (
408
+ self.access_method == other.access_method
409
+ and self.access_location == other.access_location
410
+ )
411
+
412
+ def __hash__(self) -> int:
413
+ return hash((self.access_method, self.access_location))
414
+
415
+ @property
416
+ def access_method(self) -> ObjectIdentifier:
417
+ return self._access_method
418
+
419
+ @property
420
+ def access_location(self) -> GeneralName:
421
+ return self._access_location
422
+
423
+
424
+ class BasicConstraints(ExtensionType):
425
+ oid = ExtensionOID.BASIC_CONSTRAINTS
426
+
427
+ def __init__(self, ca: bool, path_length: int | None) -> None:
428
+ if not isinstance(ca, bool):
429
+ raise TypeError("ca must be a boolean value")
430
+
431
+ if path_length is not None and not ca:
432
+ raise ValueError("path_length must be None when ca is False")
433
+
434
+ if path_length is not None and (
435
+ not isinstance(path_length, int) or path_length < 0
436
+ ):
437
+ raise TypeError(
438
+ "path_length must be a non-negative integer or None"
439
+ )
440
+
441
+ self._ca = ca
442
+ self._path_length = path_length
443
+
444
+ @property
445
+ def ca(self) -> bool:
446
+ return self._ca
447
+
448
+ @property
449
+ def path_length(self) -> int | None:
450
+ return self._path_length
451
+
452
+ def __repr__(self) -> str:
453
+ return (
454
+ f"<BasicConstraints(ca={self.ca}, path_length={self.path_length})>"
455
+ )
456
+
457
+ def __eq__(self, other: object) -> bool:
458
+ if not isinstance(other, BasicConstraints):
459
+ return NotImplemented
460
+
461
+ return self.ca == other.ca and self.path_length == other.path_length
462
+
463
+ def __hash__(self) -> int:
464
+ return hash((self.ca, self.path_length))
465
+
466
+ def public_bytes(self) -> bytes:
467
+ return rust_x509.encode_extension_value(self)
468
+
469
+
470
+ class DeltaCRLIndicator(ExtensionType):
471
+ oid = ExtensionOID.DELTA_CRL_INDICATOR
472
+
473
+ def __init__(self, crl_number: int) -> None:
474
+ if not isinstance(crl_number, int):
475
+ raise TypeError("crl_number must be an integer")
476
+
477
+ self._crl_number = crl_number
478
+
479
+ @property
480
+ def crl_number(self) -> int:
481
+ return self._crl_number
482
+
483
+ def __eq__(self, other: object) -> bool:
484
+ if not isinstance(other, DeltaCRLIndicator):
485
+ return NotImplemented
486
+
487
+ return self.crl_number == other.crl_number
488
+
489
+ def __hash__(self) -> int:
490
+ return hash(self.crl_number)
491
+
492
+ def __repr__(self) -> str:
493
+ return f"<DeltaCRLIndicator(crl_number={self.crl_number})>"
494
+
495
+ def public_bytes(self) -> bytes:
496
+ return rust_x509.encode_extension_value(self)
497
+
498
+
499
+ class CRLDistributionPoints(ExtensionType):
500
+ oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
501
+
502
+ def __init__(
503
+ self, distribution_points: Iterable[DistributionPoint]
504
+ ) -> None:
505
+ distribution_points = list(distribution_points)
506
+ if not all(
507
+ isinstance(x, DistributionPoint) for x in distribution_points
508
+ ):
509
+ raise TypeError(
510
+ "distribution_points must be a list of DistributionPoint "
511
+ "objects"
512
+ )
513
+
514
+ self._distribution_points = distribution_points
515
+
516
+ __len__, __iter__, __getitem__ = _make_sequence_methods(
517
+ "_distribution_points"
518
+ )
519
+
520
+ def __repr__(self) -> str:
521
+ return f"<CRLDistributionPoints({self._distribution_points})>"
522
+
523
+ def __eq__(self, other: object) -> bool:
524
+ if not isinstance(other, CRLDistributionPoints):
525
+ return NotImplemented
526
+
527
+ return self._distribution_points == other._distribution_points
528
+
529
+ def __hash__(self) -> int:
530
+ return hash(tuple(self._distribution_points))
531
+
532
+ def public_bytes(self) -> bytes:
533
+ return rust_x509.encode_extension_value(self)
534
+
535
+
536
+ class FreshestCRL(ExtensionType):
537
+ oid = ExtensionOID.FRESHEST_CRL
538
+
539
+ def __init__(
540
+ self, distribution_points: Iterable[DistributionPoint]
541
+ ) -> None:
542
+ distribution_points = list(distribution_points)
543
+ if not all(
544
+ isinstance(x, DistributionPoint) for x in distribution_points
545
+ ):
546
+ raise TypeError(
547
+ "distribution_points must be a list of DistributionPoint "
548
+ "objects"
549
+ )
550
+
551
+ self._distribution_points = distribution_points
552
+
553
+ __len__, __iter__, __getitem__ = _make_sequence_methods(
554
+ "_distribution_points"
555
+ )
556
+
557
+ def __repr__(self) -> str:
558
+ return f"<FreshestCRL({self._distribution_points})>"
559
+
560
+ def __eq__(self, other: object) -> bool:
561
+ if not isinstance(other, FreshestCRL):
562
+ return NotImplemented
563
+
564
+ return self._distribution_points == other._distribution_points
565
+
566
+ def __hash__(self) -> int:
567
+ return hash(tuple(self._distribution_points))
568
+
569
+ def public_bytes(self) -> bytes:
570
+ return rust_x509.encode_extension_value(self)
571
+
572
+
573
+ class DistributionPoint:
574
+ def __init__(
575
+ self,
576
+ full_name: Iterable[GeneralName] | None,
577
+ relative_name: RelativeDistinguishedName | None,
578
+ reasons: frozenset[ReasonFlags] | None,
579
+ crl_issuer: Iterable[GeneralName] | None,
580
+ ) -> None:
581
+ if full_name and relative_name:
582
+ raise ValueError(
583
+ "You cannot provide both full_name and relative_name, at "
584
+ "least one must be None."
585
+ )
586
+ if not full_name and not relative_name and not crl_issuer:
587
+ raise ValueError(
588
+ "Either full_name, relative_name or crl_issuer must be "
589
+ "provided."
590
+ )
591
+
592
+ if full_name is not None:
593
+ full_name = list(full_name)
594
+ if not all(isinstance(x, GeneralName) for x in full_name):
595
+ raise TypeError(
596
+ "full_name must be a list of GeneralName objects"
597
+ )
598
+
599
+ if relative_name:
600
+ if not isinstance(relative_name, RelativeDistinguishedName):
601
+ raise TypeError(
602
+ "relative_name must be a RelativeDistinguishedName"
603
+ )
604
+
605
+ if crl_issuer is not None:
606
+ crl_issuer = list(crl_issuer)
607
+ if not all(isinstance(x, GeneralName) for x in crl_issuer):
608
+ raise TypeError(
609
+ "crl_issuer must be None or a list of general names"
610
+ )
611
+
612
+ if reasons and (
613
+ not isinstance(reasons, frozenset)
614
+ or not all(isinstance(x, ReasonFlags) for x in reasons)
615
+ ):
616
+ raise TypeError("reasons must be None or frozenset of ReasonFlags")
617
+
618
+ if reasons and (
619
+ ReasonFlags.unspecified in reasons
620
+ or ReasonFlags.remove_from_crl in reasons
621
+ ):
622
+ raise ValueError(
623
+ "unspecified and remove_from_crl are not valid reasons in a "
624
+ "DistributionPoint"
625
+ )
626
+
627
+ self._full_name = full_name
628
+ self._relative_name = relative_name
629
+ self._reasons = reasons
630
+ self._crl_issuer = crl_issuer
631
+
632
+ def __repr__(self) -> str:
633
+ return (
634
+ "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
635
+ "tive_name}, reasons={0.reasons}, "
636
+ "crl_issuer={0.crl_issuer})>".format(self)
637
+ )
638
+
639
+ def __eq__(self, other: object) -> bool:
640
+ if not isinstance(other, DistributionPoint):
641
+ return NotImplemented
642
+
643
+ return (
644
+ self.full_name == other.full_name
645
+ and self.relative_name == other.relative_name
646
+ and self.reasons == other.reasons
647
+ and self.crl_issuer == other.crl_issuer
648
+ )
649
+
650
+ def __hash__(self) -> int:
651
+ if self.full_name is not None:
652
+ fn: tuple[GeneralName, ...] | None = tuple(self.full_name)
653
+ else:
654
+ fn = None
655
+
656
+ if self.crl_issuer is not None:
657
+ crl_issuer: tuple[GeneralName, ...] | None = tuple(self.crl_issuer)
658
+ else:
659
+ crl_issuer = None
660
+
661
+ return hash((fn, self.relative_name, self.reasons, crl_issuer))
662
+
663
+ @property
664
+ def full_name(self) -> list[GeneralName] | None:
665
+ return self._full_name
666
+
667
+ @property
668
+ def relative_name(self) -> RelativeDistinguishedName | None:
669
+ return self._relative_name
670
+
671
+ @property
672
+ def reasons(self) -> frozenset[ReasonFlags] | None:
673
+ return self._reasons
674
+
675
+ @property
676
+ def crl_issuer(self) -> list[GeneralName] | None:
677
+ return self._crl_issuer
678
+
679
+
680
+ class ReasonFlags(utils.Enum):
681
+ unspecified = "unspecified"
682
+ key_compromise = "keyCompromise"
683
+ ca_compromise = "cACompromise"
684
+ affiliation_changed = "affiliationChanged"
685
+ superseded = "superseded"
686
+ cessation_of_operation = "cessationOfOperation"
687
+ certificate_hold = "certificateHold"
688
+ privilege_withdrawn = "privilegeWithdrawn"
689
+ aa_compromise = "aACompromise"
690
+ remove_from_crl = "removeFromCRL"
691
+
692
+
693
+ # These are distribution point bit string mappings. Not to be confused with
694
+ # CRLReason reason flags bit string mappings.
695
+ # ReasonFlags ::= BIT STRING {
696
+ # unused (0),
697
+ # keyCompromise (1),
698
+ # cACompromise (2),
699
+ # affiliationChanged (3),
700
+ # superseded (4),
701
+ # cessationOfOperation (5),
702
+ # certificateHold (6),
703
+ # privilegeWithdrawn (7),
704
+ # aACompromise (8) }
705
+ _REASON_BIT_MAPPING = {
706
+ 1: ReasonFlags.key_compromise,
707
+ 2: ReasonFlags.ca_compromise,
708
+ 3: ReasonFlags.affiliation_changed,
709
+ 4: ReasonFlags.superseded,
710
+ 5: ReasonFlags.cessation_of_operation,
711
+ 6: ReasonFlags.certificate_hold,
712
+ 7: ReasonFlags.privilege_withdrawn,
713
+ 8: ReasonFlags.aa_compromise,
714
+ }
715
+
716
+ _CRLREASONFLAGS = {
717
+ ReasonFlags.key_compromise: 1,
718
+ ReasonFlags.ca_compromise: 2,
719
+ ReasonFlags.affiliation_changed: 3,
720
+ ReasonFlags.superseded: 4,
721
+ ReasonFlags.cessation_of_operation: 5,
722
+ ReasonFlags.certificate_hold: 6,
723
+ ReasonFlags.privilege_withdrawn: 7,
724
+ ReasonFlags.aa_compromise: 8,
725
+ }
726
+
727
+ # CRLReason ::= ENUMERATED {
728
+ # unspecified (0),
729
+ # keyCompromise (1),
730
+ # cACompromise (2),
731
+ # affiliationChanged (3),
732
+ # superseded (4),
733
+ # cessationOfOperation (5),
734
+ # certificateHold (6),
735
+ # -- value 7 is not used
736
+ # removeFromCRL (8),
737
+ # privilegeWithdrawn (9),
738
+ # aACompromise (10) }
739
+ _CRL_ENTRY_REASON_ENUM_TO_CODE = {
740
+ ReasonFlags.unspecified: 0,
741
+ ReasonFlags.key_compromise: 1,
742
+ ReasonFlags.ca_compromise: 2,
743
+ ReasonFlags.affiliation_changed: 3,
744
+ ReasonFlags.superseded: 4,
745
+ ReasonFlags.cessation_of_operation: 5,
746
+ ReasonFlags.certificate_hold: 6,
747
+ ReasonFlags.remove_from_crl: 8,
748
+ ReasonFlags.privilege_withdrawn: 9,
749
+ ReasonFlags.aa_compromise: 10,
750
+ }
751
+
752
+
753
+ class PolicyConstraints(ExtensionType):
754
+ oid = ExtensionOID.POLICY_CONSTRAINTS
755
+
756
+ def __init__(
757
+ self,
758
+ require_explicit_policy: int | None,
759
+ inhibit_policy_mapping: int | None,
760
+ ) -> None:
761
+ if require_explicit_policy is not None and not isinstance(
762
+ require_explicit_policy, int
763
+ ):
764
+ raise TypeError(
765
+ "require_explicit_policy must be a non-negative integer or "
766
+ "None"
767
+ )
768
+
769
+ if inhibit_policy_mapping is not None and not isinstance(
770
+ inhibit_policy_mapping, int
771
+ ):
772
+ raise TypeError(
773
+ "inhibit_policy_mapping must be a non-negative integer or None"
774
+ )
775
+
776
+ if inhibit_policy_mapping is None and require_explicit_policy is None:
777
+ raise ValueError(
778
+ "At least one of require_explicit_policy and "
779
+ "inhibit_policy_mapping must not be None"
780
+ )
781
+
782
+ self._require_explicit_policy = require_explicit_policy
783
+ self._inhibit_policy_mapping = inhibit_policy_mapping
784
+
785
+ def __repr__(self) -> str:
786
+ return (
787
+ "<PolicyConstraints(require_explicit_policy={0.require_explicit"
788
+ "_policy}, inhibit_policy_mapping={0.inhibit_policy_"
789
+ "mapping})>".format(self)
790
+ )
791
+
792
+ def __eq__(self, other: object) -> bool:
793
+ if not isinstance(other, PolicyConstraints):
794
+ return NotImplemented
795
+
796
+ return (
797
+ self.require_explicit_policy == other.require_explicit_policy
798
+ and self.inhibit_policy_mapping == other.inhibit_policy_mapping
799
+ )
800
+
801
+ def __hash__(self) -> int:
802
+ return hash(
803
+ (self.require_explicit_policy, self.inhibit_policy_mapping)
804
+ )
805
+
806
+ @property
807
+ def require_explicit_policy(self) -> int | None:
808
+ return self._require_explicit_policy
809
+
810
+ @property
811
+ def inhibit_policy_mapping(self) -> int | None:
812
+ return self._inhibit_policy_mapping
813
+
814
+ def public_bytes(self) -> bytes:
815
+ return rust_x509.encode_extension_value(self)
816
+
817
+
818
+ class CertificatePolicies(ExtensionType):
819
+ oid = ExtensionOID.CERTIFICATE_POLICIES
820
+
821
+ def __init__(self, policies: Iterable[PolicyInformation]) -> None:
822
+ policies = list(policies)
823
+ if not all(isinstance(x, PolicyInformation) for x in policies):
824
+ raise TypeError(
825
+ "Every item in the policies list must be a PolicyInformation"
826
+ )
827
+
828
+ self._policies = policies
829
+
830
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_policies")
831
+
832
+ def __repr__(self) -> str:
833
+ return f"<CertificatePolicies({self._policies})>"
834
+
835
+ def __eq__(self, other: object) -> bool:
836
+ if not isinstance(other, CertificatePolicies):
837
+ return NotImplemented
838
+
839
+ return self._policies == other._policies
840
+
841
+ def __hash__(self) -> int:
842
+ return hash(tuple(self._policies))
843
+
844
+ def public_bytes(self) -> bytes:
845
+ return rust_x509.encode_extension_value(self)
846
+
847
+
848
+ class PolicyInformation:
849
+ def __init__(
850
+ self,
851
+ policy_identifier: ObjectIdentifier,
852
+ policy_qualifiers: Iterable[str | UserNotice] | None,
853
+ ) -> None:
854
+ if not isinstance(policy_identifier, ObjectIdentifier):
855
+ raise TypeError("policy_identifier must be an ObjectIdentifier")
856
+
857
+ self._policy_identifier = policy_identifier
858
+
859
+ if policy_qualifiers is not None:
860
+ policy_qualifiers = list(policy_qualifiers)
861
+ if not all(
862
+ isinstance(x, (str, UserNotice)) for x in policy_qualifiers
863
+ ):
864
+ raise TypeError(
865
+ "policy_qualifiers must be a list of strings and/or "
866
+ "UserNotice objects or None"
867
+ )
868
+
869
+ self._policy_qualifiers = policy_qualifiers
870
+
871
+ def __repr__(self) -> str:
872
+ return (
873
+ f"<PolicyInformation(policy_identifier={self.policy_identifier}, "
874
+ f"policy_qualifiers={self.policy_qualifiers})>"
875
+ )
876
+
877
+ def __eq__(self, other: object) -> bool:
878
+ if not isinstance(other, PolicyInformation):
879
+ return NotImplemented
880
+
881
+ return (
882
+ self.policy_identifier == other.policy_identifier
883
+ and self.policy_qualifiers == other.policy_qualifiers
884
+ )
885
+
886
+ def __hash__(self) -> int:
887
+ if self.policy_qualifiers is not None:
888
+ pq = tuple(self.policy_qualifiers)
889
+ else:
890
+ pq = None
891
+
892
+ return hash((self.policy_identifier, pq))
893
+
894
+ @property
895
+ def policy_identifier(self) -> ObjectIdentifier:
896
+ return self._policy_identifier
897
+
898
+ @property
899
+ def policy_qualifiers(
900
+ self,
901
+ ) -> list[str | UserNotice] | None:
902
+ return self._policy_qualifiers
903
+
904
+
905
+ class UserNotice:
906
+ def __init__(
907
+ self,
908
+ notice_reference: NoticeReference | None,
909
+ explicit_text: str | None,
910
+ ) -> None:
911
+ if notice_reference and not isinstance(
912
+ notice_reference, NoticeReference
913
+ ):
914
+ raise TypeError(
915
+ "notice_reference must be None or a NoticeReference"
916
+ )
917
+
918
+ self._notice_reference = notice_reference
919
+ self._explicit_text = explicit_text
920
+
921
+ def __repr__(self) -> str:
922
+ return (
923
+ f"<UserNotice(notice_reference={self.notice_reference}, "
924
+ f"explicit_text={self.explicit_text!r})>"
925
+ )
926
+
927
+ def __eq__(self, other: object) -> bool:
928
+ if not isinstance(other, UserNotice):
929
+ return NotImplemented
930
+
931
+ return (
932
+ self.notice_reference == other.notice_reference
933
+ and self.explicit_text == other.explicit_text
934
+ )
935
+
936
+ def __hash__(self) -> int:
937
+ return hash((self.notice_reference, self.explicit_text))
938
+
939
+ @property
940
+ def notice_reference(self) -> NoticeReference | None:
941
+ return self._notice_reference
942
+
943
+ @property
944
+ def explicit_text(self) -> str | None:
945
+ return self._explicit_text
946
+
947
+
948
+ class NoticeReference:
949
+ def __init__(
950
+ self,
951
+ organization: str | None,
952
+ notice_numbers: Iterable[int],
953
+ ) -> None:
954
+ self._organization = organization
955
+ notice_numbers = list(notice_numbers)
956
+ if not all(isinstance(x, int) for x in notice_numbers):
957
+ raise TypeError("notice_numbers must be a list of integers")
958
+
959
+ self._notice_numbers = notice_numbers
960
+
961
+ def __repr__(self) -> str:
962
+ return (
963
+ f"<NoticeReference(organization={self.organization!r}, "
964
+ f"notice_numbers={self.notice_numbers})>"
965
+ )
966
+
967
+ def __eq__(self, other: object) -> bool:
968
+ if not isinstance(other, NoticeReference):
969
+ return NotImplemented
970
+
971
+ return (
972
+ self.organization == other.organization
973
+ and self.notice_numbers == other.notice_numbers
974
+ )
975
+
976
+ def __hash__(self) -> int:
977
+ return hash((self.organization, tuple(self.notice_numbers)))
978
+
979
+ @property
980
+ def organization(self) -> str | None:
981
+ return self._organization
982
+
983
+ @property
984
+ def notice_numbers(self) -> list[int]:
985
+ return self._notice_numbers
986
+
987
+
988
+ class ExtendedKeyUsage(ExtensionType):
989
+ oid = ExtensionOID.EXTENDED_KEY_USAGE
990
+
991
+ def __init__(self, usages: Iterable[ObjectIdentifier]) -> None:
992
+ usages = list(usages)
993
+ if not all(isinstance(x, ObjectIdentifier) for x in usages):
994
+ raise TypeError(
995
+ "Every item in the usages list must be an ObjectIdentifier"
996
+ )
997
+
998
+ self._usages = usages
999
+
1000
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_usages")
1001
+
1002
+ def __repr__(self) -> str:
1003
+ return f"<ExtendedKeyUsage({self._usages})>"
1004
+
1005
+ def __eq__(self, other: object) -> bool:
1006
+ if not isinstance(other, ExtendedKeyUsage):
1007
+ return NotImplemented
1008
+
1009
+ return self._usages == other._usages
1010
+
1011
+ def __hash__(self) -> int:
1012
+ return hash(tuple(self._usages))
1013
+
1014
+ def public_bytes(self) -> bytes:
1015
+ return rust_x509.encode_extension_value(self)
1016
+
1017
+
1018
+ class OCSPNoCheck(ExtensionType):
1019
+ oid = ExtensionOID.OCSP_NO_CHECK
1020
+
1021
+ def __eq__(self, other: object) -> bool:
1022
+ if not isinstance(other, OCSPNoCheck):
1023
+ return NotImplemented
1024
+
1025
+ return True
1026
+
1027
+ def __hash__(self) -> int:
1028
+ return hash(OCSPNoCheck)
1029
+
1030
+ def __repr__(self) -> str:
1031
+ return "<OCSPNoCheck()>"
1032
+
1033
+ def public_bytes(self) -> bytes:
1034
+ return rust_x509.encode_extension_value(self)
1035
+
1036
+
1037
+ class PrecertPoison(ExtensionType):
1038
+ oid = ExtensionOID.PRECERT_POISON
1039
+
1040
+ def __eq__(self, other: object) -> bool:
1041
+ if not isinstance(other, PrecertPoison):
1042
+ return NotImplemented
1043
+
1044
+ return True
1045
+
1046
+ def __hash__(self) -> int:
1047
+ return hash(PrecertPoison)
1048
+
1049
+ def __repr__(self) -> str:
1050
+ return "<PrecertPoison()>"
1051
+
1052
+ def public_bytes(self) -> bytes:
1053
+ return rust_x509.encode_extension_value(self)
1054
+
1055
+
1056
+ class TLSFeature(ExtensionType):
1057
+ oid = ExtensionOID.TLS_FEATURE
1058
+
1059
+ def __init__(self, features: Iterable[TLSFeatureType]) -> None:
1060
+ features = list(features)
1061
+ if (
1062
+ not all(isinstance(x, TLSFeatureType) for x in features)
1063
+ or len(features) == 0
1064
+ ):
1065
+ raise TypeError(
1066
+ "features must be a list of elements from the TLSFeatureType "
1067
+ "enum"
1068
+ )
1069
+
1070
+ self._features = features
1071
+
1072
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_features")
1073
+
1074
+ def __repr__(self) -> str:
1075
+ return f"<TLSFeature(features={self._features})>"
1076
+
1077
+ def __eq__(self, other: object) -> bool:
1078
+ if not isinstance(other, TLSFeature):
1079
+ return NotImplemented
1080
+
1081
+ return self._features == other._features
1082
+
1083
+ def __hash__(self) -> int:
1084
+ return hash(tuple(self._features))
1085
+
1086
+ def public_bytes(self) -> bytes:
1087
+ return rust_x509.encode_extension_value(self)
1088
+
1089
+
1090
+ class TLSFeatureType(utils.Enum):
1091
+ # status_request is defined in RFC 6066 and is used for what is commonly
1092
+ # called OCSP Must-Staple when present in the TLS Feature extension in an
1093
+ # X.509 certificate.
1094
+ status_request = 5
1095
+ # status_request_v2 is defined in RFC 6961 and allows multiple OCSP
1096
+ # responses to be provided. It is not currently in use by clients or
1097
+ # servers.
1098
+ status_request_v2 = 17
1099
+
1100
+
1101
+ _TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType}
1102
+
1103
+
1104
+ class InhibitAnyPolicy(ExtensionType):
1105
+ oid = ExtensionOID.INHIBIT_ANY_POLICY
1106
+
1107
+ def __init__(self, skip_certs: int) -> None:
1108
+ if not isinstance(skip_certs, int):
1109
+ raise TypeError("skip_certs must be an integer")
1110
+
1111
+ if skip_certs < 0:
1112
+ raise ValueError("skip_certs must be a non-negative integer")
1113
+
1114
+ self._skip_certs = skip_certs
1115
+
1116
+ def __repr__(self) -> str:
1117
+ return f"<InhibitAnyPolicy(skip_certs={self.skip_certs})>"
1118
+
1119
+ def __eq__(self, other: object) -> bool:
1120
+ if not isinstance(other, InhibitAnyPolicy):
1121
+ return NotImplemented
1122
+
1123
+ return self.skip_certs == other.skip_certs
1124
+
1125
+ def __hash__(self) -> int:
1126
+ return hash(self.skip_certs)
1127
+
1128
+ @property
1129
+ def skip_certs(self) -> int:
1130
+ return self._skip_certs
1131
+
1132
+ def public_bytes(self) -> bytes:
1133
+ return rust_x509.encode_extension_value(self)
1134
+
1135
+
1136
+ class KeyUsage(ExtensionType):
1137
+ oid = ExtensionOID.KEY_USAGE
1138
+
1139
+ def __init__(
1140
+ self,
1141
+ digital_signature: bool,
1142
+ content_commitment: bool,
1143
+ key_encipherment: bool,
1144
+ data_encipherment: bool,
1145
+ key_agreement: bool,
1146
+ key_cert_sign: bool,
1147
+ crl_sign: bool,
1148
+ encipher_only: bool,
1149
+ decipher_only: bool,
1150
+ ) -> None:
1151
+ if not key_agreement and (encipher_only or decipher_only):
1152
+ raise ValueError(
1153
+ "encipher_only and decipher_only can only be true when "
1154
+ "key_agreement is true"
1155
+ )
1156
+
1157
+ self._digital_signature = digital_signature
1158
+ self._content_commitment = content_commitment
1159
+ self._key_encipherment = key_encipherment
1160
+ self._data_encipherment = data_encipherment
1161
+ self._key_agreement = key_agreement
1162
+ self._key_cert_sign = key_cert_sign
1163
+ self._crl_sign = crl_sign
1164
+ self._encipher_only = encipher_only
1165
+ self._decipher_only = decipher_only
1166
+
1167
+ @property
1168
+ def digital_signature(self) -> bool:
1169
+ return self._digital_signature
1170
+
1171
+ @property
1172
+ def content_commitment(self) -> bool:
1173
+ return self._content_commitment
1174
+
1175
+ @property
1176
+ def key_encipherment(self) -> bool:
1177
+ return self._key_encipherment
1178
+
1179
+ @property
1180
+ def data_encipherment(self) -> bool:
1181
+ return self._data_encipherment
1182
+
1183
+ @property
1184
+ def key_agreement(self) -> bool:
1185
+ return self._key_agreement
1186
+
1187
+ @property
1188
+ def key_cert_sign(self) -> bool:
1189
+ return self._key_cert_sign
1190
+
1191
+ @property
1192
+ def crl_sign(self) -> bool:
1193
+ return self._crl_sign
1194
+
1195
+ @property
1196
+ def encipher_only(self) -> bool:
1197
+ if not self.key_agreement:
1198
+ raise ValueError(
1199
+ "encipher_only is undefined unless key_agreement is true"
1200
+ )
1201
+ else:
1202
+ return self._encipher_only
1203
+
1204
+ @property
1205
+ def decipher_only(self) -> bool:
1206
+ if not self.key_agreement:
1207
+ raise ValueError(
1208
+ "decipher_only is undefined unless key_agreement is true"
1209
+ )
1210
+ else:
1211
+ return self._decipher_only
1212
+
1213
+ def __repr__(self) -> str:
1214
+ try:
1215
+ encipher_only = self.encipher_only
1216
+ decipher_only = self.decipher_only
1217
+ except ValueError:
1218
+ # Users found None confusing because even though encipher/decipher
1219
+ # have no meaning unless key_agreement is true, to construct an
1220
+ # instance of the class you still need to pass False.
1221
+ encipher_only = False
1222
+ decipher_only = False
1223
+
1224
+ return (
1225
+ f"<KeyUsage(digital_signature={self.digital_signature}, "
1226
+ f"content_commitment={self.content_commitment}, "
1227
+ f"key_encipherment={self.key_encipherment}, "
1228
+ f"data_encipherment={self.data_encipherment}, "
1229
+ f"key_agreement={self.key_agreement}, "
1230
+ f"key_cert_sign={self.key_cert_sign}, crl_sign={self.crl_sign}, "
1231
+ f"encipher_only={encipher_only}, decipher_only={decipher_only})>"
1232
+ )
1233
+
1234
+ def __eq__(self, other: object) -> bool:
1235
+ if not isinstance(other, KeyUsage):
1236
+ return NotImplemented
1237
+
1238
+ return (
1239
+ self.digital_signature == other.digital_signature
1240
+ and self.content_commitment == other.content_commitment
1241
+ and self.key_encipherment == other.key_encipherment
1242
+ and self.data_encipherment == other.data_encipherment
1243
+ and self.key_agreement == other.key_agreement
1244
+ and self.key_cert_sign == other.key_cert_sign
1245
+ and self.crl_sign == other.crl_sign
1246
+ and self._encipher_only == other._encipher_only
1247
+ and self._decipher_only == other._decipher_only
1248
+ )
1249
+
1250
+ def __hash__(self) -> int:
1251
+ return hash(
1252
+ (
1253
+ self.digital_signature,
1254
+ self.content_commitment,
1255
+ self.key_encipherment,
1256
+ self.data_encipherment,
1257
+ self.key_agreement,
1258
+ self.key_cert_sign,
1259
+ self.crl_sign,
1260
+ self._encipher_only,
1261
+ self._decipher_only,
1262
+ )
1263
+ )
1264
+
1265
+ def public_bytes(self) -> bytes:
1266
+ return rust_x509.encode_extension_value(self)
1267
+
1268
+
1269
+ class PrivateKeyUsagePeriod(ExtensionType):
1270
+ oid = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD
1271
+
1272
+ def __init__(
1273
+ self,
1274
+ not_before: datetime.datetime | None,
1275
+ not_after: datetime.datetime | None,
1276
+ ) -> None:
1277
+ if (
1278
+ not isinstance(not_before, datetime.datetime)
1279
+ and not_before is not None
1280
+ ):
1281
+ raise TypeError("not_before must be a datetime.datetime or None")
1282
+
1283
+ if (
1284
+ not isinstance(not_after, datetime.datetime)
1285
+ and not_after is not None
1286
+ ):
1287
+ raise TypeError("not_after must be a datetime.datetime or None")
1288
+
1289
+ if not_before is None and not_after is None:
1290
+ raise ValueError(
1291
+ "At least one of not_before and not_after must not be None"
1292
+ )
1293
+
1294
+ if (
1295
+ not_before is not None
1296
+ and not_after is not None
1297
+ and not_before > not_after
1298
+ ):
1299
+ raise ValueError("not_before must be before not_after")
1300
+
1301
+ self._not_before = not_before
1302
+ self._not_after = not_after
1303
+
1304
+ @property
1305
+ def not_before(self) -> datetime.datetime | None:
1306
+ return self._not_before
1307
+
1308
+ @property
1309
+ def not_after(self) -> datetime.datetime | None:
1310
+ return self._not_after
1311
+
1312
+ def __repr__(self) -> str:
1313
+ return (
1314
+ f"<PrivateKeyUsagePeriod(not_before={self.not_before}, "
1315
+ f"not_after={self.not_after})>"
1316
+ )
1317
+
1318
+ def __eq__(self, other: object) -> bool:
1319
+ if not isinstance(other, PrivateKeyUsagePeriod):
1320
+ return NotImplemented
1321
+
1322
+ return (
1323
+ self.not_before == other.not_before
1324
+ and self.not_after == other.not_after
1325
+ )
1326
+
1327
+ def __hash__(self) -> int:
1328
+ return hash((self.not_before, self.not_after))
1329
+
1330
+ def public_bytes(self) -> bytes:
1331
+ return rust_x509.encode_extension_value(self)
1332
+
1333
+
1334
+ class NameConstraints(ExtensionType):
1335
+ oid = ExtensionOID.NAME_CONSTRAINTS
1336
+
1337
+ def __init__(
1338
+ self,
1339
+ permitted_subtrees: Iterable[GeneralName] | None,
1340
+ excluded_subtrees: Iterable[GeneralName] | None,
1341
+ ) -> None:
1342
+ if permitted_subtrees is not None:
1343
+ permitted_subtrees = list(permitted_subtrees)
1344
+ if not permitted_subtrees:
1345
+ raise ValueError(
1346
+ "permitted_subtrees must be a non-empty list or None"
1347
+ )
1348
+ if not all(isinstance(x, GeneralName) for x in permitted_subtrees):
1349
+ raise TypeError(
1350
+ "permitted_subtrees must be a list of GeneralName objects "
1351
+ "or None"
1352
+ )
1353
+
1354
+ self._validate_tree(permitted_subtrees)
1355
+
1356
+ if excluded_subtrees is not None:
1357
+ excluded_subtrees = list(excluded_subtrees)
1358
+ if not excluded_subtrees:
1359
+ raise ValueError(
1360
+ "excluded_subtrees must be a non-empty list or None"
1361
+ )
1362
+ if not all(isinstance(x, GeneralName) for x in excluded_subtrees):
1363
+ raise TypeError(
1364
+ "excluded_subtrees must be a list of GeneralName objects "
1365
+ "or None"
1366
+ )
1367
+
1368
+ self._validate_tree(excluded_subtrees)
1369
+
1370
+ if permitted_subtrees is None and excluded_subtrees is None:
1371
+ raise ValueError(
1372
+ "At least one of permitted_subtrees and excluded_subtrees "
1373
+ "must not be None"
1374
+ )
1375
+
1376
+ self._permitted_subtrees = permitted_subtrees
1377
+ self._excluded_subtrees = excluded_subtrees
1378
+
1379
+ def __eq__(self, other: object) -> bool:
1380
+ if not isinstance(other, NameConstraints):
1381
+ return NotImplemented
1382
+
1383
+ return (
1384
+ self.excluded_subtrees == other.excluded_subtrees
1385
+ and self.permitted_subtrees == other.permitted_subtrees
1386
+ )
1387
+
1388
+ def _validate_tree(self, tree: Iterable[GeneralName]) -> None:
1389
+ self._validate_ip_name(tree)
1390
+ self._validate_dns_name(tree)
1391
+
1392
+ def _validate_ip_name(self, tree: Iterable[GeneralName]) -> None:
1393
+ if any(
1394
+ isinstance(name, IPAddress)
1395
+ and not isinstance(
1396
+ name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
1397
+ )
1398
+ for name in tree
1399
+ ):
1400
+ raise TypeError(
1401
+ "IPAddress name constraints must be an IPv4Network or"
1402
+ " IPv6Network object"
1403
+ )
1404
+
1405
+ def _validate_dns_name(self, tree: Iterable[GeneralName]) -> None:
1406
+ if any(
1407
+ isinstance(name, DNSName) and "*" in name.value for name in tree
1408
+ ):
1409
+ raise ValueError(
1410
+ "DNSName name constraints must not contain the '*' wildcard"
1411
+ " character"
1412
+ )
1413
+
1414
+ def __repr__(self) -> str:
1415
+ return (
1416
+ f"<NameConstraints(permitted_subtrees={self.permitted_subtrees}, "
1417
+ f"excluded_subtrees={self.excluded_subtrees})>"
1418
+ )
1419
+
1420
+ def __hash__(self) -> int:
1421
+ if self.permitted_subtrees is not None:
1422
+ ps: tuple[GeneralName, ...] | None = tuple(self.permitted_subtrees)
1423
+ else:
1424
+ ps = None
1425
+
1426
+ if self.excluded_subtrees is not None:
1427
+ es: tuple[GeneralName, ...] | None = tuple(self.excluded_subtrees)
1428
+ else:
1429
+ es = None
1430
+
1431
+ return hash((ps, es))
1432
+
1433
+ @property
1434
+ def permitted_subtrees(
1435
+ self,
1436
+ ) -> list[GeneralName] | None:
1437
+ return self._permitted_subtrees
1438
+
1439
+ @property
1440
+ def excluded_subtrees(
1441
+ self,
1442
+ ) -> list[GeneralName] | None:
1443
+ return self._excluded_subtrees
1444
+
1445
+ def public_bytes(self) -> bytes:
1446
+ return rust_x509.encode_extension_value(self)
1447
+
1448
+
1449
+ class Extension(typing.Generic[ExtensionTypeVar]):
1450
+ def __init__(
1451
+ self, oid: ObjectIdentifier, critical: bool, value: ExtensionTypeVar
1452
+ ) -> None:
1453
+ if not isinstance(oid, ObjectIdentifier):
1454
+ raise TypeError(
1455
+ "oid argument must be an ObjectIdentifier instance."
1456
+ )
1457
+
1458
+ if not isinstance(critical, bool):
1459
+ raise TypeError("critical must be a boolean value")
1460
+
1461
+ self._oid = oid
1462
+ self._critical = critical
1463
+ self._value = value
1464
+
1465
+ @property
1466
+ def oid(self) -> ObjectIdentifier:
1467
+ return self._oid
1468
+
1469
+ @property
1470
+ def critical(self) -> bool:
1471
+ return self._critical
1472
+
1473
+ @property
1474
+ def value(self) -> ExtensionTypeVar:
1475
+ return self._value
1476
+
1477
+ def __repr__(self) -> str:
1478
+ return (
1479
+ f"<Extension(oid={self.oid}, critical={self.critical}, "
1480
+ f"value={self.value})>"
1481
+ )
1482
+
1483
+ def __eq__(self, other: object) -> bool:
1484
+ if not isinstance(other, Extension):
1485
+ return NotImplemented
1486
+
1487
+ return (
1488
+ self.oid == other.oid
1489
+ and self.critical == other.critical
1490
+ and self.value == other.value
1491
+ )
1492
+
1493
+ def __hash__(self) -> int:
1494
+ return hash((self.oid, self.critical, self.value))
1495
+
1496
+
1497
+ class GeneralNames:
1498
+ def __init__(self, general_names: Iterable[GeneralName]) -> None:
1499
+ general_names = list(general_names)
1500
+ if not all(isinstance(x, GeneralName) for x in general_names):
1501
+ raise TypeError(
1502
+ "Every item in the general_names list must be an "
1503
+ "object conforming to the GeneralName interface"
1504
+ )
1505
+
1506
+ self._general_names = general_names
1507
+
1508
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1509
+
1510
+ @typing.overload
1511
+ def get_values_for_type(
1512
+ self,
1513
+ type: type[DNSName]
1514
+ | type[UniformResourceIdentifier]
1515
+ | type[RFC822Name],
1516
+ ) -> list[str]: ...
1517
+
1518
+ @typing.overload
1519
+ def get_values_for_type(
1520
+ self,
1521
+ type: type[DirectoryName],
1522
+ ) -> list[Name]: ...
1523
+
1524
+ @typing.overload
1525
+ def get_values_for_type(
1526
+ self,
1527
+ type: type[RegisteredID],
1528
+ ) -> list[ObjectIdentifier]: ...
1529
+
1530
+ @typing.overload
1531
+ def get_values_for_type(
1532
+ self, type: type[IPAddress]
1533
+ ) -> list[_IPAddressTypes]: ...
1534
+
1535
+ @typing.overload
1536
+ def get_values_for_type(
1537
+ self, type: type[OtherName]
1538
+ ) -> list[OtherName]: ...
1539
+
1540
+ def get_values_for_type(
1541
+ self,
1542
+ type: type[DNSName]
1543
+ | type[DirectoryName]
1544
+ | type[IPAddress]
1545
+ | type[OtherName]
1546
+ | type[RFC822Name]
1547
+ | type[RegisteredID]
1548
+ | type[UniformResourceIdentifier],
1549
+ ) -> (
1550
+ list[_IPAddressTypes]
1551
+ | list[str]
1552
+ | list[OtherName]
1553
+ | list[Name]
1554
+ | list[ObjectIdentifier]
1555
+ ):
1556
+ # Return the value of each GeneralName, except for OtherName instances
1557
+ # which we return directly because it has two important properties not
1558
+ # just one value.
1559
+ objs = (i for i in self if isinstance(i, type))
1560
+ if type != OtherName:
1561
+ return [i.value for i in objs]
1562
+ return list(objs)
1563
+
1564
+ def __repr__(self) -> str:
1565
+ return f"<GeneralNames({self._general_names})>"
1566
+
1567
+ def __eq__(self, other: object) -> bool:
1568
+ if not isinstance(other, GeneralNames):
1569
+ return NotImplemented
1570
+
1571
+ return self._general_names == other._general_names
1572
+
1573
+ def __hash__(self) -> int:
1574
+ return hash(tuple(self._general_names))
1575
+
1576
+
1577
+ class SubjectAlternativeName(ExtensionType):
1578
+ oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
1579
+
1580
+ def __init__(self, general_names: Iterable[GeneralName]) -> None:
1581
+ self._general_names = GeneralNames(general_names)
1582
+
1583
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1584
+
1585
+ @typing.overload
1586
+ def get_values_for_type(
1587
+ self,
1588
+ type: type[DNSName]
1589
+ | type[UniformResourceIdentifier]
1590
+ | type[RFC822Name],
1591
+ ) -> list[str]: ...
1592
+
1593
+ @typing.overload
1594
+ def get_values_for_type(
1595
+ self,
1596
+ type: type[DirectoryName],
1597
+ ) -> list[Name]: ...
1598
+
1599
+ @typing.overload
1600
+ def get_values_for_type(
1601
+ self,
1602
+ type: type[RegisteredID],
1603
+ ) -> list[ObjectIdentifier]: ...
1604
+
1605
+ @typing.overload
1606
+ def get_values_for_type(
1607
+ self, type: type[IPAddress]
1608
+ ) -> list[_IPAddressTypes]: ...
1609
+
1610
+ @typing.overload
1611
+ def get_values_for_type(
1612
+ self, type: type[OtherName]
1613
+ ) -> list[OtherName]: ...
1614
+
1615
+ def get_values_for_type(
1616
+ self,
1617
+ type: type[DNSName]
1618
+ | type[DirectoryName]
1619
+ | type[IPAddress]
1620
+ | type[OtherName]
1621
+ | type[RFC822Name]
1622
+ | type[RegisteredID]
1623
+ | type[UniformResourceIdentifier],
1624
+ ) -> (
1625
+ list[_IPAddressTypes]
1626
+ | list[str]
1627
+ | list[OtherName]
1628
+ | list[Name]
1629
+ | list[ObjectIdentifier]
1630
+ ):
1631
+ return self._general_names.get_values_for_type(type)
1632
+
1633
+ def __repr__(self) -> str:
1634
+ return f"<SubjectAlternativeName({self._general_names})>"
1635
+
1636
+ def __eq__(self, other: object) -> bool:
1637
+ if not isinstance(other, SubjectAlternativeName):
1638
+ return NotImplemented
1639
+
1640
+ return self._general_names == other._general_names
1641
+
1642
+ def __hash__(self) -> int:
1643
+ return hash(self._general_names)
1644
+
1645
+ def public_bytes(self) -> bytes:
1646
+ return rust_x509.encode_extension_value(self)
1647
+
1648
+
1649
+ class IssuerAlternativeName(ExtensionType):
1650
+ oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
1651
+
1652
+ def __init__(self, general_names: Iterable[GeneralName]) -> None:
1653
+ self._general_names = GeneralNames(general_names)
1654
+
1655
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1656
+
1657
+ @typing.overload
1658
+ def get_values_for_type(
1659
+ self,
1660
+ type: type[DNSName]
1661
+ | type[UniformResourceIdentifier]
1662
+ | type[RFC822Name],
1663
+ ) -> list[str]: ...
1664
+
1665
+ @typing.overload
1666
+ def get_values_for_type(
1667
+ self,
1668
+ type: type[DirectoryName],
1669
+ ) -> list[Name]: ...
1670
+
1671
+ @typing.overload
1672
+ def get_values_for_type(
1673
+ self,
1674
+ type: type[RegisteredID],
1675
+ ) -> list[ObjectIdentifier]: ...
1676
+
1677
+ @typing.overload
1678
+ def get_values_for_type(
1679
+ self, type: type[IPAddress]
1680
+ ) -> list[_IPAddressTypes]: ...
1681
+
1682
+ @typing.overload
1683
+ def get_values_for_type(
1684
+ self, type: type[OtherName]
1685
+ ) -> list[OtherName]: ...
1686
+
1687
+ def get_values_for_type(
1688
+ self,
1689
+ type: type[DNSName]
1690
+ | type[DirectoryName]
1691
+ | type[IPAddress]
1692
+ | type[OtherName]
1693
+ | type[RFC822Name]
1694
+ | type[RegisteredID]
1695
+ | type[UniformResourceIdentifier],
1696
+ ) -> (
1697
+ list[_IPAddressTypes]
1698
+ | list[str]
1699
+ | list[OtherName]
1700
+ | list[Name]
1701
+ | list[ObjectIdentifier]
1702
+ ):
1703
+ return self._general_names.get_values_for_type(type)
1704
+
1705
+ def __repr__(self) -> str:
1706
+ return f"<IssuerAlternativeName({self._general_names})>"
1707
+
1708
+ def __eq__(self, other: object) -> bool:
1709
+ if not isinstance(other, IssuerAlternativeName):
1710
+ return NotImplemented
1711
+
1712
+ return self._general_names == other._general_names
1713
+
1714
+ def __hash__(self) -> int:
1715
+ return hash(self._general_names)
1716
+
1717
+ def public_bytes(self) -> bytes:
1718
+ return rust_x509.encode_extension_value(self)
1719
+
1720
+
1721
+ class CertificateIssuer(ExtensionType):
1722
+ oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
1723
+
1724
+ def __init__(self, general_names: Iterable[GeneralName]) -> None:
1725
+ self._general_names = GeneralNames(general_names)
1726
+
1727
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
1728
+
1729
+ @typing.overload
1730
+ def get_values_for_type(
1731
+ self,
1732
+ type: type[DNSName]
1733
+ | type[UniformResourceIdentifier]
1734
+ | type[RFC822Name],
1735
+ ) -> list[str]: ...
1736
+
1737
+ @typing.overload
1738
+ def get_values_for_type(
1739
+ self,
1740
+ type: type[DirectoryName],
1741
+ ) -> list[Name]: ...
1742
+
1743
+ @typing.overload
1744
+ def get_values_for_type(
1745
+ self,
1746
+ type: type[RegisteredID],
1747
+ ) -> list[ObjectIdentifier]: ...
1748
+
1749
+ @typing.overload
1750
+ def get_values_for_type(
1751
+ self, type: type[IPAddress]
1752
+ ) -> list[_IPAddressTypes]: ...
1753
+
1754
+ @typing.overload
1755
+ def get_values_for_type(
1756
+ self, type: type[OtherName]
1757
+ ) -> list[OtherName]: ...
1758
+
1759
+ def get_values_for_type(
1760
+ self,
1761
+ type: type[DNSName]
1762
+ | type[DirectoryName]
1763
+ | type[IPAddress]
1764
+ | type[OtherName]
1765
+ | type[RFC822Name]
1766
+ | type[RegisteredID]
1767
+ | type[UniformResourceIdentifier],
1768
+ ) -> (
1769
+ list[_IPAddressTypes]
1770
+ | list[str]
1771
+ | list[OtherName]
1772
+ | list[Name]
1773
+ | list[ObjectIdentifier]
1774
+ ):
1775
+ return self._general_names.get_values_for_type(type)
1776
+
1777
+ def __repr__(self) -> str:
1778
+ return f"<CertificateIssuer({self._general_names})>"
1779
+
1780
+ def __eq__(self, other: object) -> bool:
1781
+ if not isinstance(other, CertificateIssuer):
1782
+ return NotImplemented
1783
+
1784
+ return self._general_names == other._general_names
1785
+
1786
+ def __hash__(self) -> int:
1787
+ return hash(self._general_names)
1788
+
1789
+ def public_bytes(self) -> bytes:
1790
+ return rust_x509.encode_extension_value(self)
1791
+
1792
+
1793
+ class CRLReason(ExtensionType):
1794
+ oid = CRLEntryExtensionOID.CRL_REASON
1795
+
1796
+ def __init__(self, reason: ReasonFlags) -> None:
1797
+ if not isinstance(reason, ReasonFlags):
1798
+ raise TypeError("reason must be an element from ReasonFlags")
1799
+
1800
+ self._reason = reason
1801
+
1802
+ def __repr__(self) -> str:
1803
+ return f"<CRLReason(reason={self._reason})>"
1804
+
1805
+ def __eq__(self, other: object) -> bool:
1806
+ if not isinstance(other, CRLReason):
1807
+ return NotImplemented
1808
+
1809
+ return self.reason == other.reason
1810
+
1811
+ def __hash__(self) -> int:
1812
+ return hash(self.reason)
1813
+
1814
+ @property
1815
+ def reason(self) -> ReasonFlags:
1816
+ return self._reason
1817
+
1818
+ def public_bytes(self) -> bytes:
1819
+ return rust_x509.encode_extension_value(self)
1820
+
1821
+
1822
+ class InvalidityDate(ExtensionType):
1823
+ oid = CRLEntryExtensionOID.INVALIDITY_DATE
1824
+
1825
+ def __init__(self, invalidity_date: datetime.datetime) -> None:
1826
+ if not isinstance(invalidity_date, datetime.datetime):
1827
+ raise TypeError("invalidity_date must be a datetime.datetime")
1828
+
1829
+ self._invalidity_date = invalidity_date
1830
+
1831
+ def __repr__(self) -> str:
1832
+ return f"<InvalidityDate(invalidity_date={self._invalidity_date})>"
1833
+
1834
+ def __eq__(self, other: object) -> bool:
1835
+ if not isinstance(other, InvalidityDate):
1836
+ return NotImplemented
1837
+
1838
+ return self.invalidity_date == other.invalidity_date
1839
+
1840
+ def __hash__(self) -> int:
1841
+ return hash(self.invalidity_date)
1842
+
1843
+ @property
1844
+ def invalidity_date(self) -> datetime.datetime:
1845
+ return self._invalidity_date
1846
+
1847
+ @property
1848
+ def invalidity_date_utc(self) -> datetime.datetime:
1849
+ if self._invalidity_date.tzinfo is None:
1850
+ return self._invalidity_date.replace(tzinfo=datetime.timezone.utc)
1851
+ else:
1852
+ return self._invalidity_date.astimezone(tz=datetime.timezone.utc)
1853
+
1854
+ def public_bytes(self) -> bytes:
1855
+ return rust_x509.encode_extension_value(self)
1856
+
1857
+
1858
+ class PrecertificateSignedCertificateTimestamps(ExtensionType):
1859
+ oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
1860
+
1861
+ def __init__(
1862
+ self,
1863
+ signed_certificate_timestamps: Iterable[SignedCertificateTimestamp],
1864
+ ) -> None:
1865
+ signed_certificate_timestamps = list(signed_certificate_timestamps)
1866
+ if not all(
1867
+ isinstance(sct, SignedCertificateTimestamp)
1868
+ for sct in signed_certificate_timestamps
1869
+ ):
1870
+ raise TypeError(
1871
+ "Every item in the signed_certificate_timestamps list must be "
1872
+ "a SignedCertificateTimestamp"
1873
+ )
1874
+ self._signed_certificate_timestamps = signed_certificate_timestamps
1875
+
1876
+ __len__, __iter__, __getitem__ = _make_sequence_methods(
1877
+ "_signed_certificate_timestamps"
1878
+ )
1879
+
1880
+ def __repr__(self) -> str:
1881
+ return f"<PrecertificateSignedCertificateTimestamps({list(self)})>"
1882
+
1883
+ def __hash__(self) -> int:
1884
+ return hash(tuple(self._signed_certificate_timestamps))
1885
+
1886
+ def __eq__(self, other: object) -> bool:
1887
+ if not isinstance(other, PrecertificateSignedCertificateTimestamps):
1888
+ return NotImplemented
1889
+
1890
+ return (
1891
+ self._signed_certificate_timestamps
1892
+ == other._signed_certificate_timestamps
1893
+ )
1894
+
1895
+ def public_bytes(self) -> bytes:
1896
+ return rust_x509.encode_extension_value(self)
1897
+
1898
+
1899
+ class SignedCertificateTimestamps(ExtensionType):
1900
+ oid = ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS
1901
+
1902
+ def __init__(
1903
+ self,
1904
+ signed_certificate_timestamps: Iterable[SignedCertificateTimestamp],
1905
+ ) -> None:
1906
+ signed_certificate_timestamps = list(signed_certificate_timestamps)
1907
+ if not all(
1908
+ isinstance(sct, SignedCertificateTimestamp)
1909
+ for sct in signed_certificate_timestamps
1910
+ ):
1911
+ raise TypeError(
1912
+ "Every item in the signed_certificate_timestamps list must be "
1913
+ "a SignedCertificateTimestamp"
1914
+ )
1915
+ self._signed_certificate_timestamps = signed_certificate_timestamps
1916
+
1917
+ __len__, __iter__, __getitem__ = _make_sequence_methods(
1918
+ "_signed_certificate_timestamps"
1919
+ )
1920
+
1921
+ def __repr__(self) -> str:
1922
+ return f"<SignedCertificateTimestamps({list(self)})>"
1923
+
1924
+ def __hash__(self) -> int:
1925
+ return hash(tuple(self._signed_certificate_timestamps))
1926
+
1927
+ def __eq__(self, other: object) -> bool:
1928
+ if not isinstance(other, SignedCertificateTimestamps):
1929
+ return NotImplemented
1930
+
1931
+ return (
1932
+ self._signed_certificate_timestamps
1933
+ == other._signed_certificate_timestamps
1934
+ )
1935
+
1936
+ def public_bytes(self) -> bytes:
1937
+ return rust_x509.encode_extension_value(self)
1938
+
1939
+
1940
+ class OCSPNonce(ExtensionType):
1941
+ oid = OCSPExtensionOID.NONCE
1942
+
1943
+ def __init__(self, nonce: bytes) -> None:
1944
+ if not isinstance(nonce, bytes):
1945
+ raise TypeError("nonce must be bytes")
1946
+
1947
+ self._nonce = nonce
1948
+
1949
+ def __eq__(self, other: object) -> bool:
1950
+ if not isinstance(other, OCSPNonce):
1951
+ return NotImplemented
1952
+
1953
+ return self.nonce == other.nonce
1954
+
1955
+ def __hash__(self) -> int:
1956
+ return hash(self.nonce)
1957
+
1958
+ def __repr__(self) -> str:
1959
+ return f"<OCSPNonce(nonce={self.nonce!r})>"
1960
+
1961
+ @property
1962
+ def nonce(self) -> bytes:
1963
+ return self._nonce
1964
+
1965
+ def public_bytes(self) -> bytes:
1966
+ return rust_x509.encode_extension_value(self)
1967
+
1968
+
1969
+ class OCSPAcceptableResponses(ExtensionType):
1970
+ oid = OCSPExtensionOID.ACCEPTABLE_RESPONSES
1971
+
1972
+ def __init__(self, responses: Iterable[ObjectIdentifier]) -> None:
1973
+ responses = list(responses)
1974
+ if any(not isinstance(r, ObjectIdentifier) for r in responses):
1975
+ raise TypeError("All responses must be ObjectIdentifiers")
1976
+
1977
+ self._responses = responses
1978
+
1979
+ def __eq__(self, other: object) -> bool:
1980
+ if not isinstance(other, OCSPAcceptableResponses):
1981
+ return NotImplemented
1982
+
1983
+ return self._responses == other._responses
1984
+
1985
+ def __hash__(self) -> int:
1986
+ return hash(tuple(self._responses))
1987
+
1988
+ def __repr__(self) -> str:
1989
+ return f"<OCSPAcceptableResponses(responses={self._responses})>"
1990
+
1991
+ def __iter__(self) -> Iterator[ObjectIdentifier]:
1992
+ return iter(self._responses)
1993
+
1994
+ def public_bytes(self) -> bytes:
1995
+ return rust_x509.encode_extension_value(self)
1996
+
1997
+
1998
+ class IssuingDistributionPoint(ExtensionType):
1999
+ oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT
2000
+
2001
+ def __init__(
2002
+ self,
2003
+ full_name: Iterable[GeneralName] | None,
2004
+ relative_name: RelativeDistinguishedName | None,
2005
+ only_contains_user_certs: bool,
2006
+ only_contains_ca_certs: bool,
2007
+ only_some_reasons: frozenset[ReasonFlags] | None,
2008
+ indirect_crl: bool,
2009
+ only_contains_attribute_certs: bool,
2010
+ ) -> None:
2011
+ if full_name is not None:
2012
+ full_name = list(full_name)
2013
+
2014
+ if only_some_reasons and (
2015
+ not isinstance(only_some_reasons, frozenset)
2016
+ or not all(isinstance(x, ReasonFlags) for x in only_some_reasons)
2017
+ ):
2018
+ raise TypeError(
2019
+ "only_some_reasons must be None or frozenset of ReasonFlags"
2020
+ )
2021
+
2022
+ if only_some_reasons and (
2023
+ ReasonFlags.unspecified in only_some_reasons
2024
+ or ReasonFlags.remove_from_crl in only_some_reasons
2025
+ ):
2026
+ raise ValueError(
2027
+ "unspecified and remove_from_crl are not valid reasons in an "
2028
+ "IssuingDistributionPoint"
2029
+ )
2030
+
2031
+ if not (
2032
+ isinstance(only_contains_user_certs, bool)
2033
+ and isinstance(only_contains_ca_certs, bool)
2034
+ and isinstance(indirect_crl, bool)
2035
+ and isinstance(only_contains_attribute_certs, bool)
2036
+ ):
2037
+ raise TypeError(
2038
+ "only_contains_user_certs, only_contains_ca_certs, "
2039
+ "indirect_crl and only_contains_attribute_certs "
2040
+ "must all be boolean."
2041
+ )
2042
+
2043
+ # Per RFC5280 Section 5.2.5, the Issuing Distribution Point extension
2044
+ # in a CRL can have only one of onlyContainsUserCerts,
2045
+ # onlyContainsCACerts, onlyContainsAttributeCerts set to TRUE.
2046
+ crl_constraints = [
2047
+ only_contains_user_certs,
2048
+ only_contains_ca_certs,
2049
+ only_contains_attribute_certs,
2050
+ ]
2051
+
2052
+ if len([x for x in crl_constraints if x]) > 1:
2053
+ raise ValueError(
2054
+ "Only one of the following can be set to True: "
2055
+ "only_contains_user_certs, only_contains_ca_certs, "
2056
+ "only_contains_attribute_certs"
2057
+ )
2058
+
2059
+ if not any(
2060
+ [
2061
+ only_contains_user_certs,
2062
+ only_contains_ca_certs,
2063
+ indirect_crl,
2064
+ only_contains_attribute_certs,
2065
+ full_name,
2066
+ relative_name,
2067
+ only_some_reasons,
2068
+ ]
2069
+ ):
2070
+ raise ValueError(
2071
+ "Cannot create empty extension: "
2072
+ "if only_contains_user_certs, only_contains_ca_certs, "
2073
+ "indirect_crl, and only_contains_attribute_certs are all False"
2074
+ ", then either full_name, relative_name, or only_some_reasons "
2075
+ "must have a value."
2076
+ )
2077
+
2078
+ self._only_contains_user_certs = only_contains_user_certs
2079
+ self._only_contains_ca_certs = only_contains_ca_certs
2080
+ self._indirect_crl = indirect_crl
2081
+ self._only_contains_attribute_certs = only_contains_attribute_certs
2082
+ self._only_some_reasons = only_some_reasons
2083
+ self._full_name = full_name
2084
+ self._relative_name = relative_name
2085
+
2086
+ def __repr__(self) -> str:
2087
+ return (
2088
+ f"<IssuingDistributionPoint(full_name={self.full_name}, "
2089
+ f"relative_name={self.relative_name}, "
2090
+ f"only_contains_user_certs={self.only_contains_user_certs}, "
2091
+ f"only_contains_ca_certs={self.only_contains_ca_certs}, "
2092
+ f"only_some_reasons={self.only_some_reasons}, "
2093
+ f"indirect_crl={self.indirect_crl}, "
2094
+ "only_contains_attribute_certs="
2095
+ f"{self.only_contains_attribute_certs})>"
2096
+ )
2097
+
2098
+ def __eq__(self, other: object) -> bool:
2099
+ if not isinstance(other, IssuingDistributionPoint):
2100
+ return NotImplemented
2101
+
2102
+ return (
2103
+ self.full_name == other.full_name
2104
+ and self.relative_name == other.relative_name
2105
+ and self.only_contains_user_certs == other.only_contains_user_certs
2106
+ and self.only_contains_ca_certs == other.only_contains_ca_certs
2107
+ and self.only_some_reasons == other.only_some_reasons
2108
+ and self.indirect_crl == other.indirect_crl
2109
+ and self.only_contains_attribute_certs
2110
+ == other.only_contains_attribute_certs
2111
+ )
2112
+
2113
+ def __hash__(self) -> int:
2114
+ return hash(
2115
+ (
2116
+ self.full_name,
2117
+ self.relative_name,
2118
+ self.only_contains_user_certs,
2119
+ self.only_contains_ca_certs,
2120
+ self.only_some_reasons,
2121
+ self.indirect_crl,
2122
+ self.only_contains_attribute_certs,
2123
+ )
2124
+ )
2125
+
2126
+ @property
2127
+ def full_name(self) -> list[GeneralName] | None:
2128
+ return self._full_name
2129
+
2130
+ @property
2131
+ def relative_name(self) -> RelativeDistinguishedName | None:
2132
+ return self._relative_name
2133
+
2134
+ @property
2135
+ def only_contains_user_certs(self) -> bool:
2136
+ return self._only_contains_user_certs
2137
+
2138
+ @property
2139
+ def only_contains_ca_certs(self) -> bool:
2140
+ return self._only_contains_ca_certs
2141
+
2142
+ @property
2143
+ def only_some_reasons(
2144
+ self,
2145
+ ) -> frozenset[ReasonFlags] | None:
2146
+ return self._only_some_reasons
2147
+
2148
+ @property
2149
+ def indirect_crl(self) -> bool:
2150
+ return self._indirect_crl
2151
+
2152
+ @property
2153
+ def only_contains_attribute_certs(self) -> bool:
2154
+ return self._only_contains_attribute_certs
2155
+
2156
+ def public_bytes(self) -> bytes:
2157
+ return rust_x509.encode_extension_value(self)
2158
+
2159
+
2160
+ class MSCertificateTemplate(ExtensionType):
2161
+ oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE
2162
+
2163
+ def __init__(
2164
+ self,
2165
+ template_id: ObjectIdentifier,
2166
+ major_version: int | None,
2167
+ minor_version: int | None,
2168
+ ) -> None:
2169
+ if not isinstance(template_id, ObjectIdentifier):
2170
+ raise TypeError("oid must be an ObjectIdentifier")
2171
+ self._template_id = template_id
2172
+ if (
2173
+ major_version is not None and not isinstance(major_version, int)
2174
+ ) or (
2175
+ minor_version is not None and not isinstance(minor_version, int)
2176
+ ):
2177
+ raise TypeError(
2178
+ "major_version and minor_version must be integers or None"
2179
+ )
2180
+ self._major_version = major_version
2181
+ self._minor_version = minor_version
2182
+
2183
+ @property
2184
+ def template_id(self) -> ObjectIdentifier:
2185
+ return self._template_id
2186
+
2187
+ @property
2188
+ def major_version(self) -> int | None:
2189
+ return self._major_version
2190
+
2191
+ @property
2192
+ def minor_version(self) -> int | None:
2193
+ return self._minor_version
2194
+
2195
+ def __repr__(self) -> str:
2196
+ return (
2197
+ f"<MSCertificateTemplate(template_id={self.template_id}, "
2198
+ f"major_version={self.major_version}, "
2199
+ f"minor_version={self.minor_version})>"
2200
+ )
2201
+
2202
+ def __eq__(self, other: object) -> bool:
2203
+ if not isinstance(other, MSCertificateTemplate):
2204
+ return NotImplemented
2205
+
2206
+ return (
2207
+ self.template_id == other.template_id
2208
+ and self.major_version == other.major_version
2209
+ and self.minor_version == other.minor_version
2210
+ )
2211
+
2212
+ def __hash__(self) -> int:
2213
+ return hash((self.template_id, self.major_version, self.minor_version))
2214
+
2215
+ def public_bytes(self) -> bytes:
2216
+ return rust_x509.encode_extension_value(self)
2217
+
2218
+
2219
+ class NamingAuthority:
2220
+ def __init__(
2221
+ self,
2222
+ id: ObjectIdentifier | None,
2223
+ url: str | None,
2224
+ text: str | None,
2225
+ ) -> None:
2226
+ if id is not None and not isinstance(id, ObjectIdentifier):
2227
+ raise TypeError("id must be an ObjectIdentifier")
2228
+
2229
+ if url is not None and not isinstance(url, str):
2230
+ raise TypeError("url must be a str")
2231
+
2232
+ if text is not None and not isinstance(text, str):
2233
+ raise TypeError("text must be a str")
2234
+
2235
+ self._id = id
2236
+ self._url = url
2237
+ self._text = text
2238
+
2239
+ @property
2240
+ def id(self) -> ObjectIdentifier | None:
2241
+ return self._id
2242
+
2243
+ @property
2244
+ def url(self) -> str | None:
2245
+ return self._url
2246
+
2247
+ @property
2248
+ def text(self) -> str | None:
2249
+ return self._text
2250
+
2251
+ def __repr__(self) -> str:
2252
+ return (
2253
+ f"<NamingAuthority("
2254
+ f"id={self.id}, url={self.url}, text={self.text})>"
2255
+ )
2256
+
2257
+ def __eq__(self, other: object) -> bool:
2258
+ if not isinstance(other, NamingAuthority):
2259
+ return NotImplemented
2260
+
2261
+ return (
2262
+ self.id == other.id
2263
+ and self.url == other.url
2264
+ and self.text == other.text
2265
+ )
2266
+
2267
+ def __hash__(self) -> int:
2268
+ return hash(
2269
+ (
2270
+ self.id,
2271
+ self.url,
2272
+ self.text,
2273
+ )
2274
+ )
2275
+
2276
+
2277
+ class ProfessionInfo:
2278
+ def __init__(
2279
+ self,
2280
+ naming_authority: NamingAuthority | None,
2281
+ profession_items: Iterable[str],
2282
+ profession_oids: Iterable[ObjectIdentifier] | None,
2283
+ registration_number: str | None,
2284
+ add_profession_info: bytes | None,
2285
+ ) -> None:
2286
+ if naming_authority is not None and not isinstance(
2287
+ naming_authority, NamingAuthority
2288
+ ):
2289
+ raise TypeError("naming_authority must be a NamingAuthority")
2290
+
2291
+ profession_items = list(profession_items)
2292
+ if not all(isinstance(item, str) for item in profession_items):
2293
+ raise TypeError(
2294
+ "Every item in the profession_items list must be a str"
2295
+ )
2296
+
2297
+ if profession_oids is not None:
2298
+ profession_oids = list(profession_oids)
2299
+ if not all(
2300
+ isinstance(oid, ObjectIdentifier) for oid in profession_oids
2301
+ ):
2302
+ raise TypeError(
2303
+ "Every item in the profession_oids list must be an "
2304
+ "ObjectIdentifier"
2305
+ )
2306
+
2307
+ if registration_number is not None and not isinstance(
2308
+ registration_number, str
2309
+ ):
2310
+ raise TypeError("registration_number must be a str")
2311
+
2312
+ if add_profession_info is not None and not isinstance(
2313
+ add_profession_info, bytes
2314
+ ):
2315
+ raise TypeError("add_profession_info must be bytes")
2316
+
2317
+ self._naming_authority = naming_authority
2318
+ self._profession_items = profession_items
2319
+ self._profession_oids = profession_oids
2320
+ self._registration_number = registration_number
2321
+ self._add_profession_info = add_profession_info
2322
+
2323
+ @property
2324
+ def naming_authority(self) -> NamingAuthority | None:
2325
+ return self._naming_authority
2326
+
2327
+ @property
2328
+ def profession_items(self) -> list[str]:
2329
+ return self._profession_items
2330
+
2331
+ @property
2332
+ def profession_oids(self) -> list[ObjectIdentifier] | None:
2333
+ return self._profession_oids
2334
+
2335
+ @property
2336
+ def registration_number(self) -> str | None:
2337
+ return self._registration_number
2338
+
2339
+ @property
2340
+ def add_profession_info(self) -> bytes | None:
2341
+ return self._add_profession_info
2342
+
2343
+ def __repr__(self) -> str:
2344
+ return (
2345
+ f"<ProfessionInfo(naming_authority={self.naming_authority}, "
2346
+ f"profession_items={self.profession_items}, "
2347
+ f"profession_oids={self.profession_oids}, "
2348
+ f"registration_number={self.registration_number}, "
2349
+ f"add_profession_info={self.add_profession_info!r})>"
2350
+ )
2351
+
2352
+ def __eq__(self, other: object) -> bool:
2353
+ if not isinstance(other, ProfessionInfo):
2354
+ return NotImplemented
2355
+
2356
+ return (
2357
+ self.naming_authority == other.naming_authority
2358
+ and self.profession_items == other.profession_items
2359
+ and self.profession_oids == other.profession_oids
2360
+ and self.registration_number == other.registration_number
2361
+ and self.add_profession_info == other.add_profession_info
2362
+ )
2363
+
2364
+ def __hash__(self) -> int:
2365
+ if self.profession_oids is not None:
2366
+ profession_oids = tuple(self.profession_oids)
2367
+ else:
2368
+ profession_oids = None
2369
+ return hash(
2370
+ (
2371
+ self.naming_authority,
2372
+ tuple(self.profession_items),
2373
+ profession_oids,
2374
+ self.registration_number,
2375
+ self.add_profession_info,
2376
+ )
2377
+ )
2378
+
2379
+
2380
+ class Admission:
2381
+ def __init__(
2382
+ self,
2383
+ admission_authority: GeneralName | None,
2384
+ naming_authority: NamingAuthority | None,
2385
+ profession_infos: Iterable[ProfessionInfo],
2386
+ ) -> None:
2387
+ if admission_authority is not None and not isinstance(
2388
+ admission_authority, GeneralName
2389
+ ):
2390
+ raise TypeError("admission_authority must be a GeneralName")
2391
+
2392
+ if naming_authority is not None and not isinstance(
2393
+ naming_authority, NamingAuthority
2394
+ ):
2395
+ raise TypeError("naming_authority must be a NamingAuthority")
2396
+
2397
+ profession_infos = list(profession_infos)
2398
+ if not all(
2399
+ isinstance(info, ProfessionInfo) for info in profession_infos
2400
+ ):
2401
+ raise TypeError(
2402
+ "Every item in the profession_infos list must be a "
2403
+ "ProfessionInfo"
2404
+ )
2405
+
2406
+ self._admission_authority = admission_authority
2407
+ self._naming_authority = naming_authority
2408
+ self._profession_infos = profession_infos
2409
+
2410
+ @property
2411
+ def admission_authority(self) -> GeneralName | None:
2412
+ return self._admission_authority
2413
+
2414
+ @property
2415
+ def naming_authority(self) -> NamingAuthority | None:
2416
+ return self._naming_authority
2417
+
2418
+ @property
2419
+ def profession_infos(self) -> list[ProfessionInfo]:
2420
+ return self._profession_infos
2421
+
2422
+ def __repr__(self) -> str:
2423
+ return (
2424
+ f"<Admission(admission_authority={self.admission_authority}, "
2425
+ f"naming_authority={self.naming_authority}, "
2426
+ f"profession_infos={self.profession_infos})>"
2427
+ )
2428
+
2429
+ def __eq__(self, other: object) -> bool:
2430
+ if not isinstance(other, Admission):
2431
+ return NotImplemented
2432
+
2433
+ return (
2434
+ self.admission_authority == other.admission_authority
2435
+ and self.naming_authority == other.naming_authority
2436
+ and self.profession_infos == other.profession_infos
2437
+ )
2438
+
2439
+ def __hash__(self) -> int:
2440
+ return hash(
2441
+ (
2442
+ self.admission_authority,
2443
+ self.naming_authority,
2444
+ tuple(self.profession_infos),
2445
+ )
2446
+ )
2447
+
2448
+
2449
+ class Admissions(ExtensionType):
2450
+ oid = ExtensionOID.ADMISSIONS
2451
+
2452
+ def __init__(
2453
+ self,
2454
+ authority: GeneralName | None,
2455
+ admissions: Iterable[Admission],
2456
+ ) -> None:
2457
+ if authority is not None and not isinstance(authority, GeneralName):
2458
+ raise TypeError("authority must be a GeneralName")
2459
+
2460
+ admissions = list(admissions)
2461
+ if not all(
2462
+ isinstance(admission, Admission) for admission in admissions
2463
+ ):
2464
+ raise TypeError(
2465
+ "Every item in the contents_of_admissions list must be an "
2466
+ "Admission"
2467
+ )
2468
+
2469
+ self._authority = authority
2470
+ self._admissions = admissions
2471
+
2472
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_admissions")
2473
+
2474
+ @property
2475
+ def authority(self) -> GeneralName | None:
2476
+ return self._authority
2477
+
2478
+ def __repr__(self) -> str:
2479
+ return (
2480
+ f"<Admissions(authority={self._authority}, "
2481
+ f"admissions={self._admissions})>"
2482
+ )
2483
+
2484
+ def __eq__(self, other: object) -> bool:
2485
+ if not isinstance(other, Admissions):
2486
+ return NotImplemented
2487
+
2488
+ return (
2489
+ self.authority == other.authority
2490
+ and self._admissions == other._admissions
2491
+ )
2492
+
2493
+ def __hash__(self) -> int:
2494
+ return hash((self.authority, tuple(self._admissions)))
2495
+
2496
+ def public_bytes(self) -> bytes:
2497
+ return rust_x509.encode_extension_value(self)
2498
+
2499
+
2500
+ class UnrecognizedExtension(ExtensionType):
2501
+ def __init__(self, oid: ObjectIdentifier, value: bytes) -> None:
2502
+ if not isinstance(oid, ObjectIdentifier):
2503
+ raise TypeError("oid must be an ObjectIdentifier")
2504
+ self._oid = oid
2505
+ self._value = value
2506
+
2507
+ @property
2508
+ def oid(self) -> ObjectIdentifier: # type: ignore[override]
2509
+ return self._oid
2510
+
2511
+ @property
2512
+ def value(self) -> bytes:
2513
+ return self._value
2514
+
2515
+ def __repr__(self) -> str:
2516
+ return f"<UnrecognizedExtension(oid={self.oid}, value={self.value!r})>"
2517
+
2518
+ def __eq__(self, other: object) -> bool:
2519
+ if not isinstance(other, UnrecognizedExtension):
2520
+ return NotImplemented
2521
+
2522
+ return self.oid == other.oid and self.value == other.value
2523
+
2524
+ def __hash__(self) -> int:
2525
+ return hash((self.oid, self.value))
2526
+
2527
+ def public_bytes(self) -> bytes:
2528
+ return self.value