x509kit 0.3.1__py3-none-any.whl

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.
x509kit/__init__.py ADDED
@@ -0,0 +1,338 @@
1
+ """
2
+ x509kit — X.509 / PKCS#10 / PKCS#12 / RSA / Ed25519 / ECDSA / CRL / OCSP / NC.
3
+ Только стандартная библиотека Python.
4
+
5
+ Поддерживает:
6
+ * ASN.1 DER (strict)
7
+ * RSA PKCS#1 v1.5 + RSASSA-PSS (blinding + CRT)
8
+ * Ed25519 (RFC 8032), ECDSA (P-256/P-384/P-521/secp256k1, RFC 6979)
9
+ * X.509 v3: SAN, BasicConstraints (BC), KeyUsage (KU),
10
+ Extended Key Usage (EKU), Name Constraints (NC + intersection),
11
+ AKI/SKI, CRL Distribution Points (CRL DP), AIA (OCSP + CA Issuers)
12
+ * PKCS#10 CSR, CRL (RFC 5280), OCSP (RFC 6960)
13
+ * PKCS#8 EncryptedPrivateKeyInfo (PBES2 + PBKDF2 + AES-256-CBC/GCM)
14
+ * PKCS#12 (.p12/.pfx) — export/import/verify, совместим с OpenSSL
15
+ * RFC 4518 канонизация DN
16
+
17
+ ═══════════════════════════════════════════════════════════════════════
18
+ Ключи
19
+ ═══════════════════════════════════════════════════════════════════════
20
+
21
+ RSAKeys.generate(2048)
22
+ RSAKeys.from_pem(pem, private=True, password="...")
23
+ k.to_private_pem(password="...") / k.to_public_pem()
24
+ k.sign_pkcs1v15(msg, "sha256") / k.verify_pkcs1v15(msg, sig, "sha256")
25
+ k.sign_pss(msg, "sha256") / k.verify_pss(msg, sig, "sha256")
26
+ k.size_bits / k.is_private / k.weak
27
+
28
+ Ed25519Keys.generate() / Ed25519Keys(seed=bytes(32))
29
+ Ed25519Keys.from_pem(pem, private=True, password="...")
30
+ k.sign(msg) / k.verify(msg, sig) / k.pub
31
+
32
+ ECDSAKeys.generate("P-256"|"P-384"|"P-521"|"secp256k1")
33
+ ECDSAKeys.from_pem(pem, private=True, password="...")
34
+ k.sign(msg, "sha256") / k.verify(msg, sig, "sha256")
35
+ k.pub / k.curve_oid / k.point
36
+
37
+ ═══════════════════════════════════════════════════════════════════════
38
+ Сертификаты
39
+ ═══════════════════════════════════════════════════════════════════════
40
+
41
+ Cert(pem_or_der)
42
+ c.subject / c.issuer / c.serial / c.version
43
+ c.not_before / c.not_after / c.is_valid_at(when=None)
44
+ c.public_key / c.spki_der / c.key_algorithm_oid
45
+ c.extensions / c.ext_get(oid) / c.san
46
+ c.dns_names / c.ip_addresses / c.emails / c.uris
47
+ ^ SAN-списки по типу (удобный доступ вместо фильтрации c.san)
48
+ c.crl_distribution_points — URL'ы CRL Distribution Points
49
+ c.ski / c.aki — AKI/SKI идентификаторы
50
+ c.eku / c.has_eku("serverAuth") — Extended Key Usage
51
+ c.name_constraints — Name Constraints (dict|None)
52
+ c.aia / c.aia_ocsp / c.aia_issuers — AIA (OCSP/CA Issuers URLs)
53
+ c.name_matches(other) — RFC 4518 канонично
54
+ c.subject_matches_issuer(ca)
55
+ c.weak_hash / c.has_unknown_critical
56
+ c.verify_signature(issuer) / c.is_self_signed()
57
+ c.to_pem() / c.to_der()
58
+
59
+ CACert.create_self_signed(subject, keys, days=3650, path_len=None)
60
+ CACert.from_cert(cert, signing_key=None)
61
+ CACert.from_pem(pem, private_key_pem=None)
62
+
63
+ ca.issue_csr(csr, days=365, is_ca=False, path_len=None)
64
+ ca.issue_with_key(csr, signing_key, days=365, is_ca=False)
65
+ ^ если CA без приватного ключа или ключ передаётся явно
66
+ ca.verify_cert(cert, crl=None, ocsp_response=None)
67
+ ca.verify_chain([leaf, inter], crl=None)
68
+
69
+ ca.revoke(cert_or_serial, reason="keyCompromise")
70
+ ca.to_crl(days=7)
71
+ ca.respond_ocsp(cert_or_request, status="good", reason=None, days=7)
72
+ ca.verify_ocsp_response(response, request=None)
73
+
74
+ ca.path_len / ca.key_usage / ca.is_ca / ca.name_constraints
75
+
76
+ ═══════════════════════════════════════════════════════════════════════
77
+ CSR (PKCS#10)
78
+ ═══════════════════════════════════════════════════════════════════════
79
+
80
+ CSR.create(subject, keys, extensions=[...])
81
+ CSR(pem_or_der)
82
+ csr.subject / csr.public_key / csr.spki_der
83
+ csr.san / csr.eku / csr.has_eku("serverAuth") / csr.extensions
84
+ csr.dns_names / csr.ip_addresses / csr.emails / csr.uris
85
+ ^ SAN-списки из extensionRequest
86
+ csr.verify_signature() / csr.to_pem()
87
+
88
+ ═══════════════════════════════════════════════════════════════════════
89
+ CRL (RFC 5280 §5)
90
+ ═══════════════════════════════════════════════════════════════════════
91
+
92
+ CRL(pem_or_der) / load_pem_crls(pem)
93
+ crl.issuer / crl.this_update / crl.next_update / crl.revoked
94
+ crl.is_revoked(cert_or_serial) / crl.revoke_reason(cert_or_serial)
95
+ crl.is_valid_at() / crl.verify_signature(ca) / crl.to_pem()
96
+
97
+ CRL_REASONS — keyCompromise, cACompromise, ...
98
+
99
+ CRLBuilder()
100
+ .set_issuer(ca).set_validity(days=7)
101
+ .add_revoked(serial_or_cert, reason="keyCompromise")
102
+ .sign(ca_key)
103
+
104
+ ═══════════════════════════════════════════════════════════════════════
105
+ OCSP (RFC 6960)
106
+ ═══════════════════════════════════════════════════════════════════════
107
+
108
+ OCSPRequest.create(issuer, cert_or_serial)
109
+ OCSPRequest.create(issuer=ca, cert=leaf)
110
+ OCSPRequest.create(issuer=ca, serial=12345)
111
+ req.serial / req.nonce / req.cert_id / req.to_der() / req.to_pem()
112
+
113
+ OCSPResponse(pem_or_der)
114
+ resp.status / resp.is_successful / resp.responses
115
+ resp.get_status(cert_or_serial) — 'good'|'revoked'|'unknown'|None
116
+ resp.get_revoke_info(cert)
117
+ resp.verify_signature(issuer) / resp.is_fresh() / resp.nonce
118
+
119
+ OCSPResponseBuilder()
120
+ .set_responder(ca).set_validity(days=7).set_nonce(bytes)
121
+ .add_status(cert_or_serial, status="good"|"revoked"|"unknown",
122
+ reason="keyCompromise")
123
+ .sign(ca_key)
124
+
125
+ OCSP_STATUS_NAMES / OCSP_STATUS_CODES
126
+ OID_OCSP / OID_OCSP_BASIC / OID_OCSP_NONCE
127
+
128
+ ═══════════════════════════════════════════════════════════════════════
129
+ CertificateBuilder
130
+ ═══════════════════════════════════════════════════════════════════════
131
+
132
+ CertificateBuilder(is_ca=False)
133
+ .add_subject({"CN": "example.com", "O": "Org", "C": "XX"})
134
+ .add_issuer(ca) / .self_signed()
135
+ .add_public_key(key) — RSAKeys/Ed25519Keys/ECDSAKeys/SPKI/CSR
136
+ .add_serial_random() / .add_serial(n)
137
+ .add_validity(days=365) / .add_not_before(dt) / .add_not_after(dt)
138
+ .add_san(dns=[], ips=[], emails=[], uris=[])
139
+ .add_san_dns("a.com", "b.com") / .add_san_ip("1.2.3.4")
140
+ .add_san_email(...) / .add_san_uri(...) / .add_san_directory_name(...)
141
+ .add_basic_constraints(path_len=None)
142
+ .add_key_usage("digitalSignature", "keyEncipherment")
143
+ .add_extended_key_usage("serverAuth", "clientAuth") (.add_eku)
144
+ .add_name_constraints(permitted_dns=[...], excluded_dns=[...],
145
+ permitted_ip=[...], excluded_ip=[...])
146
+ .add_crl_distribution_point("http://ca.example.com/crl.pem")
147
+ .add_aia(ocsp=["http://..."], ca_issuers=["http://..."])
148
+ .add_ski(hex) / .add_aki(hex)
149
+ .add_extension(oid, critical, value_der) / .add_raw_extension(der)
150
+ .set_ca(path_len=0) / .set_end_entity()
151
+ .set_hash("sha256") / .set_sig_scheme("pss") / .use_pss()
152
+ .sign(ca_key) — Cert или CACert
153
+
154
+ CertificateBuilder.from_csr(csr, is_ca=False, copy_extensions=True)
155
+
156
+ ═══════════════════════════════════════════════════════════════════════
157
+ CSRBuilder
158
+ ═══════════════════════════════════════════════════════════════════════
159
+
160
+ CSRBuilder()
161
+ .add_subject({...}) / .add_public_key(key)
162
+ .add_san(...) / .add_san_dns(...) / .add_san_ip(...)
163
+ .add_extended_key_usage("serverAuth")
164
+ .set_hash("sha256") / .set_sig_scheme("pss") / .use_pss()
165
+ .sign(signing_key)
166
+
167
+ ═══════════════════════════════════════════════════════════════════════
168
+ Хелперы и OID
169
+ ═══════════════════════════════════════════════════════════════════════
170
+
171
+ ASN1 — низкоуровневый DER-парсер (parse, as_int, as_oid, ...)
172
+ ^ защита: _MAX_DER_SIZE = 50 MB, _MAX_DEPTH = 32
173
+ canonicalize_name(name) / names_equal(a, b) — RFC 4518
174
+ san_extension(dns_names=[], ips=[], emails=[], uris=[])
175
+ validate_hostname(cert, "example.com") — RFC 6125
176
+ load_pem_certs / load_pem_csrs / load_pem_bundle / load_pem_crls
177
+ ^ защита: _MAX_PEM_SIZE = 10 MB
178
+ save_pem(path, cert1, cert2, ...)
179
+ pem_encode / pem_decode / verify_chain
180
+
181
+ CertBundle([c1, c2, ...])
182
+ .from_pem(data) / .from_file(path) / .to_pem() / .save(path)
183
+
184
+ EKU_OIDS — {serverAuth, clientAuth, codeSigning, emailProtection,
185
+ timeStamping, OCSPSigning, anyExtendedKeyUsage, ...}
186
+ EC_CURVES — {OID: {p, a, b, Gx, Gy, n, size}}
187
+
188
+ OID_RSA_PSS = "1.2.840.113549.1.1.10"
189
+ OID_NAME_CONSTR = "2.5.29.30"
190
+ OID_AIA = "1.3.6.1.5.5.7.1.1"
191
+ OID_AD_CA_ISSUERS = "1.3.6.1.5.5.7.48.2"
192
+ OID_EC_PUBLIC_KEY = "1.2.840.10045.2.1"
193
+ OID_PRIME256V1 / OID_SECP384R1 / OID_SECP521R1 / OID_SECP256K1
194
+ OID_PBES2 / OID_PBKDF2 / OID_HMAC_SHA256
195
+ OID_AES_256_CBC = "2.16.840.1.101.3.4.1.42"
196
+ OID_AES_256_GCM = "2.16.840.1.101.3.4.1.46"
197
+
198
+ ═══════════════════════════════════════════════════════════════════════
199
+ PKCS#12 (.p12 / .pfx)
200
+ ═══════════════════════════════════════════════════════════════════════
201
+
202
+ PKCS12 — контейнер: приватный ключ + сертификат + цепочка (RFC 7292)
203
+
204
+ PKCS12.build(key, cert, chain=[inter], password="...", name="client")
205
+ pk.to_der() / pk.save("client.p12")
206
+
207
+ PKCS12Builder() — fluent-обёртка
208
+ .set_key(k) / .add_key(k)
209
+ .set_cert(cert) / .add_cert(cert)
210
+ .add_chain(inter, root)
211
+ .set_password("...")
212
+ .set_name("alice")
213
+ .set_iterations(2048)
214
+ .set_mac_iterations(2048)
215
+ .set_cipher("aes-256-cbc")
216
+ .build() — PKCS12
217
+ .save("alice.p12") — сразу в файл
218
+
219
+ PKCS12.load(der, password="...")
220
+ PKCS12.from_file(path, password="...")
221
+ pk.key / pk.cert / pk.chain
222
+ pk.verify_mac(password=None)
223
+ pk.verify_chain(trust_anchor=root, when=None)
224
+
225
+ # Совместимо с OpenSSL:
226
+ # openssl pkcs12 -in file.p12 -info -noout
227
+ # openssl pkcs12 -in file.p12 -nodes -out extracted.pem
228
+
229
+ ═══════════════════════════════════════════════════════════════════════
230
+ Исключения и предупреждения
231
+ ═══════════════════════════════════════════════════════════════════════
232
+
233
+ X509Error — базовое исключение
234
+ X509ParseError — ошибка парсинга DER/PEM
235
+ X509VerifyError — ошибка проверки подписи/цепочки
236
+ X509Warning — не-фатальное предупреждение (UserWarning)
237
+
238
+ Все ошибки содержат подсказку «Как исправить: ...».
239
+
240
+ Сделать warnings ошибками (для CI):
241
+ import warnings; warnings.simplefilter("error", X509Warning)
242
+
243
+ ═══════════════════════════════════════════════════════════════════════
244
+ Пример
245
+ ═══════════════════════════════════════════════════════════════════════
246
+
247
+ from x509kit import CertificateBuilder, Ed25519Keys, RSAKeys
248
+
249
+ ca_key = Ed25519Keys.generate()
250
+ ca = (CertificateBuilder(is_ca=True)
251
+ .add_subject({"C": "XX", "O": "MyOrg", "CN": "MyOrg Root CA"})
252
+ .add_public_key(ca_key)
253
+ .add_serial_random().add_validity(days=3650)
254
+ .add_basic_constraints(path_len=0)
255
+ .add_key_usage("keyCertSign", "cRLSign")
256
+ .self_signed().sign(ca_key))
257
+
258
+ leaf_key = RSAKeys.generate(2048)
259
+ leaf = (CertificateBuilder()
260
+ .add_subject({"C": "XX", "O": "MyOrg", "CN": "example.com"})
261
+ .add_issuer(ca).add_public_key(leaf_key)
262
+ .add_serial_random().add_validity(days=365)
263
+ .add_san_dns("example.com", "www.example.com")
264
+ .add_extended_key_usage("serverAuth")
265
+ .use_pss()
266
+ .sign(ca_key))
267
+
268
+ assert ca.verify_chain([leaf])
269
+ """
270
+
271
+ from .x509 import (
272
+ # Ключи
273
+ RSAKeys, Ed25519Keys, ECDSAKeys, EC_CURVES,
274
+ OID_EC_PUBLIC_KEY, OID_PRIME256V1,
275
+ OID_SECP384R1, OID_SECP521R1, OID_SECP256K1,
276
+ # Структуры
277
+ ASN1,
278
+ Name, Cert, CACert, CSR, CertBundle,
279
+ # PKCS#12
280
+ PKCS12, PKCS12Builder,
281
+ # CRL
282
+ CRL, CRLBuilder, CRL_REASONS, CRL_REASONS_REV, load_pem_crls,
283
+ # OCSP
284
+ OCSPRequest, OCSPResponse, OCSPResponseBuilder,
285
+ OCSP_STATUS_NAMES, OCSP_STATUS_CODES,
286
+ OID_OCSP, OID_OCSP_BASIC, OID_OCSP_NONCE,
287
+ # Builders
288
+ CertificateBuilder, CertBuilder, CSRBuilder,
289
+ # Хелперы
290
+ san_extension, validate_hostname,
291
+ canonicalize_name, names_equal,
292
+ load_pem_certs, load_pem_csrs, load_pem_bundle, save_pem,
293
+ pem_encode, pem_decode, verify_chain,
294
+ EKU_OIDS,
295
+ # OID-константы
296
+ OID_RSA_PSS, OID_NAME_CONSTR,
297
+ OID_AIA, OID_AD_CA_ISSUERS,
298
+ OID_PBES2, OID_PBKDF2, OID_HMAC_SHA256,
299
+ OID_AES_256_CBC, OID_AES_256_GCM,
300
+ # Исключения
301
+ X509Error, X509ParseError, X509VerifyError, X509Warning,
302
+ # Версия
303
+ __version__,
304
+ )
305
+
306
+ __all__ = [
307
+ "ASN1",
308
+ # Ключи
309
+ "RSAKeys", "Ed25519Keys", "ECDSAKeys", "EC_CURVES",
310
+ "OID_EC_PUBLIC_KEY", "OID_PRIME256V1",
311
+ "OID_SECP384R1", "OID_SECP521R1", "OID_SECP256K1",
312
+ # Структуры
313
+ "Name", "Cert", "CACert", "CSR", "CertBundle",
314
+ # CRL
315
+ "PKCS12", "PKCS12Builder",
316
+ "CRL", "CRLBuilder", "CRL_REASONS", "CRL_REASONS_REV", "load_pem_crls",
317
+ # OCSP
318
+ "OCSPRequest", "OCSPResponse", "OCSPResponseBuilder",
319
+ "OCSP_STATUS_NAMES", "OCSP_STATUS_CODES",
320
+ "OID_OCSP", "OID_OCSP_BASIC", "OID_OCSP_NONCE",
321
+ # Builders
322
+ "CertificateBuilder", "CertBuilder", "CSRBuilder",
323
+ # Хелперы
324
+ "san_extension", "validate_hostname",
325
+ "canonicalize_name", "names_equal",
326
+ "load_pem_certs", "load_pem_csrs", "load_pem_bundle", "save_pem",
327
+ "pem_encode", "pem_decode", "verify_chain",
328
+ "EKU_OIDS",
329
+ # OID-константы
330
+ "OID_RSA_PSS", "OID_NAME_CONSTR",
331
+ "OID_AIA", "OID_AD_CA_ISSUERS",
332
+ "OID_PBES2", "OID_PBKDF2", "OID_HMAC_SHA256",
333
+ "OID_AES_256_CBC", "OID_AES_256_GCM",
334
+ # Исключения
335
+ "X509Error", "X509ParseError", "X509VerifyError", "X509Warning",
336
+ # Версия
337
+ "__version__",
338
+ ]
x509kit/py.typed ADDED
File without changes