Brettapps commited on
Commit
d8ebcc3
·
verified ·
1 Parent(s): 6970182

Upload folder using huggingface_hub (part 2)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/INSTALLER +1 -0
  2. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/METADATA +110 -0
  3. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/RECORD +199 -0
  4. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/WHEEL +5 -0
  5. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/licenses/LICENSE +3 -0
  6. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/licenses/LICENSE.APACHE +202 -0
  7. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/licenses/LICENSE.BSD +27 -0
  8. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/sboms/cryptography-rust.cyclonedx.json +1365 -0
  9. .mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/sboms/sbom.json +43 -0
  10. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/hashes.py +357 -0
  11. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/hmac.py +13 -0
  12. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/hpke.py +27 -0
  13. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/__init__.py +32 -0
  14. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/argon2.py +17 -0
  15. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py +16 -0
  16. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py +16 -0
  17. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py +26 -0
  18. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py +13 -0
  19. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py +19 -0
  20. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py +13 -0
  21. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/keywrap.py +25 -0
  22. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/padding.py +69 -0
  23. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/poly1305.py +11 -0
  24. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/__init__.py +85 -0
  25. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/base.py +16 -0
  26. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py +176 -0
  27. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py +412 -0
  28. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/ssh.py +1615 -0
  29. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py +9 -0
  30. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py +101 -0
  31. .mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/twofactor/totp.py +56 -0
  32. .mcp-venv/lib/python3.13/site-packages/cryptography/py.typed +0 -0
  33. .mcp-venv/lib/python3.13/site-packages/cryptography/utils.py +136 -0
  34. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/__init__.py +270 -0
  35. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/base.py +834 -0
  36. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/certificate_transparency.py +35 -0
  37. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/extensions.py +2533 -0
  38. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/general_name.py +281 -0
  39. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/name.py +489 -0
  40. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/ocsp.py +379 -0
  41. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/oid.py +37 -0
  42. .mcp-venv/lib/python3.13/site-packages/cryptography/x509/verification.py +34 -0
  43. .mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/INSTALLER +1 -0
  44. .mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/METADATA +202 -0
  45. .mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/RECORD +29 -0
  46. .mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/WHEEL +5 -0
  47. .mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt +22 -0
  48. .mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/top_level.txt +1 -0
  49. .mcp-venv/lib/python3.13/site-packages/h11/__init__.py +62 -0
  50. .mcp-venv/lib/python3.13/site-packages/h11/_abnf.py +132 -0
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/METADATA ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: cryptography
3
+ Version: 50.0.0
4
+ Classifier: Development Status :: 5 - Production/Stable
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: Natural Language :: English
7
+ Classifier: Operating System :: MacOS :: MacOS X
8
+ Classifier: Operating System :: POSIX
9
+ Classifier: Operating System :: POSIX :: BSD
10
+ Classifier: Operating System :: POSIX :: Linux
11
+ Classifier: Operating System :: Microsoft :: Windows
12
+ Classifier: Programming Language :: Python
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Programming Language :: Python :: Implementation :: CPython
22
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
23
+ Classifier: Programming Language :: Python :: Free Threading :: 3 - Stable
24
+ Classifier: Topic :: Security :: Cryptography
25
+ Requires-Dist: cffi>=2.0.0 ; platform_python_implementation != 'PyPy'
26
+ Requires-Dist: typing-extensions>=4.13.2 ; python_full_version < '3.11'
27
+ Requires-Dist: bcrypt>=3.1.5 ; extra == 'ssh'
28
+ Provides-Extra: ssh
29
+ License-File: LICENSE
30
+ License-File: LICENSE.APACHE
31
+ License-File: LICENSE.BSD
32
+ Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers.
33
+ Author-email: The Python Cryptographic Authority and individual contributors <cryptography-dev@python.org>
34
+ License-Expression: Apache-2.0 OR BSD-3-Clause
35
+ Requires-Python: >=3.9, !=3.9.0, !=3.9.1
36
+ Description-Content-Type: text/x-rst; charset=UTF-8
37
+ Project-URL: changelog, https://cryptography.io/en/latest/changelog/
38
+ Project-URL: documentation, https://cryptography.io/
39
+ Project-URL: homepage, https://github.com/pyca/cryptography
40
+ Project-URL: issues, https://github.com/pyca/cryptography/issues
41
+ Project-URL: source, https://github.com/pyca/cryptography/
42
+
43
+ pyca/cryptography
44
+ =================
45
+
46
+ .. image:: https://img.shields.io/pypi/v/cryptography.svg
47
+ :target: https://pypi.org/project/cryptography/
48
+ :alt: Latest Version
49
+
50
+ .. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest
51
+ :target: https://cryptography.io
52
+ :alt: Latest Docs
53
+
54
+ .. image:: https://github.com/pyca/cryptography/actions/workflows/ci.yml/badge.svg
55
+ :target: https://github.com/pyca/cryptography/actions/workflows/ci.yml?query=branch%3Amain
56
+
57
+ ``cryptography`` is a package which provides cryptographic recipes and
58
+ primitives to Python developers. Our goal is for it to be your "cryptographic
59
+ standard library". It supports Python 3.9+ and PyPy3 7.3.11+.
60
+
61
+ ``cryptography`` includes both high level recipes and low level interfaces to
62
+ common cryptographic algorithms such as symmetric ciphers, message digests, and
63
+ key derivation functions. For example, to encrypt something with
64
+ ``cryptography``'s high level symmetric encryption recipe:
65
+
66
+ .. code-block:: pycon
67
+
68
+ >>> from cryptography.fernet import Fernet
69
+ >>> # Put this somewhere safe!
70
+ >>> key = Fernet.generate_key()
71
+ >>> f = Fernet(key)
72
+ >>> token = f.encrypt(b"A really secret message. Not for prying eyes.")
73
+ >>> token
74
+ b'...'
75
+ >>> f.decrypt(token)
76
+ b'A really secret message. Not for prying eyes.'
77
+
78
+ You can find more information in the `documentation`_.
79
+
80
+ You can install ``cryptography`` with:
81
+
82
+ .. code-block:: console
83
+
84
+ $ pip install cryptography
85
+
86
+ For full details see `the installation documentation`_.
87
+
88
+ Discussion
89
+ ~~~~~~~~~~
90
+
91
+ If you run into bugs, you can file them in our `issue tracker`_.
92
+
93
+ We maintain a `cryptography-dev`_ mailing list for development discussion.
94
+
95
+ You can also join ``#pyca`` on ``irc.libera.chat`` to ask questions or get
96
+ involved.
97
+
98
+ Security
99
+ ~~~~~~~~
100
+
101
+ Need to report a security issue? Please consult our `security reporting`_
102
+ documentation.
103
+
104
+
105
+ .. _`documentation`: https://cryptography.io/
106
+ .. _`the installation documentation`: https://cryptography.io/en/latest/installation/
107
+ .. _`issue tracker`: https://github.com/pyca/cryptography/issues
108
+ .. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev
109
+ .. _`security reporting`: https://cryptography.io/en/latest/security/
110
+
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/RECORD ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ cryptography-50.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ cryptography-50.0.0.dist-info/METADATA,sha256=1ONF-Cy3g4d9cyYfADA1d83yDRMikXbC0DoKVgPLOrU,4343
3
+ cryptography-50.0.0.dist-info/RECORD,,
4
+ cryptography-50.0.0.dist-info/WHEEL,sha256=ObQlzmyJjoP4uM3utl2uaQ06ufI4LKnDhg53v200B3o,109
5
+ cryptography-50.0.0.dist-info/licenses/LICENSE,sha256=Pgx8CRqUi4JTO6mP18u0BDLW8amsv4X1ki0vmak65rs,197
6
+ cryptography-50.0.0.dist-info/licenses/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360
7
+ cryptography-50.0.0.dist-info/licenses/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532
8
+ cryptography-50.0.0.dist-info/sboms/cryptography-rust.cyclonedx.json,sha256=37hpPvBk1cczEk7Pe2369H-MfrP0RYEqmbiTbjdGtcA,45685
9
+ cryptography-50.0.0.dist-info/sboms/sbom.json,sha256=Ow5KjdWCtUUDLAwciwzmVqJAdsCoTtvzWfopBsB4OOU,1206
10
+ cryptography/__about__.py,sha256=rM2noC1TeiQiQ4o8wL-OmtXas5OXwhkWPFo7yTZ-XSM,445
11
+ cryptography/__init__.py,sha256=mthuUrTd4FROCpUYrTIqhjz6s6T9djAZrV7nZ1oMm2o,364
12
+ cryptography/__pycache__/__about__.cpython-313.pyc,,
13
+ cryptography/__pycache__/__init__.cpython-313.pyc,,
14
+ cryptography/__pycache__/cobblestone.cpython-313.pyc,,
15
+ cryptography/__pycache__/exceptions.cpython-313.pyc,,
16
+ cryptography/__pycache__/fernet.cpython-313.pyc,,
17
+ cryptography/__pycache__/utils.cpython-313.pyc,,
18
+ cryptography/cobblestone.py,sha256=T_-F08-AUf3ljaypZeklNTV1hWObH57oo45mVSzk9wc,693
19
+ cryptography/exceptions.py,sha256=835EWILc2fwxw-gyFMriciC2SqhViETB10LBSytnDIc,1087
20
+ cryptography/fernet.py,sha256=2sLCPOmejhOVbudcS3QsM1PIuHbxCeRcRtWkncQ3mCo,7687
21
+ cryptography/hazmat/__init__.py,sha256=5IwrLWrVp0AjEr_4FdWG_V057NSJGY_W4egNNsuct0g,455
22
+ cryptography/hazmat/__pycache__/__init__.cpython-313.pyc,,
23
+ cryptography/hazmat/__pycache__/_oid.cpython-313.pyc,,
24
+ cryptography/hazmat/_oid.py,sha256=Ohe2nUE6XjKx1UF6TAsGUy2v8GUJ-Vi9DS4yxSukt5U,18150
25
+ cryptography/hazmat/asn1/__init__.py,sha256=YqYToHGFjLOKigRC00HGj6hrjEwbu1SPpAiu6-u-fao,812
26
+ cryptography/hazmat/asn1/__pycache__/__init__.cpython-313.pyc,,
27
+ cryptography/hazmat/asn1/__pycache__/asn1.cpython-313.pyc,,
28
+ cryptography/hazmat/asn1/asn1.py,sha256=9mcfrmdvK7KtjhRYofMzAjW0u7nvqbfsvPfbhNQK1BQ,19152
29
+ cryptography/hazmat/backends/__init__.py,sha256=O5jvKFQdZnXhKeqJ-HtulaEL9Ni7mr1mDzZY5kHlYhI,361
30
+ cryptography/hazmat/backends/__pycache__/__init__.cpython-313.pyc,,
31
+ cryptography/hazmat/backends/openssl/__init__.py,sha256=p3jmJfnCag9iE5sdMrN6VvVEu55u46xaS_IjoI0SrmA,305
32
+ cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-313.pyc,,
33
+ cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-313.pyc,,
34
+ cryptography/hazmat/backends/openssl/backend.py,sha256=0NczFbiwGxfq9qi28oHYr08r_r7VQg4AXHjb0oFPwqA,10475
35
+ cryptography/hazmat/bindings/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
36
+ cryptography/hazmat/bindings/__pycache__/__init__.cpython-313.pyc,,
37
+ cryptography/hazmat/bindings/_rust.abi3.so,sha256=YT7FcFlL4mkc4Y_oqlGqRxZYTA5Ybsl915DEuXV7WoM,14357504
38
+ cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=uUnnvOq_uameYnBNpmsv3SRAVO0WQGpjI58aR1lL4Kw,2285
39
+ cryptography/hazmat/bindings/_rust/_openssl.pyi,sha256=T_5TpYO8bghIPjAQ3BtAABqw-CcYskHp92wm5PNY6dc,228
40
+ cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=BrGjC8J6nwuS-r3EVcdXJB8ndotfY9mbQYOfpbPG0HA,354
41
+ cryptography/hazmat/bindings/_rust/cobblestone.pyi,sha256=9lUf1W1hTrszEJ4YpScJNIPSD9BOM7o-C82-mtSDG9o,1325
42
+ cryptography/hazmat/bindings/_rust/declarative_asn1.pyi,sha256=MBmOZzLTdmPJ6-1K6Aq3PTuHJ1MGgRfIu0hIgag7ocE,3866
43
+ cryptography/hazmat/bindings/_rust/exceptions.pyi,sha256=exXr2xw_0pB1kk93cYbM3MohbzoUkjOms1ZMUi0uQZE,640
44
+ cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=VPVWuKHI9EMs09ZLRYAGvR0Iz0mCMmEzXAkgJHovpoM,4020
45
+ cryptography/hazmat/bindings/_rust/openssl/__init__.pyi,sha256=O6GOyvDxt6ylicB2aFGuu5RcGZy9UjKnYqGR8rqzvdw,1578
46
+ cryptography/hazmat/bindings/_rust/openssl/aead.pyi,sha256=7d--xdc0vuzRe4S2uuQaGm-9GGKv4NcSLQcLyWcaD6s,4582
47
+ cryptography/hazmat/bindings/_rust/openssl/ciphers.pyi,sha256=LhPzHWSXJq4grAJXn6zSvSSdV-aYIIscHDwIPlJGGPs,1315
48
+ cryptography/hazmat/bindings/_rust/openssl/cmac.pyi,sha256=nPH0X57RYpsAkRowVpjQiHE566ThUTx7YXrsadmrmHk,564
49
+ cryptography/hazmat/bindings/_rust/openssl/dh.pyi,sha256=Z3TC-G04-THtSdAOPLM1h2G7ml5bda1ElZUcn5wpuhk,1564
50
+ cryptography/hazmat/bindings/_rust/openssl/dsa.pyi,sha256=qBtkgj2albt2qFcnZ9UDrhzoNhCVO7HTby5VSf1EXMI,1299
51
+ cryptography/hazmat/bindings/_rust/openssl/ec.pyi,sha256=zJy0pRa5n-_p2dm45PxECB_-B6SVZyNKfjxFDpPqT38,1691
52
+ cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi,sha256=VXfXd5G6hUivg399R1DYdmW3eTb0EebzDTqjRC2gaRw,532
53
+ cryptography/hazmat/bindings/_rust/openssl/ed448.pyi,sha256=Yx49lqdnjsD7bxiDV1kcaMrDktug5evi5a6zerMiy2s,514
54
+ cryptography/hazmat/bindings/_rust/openssl/hashes.pyi,sha256=bFe3T13UeyRInUJMD-R5ArGTGLqWDiWo2Lv2KGzUbf4,1076
55
+ cryptography/hazmat/bindings/_rust/openssl/hmac.pyi,sha256=BXZn7NDjL3JAbYW0SQ8pg1iyC5DbQXVhUAiwsi8DFR8,702
56
+ cryptography/hazmat/bindings/_rust/openssl/hpke.pyi,sha256=p_hGLn6YH-EarJF1V5bUsUtjipviEApcR5O0sUHJLtc,2914
57
+ cryptography/hazmat/bindings/_rust/openssl/kdf.pyi,sha256=HiiLdEB9nqMsTvMwiFppQpfPz6fHUz9_gpjEB_XAOXA,6619
58
+ cryptography/hazmat/bindings/_rust/openssl/keys.pyi,sha256=teIt8M6ZEMJrn4s3W0UnW0DZ-30Jd68WnSsKKG124l0,912
59
+ cryptography/hazmat/bindings/_rust/openssl/keywrap.pyi,sha256=mGCJEoQ4lxi4CROTBEuUzb9U4ky8n52L3iDvCOXNBRI,733
60
+ cryptography/hazmat/bindings/_rust/openssl/mldsa.pyi,sha256=H84XDW0TQ3LHhdGJD5uPaDT5ijEiK6MZytXYc8rBNf4,1421
61
+ cryptography/hazmat/bindings/_rust/openssl/mlkem.pyi,sha256=byoeus4-lIOlWlEiRQdCc00qCkXpOB5peBY6yo9ik8s,835
62
+ cryptography/hazmat/bindings/_rust/openssl/poly1305.pyi,sha256=_SW9NtQ5FDlAbdclFtWpT4lGmxKIKHpN-4j8J2BzYfQ,585
63
+ cryptography/hazmat/bindings/_rust/openssl/rsa.pyi,sha256=2OQCNSXkxgc-3uw1xiCCloIQTV6p9_kK79Yu0rhZgPc,1364
64
+ cryptography/hazmat/bindings/_rust/openssl/x25519.pyi,sha256=ewn4GpQyb7zPwE-ni7GtyQgMC0A1mLuqYsSyqv6nI_s,523
65
+ cryptography/hazmat/bindings/_rust/openssl/x448.pyi,sha256=juTZTmli8jO_5Vcufg-vHvx_tCyezmSLIh_9PU3TczI,505
66
+ cryptography/hazmat/bindings/_rust/pkcs12.pyi,sha256=vEEd5wDiZvb8ZGFaziLCaWLzAwoG_tvPUxLQw5_uOl8,1605
67
+ cryptography/hazmat/bindings/_rust/pkcs7.pyi,sha256=txGBJijqZshEcqra6byPNbnisIdlxzOSIHP2hl9arPs,1601
68
+ cryptography/hazmat/bindings/_rust/test_support.pyi,sha256=PPhld-WkO743iXFPebeG0LtgK0aTzGdjcIsay1Gm5GE,757
69
+ cryptography/hazmat/bindings/_rust/x509.pyi,sha256=LVT4htBNse5gijQh4GhVNYEbAO0E1ANgE28tWqw3g4I,10211
70
+ cryptography/hazmat/bindings/openssl/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
71
+ cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-313.pyc,,
72
+ cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-313.pyc,,
73
+ cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-313.pyc,,
74
+ cryptography/hazmat/bindings/openssl/_conditional.py,sha256=vfzi-xHdStAcJQjLqqOlSos94L8D_tqFtBe7Ovw-KtY,5611
75
+ cryptography/hazmat/bindings/openssl/binding.py,sha256=FsuLxbTnrqW60-dAWtakgufeq7TnqaQai1Pc7Dowrjo,3706
76
+ cryptography/hazmat/decrepit/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
77
+ cryptography/hazmat/decrepit/__pycache__/__init__.cpython-313.pyc,,
78
+ cryptography/hazmat/decrepit/ciphers/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
79
+ cryptography/hazmat/decrepit/ciphers/__pycache__/__init__.cpython-313.pyc,,
80
+ cryptography/hazmat/decrepit/ciphers/__pycache__/algorithms.cpython-313.pyc,,
81
+ cryptography/hazmat/decrepit/ciphers/__pycache__/modes.cpython-313.pyc,,
82
+ cryptography/hazmat/decrepit/ciphers/algorithms.py,sha256=WSPjM2sXfrLDXrtN5R7N6rA1XF7b93I1e_lvD4yx2oA,3752
83
+ cryptography/hazmat/decrepit/ciphers/modes.py,sha256=Oq_PEwCke5OLczOfr_vzAOJ6wPx-rlsvHAXPBuh5b9o,1649
84
+ cryptography/hazmat/primitives/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
85
+ cryptography/hazmat/primitives/__pycache__/__init__.cpython-313.pyc,,
86
+ cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-313.pyc,,
87
+ cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-313.pyc,,
88
+ cryptography/hazmat/primitives/__pycache__/_modes.cpython-313.pyc,,
89
+ cryptography/hazmat/primitives/__pycache__/_serialization.cpython-313.pyc,,
90
+ cryptography/hazmat/primitives/__pycache__/cmac.cpython-313.pyc,,
91
+ cryptography/hazmat/primitives/__pycache__/constant_time.cpython-313.pyc,,
92
+ cryptography/hazmat/primitives/__pycache__/hashes.cpython-313.pyc,,
93
+ cryptography/hazmat/primitives/__pycache__/hmac.cpython-313.pyc,,
94
+ cryptography/hazmat/primitives/__pycache__/hpke.cpython-313.pyc,,
95
+ cryptography/hazmat/primitives/__pycache__/keywrap.cpython-313.pyc,,
96
+ cryptography/hazmat/primitives/__pycache__/padding.cpython-313.pyc,,
97
+ cryptography/hazmat/primitives/__pycache__/poly1305.cpython-313.pyc,,
98
+ cryptography/hazmat/primitives/_asymmetric.py,sha256=RhgcouUB6HTiFDBrR1LxqkMjpUxIiNvQ1r_zJjRG6qQ,532
99
+ cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=Eh3i7lwedHfi0eLSsH93PZxQKzY9I6lkK67vL4V5tOc,1522
100
+ cryptography/hazmat/primitives/_modes.py,sha256=_EiAOD8Jb6WpFXluwkcUT3ECz_TH8xjGvbQlGkNm59Q,3075
101
+ cryptography/hazmat/primitives/_serialization.py,sha256=hi0xJblBAZ8pmZx2lWa-lruphxvvvG3g9DNK0G8Odfs,4440
102
+ cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=wHCbWfaefa-fk6THSw9th9fJUsStJo7245wfFBqmduA,216
103
+ cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-313.pyc,,
104
+ cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-313.pyc,,
105
+ cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-313.pyc,,
106
+ cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-313.pyc,,
107
+ cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-313.pyc,,
108
+ cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-313.pyc,,
109
+ cryptography/hazmat/primitives/asymmetric/__pycache__/mldsa.cpython-313.pyc,,
110
+ cryptography/hazmat/primitives/asymmetric/__pycache__/mlkem.cpython-313.pyc,,
111
+ cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-313.pyc,,
112
+ cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-313.pyc,,
113
+ cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-313.pyc,,
114
+ cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-313.pyc,,
115
+ cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-313.pyc,,
116
+ cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-313.pyc,,
117
+ cryptography/hazmat/primitives/asymmetric/dh.py,sha256=Rnt2fLaDpQEjQSX8fNtlmTXOJHjlt_DKQZ1Vlfhdja4,5793
118
+ cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=kQzTViqAI9PiELNOBco_n6MfP3N9ehIPkSduOpupt0M,4482
119
+ cryptography/hazmat/primitives/asymmetric/ec.py,sha256=LklVCLLxbbQzqiE6HRaYTRauLMphYUw3tE6c8oBIxYQ,10183
120
+ cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=mbffLvs-3PgCDeg1rQXVXh7GLntlVL4ATjkIEc4pt5M,2998
121
+ cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=n0dK6y-VLxuw-zvrDxuPT4598hymgX-1Ry_jq9aUQhE,4002
122
+ cryptography/hazmat/primitives/asymmetric/mldsa.py,sha256=LHMaaU0m66EsSrSodWf4e2kdmdDRTEGRC1y-fCKxGK0,13803
123
+ cryptography/hazmat/primitives/asymmetric/mlkem.py,sha256=wvVkeFT-4of-VcUAER2-zI_5hXT6rwTJPMCQ8gF9GTA,7901
124
+ cryptography/hazmat/primitives/asymmetric/padding.py,sha256=jbgajvGHYwkPjMDljHu5lxMBlDfmCxWUe2AF2S6KE10,3678
125
+ cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=lIE7lGe449W5URLTKCpvFGerITouKoZV9GwuTzScsSo,8492
126
+ cryptography/hazmat/primitives/asymmetric/types.py,sha256=SjJhTrnFRLlTPdYrBD1poMi6cjYG-fh0fSIaQn3QUiw,2588
127
+ cryptography/hazmat/primitives/asymmetric/utils.py,sha256=Qs8Re9GFPjW_tNp_73IeJEjPCf0slOIsWOxo6qymT6k,821
128
+ cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=lQcgUk-Piubj8ynFNWQeYme3tYZMgHQqkRKkIDOHLzo,3888
129
+ cryptography/hazmat/primitives/asymmetric/x448.py,sha256=b37ig7k7poG6SJDry42j-ElCj5q4eQ0X5CFmN0Sn8z8,3913
130
+ cryptography/hazmat/primitives/ciphers/__init__.py,sha256=eyEXmjk6_CZXaOPYDr7vAYGXr29QvzgWL2-4CSolLFs,680
131
+ cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-313.pyc,,
132
+ cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-313.pyc,,
133
+ cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-313.pyc,,
134
+ cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-313.pyc,,
135
+ cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-313.pyc,,
136
+ cryptography/hazmat/primitives/ciphers/aead.py,sha256=Fzlyx7w8KYQakzDp1zWgJnIr62zgZrgVh1u2h4exB54,634
137
+ cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=IGfCycYJOh1TvoI34rfw8KfJ_xmt1p_DpBht2Fghceo,3496
138
+ cryptography/hazmat/primitives/ciphers/base.py,sha256=aBC7HHBBoixebmparVr0UlODs3VD0A7B6oz_AaRjDv8,4253
139
+ cryptography/hazmat/primitives/ciphers/modes.py,sha256=H7AZSgJiSTBCi0grL97NxakS950JyFKYLsra8tjHPxQ,6003
140
+ cryptography/hazmat/primitives/cmac.py,sha256=sz_s6H_cYnOvx-VNWdIKhRhe3Ymp8z8J0D3CBqOX3gg,338
141
+ cryptography/hazmat/primitives/constant_time.py,sha256=xdunWT0nf8OvKdcqUhhlFKayGp4_PgVJRU2W1wLSr_A,422
142
+ cryptography/hazmat/primitives/hashes.py,sha256=Srtwgc3_pFvZfIhRj9e1p4Wdi-F_PpleGHlqJARgtOg,7916
143
+ cryptography/hazmat/primitives/hmac.py,sha256=RpB3z9z5skirCQrm7zQbtnp9pLMnAjrlTUvKqF5aDDc,423
144
+ cryptography/hazmat/primitives/hpke.py,sha256=RsHissC5l-dTPn1p2JbcrIrAnDBrLqM5ugBFSGpmKu4,865
145
+ cryptography/hazmat/primitives/kdf/__init__.py,sha256=v3yiYBGU272EojNXbwfYZdbbfI9cVOCCG3nXhTDda3k,1037
146
+ cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-313.pyc,,
147
+ cryptography/hazmat/primitives/kdf/__pycache__/argon2.cpython-313.pyc,,
148
+ cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-313.pyc,,
149
+ cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-313.pyc,,
150
+ cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-313.pyc,,
151
+ cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-313.pyc,,
152
+ cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-313.pyc,,
153
+ cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-313.pyc,,
154
+ cryptography/hazmat/primitives/kdf/argon2.py,sha256=ZJx-enUlAA4o7b46C1wlzG_XAQQW0wIkFgUKkrM_wA8,632
155
+ cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=BFnOKS72txKF0yQvASr0Na7uhzvLHpUCckK5iNAC_aQ,591
156
+ cryptography/hazmat/primitives/kdf/hkdf.py,sha256=M0lAEfRoc4kpp4-nwDj9yB-vNZukIOYEQrUlWsBNn9o,543
157
+ cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=C3w99vjFqhqzAxzFOH4zzvVoHkb5AC6Lz6AEQGV7d_g,737
158
+ cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=Xchkk99s-Mk6b6KSCouqdk8FVyiNVOSFIenmnW3tLgQ,468
159
+ cryptography/hazmat/primitives/kdf/scrypt.py,sha256=XyWUdUUmhuI9V6TqAPOvujCSMGv1XQdg0a21IWCmO-U,590
160
+ cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=QKjhRehuTsAstL384bKfvjuv1yfdamAHVhsBRWen2Vw,456
161
+ cryptography/hazmat/primitives/keywrap.py,sha256=t9t8KZuzZ4Us30ASUhI27MZPPPKy4EERRDkAK-lM7TQ,735
162
+ cryptography/hazmat/primitives/padding.py,sha256=QT-U-NvV2eQGO1wVPbDiNGNSc9keRDS-ig5cQOrLz0E,1865
163
+ cryptography/hazmat/primitives/poly1305.py,sha256=P5EPQV-RB_FJPahpg01u0Ts4S_PnAmsroxIGXbGeRRo,355
164
+ cryptography/hazmat/primitives/serialization/__init__.py,sha256=fXcu49ugL9rxhpRl_wZjnMqE9DCkhCMcsRxfj_qTveg,2217
165
+ cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-313.pyc,,
166
+ cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-313.pyc,,
167
+ cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-313.pyc,,
168
+ cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-313.pyc,,
169
+ cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-313.pyc,,
170
+ cryptography/hazmat/primitives/serialization/base.py,sha256=SABrvo0S86QcoBlj7DpjeLWy2lzQMryiioJ6DrEYQVA,651
171
+ cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=mS9cFNG4afzvseoc5e1MWoY2VskfL8N8Y_OFjl67luY,5104
172
+ cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=mFM7OFuZ8cCxUGUoo4Cof6BnCHc_Ibx1AQjjfxnPlxo,13998
173
+ cryptography/hazmat/primitives/serialization/ssh.py,sha256=FisXe_nUKdPGfqENVhKpmoazmaI8qH8Ge-VGbc0dykw,53592
174
+ cryptography/hazmat/primitives/twofactor/__init__.py,sha256=tmMZGB-g4IU1r7lIFqASU019zr0uPp_wEBYcwdDCKCA,258
175
+ cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-313.pyc,,
176
+ cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-313.pyc,,
177
+ cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-313.pyc,,
178
+ cryptography/hazmat/primitives/twofactor/hotp.py,sha256=ivZo5BrcCGWLsqql4nZV0XXCjyGPi_iHfDFltGlOJwk,3256
179
+ cryptography/hazmat/primitives/twofactor/totp.py,sha256=m5LPpRL00kp4zY8gTjr55Hfz9aMlPS53kHmVkSQCmdY,1652
180
+ cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
181
+ cryptography/utils.py,sha256=Ia7S0QZzS0ezwpIHQfY8G1e-o4GjrHijEXXjwAr1iuI,4635
182
+ cryptography/x509/__init__.py,sha256=0KVNTmRtdYNX_i_ewsTNzbTm2e1qyfoOhc4emog5hL4,8253
183
+ cryptography/x509/__pycache__/__init__.cpython-313.pyc,,
184
+ cryptography/x509/__pycache__/base.cpython-313.pyc,,
185
+ cryptography/x509/__pycache__/certificate_transparency.cpython-313.pyc,,
186
+ cryptography/x509/__pycache__/extensions.cpython-313.pyc,,
187
+ cryptography/x509/__pycache__/general_name.cpython-313.pyc,,
188
+ cryptography/x509/__pycache__/name.cpython-313.pyc,,
189
+ cryptography/x509/__pycache__/ocsp.cpython-313.pyc,,
190
+ cryptography/x509/__pycache__/oid.cpython-313.pyc,,
191
+ cryptography/x509/__pycache__/verification.cpython-313.pyc,,
192
+ cryptography/x509/base.py,sha256=UIMKkwmsx10BR3_gnBRBCBTwQp1-O8wkfVm7azH-_mE,28311
193
+ cryptography/x509/certificate_transparency.py,sha256=JqoOIDhlwInrYMFW6IFn77WJ0viF-PB_rlZV3vs9MYc,797
194
+ cryptography/x509/extensions.py,sha256=-iXcwWnIL1zl5Ml3BVJFkEo_71ncXe84ehvqzW1sK4M,77975
195
+ cryptography/x509/general_name.py,sha256=sP_rV11Qlpsk4x3XXGJY_Mv0Q_s9dtjeLckHsjpLQoQ,7836
196
+ cryptography/x509/name.py,sha256=oI2w6VdY8zgw7qpNhlxEx512W0AhWDXQrDYf5EsM2PY,15566
197
+ cryptography/x509/ocsp.py,sha256=Yey6NdFV1MPjop24Mj_VenjEpg3kUaMopSWOK0AbeBs,12699
198
+ cryptography/x509/oid.py,sha256=BUzgXXGVWilkBkdKPTm9R4qElE9gAGHgdYPMZAp7PJo,931
199
+ cryptography/x509/verification.py,sha256=gR2C2c-XZQtblZhT5T5vjSKOtCb74ef2alPVmEcwFlM,958
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.14.1)
3
+ Root-Is-Purelib: false
4
+ Tag: cp311-abi3-manylinux_2_34_x86_64
5
+
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/licenses/LICENSE ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ This software is made available under the terms of *either* of the licenses
2
+ found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made
3
+ under the terms of *both* these licenses.
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/licenses/LICENSE.APACHE ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ https://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ https://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/licenses/LICENSE.BSD ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) Individual contributors.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of PyCA Cryptography nor the names of its contributors
15
+ may be used to endorse or promote products derived from this software
16
+ without specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/sboms/cryptography-rust.cyclonedx.json ADDED
@@ -0,0 +1,1365 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bomFormat": "CycloneDX",
3
+ "specVersion": "1.5",
4
+ "version": 1,
5
+ "serialNumber": "urn:uuid:4de2bf3d-09cb-4570-8848-6e42c6141788",
6
+ "metadata": {
7
+ "timestamp": "2026-07-31T14:08:58.786399420Z",
8
+ "tools": [
9
+ {
10
+ "vendor": "CycloneDX",
11
+ "name": "cargo-cyclonedx",
12
+ "version": "0.5.9"
13
+ }
14
+ ],
15
+ "authors": [
16
+ {
17
+ "name": "The cryptography developers",
18
+ "email": "cryptography-dev@python.org"
19
+ }
20
+ ],
21
+ "component": {
22
+ "type": "library",
23
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust#cryptography-rust@0.50.0",
24
+ "author": "The cryptography developers <cryptography-dev@python.org>",
25
+ "name": "cryptography-rust",
26
+ "version": "0.50.0",
27
+ "scope": "required",
28
+ "licenses": [
29
+ {
30
+ "expression": "Apache-2.0 OR BSD-3-Clause"
31
+ }
32
+ ],
33
+ "purl": "pkg:cargo/cryptography-rust@0.50.0?download_url=file://.",
34
+ "components": [
35
+ {
36
+ "type": "library",
37
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust#cryptography-rust@0.50.0 bin-target-0",
38
+ "name": "cryptography_rust",
39
+ "version": "0.50.0",
40
+ "purl": "pkg:cargo/cryptography-rust@0.50.0?download_url=file://.#src/lib.rs"
41
+ }
42
+ ]
43
+ },
44
+ "properties": [
45
+ {
46
+ "name": "cdx:rustc:sbom:target:all_targets",
47
+ "value": "true"
48
+ }
49
+ ]
50
+ },
51
+ "components": [
52
+ {
53
+ "type": "library",
54
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-cffi#0.50.0",
55
+ "author": "The cryptography developers <cryptography-dev@python.org>",
56
+ "name": "cryptography-cffi",
57
+ "version": "0.50.0",
58
+ "scope": "required",
59
+ "licenses": [
60
+ {
61
+ "expression": "Apache-2.0 OR BSD-3-Clause"
62
+ }
63
+ ],
64
+ "purl": "pkg:cargo/cryptography-cffi@0.50.0?download_url=file://cryptography-cffi"
65
+ },
66
+ {
67
+ "type": "library",
68
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-crypto#0.50.0",
69
+ "author": "The cryptography developers <cryptography-dev@python.org>",
70
+ "name": "cryptography-crypto",
71
+ "version": "0.50.0",
72
+ "scope": "required",
73
+ "licenses": [
74
+ {
75
+ "expression": "Apache-2.0 OR BSD-3-Clause"
76
+ }
77
+ ],
78
+ "purl": "pkg:cargo/cryptography-crypto@0.50.0?download_url=file://cryptography-crypto"
79
+ },
80
+ {
81
+ "type": "library",
82
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-keepalive#0.50.0",
83
+ "author": "The cryptography developers <cryptography-dev@python.org>",
84
+ "name": "cryptography-keepalive",
85
+ "version": "0.50.0",
86
+ "scope": "required",
87
+ "licenses": [
88
+ {
89
+ "expression": "Apache-2.0 OR BSD-3-Clause"
90
+ }
91
+ ],
92
+ "purl": "pkg:cargo/cryptography-keepalive@0.50.0?download_url=file://cryptography-keepalive"
93
+ },
94
+ {
95
+ "type": "library",
96
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-key-parsing#0.50.0",
97
+ "author": "The cryptography developers <cryptography-dev@python.org>",
98
+ "name": "cryptography-key-parsing",
99
+ "version": "0.50.0",
100
+ "scope": "required",
101
+ "licenses": [
102
+ {
103
+ "expression": "Apache-2.0 OR BSD-3-Clause"
104
+ }
105
+ ],
106
+ "purl": "pkg:cargo/cryptography-key-parsing@0.50.0?download_url=file://cryptography-key-parsing"
107
+ },
108
+ {
109
+ "type": "library",
110
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-openssl#0.50.0",
111
+ "author": "The cryptography developers <cryptography-dev@python.org>",
112
+ "name": "cryptography-openssl",
113
+ "version": "0.50.0",
114
+ "scope": "required",
115
+ "licenses": [
116
+ {
117
+ "expression": "Apache-2.0 OR BSD-3-Clause"
118
+ }
119
+ ],
120
+ "purl": "pkg:cargo/cryptography-openssl@0.50.0?download_url=file://cryptography-openssl"
121
+ },
122
+ {
123
+ "type": "library",
124
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-x509#0.50.0",
125
+ "author": "The cryptography developers <cryptography-dev@python.org>",
126
+ "name": "cryptography-x509",
127
+ "version": "0.50.0",
128
+ "scope": "required",
129
+ "licenses": [
130
+ {
131
+ "expression": "Apache-2.0 OR BSD-3-Clause"
132
+ }
133
+ ],
134
+ "purl": "pkg:cargo/cryptography-x509@0.50.0?download_url=file://cryptography-x509"
135
+ },
136
+ {
137
+ "type": "library",
138
+ "bom-ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-x509-verification#0.50.0",
139
+ "author": "The cryptography developers <cryptography-dev@python.org>",
140
+ "name": "cryptography-x509-verification",
141
+ "version": "0.50.0",
142
+ "scope": "required",
143
+ "licenses": [
144
+ {
145
+ "expression": "Apache-2.0 OR BSD-3-Clause"
146
+ }
147
+ ],
148
+ "purl": "pkg:cargo/cryptography-x509-verification@0.50.0?download_url=file://cryptography-x509-verification"
149
+ },
150
+ {
151
+ "type": "library",
152
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1",
153
+ "author": "Alex Gaynor <alex.gaynor@gmail.com>",
154
+ "name": "asn1",
155
+ "version": "0.24.1",
156
+ "description": "ASN.1 (DER) parser and writer for Rust.",
157
+ "scope": "required",
158
+ "hashes": [
159
+ {
160
+ "alg": "SHA-256",
161
+ "content": "c9795210620c0cb3f9a7ce4f882808c38e1ef7b347c90591dceae0886e031fb1"
162
+ }
163
+ ],
164
+ "licenses": [
165
+ {
166
+ "expression": "BSD-3-Clause"
167
+ }
168
+ ],
169
+ "purl": "pkg:cargo/asn1@0.24.1",
170
+ "externalReferences": [
171
+ {
172
+ "type": "vcs",
173
+ "url": "https://github.com/alex/rust-asn1"
174
+ }
175
+ ]
176
+ },
177
+ {
178
+ "type": "library",
179
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1",
180
+ "author": "Alex Gaynor <alex.gaynor@gmail.com>",
181
+ "name": "asn1_derive",
182
+ "version": "0.24.1",
183
+ "description": "#[derive] support for asn1",
184
+ "scope": "required",
185
+ "hashes": [
186
+ {
187
+ "alg": "SHA-256",
188
+ "content": "909e307f1cc32bb8bccbd98f446e6d1bf03fa30f7b53a4337da7181ad30fa11a"
189
+ }
190
+ ],
191
+ "licenses": [
192
+ {
193
+ "expression": "BSD-3-Clause"
194
+ }
195
+ ],
196
+ "purl": "pkg:cargo/asn1_derive@0.24.1",
197
+ "externalReferences": [
198
+ {
199
+ "type": "vcs",
200
+ "url": "https://github.com/alex/rust-asn1"
201
+ }
202
+ ]
203
+ },
204
+ {
205
+ "type": "library",
206
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.23.0",
207
+ "author": "Marshall Pierce <marshall@mpierce.org>",
208
+ "name": "base64",
209
+ "version": "0.23.0",
210
+ "description": "encodes and decodes base64 as bytes or utf8",
211
+ "scope": "required",
212
+ "hashes": [
213
+ {
214
+ "alg": "SHA-256",
215
+ "content": "b25655df2c3cdd83c5e5b293b88acd880332b2ddadd7c30ac43144fdc0033da9"
216
+ }
217
+ ],
218
+ "licenses": [
219
+ {
220
+ "expression": "MIT OR Apache-2.0"
221
+ }
222
+ ],
223
+ "purl": "pkg:cargo/base64@0.23.0",
224
+ "externalReferences": [
225
+ {
226
+ "type": "documentation",
227
+ "url": "https://docs.rs/base64"
228
+ },
229
+ {
230
+ "type": "vcs",
231
+ "url": "https://github.com/marshallpierce/rust-base64"
232
+ }
233
+ ]
234
+ },
235
+ {
236
+ "type": "library",
237
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.13.1",
238
+ "author": "The Rust Project Developers",
239
+ "name": "bitflags",
240
+ "version": "2.13.1",
241
+ "description": "A macro to generate structures which behave like bitflags. ",
242
+ "scope": "required",
243
+ "hashes": [
244
+ {
245
+ "alg": "SHA-256",
246
+ "content": "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
247
+ }
248
+ ],
249
+ "licenses": [
250
+ {
251
+ "expression": "MIT OR Apache-2.0"
252
+ }
253
+ ],
254
+ "purl": "pkg:cargo/bitflags@2.13.1",
255
+ "externalReferences": [
256
+ {
257
+ "type": "documentation",
258
+ "url": "https://docs.rs/bitflags"
259
+ },
260
+ {
261
+ "type": "website",
262
+ "url": "https://github.com/bitflags/bitflags"
263
+ },
264
+ {
265
+ "type": "vcs",
266
+ "url": "https://github.com/bitflags/bitflags"
267
+ }
268
+ ]
269
+ },
270
+ {
271
+ "type": "library",
272
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.4.0",
273
+ "author": "Alex Crichton <alex@alexcrichton.com>",
274
+ "name": "cc",
275
+ "version": "1.4.0",
276
+ "description": "A build-time dependency for Cargo build scripts to assist in invoking the native C compiler to compile native C code into a static archive to be linked into Rust code. ",
277
+ "scope": "excluded",
278
+ "hashes": [
279
+ {
280
+ "alg": "SHA-256",
281
+ "content": "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9"
282
+ }
283
+ ],
284
+ "licenses": [
285
+ {
286
+ "expression": "MIT OR Apache-2.0"
287
+ }
288
+ ],
289
+ "purl": "pkg:cargo/cc@1.4.0",
290
+ "externalReferences": [
291
+ {
292
+ "type": "documentation",
293
+ "url": "https://docs.rs/cc"
294
+ },
295
+ {
296
+ "type": "website",
297
+ "url": "https://github.com/rust-lang/cc-rs"
298
+ },
299
+ {
300
+ "type": "vcs",
301
+ "url": "https://github.com/rust-lang/cc-rs"
302
+ }
303
+ ]
304
+ },
305
+ {
306
+ "type": "library",
307
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4",
308
+ "author": "Alex Crichton <alex@alexcrichton.com>",
309
+ "name": "cfg-if",
310
+ "version": "1.0.4",
311
+ "description": "A macro to ergonomically define an item depending on a large number of #[cfg] parameters. Structured like an if-else chain, the first matching branch is the item that gets emitted. ",
312
+ "scope": "required",
313
+ "hashes": [
314
+ {
315
+ "alg": "SHA-256",
316
+ "content": "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
317
+ }
318
+ ],
319
+ "licenses": [
320
+ {
321
+ "expression": "MIT OR Apache-2.0"
322
+ }
323
+ ],
324
+ "purl": "pkg:cargo/cfg-if@1.0.4",
325
+ "externalReferences": [
326
+ {
327
+ "type": "vcs",
328
+ "url": "https://github.com/rust-lang/cfg-if"
329
+ }
330
+ ]
331
+ },
332
+ {
333
+ "type": "library",
334
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9",
335
+ "name": "find-msvc-tools",
336
+ "version": "0.1.9",
337
+ "description": "Find windows-specific tools, read MSVC versions from the registry and from COM interfaces",
338
+ "scope": "excluded",
339
+ "hashes": [
340
+ {
341
+ "alg": "SHA-256",
342
+ "content": "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
343
+ }
344
+ ],
345
+ "licenses": [
346
+ {
347
+ "expression": "MIT OR Apache-2.0"
348
+ }
349
+ ],
350
+ "purl": "pkg:cargo/find-msvc-tools@0.1.9",
351
+ "externalReferences": [
352
+ {
353
+ "type": "documentation",
354
+ "url": "https://docs.rs/find-msvc-tools"
355
+ },
356
+ {
357
+ "type": "vcs",
358
+ "url": "https://github.com/rust-lang/cc-rs"
359
+ }
360
+ ]
361
+ },
362
+ {
363
+ "type": "library",
364
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1",
365
+ "author": "Steven Fackler <sfackler@gmail.com>",
366
+ "name": "foreign-types-shared",
367
+ "version": "0.1.1",
368
+ "description": "An internal crate used by foreign-types",
369
+ "scope": "required",
370
+ "hashes": [
371
+ {
372
+ "alg": "SHA-256",
373
+ "content": "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
374
+ }
375
+ ],
376
+ "licenses": [
377
+ {
378
+ "expression": "MIT OR Apache-2.0"
379
+ }
380
+ ],
381
+ "purl": "pkg:cargo/foreign-types-shared@0.1.1",
382
+ "externalReferences": [
383
+ {
384
+ "type": "vcs",
385
+ "url": "https://github.com/sfackler/foreign-types"
386
+ }
387
+ ]
388
+ },
389
+ {
390
+ "type": "library",
391
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2",
392
+ "author": "Steven Fackler <sfackler@gmail.com>",
393
+ "name": "foreign-types",
394
+ "version": "0.3.2",
395
+ "description": "A framework for Rust wrappers over C APIs",
396
+ "scope": "required",
397
+ "hashes": [
398
+ {
399
+ "alg": "SHA-256",
400
+ "content": "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
401
+ }
402
+ ],
403
+ "licenses": [
404
+ {
405
+ "expression": "MIT OR Apache-2.0"
406
+ }
407
+ ],
408
+ "purl": "pkg:cargo/foreign-types@0.3.2",
409
+ "externalReferences": [
410
+ {
411
+ "type": "vcs",
412
+ "url": "https://github.com/sfackler/foreign-types"
413
+ }
414
+ ]
415
+ },
416
+ {
417
+ "type": "library",
418
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0",
419
+ "name": "heck",
420
+ "version": "0.5.0",
421
+ "description": "heck is a case conversion library.",
422
+ "scope": "required",
423
+ "hashes": [
424
+ {
425
+ "alg": "SHA-256",
426
+ "content": "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
427
+ }
428
+ ],
429
+ "licenses": [
430
+ {
431
+ "expression": "MIT OR Apache-2.0"
432
+ }
433
+ ],
434
+ "purl": "pkg:cargo/heck@0.5.0",
435
+ "externalReferences": [
436
+ {
437
+ "type": "vcs",
438
+ "url": "https://github.com/withoutboats/heck"
439
+ }
440
+ ]
441
+ },
442
+ {
443
+ "type": "library",
444
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18",
445
+ "author": "David Tolnay <dtolnay@gmail.com>",
446
+ "name": "itoa",
447
+ "version": "1.0.18",
448
+ "description": "Fast integer primitive to string conversion",
449
+ "scope": "required",
450
+ "hashes": [
451
+ {
452
+ "alg": "SHA-256",
453
+ "content": "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
454
+ }
455
+ ],
456
+ "licenses": [
457
+ {
458
+ "expression": "MIT OR Apache-2.0"
459
+ }
460
+ ],
461
+ "purl": "pkg:cargo/itoa@1.0.18",
462
+ "externalReferences": [
463
+ {
464
+ "type": "documentation",
465
+ "url": "https://docs.rs/itoa"
466
+ },
467
+ {
468
+ "type": "vcs",
469
+ "url": "https://github.com/dtolnay/itoa"
470
+ }
471
+ ]
472
+ },
473
+ {
474
+ "type": "library",
475
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189",
476
+ "name": "libc",
477
+ "version": "0.2.189",
478
+ "description": "Raw FFI bindings to platform libraries like libc.",
479
+ "scope": "required",
480
+ "hashes": [
481
+ {
482
+ "alg": "SHA-256",
483
+ "content": "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2"
484
+ }
485
+ ],
486
+ "licenses": [
487
+ {
488
+ "expression": "MIT OR Apache-2.0"
489
+ }
490
+ ],
491
+ "purl": "pkg:cargo/libc@0.2.189",
492
+ "externalReferences": [
493
+ {
494
+ "type": "vcs",
495
+ "url": "https://github.com/rust-lang/libc"
496
+ }
497
+ ]
498
+ },
499
+ {
500
+ "type": "library",
501
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4",
502
+ "author": "Aleksey Kladov <aleksey.kladov@gmail.com>",
503
+ "name": "once_cell",
504
+ "version": "1.21.4",
505
+ "description": "Single assignment cells and lazy values.",
506
+ "scope": "required",
507
+ "hashes": [
508
+ {
509
+ "alg": "SHA-256",
510
+ "content": "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
511
+ }
512
+ ],
513
+ "licenses": [
514
+ {
515
+ "expression": "MIT OR Apache-2.0"
516
+ }
517
+ ],
518
+ "purl": "pkg:cargo/once_cell@1.21.4",
519
+ "externalReferences": [
520
+ {
521
+ "type": "documentation",
522
+ "url": "https://docs.rs/once_cell"
523
+ },
524
+ {
525
+ "type": "vcs",
526
+ "url": "https://github.com/matklad/once_cell"
527
+ }
528
+ ]
529
+ },
530
+ {
531
+ "type": "library",
532
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1",
533
+ "name": "openssl-macros",
534
+ "version": "0.1.1",
535
+ "description": "Internal macros used by the openssl crate.",
536
+ "scope": "required",
537
+ "hashes": [
538
+ {
539
+ "alg": "SHA-256",
540
+ "content": "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
541
+ }
542
+ ],
543
+ "licenses": [
544
+ {
545
+ "expression": "MIT OR Apache-2.0"
546
+ }
547
+ ],
548
+ "purl": "pkg:cargo/openssl-macros@0.1.1"
549
+ },
550
+ {
551
+ "type": "library",
552
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117",
553
+ "author": "Alex Crichton <alex@alexcrichton.com>, Steven Fackler <sfackler@gmail.com>",
554
+ "name": "openssl-sys",
555
+ "version": "0.9.117",
556
+ "description": "FFI bindings to OpenSSL",
557
+ "scope": "required",
558
+ "hashes": [
559
+ {
560
+ "alg": "SHA-256",
561
+ "content": "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695"
562
+ }
563
+ ],
564
+ "licenses": [
565
+ {
566
+ "expression": "MIT"
567
+ }
568
+ ],
569
+ "purl": "pkg:cargo/openssl-sys@0.9.117",
570
+ "externalReferences": [
571
+ {
572
+ "type": "other",
573
+ "url": "openssl"
574
+ },
575
+ {
576
+ "type": "vcs",
577
+ "url": "https://github.com/rust-openssl/rust-openssl"
578
+ }
579
+ ]
580
+ },
581
+ {
582
+ "type": "library",
583
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81",
584
+ "author": "Steven Fackler <sfackler@gmail.com>",
585
+ "name": "openssl",
586
+ "version": "0.10.81",
587
+ "description": "OpenSSL bindings",
588
+ "scope": "required",
589
+ "hashes": [
590
+ {
591
+ "alg": "SHA-256",
592
+ "content": "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45"
593
+ }
594
+ ],
595
+ "licenses": [
596
+ {
597
+ "expression": "Apache-2.0"
598
+ }
599
+ ],
600
+ "purl": "pkg:cargo/openssl@0.10.81",
601
+ "externalReferences": [
602
+ {
603
+ "type": "vcs",
604
+ "url": "https://github.com/rust-openssl/rust-openssl"
605
+ }
606
+ ]
607
+ },
608
+ {
609
+ "type": "library",
610
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pem@4.0.0",
611
+ "author": "Jonathan Creekmore <jonathan@thecreekmores.org>",
612
+ "name": "pem",
613
+ "version": "4.0.0",
614
+ "description": "Parse and encode PEM-encoded data.",
615
+ "scope": "required",
616
+ "hashes": [
617
+ {
618
+ "alg": "SHA-256",
619
+ "content": "d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120"
620
+ }
621
+ ],
622
+ "licenses": [
623
+ {
624
+ "expression": "MIT"
625
+ }
626
+ ],
627
+ "purl": "pkg:cargo/pem@4.0.0",
628
+ "externalReferences": [
629
+ {
630
+ "type": "documentation",
631
+ "url": "https://docs.rs/pem/"
632
+ },
633
+ {
634
+ "type": "website",
635
+ "url": "https://github.com/jcreekmore/pem-rs.git"
636
+ },
637
+ {
638
+ "type": "vcs",
639
+ "url": "https://github.com/jcreekmore/pem-rs.git"
640
+ }
641
+ ]
642
+ },
643
+ {
644
+ "type": "library",
645
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33",
646
+ "author": "Alex Crichton <alex@alexcrichton.com>",
647
+ "name": "pkg-config",
648
+ "version": "0.3.33",
649
+ "description": "A library to run the pkg-config system tool at build time in order to be used in Cargo build scripts. ",
650
+ "scope": "excluded",
651
+ "hashes": [
652
+ {
653
+ "alg": "SHA-256",
654
+ "content": "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"
655
+ }
656
+ ],
657
+ "licenses": [
658
+ {
659
+ "expression": "MIT OR Apache-2.0"
660
+ }
661
+ ],
662
+ "purl": "pkg:cargo/pkg-config@0.3.33",
663
+ "externalReferences": [
664
+ {
665
+ "type": "documentation",
666
+ "url": "https://docs.rs/pkg-config"
667
+ },
668
+ {
669
+ "type": "vcs",
670
+ "url": "https://github.com/rust-lang/pkg-config-rs"
671
+ }
672
+ ]
673
+ },
674
+ {
675
+ "type": "library",
676
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.14.0",
677
+ "name": "portable-atomic",
678
+ "version": "1.14.0",
679
+ "description": "Portable atomic types including support for 128-bit atomics, atomic float, etc. ",
680
+ "scope": "required",
681
+ "hashes": [
682
+ {
683
+ "alg": "SHA-256",
684
+ "content": "3d20d5497ef88037a52ff98267d066e7f11fcc5e99bbfbd58a42336193aacec3"
685
+ }
686
+ ],
687
+ "licenses": [
688
+ {
689
+ "expression": "Apache-2.0 OR MIT"
690
+ }
691
+ ],
692
+ "purl": "pkg:cargo/portable-atomic@1.14.0",
693
+ "externalReferences": [
694
+ {
695
+ "type": "vcs",
696
+ "url": "https://github.com/taiki-e/portable-atomic"
697
+ }
698
+ ]
699
+ },
700
+ {
701
+ "type": "library",
702
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107",
703
+ "author": "David Tolnay <dtolnay@gmail.com>, Alex Crichton <alex@alexcrichton.com>",
704
+ "name": "proc-macro2",
705
+ "version": "1.0.107",
706
+ "description": "A substitute implementation of the compiler's `proc_macro` API to decouple token-based libraries from the procedural macro use case.",
707
+ "scope": "required",
708
+ "hashes": [
709
+ {
710
+ "alg": "SHA-256",
711
+ "content": "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9"
712
+ }
713
+ ],
714
+ "licenses": [
715
+ {
716
+ "expression": "MIT OR Apache-2.0"
717
+ }
718
+ ],
719
+ "purl": "pkg:cargo/proc-macro2@1.0.107",
720
+ "externalReferences": [
721
+ {
722
+ "type": "documentation",
723
+ "url": "https://docs.rs/proc-macro2"
724
+ },
725
+ {
726
+ "type": "vcs",
727
+ "url": "https://github.com/dtolnay/proc-macro2"
728
+ }
729
+ ]
730
+ },
731
+ {
732
+ "type": "library",
733
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0",
734
+ "author": "PyO3 Project and Contributors <https://github.com/PyO3>",
735
+ "name": "pyo3-build-config",
736
+ "version": "0.29.0",
737
+ "description": "Build configuration for the PyO3 ecosystem",
738
+ "scope": "excluded",
739
+ "hashes": [
740
+ {
741
+ "alg": "SHA-256",
742
+ "content": "c5e2a7d2f0d013342f295c048ad19237add5154a55b1c5a254c0ec93d4109078"
743
+ }
744
+ ],
745
+ "licenses": [
746
+ {
747
+ "expression": "MIT OR Apache-2.0"
748
+ }
749
+ ],
750
+ "purl": "pkg:cargo/pyo3-build-config@0.29.0",
751
+ "externalReferences": [
752
+ {
753
+ "type": "website",
754
+ "url": "https://github.com/pyo3/pyo3"
755
+ },
756
+ {
757
+ "type": "vcs",
758
+ "url": "https://github.com/pyo3/pyo3"
759
+ }
760
+ ]
761
+ },
762
+ {
763
+ "type": "library",
764
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0",
765
+ "author": "PyO3 Project and Contributors <https://github.com/PyO3>",
766
+ "name": "pyo3-ffi",
767
+ "version": "0.29.0",
768
+ "description": "Python-API bindings for the PyO3 ecosystem",
769
+ "scope": "required",
770
+ "hashes": [
771
+ {
772
+ "alg": "SHA-256",
773
+ "content": "ca85c467da1bbc8d866eea5deff9cf29ea5f7785054a17da36e65bda9c05845b"
774
+ }
775
+ ],
776
+ "licenses": [
777
+ {
778
+ "expression": "MIT OR Apache-2.0"
779
+ }
780
+ ],
781
+ "purl": "pkg:cargo/pyo3-ffi@0.29.0",
782
+ "externalReferences": [
783
+ {
784
+ "type": "website",
785
+ "url": "https://github.com/pyo3/pyo3"
786
+ },
787
+ {
788
+ "type": "other",
789
+ "url": "python"
790
+ },
791
+ {
792
+ "type": "vcs",
793
+ "url": "https://github.com/pyo3/pyo3"
794
+ }
795
+ ]
796
+ },
797
+ {
798
+ "type": "library",
799
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0",
800
+ "author": "PyO3 Project and Contributors <https://github.com/PyO3>",
801
+ "name": "pyo3-macros-backend",
802
+ "version": "0.29.0",
803
+ "description": "Code generation for PyO3 package",
804
+ "scope": "required",
805
+ "hashes": [
806
+ {
807
+ "alg": "SHA-256",
808
+ "content": "4ca3a1557399783172dc5bf39cfca835157732532cba56b71d2292161e53b362"
809
+ }
810
+ ],
811
+ "licenses": [
812
+ {
813
+ "expression": "MIT OR Apache-2.0"
814
+ }
815
+ ],
816
+ "purl": "pkg:cargo/pyo3-macros-backend@0.29.0",
817
+ "externalReferences": [
818
+ {
819
+ "type": "website",
820
+ "url": "https://github.com/pyo3/pyo3"
821
+ },
822
+ {
823
+ "type": "vcs",
824
+ "url": "https://github.com/pyo3/pyo3"
825
+ }
826
+ ]
827
+ },
828
+ {
829
+ "type": "library",
830
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0",
831
+ "author": "PyO3 Project and Contributors <https://github.com/PyO3>",
832
+ "name": "pyo3-macros",
833
+ "version": "0.29.0",
834
+ "description": "Proc macros for PyO3 package",
835
+ "scope": "required",
836
+ "hashes": [
837
+ {
838
+ "alg": "SHA-256",
839
+ "content": "9ac53762fd065daa3194dd09337a38bd793a188100fd1a9304c4ab312d901771"
840
+ }
841
+ ],
842
+ "licenses": [
843
+ {
844
+ "expression": "MIT OR Apache-2.0"
845
+ }
846
+ ],
847
+ "purl": "pkg:cargo/pyo3-macros@0.29.0",
848
+ "externalReferences": [
849
+ {
850
+ "type": "website",
851
+ "url": "https://github.com/pyo3/pyo3"
852
+ },
853
+ {
854
+ "type": "vcs",
855
+ "url": "https://github.com/pyo3/pyo3"
856
+ }
857
+ ]
858
+ },
859
+ {
860
+ "type": "library",
861
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0",
862
+ "author": "PyO3 Project and Contributors <https://github.com/PyO3>",
863
+ "name": "pyo3",
864
+ "version": "0.29.0",
865
+ "description": "Bindings to Python interpreter",
866
+ "scope": "required",
867
+ "hashes": [
868
+ {
869
+ "alg": "SHA-256",
870
+ "content": "cd274650b21d4bfc26a0a47587962c1edb425f69287324355cd040c3ea66071c"
871
+ }
872
+ ],
873
+ "licenses": [
874
+ {
875
+ "expression": "MIT OR Apache-2.0"
876
+ }
877
+ ],
878
+ "purl": "pkg:cargo/pyo3@0.29.0",
879
+ "externalReferences": [
880
+ {
881
+ "type": "documentation",
882
+ "url": "https://docs.rs/crate/pyo3/"
883
+ },
884
+ {
885
+ "type": "website",
886
+ "url": "https://github.com/pyo3/pyo3"
887
+ },
888
+ {
889
+ "type": "other",
890
+ "url": "pyo3-python"
891
+ },
892
+ {
893
+ "type": "vcs",
894
+ "url": "https://github.com/pyo3/pyo3"
895
+ }
896
+ ]
897
+ },
898
+ {
899
+ "type": "library",
900
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47",
901
+ "author": "David Tolnay <dtolnay@gmail.com>",
902
+ "name": "quote",
903
+ "version": "1.0.47",
904
+ "description": "Quasi-quoting macro quote!(...)",
905
+ "scope": "required",
906
+ "hashes": [
907
+ {
908
+ "alg": "SHA-256",
909
+ "content": "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001"
910
+ }
911
+ ],
912
+ "licenses": [
913
+ {
914
+ "expression": "MIT OR Apache-2.0"
915
+ }
916
+ ],
917
+ "purl": "pkg:cargo/quote@1.0.47",
918
+ "externalReferences": [
919
+ {
920
+ "type": "documentation",
921
+ "url": "https://docs.rs/quote/"
922
+ },
923
+ {
924
+ "type": "vcs",
925
+ "url": "https://github.com/dtolnay/quote"
926
+ }
927
+ ]
928
+ },
929
+ {
930
+ "type": "library",
931
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.3.0",
932
+ "author": "Lukas Bergdoll <lukas.bergdoll@gmail.com>",
933
+ "name": "self_cell",
934
+ "version": "1.3.0",
935
+ "description": "Safe-to-use proc-macro-free self-referential structs in stable Rust.",
936
+ "scope": "required",
937
+ "hashes": [
938
+ {
939
+ "alg": "SHA-256",
940
+ "content": "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813"
941
+ }
942
+ ],
943
+ "licenses": [
944
+ {
945
+ "expression": "Apache-2.0 OR GPL-2.0-only"
946
+ }
947
+ ],
948
+ "purl": "pkg:cargo/self_cell@1.3.0",
949
+ "externalReferences": [
950
+ {
951
+ "type": "documentation",
952
+ "url": "https://docs.rs/self_cell"
953
+ },
954
+ {
955
+ "type": "vcs",
956
+ "url": "https://github.com/Voultapher/self_cell"
957
+ }
958
+ ]
959
+ },
960
+ {
961
+ "type": "library",
962
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#shlex@2.0.1",
963
+ "author": "comex <comexk@gmail.com>, Fenhl <fenhl@fenhl.net>, Adrian Taylor <adetaylor@chromium.org>, Alex Touchet <alextouchet@outlook.com>, Daniel Parks <dp+git@oxidized.org>, Garrett Berg <googberg@gmail.com>",
964
+ "name": "shlex",
965
+ "version": "2.0.1",
966
+ "description": "Split a string into shell words, like Python's shlex.",
967
+ "scope": "excluded",
968
+ "hashes": [
969
+ {
970
+ "alg": "SHA-256",
971
+ "content": "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
972
+ }
973
+ ],
974
+ "licenses": [
975
+ {
976
+ "expression": "MIT OR Apache-2.0"
977
+ }
978
+ ],
979
+ "purl": "pkg:cargo/shlex@2.0.1",
980
+ "externalReferences": [
981
+ {
982
+ "type": "vcs",
983
+ "url": "https://github.com/comex/rust-shlex"
984
+ }
985
+ ]
986
+ },
987
+ {
988
+ "type": "library",
989
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119",
990
+ "author": "David Tolnay <dtolnay@gmail.com>",
991
+ "name": "syn",
992
+ "version": "2.0.119",
993
+ "description": "Parser for Rust source code",
994
+ "scope": "required",
995
+ "hashes": [
996
+ {
997
+ "alg": "SHA-256",
998
+ "content": "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
999
+ }
1000
+ ],
1001
+ "licenses": [
1002
+ {
1003
+ "expression": "MIT OR Apache-2.0"
1004
+ }
1005
+ ],
1006
+ "purl": "pkg:cargo/syn@2.0.119",
1007
+ "externalReferences": [
1008
+ {
1009
+ "type": "documentation",
1010
+ "url": "https://docs.rs/syn"
1011
+ },
1012
+ {
1013
+ "type": "vcs",
1014
+ "url": "https://github.com/dtolnay/syn"
1015
+ }
1016
+ ]
1017
+ },
1018
+ {
1019
+ "type": "library",
1020
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5",
1021
+ "author": "Dan Gohman <sunfish@mozilla.com>",
1022
+ "name": "target-lexicon",
1023
+ "version": "0.13.5",
1024
+ "description": "LLVM target triple types",
1025
+ "scope": "excluded",
1026
+ "hashes": [
1027
+ {
1028
+ "alg": "SHA-256",
1029
+ "content": "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
1030
+ }
1031
+ ],
1032
+ "licenses": [
1033
+ {
1034
+ "expression": "Apache-2.0 WITH LLVM-exception"
1035
+ }
1036
+ ],
1037
+ "purl": "pkg:cargo/target-lexicon@0.13.5",
1038
+ "externalReferences": [
1039
+ {
1040
+ "type": "documentation",
1041
+ "url": "https://docs.rs/target-lexicon/"
1042
+ },
1043
+ {
1044
+ "type": "vcs",
1045
+ "url": "https://github.com/bytecodealliance/target-lexicon"
1046
+ }
1047
+ ]
1048
+ },
1049
+ {
1050
+ "type": "library",
1051
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24",
1052
+ "author": "David Tolnay <dtolnay@gmail.com>",
1053
+ "name": "unicode-ident",
1054
+ "version": "1.0.24",
1055
+ "description": "Determine whether characters have the XID_Start or XID_Continue properties according to Unicode Standard Annex #31",
1056
+ "scope": "required",
1057
+ "hashes": [
1058
+ {
1059
+ "alg": "SHA-256",
1060
+ "content": "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
1061
+ }
1062
+ ],
1063
+ "licenses": [
1064
+ {
1065
+ "expression": "(MIT OR Apache-2.0) AND Unicode-3.0"
1066
+ }
1067
+ ],
1068
+ "purl": "pkg:cargo/unicode-ident@1.0.24",
1069
+ "externalReferences": [
1070
+ {
1071
+ "type": "documentation",
1072
+ "url": "https://docs.rs/unicode-ident"
1073
+ },
1074
+ {
1075
+ "type": "vcs",
1076
+ "url": "https://github.com/dtolnay/unicode-ident"
1077
+ }
1078
+ ]
1079
+ },
1080
+ {
1081
+ "type": "library",
1082
+ "bom-ref": "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15",
1083
+ "author": "Jim McGrath <jimmc2@gmail.com>",
1084
+ "name": "vcpkg",
1085
+ "version": "0.2.15",
1086
+ "description": "A library to find native dependencies in a vcpkg tree at build time in order to be used in Cargo build scripts. ",
1087
+ "scope": "excluded",
1088
+ "hashes": [
1089
+ {
1090
+ "alg": "SHA-256",
1091
+ "content": "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
1092
+ }
1093
+ ],
1094
+ "licenses": [
1095
+ {
1096
+ "expression": "MIT OR Apache-2.0"
1097
+ }
1098
+ ],
1099
+ "purl": "pkg:cargo/vcpkg@0.2.15",
1100
+ "externalReferences": [
1101
+ {
1102
+ "type": "documentation",
1103
+ "url": "https://docs.rs/vcpkg"
1104
+ },
1105
+ {
1106
+ "type": "vcs",
1107
+ "url": "https://github.com/mcgoo/vcpkg-rs"
1108
+ }
1109
+ ]
1110
+ }
1111
+ ],
1112
+ "dependencies": [
1113
+ {
1114
+ "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust#cryptography-rust@0.50.0",
1115
+ "dependsOn": [
1116
+ "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1",
1117
+ "registry+https://github.com/rust-lang/crates.io-index#base64@0.23.0",
1118
+ "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4",
1119
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-cffi#0.50.0",
1120
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-crypto#0.50.0",
1121
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-keepalive#0.50.0",
1122
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-key-parsing#0.50.0",
1123
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-openssl#0.50.0",
1124
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-x509#0.50.0",
1125
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-x509-verification#0.50.0",
1126
+ "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1",
1127
+ "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81",
1128
+ "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117",
1129
+ "registry+https://github.com/rust-lang/crates.io-index#pem@4.0.0",
1130
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0",
1131
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0",
1132
+ "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.3.0"
1133
+ ]
1134
+ },
1135
+ {
1136
+ "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-cffi#0.50.0",
1137
+ "dependsOn": [
1138
+ "registry+https://github.com/rust-lang/crates.io-index#cc@1.4.0",
1139
+ "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117",
1140
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0",
1141
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0"
1142
+ ]
1143
+ },
1144
+ {
1145
+ "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-crypto#0.50.0",
1146
+ "dependsOn": [
1147
+ "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81"
1148
+ ]
1149
+ },
1150
+ {
1151
+ "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-keepalive#0.50.0",
1152
+ "dependsOn": [
1153
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0"
1154
+ ]
1155
+ },
1156
+ {
1157
+ "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-key-parsing#0.50.0",
1158
+ "dependsOn": [
1159
+ "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1",
1160
+ "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4",
1161
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-crypto#0.50.0",
1162
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-openssl#0.50.0",
1163
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-x509#0.50.0",
1164
+ "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81",
1165
+ "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117",
1166
+ "registry+https://github.com/rust-lang/crates.io-index#pem@4.0.0"
1167
+ ]
1168
+ },
1169
+ {
1170
+ "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-openssl#0.50.0",
1171
+ "dependsOn": [
1172
+ "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4",
1173
+ "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2",
1174
+ "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1",
1175
+ "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81",
1176
+ "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117"
1177
+ ]
1178
+ },
1179
+ {
1180
+ "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-x509#0.50.0",
1181
+ "dependsOn": [
1182
+ "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1"
1183
+ ]
1184
+ },
1185
+ {
1186
+ "ref": "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-x509-verification#0.50.0",
1187
+ "dependsOn": [
1188
+ "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1",
1189
+ "path+file:///__w/cryptography/cryptography/tmpwheelhouse/.tmpWfh3cH/cryptography-50.0.0/src/rust/cryptography-x509#0.50.0"
1190
+ ]
1191
+ },
1192
+ {
1193
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#asn1@0.24.1",
1194
+ "dependsOn": [
1195
+ "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1",
1196
+ "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18"
1197
+ ]
1198
+ },
1199
+ {
1200
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#asn1_derive@0.24.1",
1201
+ "dependsOn": [
1202
+ "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107",
1203
+ "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47",
1204
+ "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119"
1205
+ ]
1206
+ },
1207
+ {
1208
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#base64@0.23.0"
1209
+ },
1210
+ {
1211
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.13.1"
1212
+ },
1213
+ {
1214
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#cc@1.4.0",
1215
+ "dependsOn": [
1216
+ "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9",
1217
+ "registry+https://github.com/rust-lang/crates.io-index#shlex@2.0.1"
1218
+ ]
1219
+ },
1220
+ {
1221
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4"
1222
+ },
1223
+ {
1224
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#find-msvc-tools@0.1.9"
1225
+ },
1226
+ {
1227
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1"
1228
+ },
1229
+ {
1230
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2",
1231
+ "dependsOn": [
1232
+ "registry+https://github.com/rust-lang/crates.io-index#foreign-types-shared@0.1.1"
1233
+ ]
1234
+ },
1235
+ {
1236
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0"
1237
+ },
1238
+ {
1239
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#itoa@1.0.18"
1240
+ },
1241
+ {
1242
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189"
1243
+ },
1244
+ {
1245
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4"
1246
+ },
1247
+ {
1248
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1",
1249
+ "dependsOn": [
1250
+ "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107",
1251
+ "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47",
1252
+ "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119"
1253
+ ]
1254
+ },
1255
+ {
1256
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117",
1257
+ "dependsOn": [
1258
+ "registry+https://github.com/rust-lang/crates.io-index#cc@1.4.0",
1259
+ "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189",
1260
+ "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33",
1261
+ "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15"
1262
+ ]
1263
+ },
1264
+ {
1265
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#openssl@0.10.81",
1266
+ "dependsOn": [
1267
+ "registry+https://github.com/rust-lang/crates.io-index#bitflags@2.13.1",
1268
+ "registry+https://github.com/rust-lang/crates.io-index#cfg-if@1.0.4",
1269
+ "registry+https://github.com/rust-lang/crates.io-index#foreign-types@0.3.2",
1270
+ "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189",
1271
+ "registry+https://github.com/rust-lang/crates.io-index#openssl-macros@0.1.1",
1272
+ "registry+https://github.com/rust-lang/crates.io-index#openssl-sys@0.9.117"
1273
+ ]
1274
+ },
1275
+ {
1276
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#pem@4.0.0",
1277
+ "dependsOn": [
1278
+ "registry+https://github.com/rust-lang/crates.io-index#base64@0.23.0"
1279
+ ]
1280
+ },
1281
+ {
1282
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#pkg-config@0.3.33"
1283
+ },
1284
+ {
1285
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.14.0"
1286
+ },
1287
+ {
1288
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107",
1289
+ "dependsOn": [
1290
+ "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24"
1291
+ ]
1292
+ },
1293
+ {
1294
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0",
1295
+ "dependsOn": [
1296
+ "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5"
1297
+ ]
1298
+ },
1299
+ {
1300
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0",
1301
+ "dependsOn": [
1302
+ "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189",
1303
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0"
1304
+ ]
1305
+ },
1306
+ {
1307
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0",
1308
+ "dependsOn": [
1309
+ "registry+https://github.com/rust-lang/crates.io-index#heck@0.5.0",
1310
+ "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107",
1311
+ "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47",
1312
+ "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119"
1313
+ ]
1314
+ },
1315
+ {
1316
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0",
1317
+ "dependsOn": [
1318
+ "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107",
1319
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros-backend@0.29.0",
1320
+ "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47",
1321
+ "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119"
1322
+ ]
1323
+ },
1324
+ {
1325
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#pyo3@0.29.0",
1326
+ "dependsOn": [
1327
+ "registry+https://github.com/rust-lang/crates.io-index#libc@0.2.189",
1328
+ "registry+https://github.com/rust-lang/crates.io-index#once_cell@1.21.4",
1329
+ "registry+https://github.com/rust-lang/crates.io-index#portable-atomic@1.14.0",
1330
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3-build-config@0.29.0",
1331
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3-ffi@0.29.0",
1332
+ "registry+https://github.com/rust-lang/crates.io-index#pyo3-macros@0.29.0"
1333
+ ]
1334
+ },
1335
+ {
1336
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47",
1337
+ "dependsOn": [
1338
+ "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107"
1339
+ ]
1340
+ },
1341
+ {
1342
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#self_cell@1.3.0"
1343
+ },
1344
+ {
1345
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#shlex@2.0.1"
1346
+ },
1347
+ {
1348
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#syn@2.0.119",
1349
+ "dependsOn": [
1350
+ "registry+https://github.com/rust-lang/crates.io-index#proc-macro2@1.0.107",
1351
+ "registry+https://github.com/rust-lang/crates.io-index#quote@1.0.47",
1352
+ "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24"
1353
+ ]
1354
+ },
1355
+ {
1356
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#target-lexicon@0.13.5"
1357
+ },
1358
+ {
1359
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#unicode-ident@1.0.24"
1360
+ },
1361
+ {
1362
+ "ref": "registry+https://github.com/rust-lang/crates.io-index#vcpkg@0.2.15"
1363
+ }
1364
+ ]
1365
+ }
.mcp-venv/lib/python3.13/site-packages/cryptography-50.0.0.dist-info/sboms/sbom.json ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bomFormat": "CycloneDX",
3
+ "specVersion": "1.5",
4
+ "version": 1,
5
+ "serialNumber": "urn:uuid:6120948b-27bc-4bc5-b880-1557c2ab4bd1",
6
+ "metadata": {
7
+ "timestamp": "2026-07-31T11:10:12Z"
8
+ },
9
+ "components": [
10
+ {
11
+ "type": "library",
12
+ "name": "openssl",
13
+ "version": "4.0.1",
14
+ "purl": "pkg:generic/openssl@4.0.1?download_url=https://github.com/openssl/openssl/releases/download/openssl-4.0.1/openssl-4.0.1.tar.gz",
15
+ "hashes": [
16
+ {
17
+ "alg": "SHA-256",
18
+ "content": "2db3f3a0d6ea4b59e1f094ace2c8cd536dffb87cdc39084c5afa1e6f7f37dd09"
19
+ }
20
+ ],
21
+ "externalReferences": [
22
+ {
23
+ "type": "distribution",
24
+ "url": "https://github.com/openssl/openssl/releases/download/openssl-4.0.1/openssl-4.0.1.tar.gz"
25
+ }
26
+ ],
27
+ "properties": [
28
+ {
29
+ "name": "build:operating-system",
30
+ "value": "linux"
31
+ },
32
+ {
33
+ "name": "build:architecture",
34
+ "value": "x86_64"
35
+ },
36
+ {
37
+ "name": "build:flags",
38
+ "value": "no-zlib no-shared no-module no-comp no-apps no-docs no-sm2-precomp no-atexit enable-ec_nistp_64_gcc_128"
39
+ }
40
+ ]
41
+ }
42
+ ]
43
+ }
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/hashes.py ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 sys
9
+
10
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
11
+ from cryptography.utils import Buffer
12
+
13
+ __all__ = [
14
+ "MD5",
15
+ "SHA1",
16
+ "SHA3_224",
17
+ "SHA3_256",
18
+ "SHA3_384",
19
+ "SHA3_512",
20
+ "SHA224",
21
+ "SHA256",
22
+ "SHA384",
23
+ "SHA512",
24
+ "SHA512_224",
25
+ "SHA512_256",
26
+ "SHAKE128",
27
+ "SHAKE256",
28
+ "SM3",
29
+ "BLAKE2b",
30
+ "BLAKE2s",
31
+ "ExtendableOutputFunction",
32
+ "Hash",
33
+ "HashAlgorithm",
34
+ "HashContext",
35
+ "XOFHash",
36
+ ]
37
+
38
+
39
+ class HashAlgorithm(metaclass=abc.ABCMeta):
40
+ @property
41
+ @abc.abstractmethod
42
+ def name(self) -> str:
43
+ """
44
+ A string naming this algorithm (e.g. "sha256", "md5").
45
+ """
46
+
47
+ @property
48
+ @abc.abstractmethod
49
+ def digest_size(self) -> int:
50
+ """
51
+ The size of the resulting digest in bytes.
52
+ """
53
+
54
+ @property
55
+ @abc.abstractmethod
56
+ def block_size(self) -> int | None:
57
+ """
58
+ The internal block size of the hash function, or None if the hash
59
+ function does not use blocks internally (e.g. SHA3).
60
+ """
61
+
62
+
63
+ class HashContext(metaclass=abc.ABCMeta):
64
+ @property
65
+ @abc.abstractmethod
66
+ def algorithm(self) -> HashAlgorithm:
67
+ """
68
+ A HashAlgorithm that will be used by this context.
69
+ """
70
+
71
+ @abc.abstractmethod
72
+ def update(self, data: Buffer) -> None:
73
+ """
74
+ Processes the provided bytes through the hash.
75
+ """
76
+
77
+ @abc.abstractmethod
78
+ def finalize(self) -> bytes:
79
+ """
80
+ Finalizes the hash context and returns the hash digest as bytes.
81
+ """
82
+
83
+ @abc.abstractmethod
84
+ def copy(self) -> HashContext:
85
+ """
86
+ Return a HashContext that is a copy of the current context.
87
+ """
88
+
89
+
90
+ Hash = rust_openssl.hashes.Hash
91
+ HashContext.register(Hash)
92
+
93
+ XOFHash = rust_openssl.hashes.XOFHash
94
+
95
+
96
+ class ExtendableOutputFunction(metaclass=abc.ABCMeta):
97
+ """
98
+ An interface for extendable output functions.
99
+ """
100
+
101
+
102
+ class SHA1(HashAlgorithm):
103
+ name = "sha1"
104
+ digest_size = 20
105
+ block_size = 64
106
+
107
+ def __eq__(self, other: object) -> bool:
108
+ if not isinstance(other, SHA1):
109
+ return NotImplemented
110
+
111
+ return True
112
+
113
+
114
+ class SHA512_224(HashAlgorithm): # noqa: N801
115
+ name = "sha512-224"
116
+ digest_size = 28
117
+ block_size = 128
118
+
119
+ def __eq__(self, other: object) -> bool:
120
+ if not isinstance(other, SHA512_224):
121
+ return NotImplemented
122
+
123
+ return True
124
+
125
+
126
+ class SHA512_256(HashAlgorithm): # noqa: N801
127
+ name = "sha512-256"
128
+ digest_size = 32
129
+ block_size = 128
130
+
131
+ def __eq__(self, other: object) -> bool:
132
+ if not isinstance(other, SHA512_256):
133
+ return NotImplemented
134
+
135
+ return True
136
+
137
+
138
+ class SHA224(HashAlgorithm):
139
+ name = "sha224"
140
+ digest_size = 28
141
+ block_size = 64
142
+
143
+ def __eq__(self, other: object) -> bool:
144
+ if not isinstance(other, SHA224):
145
+ return NotImplemented
146
+
147
+ return True
148
+
149
+
150
+ class SHA256(HashAlgorithm):
151
+ name = "sha256"
152
+ digest_size = 32
153
+ block_size = 64
154
+
155
+ def __eq__(self, other: object) -> bool:
156
+ if not isinstance(other, SHA256):
157
+ return NotImplemented
158
+
159
+ return True
160
+
161
+
162
+ class SHA384(HashAlgorithm):
163
+ name = "sha384"
164
+ digest_size = 48
165
+ block_size = 128
166
+
167
+ def __eq__(self, other: object) -> bool:
168
+ if not isinstance(other, SHA384):
169
+ return NotImplemented
170
+
171
+ return True
172
+
173
+
174
+ class SHA512(HashAlgorithm):
175
+ name = "sha512"
176
+ digest_size = 64
177
+ block_size = 128
178
+
179
+ def __eq__(self, other: object) -> bool:
180
+ if not isinstance(other, SHA512):
181
+ return NotImplemented
182
+
183
+ return True
184
+
185
+
186
+ class SHA3_224(HashAlgorithm): # noqa: N801
187
+ name = "sha3-224"
188
+ digest_size = 28
189
+ block_size = None
190
+
191
+ def __eq__(self, other: object) -> bool:
192
+ if not isinstance(other, SHA3_224):
193
+ return NotImplemented
194
+
195
+ return True
196
+
197
+
198
+ class SHA3_256(HashAlgorithm): # noqa: N801
199
+ name = "sha3-256"
200
+ digest_size = 32
201
+ block_size = None
202
+
203
+ def __eq__(self, other: object) -> bool:
204
+ if not isinstance(other, SHA3_256):
205
+ return NotImplemented
206
+
207
+ return True
208
+
209
+
210
+ class SHA3_384(HashAlgorithm): # noqa: N801
211
+ name = "sha3-384"
212
+ digest_size = 48
213
+ block_size = None
214
+
215
+ def __eq__(self, other: object) -> bool:
216
+ if not isinstance(other, SHA3_384):
217
+ return NotImplemented
218
+
219
+ return True
220
+
221
+
222
+ class SHA3_512(HashAlgorithm): # noqa: N801
223
+ name = "sha3-512"
224
+ digest_size = 64
225
+ block_size = None
226
+
227
+ def __eq__(self, other: object) -> bool:
228
+ if not isinstance(other, SHA3_512):
229
+ return NotImplemented
230
+
231
+ return True
232
+
233
+
234
+ class SHAKE128(HashAlgorithm, ExtendableOutputFunction):
235
+ name = "shake128"
236
+ block_size = None
237
+
238
+ def __init__(self, digest_size: int):
239
+ if not isinstance(digest_size, int):
240
+ raise TypeError("digest_size must be an integer")
241
+
242
+ if digest_size < 1:
243
+ raise ValueError("digest_size must be a positive integer")
244
+
245
+ self._digest_size = digest_size
246
+
247
+ def __eq__(self, other: object) -> bool:
248
+ if not isinstance(other, SHAKE128):
249
+ return NotImplemented
250
+
251
+ return self._digest_size == other._digest_size
252
+
253
+ @property
254
+ def digest_size(self) -> int:
255
+ return self._digest_size
256
+
257
+ @classmethod
258
+ def xof(cls):
259
+ return cls(sys.maxsize)
260
+
261
+
262
+ class SHAKE256(HashAlgorithm, ExtendableOutputFunction):
263
+ name = "shake256"
264
+ block_size = None
265
+
266
+ def __init__(self, digest_size: int):
267
+ if not isinstance(digest_size, int):
268
+ raise TypeError("digest_size must be an integer")
269
+
270
+ if digest_size < 1:
271
+ raise ValueError("digest_size must be a positive integer")
272
+
273
+ self._digest_size = digest_size
274
+
275
+ def __eq__(self, other: object) -> bool:
276
+ if not isinstance(other, SHAKE256):
277
+ return NotImplemented
278
+
279
+ return self._digest_size == other._digest_size
280
+
281
+ @property
282
+ def digest_size(self) -> int:
283
+ return self._digest_size
284
+
285
+ @classmethod
286
+ def xof(cls):
287
+ return cls(sys.maxsize)
288
+
289
+
290
+ class MD5(HashAlgorithm):
291
+ name = "md5"
292
+ digest_size = 16
293
+ block_size = 64
294
+
295
+ def __eq__(self, other: object) -> bool:
296
+ if not isinstance(other, MD5):
297
+ return NotImplemented
298
+
299
+ return True
300
+
301
+
302
+ class BLAKE2b(HashAlgorithm):
303
+ name = "blake2b"
304
+ _max_digest_size = 64
305
+ _min_digest_size = 1
306
+ block_size = 128
307
+
308
+ def __init__(self, digest_size: int):
309
+ if digest_size != 64:
310
+ raise ValueError("Digest size must be 64")
311
+
312
+ self._digest_size = digest_size
313
+
314
+ def __eq__(self, other: object) -> bool:
315
+ if not isinstance(other, BLAKE2b):
316
+ return NotImplemented
317
+
318
+ return self._digest_size == other._digest_size
319
+
320
+ @property
321
+ def digest_size(self) -> int:
322
+ return self._digest_size
323
+
324
+
325
+ class BLAKE2s(HashAlgorithm):
326
+ name = "blake2s"
327
+ block_size = 64
328
+ _max_digest_size = 32
329
+ _min_digest_size = 1
330
+
331
+ def __init__(self, digest_size: int):
332
+ if digest_size != 32:
333
+ raise ValueError("Digest size must be 32")
334
+
335
+ self._digest_size = digest_size
336
+
337
+ def __eq__(self, other: object) -> bool:
338
+ if not isinstance(other, BLAKE2s):
339
+ return NotImplemented
340
+
341
+ return self._digest_size == other._digest_size
342
+
343
+ @property
344
+ def digest_size(self) -> int:
345
+ return self._digest_size
346
+
347
+
348
+ class SM3(HashAlgorithm):
349
+ name = "sm3"
350
+ digest_size = 32
351
+ block_size = 64
352
+
353
+ def __eq__(self, other: object) -> bool:
354
+ if not isinstance(other, SM3):
355
+ return NotImplemented
356
+
357
+ return True
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/hmac.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+ from cryptography.hazmat.primitives import hashes
9
+
10
+ __all__ = ["HMAC"]
11
+
12
+ HMAC = rust_openssl.hmac.HMAC
13
+ hashes.HashContext.register(HMAC)
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/hpke.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+
9
+ AEAD = rust_openssl.hpke.AEAD
10
+ KDF = rust_openssl.hpke.KDF
11
+ KEM = rust_openssl.hpke.KEM
12
+ MLKEM768X25519PrivateKey = rust_openssl.hpke.MLKEM768X25519PrivateKey
13
+ MLKEM768X25519PublicKey = rust_openssl.hpke.MLKEM768X25519PublicKey
14
+ MLKEM1024P384PrivateKey = rust_openssl.hpke.MLKEM1024P384PrivateKey
15
+ MLKEM1024P384PublicKey = rust_openssl.hpke.MLKEM1024P384PublicKey
16
+ Suite = rust_openssl.hpke.Suite
17
+
18
+ __all__ = [
19
+ "AEAD",
20
+ "KDF",
21
+ "KEM",
22
+ "MLKEM768X25519PrivateKey",
23
+ "MLKEM768X25519PublicKey",
24
+ "MLKEM1024P384PrivateKey",
25
+ "MLKEM1024P384PublicKey",
26
+ "Suite",
27
+ ]
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/__init__.py ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
9
+ from cryptography.utils import Buffer
10
+
11
+
12
+ class KeyDerivationFunction(metaclass=abc.ABCMeta):
13
+ @abc.abstractmethod
14
+ def derive(self, key_material: bytes) -> bytes:
15
+ """
16
+ Deterministically generates and returns a new key based on the existing
17
+ key material.
18
+ """
19
+
20
+ @abc.abstractmethod
21
+ def derive_into(self, key_material: bytes, buffer: Buffer) -> None:
22
+ """
23
+ Deterministically generates a new key based on the existing key
24
+ material and stores it in the provided buffer.
25
+ """
26
+
27
+ @abc.abstractmethod
28
+ def verify(self, key_material: bytes, expected_key: bytes) -> None:
29
+ """
30
+ Checks whether the key generated by the key material matches the
31
+ expected derived key. Raises an exception if they do not match.
32
+ """
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/argon2.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+ from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
9
+
10
+ Argon2d = rust_openssl.kdf.Argon2d
11
+ Argon2i = rust_openssl.kdf.Argon2i
12
+ Argon2id = rust_openssl.kdf.Argon2id
13
+ KeyDerivationFunction.register(Argon2d)
14
+ KeyDerivationFunction.register(Argon2i)
15
+ KeyDerivationFunction.register(Argon2id)
16
+
17
+ __all__ = ["Argon2d", "Argon2i", "Argon2id"]
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+ from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
9
+
10
+ ConcatKDFHash = rust_openssl.kdf.ConcatKDFHash
11
+ ConcatKDFHMAC = rust_openssl.kdf.ConcatKDFHMAC
12
+
13
+ KeyDerivationFunction.register(ConcatKDFHash)
14
+ KeyDerivationFunction.register(ConcatKDFHMAC)
15
+
16
+ __all__ = ["ConcatKDFHMAC", "ConcatKDFHash"]
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+ from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
9
+
10
+ HKDF = rust_openssl.kdf.HKDF
11
+ HKDFExpand = rust_openssl.kdf.HKDFExpand
12
+
13
+ KeyDerivationFunction.register(HKDF)
14
+ KeyDerivationFunction.register(HKDFExpand)
15
+
16
+ __all__ = ["HKDF", "HKDFExpand"]
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography import utils
8
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
9
+ from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
10
+
11
+
12
+ class Mode(utils.Enum):
13
+ CounterMode = "ctr"
14
+
15
+
16
+ class CounterLocation(utils.Enum):
17
+ BeforeFixed = "before_fixed"
18
+ AfterFixed = "after_fixed"
19
+ MiddleFixed = "middle_fixed"
20
+
21
+
22
+ KBKDFHMAC = rust_openssl.kdf.KBKDFHMAC
23
+ KeyDerivationFunction.register(KBKDFHMAC)
24
+
25
+ KBKDFCMAC = rust_openssl.kdf.KBKDFCMAC
26
+ KeyDerivationFunction.register(KBKDFCMAC)
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+ from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
9
+
10
+ PBKDF2HMAC = rust_openssl.kdf.PBKDF2HMAC
11
+ KeyDerivationFunction.register(PBKDF2HMAC)
12
+
13
+ __all__ = ["PBKDF2HMAC"]
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 sys
8
+
9
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
10
+ from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
11
+
12
+ # This is used by the scrypt tests to skip tests that require more memory
13
+ # than the MEM_LIMIT
14
+ _MEM_LIMIT = sys.maxsize // 2
15
+
16
+ Scrypt = rust_openssl.kdf.Scrypt
17
+ KeyDerivationFunction.register(Scrypt)
18
+
19
+ __all__ = ["Scrypt"]
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+ from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
9
+
10
+ X963KDF = rust_openssl.kdf.X963KDF
11
+ KeyDerivationFunction.register(X963KDF)
12
+
13
+ __all__ = ["X963KDF"]
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/keywrap.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+
9
+ __all__ = [
10
+ "InvalidUnwrap",
11
+ "aes_key_unwrap",
12
+ "aes_key_unwrap_with_padding",
13
+ "aes_key_wrap",
14
+ "aes_key_wrap_with_padding",
15
+ ]
16
+
17
+
18
+ class InvalidUnwrap(Exception):
19
+ pass
20
+
21
+
22
+ aes_key_wrap = rust_openssl.keywrap.aes_key_wrap
23
+ aes_key_unwrap = rust_openssl.keywrap.aes_key_unwrap
24
+ aes_key_wrap_with_padding = rust_openssl.keywrap.aes_key_wrap_with_padding
25
+ aes_key_unwrap_with_padding = rust_openssl.keywrap.aes_key_unwrap_with_padding
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/padding.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
9
+ from cryptography import utils
10
+ from cryptography.hazmat.bindings._rust import (
11
+ ANSIX923PaddingContext,
12
+ ANSIX923UnpaddingContext,
13
+ PKCS7PaddingContext,
14
+ PKCS7UnpaddingContext,
15
+ )
16
+
17
+
18
+ class PaddingContext(metaclass=abc.ABCMeta):
19
+ @abc.abstractmethod
20
+ def update(self, data: utils.Buffer) -> bytes:
21
+ """
22
+ Pads the provided bytes and returns any available data as bytes.
23
+ """
24
+
25
+ @abc.abstractmethod
26
+ def finalize(self) -> bytes:
27
+ """
28
+ Finalize the padding, returns bytes.
29
+ """
30
+
31
+
32
+ def _byte_padding_check(block_size: int) -> None:
33
+ if not (0 <= block_size <= 2040):
34
+ raise ValueError("block_size must be in range(0, 2041).")
35
+
36
+ if block_size % 8 != 0:
37
+ raise ValueError("block_size must be a multiple of 8.")
38
+
39
+
40
+ class PKCS7:
41
+ def __init__(self, block_size: int):
42
+ _byte_padding_check(block_size)
43
+ self.block_size = block_size
44
+
45
+ def padder(self) -> PaddingContext:
46
+ return PKCS7PaddingContext(self.block_size)
47
+
48
+ def unpadder(self) -> PaddingContext:
49
+ return PKCS7UnpaddingContext(self.block_size)
50
+
51
+
52
+ PaddingContext.register(PKCS7PaddingContext)
53
+ PaddingContext.register(PKCS7UnpaddingContext)
54
+
55
+
56
+ class ANSIX923:
57
+ def __init__(self, block_size: int):
58
+ _byte_padding_check(block_size)
59
+ self.block_size = block_size
60
+
61
+ def padder(self) -> PaddingContext:
62
+ return ANSIX923PaddingContext(self.block_size)
63
+
64
+ def unpadder(self) -> PaddingContext:
65
+ return ANSIX923UnpaddingContext(self.block_size)
66
+
67
+
68
+ PaddingContext.register(ANSIX923PaddingContext)
69
+ PaddingContext.register(ANSIX923UnpaddingContext)
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/poly1305.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+
9
+ __all__ = ["Poly1305"]
10
+
11
+ Poly1305 = rust_openssl.poly1305.Poly1305
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/__init__.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography import utils
8
+ from cryptography.hazmat.primitives._serialization import (
9
+ BestAvailableEncryption,
10
+ Encoding,
11
+ KeySerializationEncryption,
12
+ NoEncryption,
13
+ ParameterFormat,
14
+ PrivateFormat,
15
+ PublicFormat,
16
+ _KeySerializationEncryption,
17
+ )
18
+ from cryptography.hazmat.primitives.asymmetric.dh import _FFDH_DEPRECATION_MSG
19
+ from cryptography.hazmat.primitives.serialization.base import (
20
+ load_der_parameters,
21
+ load_der_private_key,
22
+ load_der_public_key,
23
+ load_pem_parameters,
24
+ load_pem_private_key,
25
+ load_pem_public_key,
26
+ )
27
+ from cryptography.hazmat.primitives.serialization.ssh import (
28
+ SSHCertificate,
29
+ SSHCertificateBuilder,
30
+ SSHCertificateType,
31
+ SSHCertPrivateKeyTypes,
32
+ SSHCertPublicKeyTypes,
33
+ SSHPrivateKeyTypes,
34
+ SSHPublicKeyTypes,
35
+ load_ssh_private_key,
36
+ load_ssh_public_identity,
37
+ load_ssh_public_key,
38
+ ssh_key_fingerprint,
39
+ )
40
+
41
+ __all__ = [
42
+ "BestAvailableEncryption",
43
+ "Encoding",
44
+ "KeySerializationEncryption",
45
+ "NoEncryption",
46
+ "ParameterFormat",
47
+ "PrivateFormat",
48
+ "PublicFormat",
49
+ "SSHCertPrivateKeyTypes",
50
+ "SSHCertPublicKeyTypes",
51
+ "SSHCertificate",
52
+ "SSHCertificateBuilder",
53
+ "SSHCertificateType",
54
+ "SSHPrivateKeyTypes",
55
+ "SSHPublicKeyTypes",
56
+ "_KeySerializationEncryption",
57
+ "load_der_parameters",
58
+ "load_der_private_key",
59
+ "load_der_public_key",
60
+ "load_pem_parameters",
61
+ "load_pem_private_key",
62
+ "load_pem_public_key",
63
+ "load_ssh_private_key",
64
+ "load_ssh_public_identity",
65
+ "load_ssh_public_key",
66
+ "ssh_key_fingerprint",
67
+ ]
68
+
69
+ # These can only load FFDH parameters, so the functions themselves are
70
+ # deprecated alongside the rest of FFDH.
71
+ utils.deprecated(
72
+ load_pem_parameters,
73
+ __name__,
74
+ _FFDH_DEPRECATION_MSG,
75
+ utils.DeprecatedIn50,
76
+ name="load_pem_parameters",
77
+ )
78
+
79
+ utils.deprecated(
80
+ load_der_parameters,
81
+ __name__,
82
+ _FFDH_DEPRECATION_MSG,
83
+ utils.DeprecatedIn50,
84
+ name="load_der_parameters",
85
+ )
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/base.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat.bindings._rust import openssl as rust_openssl
8
+
9
+ load_pem_private_key = rust_openssl.keys.load_pem_private_key
10
+ load_der_private_key = rust_openssl.keys.load_der_private_key
11
+
12
+ load_pem_public_key = rust_openssl.keys.load_pem_public_key
13
+ load_der_public_key = rust_openssl.keys.load_der_public_key
14
+
15
+ load_pem_parameters = rust_openssl.dh.from_pem_parameters
16
+ load_der_parameters = rust_openssl.dh.from_der_parameters
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 typing
8
+ from collections.abc import Iterable
9
+
10
+ from cryptography import x509
11
+ from cryptography.hazmat.bindings._rust import pkcs12 as rust_pkcs12
12
+ from cryptography.hazmat.primitives import serialization
13
+ from cryptography.hazmat.primitives._serialization import PBES as PBES
14
+ from cryptography.hazmat.primitives.asymmetric import (
15
+ dsa,
16
+ ec,
17
+ ed448,
18
+ ed25519,
19
+ rsa,
20
+ )
21
+ from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes
22
+
23
+ __all__ = [
24
+ "PBES",
25
+ "PKCS12Certificate",
26
+ "PKCS12KeyAndCertificates",
27
+ "PKCS12PrivateKeyTypes",
28
+ "load_key_and_certificates",
29
+ "load_pkcs12",
30
+ "serialize_java_truststore",
31
+ "serialize_key_and_certificates",
32
+ ]
33
+
34
+ PKCS12PrivateKeyTypes = typing.Union[
35
+ rsa.RSAPrivateKey,
36
+ dsa.DSAPrivateKey,
37
+ ec.EllipticCurvePrivateKey,
38
+ ed25519.Ed25519PrivateKey,
39
+ ed448.Ed448PrivateKey,
40
+ ]
41
+
42
+
43
+ PKCS12Certificate = rust_pkcs12.PKCS12Certificate
44
+
45
+
46
+ class PKCS12KeyAndCertificates:
47
+ def __init__(
48
+ self,
49
+ key: PrivateKeyTypes | None,
50
+ cert: PKCS12Certificate | None,
51
+ additional_certs: list[PKCS12Certificate],
52
+ ):
53
+ if key is not None and not isinstance(
54
+ key,
55
+ (
56
+ rsa.RSAPrivateKey,
57
+ dsa.DSAPrivateKey,
58
+ ec.EllipticCurvePrivateKey,
59
+ ed25519.Ed25519PrivateKey,
60
+ ed448.Ed448PrivateKey,
61
+ ),
62
+ ):
63
+ raise TypeError(
64
+ "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448"
65
+ " private key, or None."
66
+ )
67
+ if cert is not None and not isinstance(cert, PKCS12Certificate):
68
+ raise TypeError("cert must be a PKCS12Certificate object or None")
69
+ if not all(
70
+ isinstance(add_cert, PKCS12Certificate)
71
+ for add_cert in additional_certs
72
+ ):
73
+ raise TypeError(
74
+ "all values in additional_certs must be PKCS12Certificate"
75
+ " objects"
76
+ )
77
+ self._key = key
78
+ self._cert = cert
79
+ self._additional_certs = additional_certs
80
+
81
+ @property
82
+ def key(self) -> PrivateKeyTypes | None:
83
+ return self._key
84
+
85
+ @property
86
+ def cert(self) -> PKCS12Certificate | None:
87
+ return self._cert
88
+
89
+ @property
90
+ def additional_certs(self) -> list[PKCS12Certificate]:
91
+ return self._additional_certs
92
+
93
+ def __eq__(self, other: object) -> bool:
94
+ if not isinstance(other, PKCS12KeyAndCertificates):
95
+ return NotImplemented
96
+
97
+ return (
98
+ self.key == other.key
99
+ and self.cert == other.cert
100
+ and self.additional_certs == other.additional_certs
101
+ )
102
+
103
+ def __hash__(self) -> int:
104
+ return hash((self.key, self.cert, tuple(self.additional_certs)))
105
+
106
+ def __repr__(self) -> str:
107
+ fmt = (
108
+ "<PKCS12KeyAndCertificates(key={}, cert={}, additional_certs={})>"
109
+ )
110
+ return fmt.format(self.key, self.cert, self.additional_certs)
111
+
112
+
113
+ load_key_and_certificates = rust_pkcs12.load_key_and_certificates
114
+ load_pkcs12 = rust_pkcs12.load_pkcs12
115
+
116
+
117
+ _PKCS12CATypes = typing.Union[
118
+ x509.Certificate,
119
+ PKCS12Certificate,
120
+ ]
121
+
122
+
123
+ def serialize_java_truststore(
124
+ certs: Iterable[PKCS12Certificate],
125
+ encryption_algorithm: serialization.KeySerializationEncryption,
126
+ ) -> bytes:
127
+ if not certs:
128
+ raise ValueError("You must supply at least one cert")
129
+
130
+ if not isinstance(
131
+ encryption_algorithm, serialization.KeySerializationEncryption
132
+ ):
133
+ raise TypeError(
134
+ "Key encryption algorithm must be a "
135
+ "KeySerializationEncryption instance"
136
+ )
137
+
138
+ return rust_pkcs12.serialize_java_truststore(certs, encryption_algorithm)
139
+
140
+
141
+ def serialize_key_and_certificates(
142
+ name: bytes | None,
143
+ key: PKCS12PrivateKeyTypes | None,
144
+ cert: x509.Certificate | None,
145
+ cas: Iterable[_PKCS12CATypes] | None,
146
+ encryption_algorithm: serialization.KeySerializationEncryption,
147
+ ) -> bytes:
148
+ if key is not None and not isinstance(
149
+ key,
150
+ (
151
+ rsa.RSAPrivateKey,
152
+ dsa.DSAPrivateKey,
153
+ ec.EllipticCurvePrivateKey,
154
+ ed25519.Ed25519PrivateKey,
155
+ ed448.Ed448PrivateKey,
156
+ ),
157
+ ):
158
+ raise TypeError(
159
+ "Key must be RSA, DSA, EllipticCurve, ED25519, or ED448"
160
+ " private key, or None."
161
+ )
162
+
163
+ if not isinstance(
164
+ encryption_algorithm, serialization.KeySerializationEncryption
165
+ ):
166
+ raise TypeError(
167
+ "Key encryption algorithm must be a "
168
+ "KeySerializationEncryption instance"
169
+ )
170
+
171
+ if key is None and cert is None and not cas:
172
+ raise ValueError("You must supply at least one of key, cert, or cas")
173
+
174
+ return rust_pkcs12.serialize_key_and_certificates(
175
+ name, key, cert, cas, encryption_algorithm
176
+ )
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py ADDED
@@ -0,0 +1,412 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 email.base64mime
8
+ import email.generator
9
+ import email.message
10
+ import email.policy
11
+ import io
12
+ import typing
13
+ from collections.abc import Iterable
14
+
15
+ from cryptography import utils, x509
16
+ from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
17
+ from cryptography.hazmat.bindings._rust import pkcs7 as rust_pkcs7
18
+ from cryptography.hazmat.primitives import hashes, serialization
19
+ from cryptography.hazmat.primitives.asymmetric import ec, padding, rsa
20
+ from cryptography.hazmat.primitives.ciphers import (
21
+ algorithms,
22
+ )
23
+ from cryptography.utils import _check_byteslike
24
+
25
+ load_pem_pkcs7_certificates = rust_pkcs7.load_pem_pkcs7_certificates
26
+
27
+ load_der_pkcs7_certificates = rust_pkcs7.load_der_pkcs7_certificates
28
+
29
+ serialize_certificates = rust_pkcs7.serialize_certificates
30
+
31
+ PKCS7HashTypes = typing.Union[
32
+ hashes.SHA224,
33
+ hashes.SHA256,
34
+ hashes.SHA384,
35
+ hashes.SHA512,
36
+ ]
37
+
38
+ PKCS7PrivateKeyTypes = typing.Union[
39
+ rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey
40
+ ]
41
+
42
+ ContentEncryptionAlgorithm = typing.Union[
43
+ type[algorithms.AES128], type[algorithms.AES256]
44
+ ]
45
+
46
+
47
+ class PKCS7Options(utils.Enum):
48
+ Text = "Add text/plain MIME type"
49
+ Binary = "Don't translate input data into canonical MIME format"
50
+ DetachedSignature = "Don't embed data in the PKCS7 structure"
51
+ NoCapabilities = "Don't embed SMIME capabilities"
52
+ NoAttributes = "Don't embed authenticatedAttributes"
53
+ NoCerts = "Don't embed signer certificate"
54
+
55
+
56
+ class PKCS7SignatureBuilder:
57
+ def __init__(
58
+ self,
59
+ data: utils.Buffer | None = None,
60
+ signers: list[
61
+ tuple[
62
+ x509.Certificate,
63
+ PKCS7PrivateKeyTypes,
64
+ PKCS7HashTypes,
65
+ padding.PSS | padding.PKCS1v15 | None,
66
+ ]
67
+ ] = [],
68
+ additional_certs: list[x509.Certificate] = [],
69
+ ):
70
+ self._data = data
71
+ self._signers = signers
72
+ self._additional_certs = additional_certs
73
+
74
+ def set_data(self, data: utils.Buffer) -> PKCS7SignatureBuilder:
75
+ _check_byteslike("data", data)
76
+ if self._data is not None:
77
+ raise ValueError("data may only be set once")
78
+
79
+ return PKCS7SignatureBuilder(data, self._signers)
80
+
81
+ def add_signer(
82
+ self,
83
+ certificate: x509.Certificate,
84
+ private_key: PKCS7PrivateKeyTypes,
85
+ hash_algorithm: PKCS7HashTypes,
86
+ *,
87
+ rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
88
+ ) -> PKCS7SignatureBuilder:
89
+ if not isinstance(
90
+ hash_algorithm,
91
+ (
92
+ hashes.SHA224,
93
+ hashes.SHA256,
94
+ hashes.SHA384,
95
+ hashes.SHA512,
96
+ ),
97
+ ):
98
+ raise TypeError(
99
+ "hash_algorithm must be one of hashes.SHA224, "
100
+ "SHA256, SHA384, or SHA512"
101
+ )
102
+ if not isinstance(certificate, x509.Certificate):
103
+ raise TypeError("certificate must be a x509.Certificate")
104
+
105
+ if not isinstance(
106
+ private_key, (rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey)
107
+ ):
108
+ raise TypeError("Only RSA & EC keys are supported at this time.")
109
+
110
+ if rsa_padding is not None:
111
+ if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
112
+ raise TypeError("Padding must be PSS or PKCS1v15")
113
+ if not isinstance(private_key, rsa.RSAPrivateKey):
114
+ raise TypeError("Padding is only supported for RSA keys")
115
+
116
+ return PKCS7SignatureBuilder(
117
+ self._data,
118
+ [
119
+ *self._signers,
120
+ (certificate, private_key, hash_algorithm, rsa_padding),
121
+ ],
122
+ )
123
+
124
+ def add_certificate(
125
+ self, certificate: x509.Certificate
126
+ ) -> PKCS7SignatureBuilder:
127
+ if not isinstance(certificate, x509.Certificate):
128
+ raise TypeError("certificate must be a x509.Certificate")
129
+
130
+ return PKCS7SignatureBuilder(
131
+ self._data, self._signers, [*self._additional_certs, certificate]
132
+ )
133
+
134
+ def sign(
135
+ self,
136
+ encoding: serialization.Encoding,
137
+ options: Iterable[PKCS7Options],
138
+ backend: typing.Any = None,
139
+ ) -> bytes:
140
+ if len(self._signers) == 0:
141
+ raise ValueError("Must have at least one signer")
142
+ if self._data is None:
143
+ raise ValueError("You must add data to sign")
144
+ options = list(options)
145
+ if not all(isinstance(x, PKCS7Options) for x in options):
146
+ raise ValueError("options must be from the PKCS7Options enum")
147
+ if encoding not in (
148
+ serialization.Encoding.PEM,
149
+ serialization.Encoding.DER,
150
+ serialization.Encoding.SMIME,
151
+ ):
152
+ raise ValueError(
153
+ "Must be PEM, DER, or SMIME from the Encoding enum"
154
+ )
155
+
156
+ # Text is a meaningless option unless it is accompanied by
157
+ # DetachedSignature
158
+ if (
159
+ PKCS7Options.Text in options
160
+ and PKCS7Options.DetachedSignature not in options
161
+ ):
162
+ raise ValueError(
163
+ "When passing the Text option you must also pass "
164
+ "DetachedSignature"
165
+ )
166
+
167
+ if PKCS7Options.Text in options and encoding in (
168
+ serialization.Encoding.DER,
169
+ serialization.Encoding.PEM,
170
+ ):
171
+ raise ValueError(
172
+ "The Text option is only available for SMIME serialization"
173
+ )
174
+
175
+ # No attributes implies no capabilities so we'll error if you try to
176
+ # pass both.
177
+ if (
178
+ PKCS7Options.NoAttributes in options
179
+ and PKCS7Options.NoCapabilities in options
180
+ ):
181
+ raise ValueError(
182
+ "NoAttributes is a superset of NoCapabilities. Do not pass "
183
+ "both values."
184
+ )
185
+
186
+ return rust_pkcs7.sign_and_serialize(self, encoding, options)
187
+
188
+
189
+ class PKCS7EnvelopeBuilder:
190
+ def __init__(
191
+ self,
192
+ *,
193
+ _data: bytes | None = None,
194
+ _recipients: list[x509.Certificate] | None = None,
195
+ _content_encryption_algorithm: ContentEncryptionAlgorithm
196
+ | None = None,
197
+ ):
198
+ from cryptography.hazmat.backends.openssl.backend import (
199
+ backend as ossl,
200
+ )
201
+
202
+ if not ossl.rsa_encryption_supported(padding=padding.PKCS1v15()):
203
+ raise UnsupportedAlgorithm(
204
+ "RSA with PKCS1 v1.5 padding is not supported by this version"
205
+ " of OpenSSL.",
206
+ _Reasons.UNSUPPORTED_PADDING,
207
+ )
208
+ self._data = _data
209
+ self._recipients = _recipients if _recipients is not None else []
210
+ self._content_encryption_algorithm = _content_encryption_algorithm
211
+
212
+ def set_data(self, data: bytes) -> PKCS7EnvelopeBuilder:
213
+ _check_byteslike("data", data)
214
+ if self._data is not None:
215
+ raise ValueError("data may only be set once")
216
+
217
+ return PKCS7EnvelopeBuilder(
218
+ _data=data,
219
+ _recipients=self._recipients,
220
+ _content_encryption_algorithm=self._content_encryption_algorithm,
221
+ )
222
+
223
+ def add_recipient(
224
+ self,
225
+ certificate: x509.Certificate,
226
+ ) -> PKCS7EnvelopeBuilder:
227
+ if not isinstance(certificate, x509.Certificate):
228
+ raise TypeError("certificate must be a x509.Certificate")
229
+
230
+ if not isinstance(certificate.public_key(), rsa.RSAPublicKey):
231
+ raise TypeError("Only RSA keys are supported at this time.")
232
+
233
+ return PKCS7EnvelopeBuilder(
234
+ _data=self._data,
235
+ _recipients=[
236
+ *self._recipients,
237
+ certificate,
238
+ ],
239
+ _content_encryption_algorithm=self._content_encryption_algorithm,
240
+ )
241
+
242
+ def set_content_encryption_algorithm(
243
+ self, content_encryption_algorithm: ContentEncryptionAlgorithm
244
+ ) -> PKCS7EnvelopeBuilder:
245
+ if self._content_encryption_algorithm is not None:
246
+ raise ValueError("Content encryption algo may only be set once")
247
+ if content_encryption_algorithm not in {
248
+ algorithms.AES128,
249
+ algorithms.AES256,
250
+ }:
251
+ raise TypeError("Only AES128 and AES256 are supported")
252
+
253
+ return PKCS7EnvelopeBuilder(
254
+ _data=self._data,
255
+ _recipients=self._recipients,
256
+ _content_encryption_algorithm=content_encryption_algorithm,
257
+ )
258
+
259
+ def encrypt(
260
+ self,
261
+ encoding: serialization.Encoding,
262
+ options: Iterable[PKCS7Options],
263
+ ) -> bytes:
264
+ if len(self._recipients) == 0:
265
+ raise ValueError("Must have at least one recipient")
266
+ if self._data is None:
267
+ raise ValueError("You must add data to encrypt")
268
+
269
+ # The default content encryption algorithm is AES-128-CBC, which the
270
+ # S/MIME v3.2 RFC specifies as MUST support (https://datatracker.ietf.org/doc/html/rfc5751#section-2.7)
271
+ # however rest of S/MIME v3.2 is not currently supported
272
+ content_encryption_algorithm = (
273
+ self._content_encryption_algorithm or algorithms.AES128
274
+ )
275
+
276
+ options = list(options)
277
+ if not all(isinstance(x, PKCS7Options) for x in options):
278
+ raise ValueError("options must be from the PKCS7Options enum")
279
+ if encoding not in (
280
+ serialization.Encoding.PEM,
281
+ serialization.Encoding.DER,
282
+ serialization.Encoding.SMIME,
283
+ ):
284
+ raise ValueError(
285
+ "Must be PEM, DER, or SMIME from the Encoding enum"
286
+ )
287
+
288
+ # Only allow options that make sense for encryption
289
+ if any(
290
+ opt not in [PKCS7Options.Text, PKCS7Options.Binary]
291
+ for opt in options
292
+ ):
293
+ raise ValueError(
294
+ "Only the following options are supported for encryption: "
295
+ "Text, Binary"
296
+ )
297
+ elif PKCS7Options.Text in options and PKCS7Options.Binary in options:
298
+ # OpenSSL accepts both options at the same time, but ignores Text.
299
+ # We fail defensively to avoid unexpected outputs.
300
+ raise ValueError(
301
+ "Cannot use Binary and Text options at the same time"
302
+ )
303
+
304
+ return rust_pkcs7.encrypt_and_serialize(
305
+ self, content_encryption_algorithm, encoding, options
306
+ )
307
+
308
+
309
+ pkcs7_decrypt_der = rust_pkcs7.decrypt_der
310
+ pkcs7_decrypt_pem = rust_pkcs7.decrypt_pem
311
+ pkcs7_decrypt_smime = rust_pkcs7.decrypt_smime
312
+
313
+
314
+ def _smime_signed_encode(
315
+ data: bytes, signature: bytes, micalg: str, text_mode: bool
316
+ ) -> bytes:
317
+ # This function works pretty hard to replicate what OpenSSL does
318
+ # precisely. For good and for ill.
319
+
320
+ m = email.message.Message()
321
+ m.add_header("MIME-Version", "1.0")
322
+ m.add_header(
323
+ "Content-Type",
324
+ "multipart/signed",
325
+ protocol="application/x-pkcs7-signature",
326
+ micalg=micalg,
327
+ )
328
+
329
+ m.preamble = "This is an S/MIME signed message\n"
330
+
331
+ msg_part = OpenSSLMimePart()
332
+ msg_part.set_payload(data)
333
+ if text_mode:
334
+ msg_part.add_header("Content-Type", "text/plain")
335
+ m.attach(msg_part)
336
+
337
+ sig_part = email.message.MIMEPart()
338
+ sig_part.add_header(
339
+ "Content-Type", "application/x-pkcs7-signature", name="smime.p7s"
340
+ )
341
+ sig_part.add_header("Content-Transfer-Encoding", "base64")
342
+ sig_part.add_header(
343
+ "Content-Disposition", "attachment", filename="smime.p7s"
344
+ )
345
+ sig_part.set_payload(
346
+ email.base64mime.body_encode(signature, maxlinelen=65)
347
+ )
348
+ del sig_part["MIME-Version"]
349
+ m.attach(sig_part)
350
+
351
+ fp = io.BytesIO()
352
+ g = email.generator.BytesGenerator(
353
+ fp,
354
+ maxheaderlen=0,
355
+ mangle_from_=False,
356
+ policy=m.policy.clone(linesep="\r\n"),
357
+ )
358
+ g.flatten(m)
359
+ return fp.getvalue()
360
+
361
+
362
+ def _smime_enveloped_encode(data: bytes) -> bytes:
363
+ m = email.message.Message()
364
+ m.add_header("MIME-Version", "1.0")
365
+ m.add_header("Content-Disposition", "attachment", filename="smime.p7m")
366
+ m.add_header(
367
+ "Content-Type",
368
+ "application/pkcs7-mime",
369
+ smime_type="enveloped-data",
370
+ name="smime.p7m",
371
+ )
372
+ m.add_header("Content-Transfer-Encoding", "base64")
373
+
374
+ m.set_payload(email.base64mime.body_encode(data, maxlinelen=65))
375
+
376
+ return m.as_bytes(policy=m.policy.clone(linesep="\n", max_line_length=0))
377
+
378
+
379
+ def _smime_enveloped_decode(data: bytes) -> bytes:
380
+ m = email.message_from_bytes(data)
381
+ if m.get_content_type() not in {
382
+ "application/x-pkcs7-mime",
383
+ "application/pkcs7-mime",
384
+ }:
385
+ raise ValueError("Not an S/MIME enveloped message")
386
+ return bytes(m.get_payload(decode=True))
387
+
388
+
389
+ def _smime_remove_text_headers(data: bytes) -> bytes:
390
+ m = email.message_from_bytes(data)
391
+ # Using get() instead of get_content_type() since it has None as default,
392
+ # where the latter has "text/plain". Both methods are case-insensitive.
393
+ content_type = m.get("content-type")
394
+ if content_type is None:
395
+ raise ValueError(
396
+ "Decrypted MIME data has no 'Content-Type' header. "
397
+ "Please remove the 'Text' option to parse it manually."
398
+ )
399
+ if "text/plain" not in content_type:
400
+ raise ValueError(
401
+ f"Decrypted MIME data content type is '{content_type}', not "
402
+ "'text/plain'. Remove the 'Text' option to parse it manually."
403
+ )
404
+ return bytes(m.get_payload(decode=True))
405
+
406
+
407
+ class OpenSSLMimePart(email.message.MIMEPart):
408
+ # A MIMEPart subclass that replicates OpenSSL's behavior of not including
409
+ # a newline if there are no headers.
410
+ def _write_headers(self, generator) -> None:
411
+ if list(self.raw_items()):
412
+ generator._write_headers(self)
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/serialization/ssh.py ADDED
@@ -0,0 +1,1615 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 binascii
8
+ import enum
9
+ import os
10
+ import re
11
+ import typing
12
+ import warnings
13
+ from dataclasses import dataclass
14
+
15
+ from cryptography import utils
16
+ from cryptography.exceptions import UnsupportedAlgorithm
17
+ from cryptography.hazmat.primitives import hashes
18
+ from cryptography.hazmat.primitives.asymmetric import (
19
+ dsa,
20
+ ec,
21
+ ed25519,
22
+ padding,
23
+ rsa,
24
+ )
25
+ from cryptography.hazmat.primitives.asymmetric import utils as asym_utils
26
+ from cryptography.hazmat.primitives.ciphers import (
27
+ AEADDecryptionContext,
28
+ Cipher,
29
+ algorithms,
30
+ modes,
31
+ )
32
+ from cryptography.hazmat.primitives.serialization import (
33
+ Encoding,
34
+ KeySerializationEncryption,
35
+ NoEncryption,
36
+ PrivateFormat,
37
+ PublicFormat,
38
+ _KeySerializationEncryption,
39
+ )
40
+
41
+ try:
42
+ from bcrypt import kdf as _bcrypt_kdf
43
+
44
+ _bcrypt_supported = True
45
+ except ImportError:
46
+ _bcrypt_supported = False
47
+
48
+ def _bcrypt_kdf(
49
+ password: bytes,
50
+ salt: bytes,
51
+ desired_key_bytes: int,
52
+ rounds: int,
53
+ ignore_few_rounds: bool = False,
54
+ ) -> bytes:
55
+ raise UnsupportedAlgorithm("Need bcrypt module")
56
+
57
+
58
+ _SSH_ED25519 = b"ssh-ed25519"
59
+ _SSH_RSA = b"ssh-rsa"
60
+ _SSH_DSA = b"ssh-dss"
61
+ _ECDSA_NISTP256 = b"ecdsa-sha2-nistp256"
62
+ _ECDSA_NISTP384 = b"ecdsa-sha2-nistp384"
63
+ _ECDSA_NISTP521 = b"ecdsa-sha2-nistp521"
64
+ _CERT_SUFFIX = b"-cert-v01@openssh.com"
65
+
66
+ # U2F application string suffixed pubkey
67
+ _SK_SSH_ED25519 = b"sk-ssh-ed25519@openssh.com"
68
+ _SK_SSH_ECDSA_NISTP256 = b"sk-ecdsa-sha2-nistp256@openssh.com"
69
+
70
+ # These are not key types, only algorithms, so they cannot appear
71
+ # as a public key type
72
+ _SSH_RSA_SHA256 = b"rsa-sha2-256"
73
+ _SSH_RSA_SHA512 = b"rsa-sha2-512"
74
+
75
+ _SSH_PUBKEY_RC = re.compile(rb"\A(\S+)[ \t]+(\S+)")
76
+ _SK_MAGIC = b"openssh-key-v1\0"
77
+ _SK_START = b"-----BEGIN OPENSSH PRIVATE KEY-----"
78
+ _SK_END = b"-----END OPENSSH PRIVATE KEY-----"
79
+ _BCRYPT = b"bcrypt"
80
+ _NONE = b"none"
81
+ _DEFAULT_CIPHER = b"aes256-ctr"
82
+ _DEFAULT_ROUNDS = 16
83
+
84
+ # re is only way to work on bytes-like data
85
+ _PEM_RC = re.compile(_SK_START + b"(.*?)" + _SK_END, re.DOTALL)
86
+
87
+ # padding for max blocksize
88
+ _PADDING = memoryview(bytearray(range(1, 1 + 16)))
89
+
90
+
91
+ @dataclass
92
+ class _SSHCipher:
93
+ alg: type[algorithms.AES]
94
+ key_len: int
95
+ mode: type[modes.CTR] | type[modes.CBC] | type[modes.GCM]
96
+ block_len: int
97
+ iv_len: int
98
+ tag_len: int | None
99
+ is_aead: bool
100
+
101
+
102
+ # ciphers that are actually used in key wrapping
103
+ _SSH_CIPHERS: dict[bytes, _SSHCipher] = {
104
+ b"aes256-ctr": _SSHCipher(
105
+ alg=algorithms.AES,
106
+ key_len=32,
107
+ mode=modes.CTR,
108
+ block_len=16,
109
+ iv_len=16,
110
+ tag_len=None,
111
+ is_aead=False,
112
+ ),
113
+ b"aes256-cbc": _SSHCipher(
114
+ alg=algorithms.AES,
115
+ key_len=32,
116
+ mode=modes.CBC,
117
+ block_len=16,
118
+ iv_len=16,
119
+ tag_len=None,
120
+ is_aead=False,
121
+ ),
122
+ b"aes256-gcm@openssh.com": _SSHCipher(
123
+ alg=algorithms.AES,
124
+ key_len=32,
125
+ mode=modes.GCM,
126
+ block_len=16,
127
+ iv_len=12,
128
+ tag_len=16,
129
+ is_aead=True,
130
+ ),
131
+ }
132
+
133
+ # map local curve name to key type
134
+ _ECDSA_KEY_TYPE = {
135
+ "secp256r1": _ECDSA_NISTP256,
136
+ "secp384r1": _ECDSA_NISTP384,
137
+ "secp521r1": _ECDSA_NISTP521,
138
+ }
139
+
140
+
141
+ def _get_ssh_key_type(key: SSHPrivateKeyTypes | SSHPublicKeyTypes) -> bytes:
142
+ if isinstance(key, ec.EllipticCurvePrivateKey):
143
+ key_type = _ecdsa_key_type(key.public_key())
144
+ elif isinstance(key, ec.EllipticCurvePublicKey):
145
+ key_type = _ecdsa_key_type(key)
146
+ elif isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)):
147
+ key_type = _SSH_RSA
148
+ elif isinstance(key, (dsa.DSAPrivateKey, dsa.DSAPublicKey)):
149
+ key_type = _SSH_DSA
150
+ elif isinstance(
151
+ key, (ed25519.Ed25519PrivateKey, ed25519.Ed25519PublicKey)
152
+ ):
153
+ key_type = _SSH_ED25519
154
+ else:
155
+ raise ValueError("Unsupported key type")
156
+
157
+ return key_type
158
+
159
+
160
+ def _ecdsa_key_type(public_key: ec.EllipticCurvePublicKey) -> bytes:
161
+ """Return SSH key_type and curve_name for private key."""
162
+ curve = public_key.curve
163
+ if curve.name not in _ECDSA_KEY_TYPE:
164
+ raise ValueError(
165
+ f"Unsupported curve for ssh private key: {curve.name!r}"
166
+ )
167
+ return _ECDSA_KEY_TYPE[curve.name]
168
+
169
+
170
+ def _check_block_size(data: utils.Buffer, block_len: int) -> None:
171
+ """Require data to be full blocks"""
172
+ if not data or len(data) % block_len != 0:
173
+ raise ValueError("Corrupt data: missing padding")
174
+
175
+
176
+ def _check_empty(data: utils.Buffer) -> None:
177
+ """All data should have been parsed."""
178
+ if data:
179
+ raise ValueError("Corrupt data: unparsed data")
180
+
181
+
182
+ def _init_cipher(
183
+ ciphername: bytes,
184
+ password: bytes | None,
185
+ salt: bytes,
186
+ rounds: int,
187
+ ) -> Cipher[modes.CBC | modes.CTR | modes.GCM]:
188
+ """Generate key + iv and return cipher."""
189
+ if not password:
190
+ raise TypeError(
191
+ "Key is password-protected, but password was not provided."
192
+ )
193
+
194
+ ciph = _SSH_CIPHERS[ciphername]
195
+ seed = _bcrypt_kdf(
196
+ password, salt, ciph.key_len + ciph.iv_len, rounds, True
197
+ )
198
+ return Cipher(
199
+ ciph.alg(seed[: ciph.key_len]),
200
+ ciph.mode(seed[ciph.key_len :]),
201
+ )
202
+
203
+
204
+ def _get_u32(data: memoryview) -> tuple[int, memoryview]:
205
+ """Uint32"""
206
+ if len(data) < 4:
207
+ raise ValueError("Invalid data")
208
+ return int.from_bytes(data[:4], byteorder="big"), data[4:]
209
+
210
+
211
+ def _get_u64(data: memoryview) -> tuple[int, memoryview]:
212
+ """Uint64"""
213
+ if len(data) < 8:
214
+ raise ValueError("Invalid data")
215
+ return int.from_bytes(data[:8], byteorder="big"), data[8:]
216
+
217
+
218
+ def _get_sshstr(data: memoryview) -> tuple[memoryview, memoryview]:
219
+ """Bytes with u32 length prefix"""
220
+ n, data = _get_u32(data)
221
+ if n > len(data):
222
+ raise ValueError("Invalid data")
223
+ return data[:n], data[n:]
224
+
225
+
226
+ def _get_mpint(data: memoryview) -> tuple[int, memoryview]:
227
+ """Big integer."""
228
+ val, data = _get_sshstr(data)
229
+ if val and val[0] > 0x7F:
230
+ raise ValueError("Invalid data")
231
+ return int.from_bytes(val, "big"), data
232
+
233
+
234
+ def _to_mpint(val: int) -> bytes:
235
+ """Storage format for signed bigint."""
236
+ if val < 0:
237
+ raise ValueError("negative mpint not allowed")
238
+ if not val:
239
+ return b""
240
+ nbytes = (val.bit_length() + 8) // 8
241
+ return utils.int_to_bytes(val, nbytes)
242
+
243
+
244
+ class _FragList:
245
+ """Build recursive structure without data copy."""
246
+
247
+ flist: list[utils.Buffer]
248
+
249
+ def __init__(self, init: list[utils.Buffer] | None = None) -> None:
250
+ self.flist = []
251
+ if init:
252
+ self.flist.extend(init)
253
+
254
+ def put_raw(self, val: utils.Buffer) -> None:
255
+ """Add plain bytes"""
256
+ self.flist.append(val)
257
+
258
+ def put_u32(self, val: int) -> None:
259
+ """Big-endian uint32"""
260
+ self.flist.append(val.to_bytes(length=4, byteorder="big"))
261
+
262
+ def put_u64(self, val: int) -> None:
263
+ """Big-endian uint64"""
264
+ self.flist.append(val.to_bytes(length=8, byteorder="big"))
265
+
266
+ def put_sshstr(self, val: bytes | _FragList) -> None:
267
+ """Bytes prefixed with u32 length"""
268
+ if isinstance(val, (bytes, memoryview, bytearray)):
269
+ self.put_u32(len(val))
270
+ self.flist.append(val)
271
+ else:
272
+ self.put_u32(val.size())
273
+ self.flist.extend(val.flist)
274
+
275
+ def put_mpint(self, val: int) -> None:
276
+ """Big-endian bigint prefixed with u32 length"""
277
+ self.put_sshstr(_to_mpint(val))
278
+
279
+ def size(self) -> int:
280
+ """Current number of bytes"""
281
+ return sum(map(len, self.flist))
282
+
283
+ def render(self, dstbuf: memoryview, pos: int = 0) -> int:
284
+ """Write into bytearray"""
285
+ for frag in self.flist:
286
+ flen = len(frag)
287
+ start, pos = pos, pos + flen
288
+ dstbuf[start:pos] = frag
289
+ return pos
290
+
291
+ def tobytes(self) -> bytes:
292
+ """Return as bytes"""
293
+ buf = memoryview(bytearray(self.size()))
294
+ self.render(buf)
295
+ return buf.tobytes()
296
+
297
+
298
+ class _SSHFormatRSA:
299
+ """Format for RSA keys.
300
+
301
+ Public:
302
+ mpint e, n
303
+ Private:
304
+ mpint n, e, d, iqmp, p, q
305
+ """
306
+
307
+ def get_public(
308
+ self, data: memoryview
309
+ ) -> tuple[tuple[int, int], memoryview]:
310
+ """RSA public fields"""
311
+ e, data = _get_mpint(data)
312
+ n, data = _get_mpint(data)
313
+ return (e, n), data
314
+
315
+ def load_public(
316
+ self, data: memoryview
317
+ ) -> tuple[rsa.RSAPublicKey, memoryview]:
318
+ """Make RSA public key from data."""
319
+ (e, n), data = self.get_public(data)
320
+ public_numbers = rsa.RSAPublicNumbers(e, n)
321
+ public_key = public_numbers.public_key()
322
+ return public_key, data
323
+
324
+ def load_private(
325
+ self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool
326
+ ) -> tuple[rsa.RSAPrivateKey, memoryview]:
327
+ """Make RSA private key from data."""
328
+ n, data = _get_mpint(data)
329
+ e, data = _get_mpint(data)
330
+ d, data = _get_mpint(data)
331
+ iqmp, data = _get_mpint(data)
332
+ p, data = _get_mpint(data)
333
+ q, data = _get_mpint(data)
334
+
335
+ if (e, n) != pubfields:
336
+ raise ValueError("Corrupt data: rsa field mismatch")
337
+ dmp1 = rsa.rsa_crt_dmp1(d, p)
338
+ dmq1 = rsa.rsa_crt_dmq1(d, q)
339
+ public_numbers = rsa.RSAPublicNumbers(e, n)
340
+ private_numbers = rsa.RSAPrivateNumbers(
341
+ p, q, d, dmp1, dmq1, iqmp, public_numbers
342
+ )
343
+ private_key = private_numbers.private_key(
344
+ unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation
345
+ )
346
+ return private_key, data
347
+
348
+ def encode_public(
349
+ self, public_key: rsa.RSAPublicKey, f_pub: _FragList
350
+ ) -> None:
351
+ """Write RSA public key"""
352
+ pubn = public_key.public_numbers()
353
+ f_pub.put_mpint(pubn.e)
354
+ f_pub.put_mpint(pubn.n)
355
+
356
+ def encode_private(
357
+ self, private_key: rsa.RSAPrivateKey, f_priv: _FragList
358
+ ) -> None:
359
+ """Write RSA private key"""
360
+ private_numbers = private_key.private_numbers()
361
+ public_numbers = private_numbers.public_numbers
362
+
363
+ f_priv.put_mpint(public_numbers.n)
364
+ f_priv.put_mpint(public_numbers.e)
365
+
366
+ f_priv.put_mpint(private_numbers.d)
367
+ f_priv.put_mpint(private_numbers.iqmp)
368
+ f_priv.put_mpint(private_numbers.p)
369
+ f_priv.put_mpint(private_numbers.q)
370
+
371
+
372
+ class _SSHFormatDSA:
373
+ """Format for DSA keys.
374
+
375
+ Public:
376
+ mpint p, q, g, y
377
+ Private:
378
+ mpint p, q, g, y, x
379
+ """
380
+
381
+ def get_public(self, data: memoryview) -> tuple[tuple, memoryview]:
382
+ """DSA public fields"""
383
+ p, data = _get_mpint(data)
384
+ q, data = _get_mpint(data)
385
+ g, data = _get_mpint(data)
386
+ y, data = _get_mpint(data)
387
+ return (p, q, g, y), data
388
+
389
+ def load_public(
390
+ self, data: memoryview
391
+ ) -> tuple[dsa.DSAPublicKey, memoryview]:
392
+ """Make DSA public key from data."""
393
+ (p, q, g, y), data = self.get_public(data)
394
+ parameter_numbers = dsa.DSAParameterNumbers(p, q, g)
395
+ public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers)
396
+ self._validate(public_numbers)
397
+ public_key = public_numbers.public_key()
398
+ return public_key, data
399
+
400
+ def load_private(
401
+ self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool
402
+ ) -> tuple[dsa.DSAPrivateKey, memoryview]:
403
+ """Make DSA private key from data."""
404
+ (p, q, g, y), data = self.get_public(data)
405
+ x, data = _get_mpint(data)
406
+
407
+ if (p, q, g, y) != pubfields:
408
+ raise ValueError("Corrupt data: dsa field mismatch")
409
+ parameter_numbers = dsa.DSAParameterNumbers(p, q, g)
410
+ public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers)
411
+ self._validate(public_numbers)
412
+ private_numbers = dsa.DSAPrivateNumbers(x, public_numbers)
413
+ private_key = private_numbers.private_key()
414
+ return private_key, data
415
+
416
+ def encode_public(
417
+ self, public_key: dsa.DSAPublicKey, f_pub: _FragList
418
+ ) -> None:
419
+ """Write DSA public key"""
420
+ public_numbers = public_key.public_numbers()
421
+ parameter_numbers = public_numbers.parameter_numbers
422
+ self._validate(public_numbers)
423
+
424
+ f_pub.put_mpint(parameter_numbers.p)
425
+ f_pub.put_mpint(parameter_numbers.q)
426
+ f_pub.put_mpint(parameter_numbers.g)
427
+ f_pub.put_mpint(public_numbers.y)
428
+
429
+ def encode_private(
430
+ self, private_key: dsa.DSAPrivateKey, f_priv: _FragList
431
+ ) -> None:
432
+ """Write DSA private key"""
433
+ self.encode_public(private_key.public_key(), f_priv)
434
+ f_priv.put_mpint(private_key.private_numbers().x)
435
+
436
+ def _validate(self, public_numbers: dsa.DSAPublicNumbers) -> None:
437
+ parameter_numbers = public_numbers.parameter_numbers
438
+ if parameter_numbers.p.bit_length() != 1024:
439
+ raise ValueError("SSH supports only 1024 bit DSA keys")
440
+
441
+
442
+ class _SSHFormatECDSA:
443
+ """Format for ECDSA keys.
444
+
445
+ Public:
446
+ str curve
447
+ bytes point
448
+ Private:
449
+ str curve
450
+ bytes point
451
+ mpint secret
452
+ """
453
+
454
+ def __init__(self, ssh_curve_name: bytes, curve: ec.EllipticCurve):
455
+ self.ssh_curve_name = ssh_curve_name
456
+ self.curve = curve
457
+
458
+ def get_public(
459
+ self, data: memoryview
460
+ ) -> tuple[tuple[memoryview, memoryview], memoryview]:
461
+ """ECDSA public fields"""
462
+ curve, data = _get_sshstr(data)
463
+ point, data = _get_sshstr(data)
464
+ if curve != self.ssh_curve_name:
465
+ raise ValueError("Curve name mismatch")
466
+ if len(point) == 0:
467
+ raise ValueError("Invalid EC point: empty data")
468
+ if point[0] != 4:
469
+ raise NotImplementedError("Need uncompressed point")
470
+ return (curve, point), data
471
+
472
+ def load_public(
473
+ self, data: memoryview
474
+ ) -> tuple[ec.EllipticCurvePublicKey, memoryview]:
475
+ """Make ECDSA public key from data."""
476
+ (_, point), data = self.get_public(data)
477
+ public_key = ec.EllipticCurvePublicKey.from_encoded_point(
478
+ self.curve, point.tobytes()
479
+ )
480
+ return public_key, data
481
+
482
+ def load_private(
483
+ self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool
484
+ ) -> tuple[ec.EllipticCurvePrivateKey, memoryview]:
485
+ """Make ECDSA private key from data."""
486
+ (curve_name, point), data = self.get_public(data)
487
+ secret, data = _get_mpint(data)
488
+
489
+ if (curve_name, point) != pubfields:
490
+ raise ValueError("Corrupt data: ecdsa field mismatch")
491
+ private_key = ec.derive_private_key(secret, self.curve)
492
+ return private_key, data
493
+
494
+ def encode_public(
495
+ self, public_key: ec.EllipticCurvePublicKey, f_pub: _FragList
496
+ ) -> None:
497
+ """Write ECDSA public key"""
498
+ point = public_key.public_bytes(
499
+ Encoding.X962, PublicFormat.UncompressedPoint
500
+ )
501
+ f_pub.put_sshstr(self.ssh_curve_name)
502
+ f_pub.put_sshstr(point)
503
+
504
+ def encode_private(
505
+ self, private_key: ec.EllipticCurvePrivateKey, f_priv: _FragList
506
+ ) -> None:
507
+ """Write ECDSA private key"""
508
+ public_key = private_key.public_key()
509
+ private_numbers = private_key.private_numbers()
510
+
511
+ self.encode_public(public_key, f_priv)
512
+ f_priv.put_mpint(private_numbers.private_value)
513
+
514
+
515
+ class _SSHFormatEd25519:
516
+ """Format for Ed25519 keys.
517
+
518
+ Public:
519
+ bytes point
520
+ Private:
521
+ bytes point
522
+ bytes secret_and_point
523
+ """
524
+
525
+ def get_public(
526
+ self, data: memoryview
527
+ ) -> tuple[tuple[memoryview], memoryview]:
528
+ """Ed25519 public fields"""
529
+ point, data = _get_sshstr(data)
530
+ return (point,), data
531
+
532
+ def load_public(
533
+ self, data: memoryview
534
+ ) -> tuple[ed25519.Ed25519PublicKey, memoryview]:
535
+ """Make Ed25519 public key from data."""
536
+ (point,), data = self.get_public(data)
537
+ public_key = ed25519.Ed25519PublicKey.from_public_bytes(
538
+ point.tobytes()
539
+ )
540
+ return public_key, data
541
+
542
+ def load_private(
543
+ self, data: memoryview, pubfields, unsafe_skip_rsa_key_validation: bool
544
+ ) -> tuple[ed25519.Ed25519PrivateKey, memoryview]:
545
+ """Make Ed25519 private key from data."""
546
+ (point,), data = self.get_public(data)
547
+ keypair, data = _get_sshstr(data)
548
+
549
+ secret = keypair[:32]
550
+ point2 = keypair[32:]
551
+ if point != point2 or (point,) != pubfields:
552
+ raise ValueError("Corrupt data: ed25519 field mismatch")
553
+ private_key = ed25519.Ed25519PrivateKey.from_private_bytes(secret)
554
+ return private_key, data
555
+
556
+ def encode_public(
557
+ self, public_key: ed25519.Ed25519PublicKey, f_pub: _FragList
558
+ ) -> None:
559
+ """Write Ed25519 public key"""
560
+ raw_public_key = public_key.public_bytes(
561
+ Encoding.Raw, PublicFormat.Raw
562
+ )
563
+ f_pub.put_sshstr(raw_public_key)
564
+
565
+ def encode_private(
566
+ self, private_key: ed25519.Ed25519PrivateKey, f_priv: _FragList
567
+ ) -> None:
568
+ """Write Ed25519 private key"""
569
+ public_key = private_key.public_key()
570
+ raw_private_key = private_key.private_bytes(
571
+ Encoding.Raw, PrivateFormat.Raw, NoEncryption()
572
+ )
573
+ raw_public_key = public_key.public_bytes(
574
+ Encoding.Raw, PublicFormat.Raw
575
+ )
576
+ f_keypair = _FragList([raw_private_key, raw_public_key])
577
+
578
+ self.encode_public(public_key, f_priv)
579
+ f_priv.put_sshstr(f_keypair)
580
+
581
+
582
+ def load_application(data) -> tuple[memoryview, memoryview]:
583
+ """
584
+ U2F application strings
585
+ """
586
+ application, data = _get_sshstr(data)
587
+ if not application.tobytes().startswith(b"ssh:"):
588
+ raise ValueError(
589
+ "U2F application string does not start with b'ssh:' "
590
+ f"({application})"
591
+ )
592
+ return application, data
593
+
594
+
595
+ class _SSHFormatSKEd25519:
596
+ """
597
+ The format of a sk-ssh-ed25519@openssh.com public key is:
598
+
599
+ string "sk-ssh-ed25519@openssh.com"
600
+ string public key
601
+ string application (user-specified, but typically "ssh:")
602
+ """
603
+
604
+ def load_public(
605
+ self, data: memoryview
606
+ ) -> tuple[ed25519.Ed25519PublicKey, memoryview]:
607
+ """Make Ed25519 public key from data."""
608
+ public_key, data = _lookup_kformat(_SSH_ED25519).load_public(data)
609
+ _, data = load_application(data)
610
+ return public_key, data
611
+
612
+ def get_public(self, data: memoryview) -> typing.NoReturn:
613
+ # Confusingly `get_public` is an entry point used by private key
614
+ # loading.
615
+ raise UnsupportedAlgorithm(
616
+ "sk-ssh-ed25519 private keys cannot be loaded"
617
+ )
618
+
619
+
620
+ class _SSHFormatSKECDSA:
621
+ """
622
+ The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is:
623
+
624
+ string "sk-ecdsa-sha2-nistp256@openssh.com"
625
+ string curve name
626
+ ec_point Q
627
+ string application (user-specified, but typically "ssh:")
628
+ """
629
+
630
+ def load_public(
631
+ self, data: memoryview
632
+ ) -> tuple[ec.EllipticCurvePublicKey, memoryview]:
633
+ """Make ECDSA public key from data."""
634
+ public_key, data = _lookup_kformat(_ECDSA_NISTP256).load_public(data)
635
+ _, data = load_application(data)
636
+ return public_key, data
637
+
638
+ def get_public(self, data: memoryview) -> typing.NoReturn:
639
+ # Confusingly `get_public` is an entry point used by private key
640
+ # loading.
641
+ raise UnsupportedAlgorithm(
642
+ "sk-ecdsa-sha2-nistp256 private keys cannot be loaded"
643
+ )
644
+
645
+
646
+ _KEY_FORMATS = {
647
+ _SSH_RSA: _SSHFormatRSA(),
648
+ _SSH_DSA: _SSHFormatDSA(),
649
+ _SSH_ED25519: _SSHFormatEd25519(),
650
+ _ECDSA_NISTP256: _SSHFormatECDSA(b"nistp256", ec.SECP256R1()),
651
+ _ECDSA_NISTP384: _SSHFormatECDSA(b"nistp384", ec.SECP384R1()),
652
+ _ECDSA_NISTP521: _SSHFormatECDSA(b"nistp521", ec.SECP521R1()),
653
+ _SK_SSH_ED25519: _SSHFormatSKEd25519(),
654
+ _SK_SSH_ECDSA_NISTP256: _SSHFormatSKECDSA(),
655
+ }
656
+
657
+
658
+ def _lookup_kformat(key_type: utils.Buffer):
659
+ """Return valid format or throw error"""
660
+ if not isinstance(key_type, bytes):
661
+ key_type = memoryview(key_type).tobytes()
662
+ if key_type in _KEY_FORMATS:
663
+ return _KEY_FORMATS[key_type]
664
+ raise UnsupportedAlgorithm(f"Unsupported key type: {key_type!r}")
665
+
666
+
667
+ SSHPrivateKeyTypes = typing.Union[
668
+ ec.EllipticCurvePrivateKey,
669
+ rsa.RSAPrivateKey,
670
+ dsa.DSAPrivateKey,
671
+ ed25519.Ed25519PrivateKey,
672
+ ]
673
+
674
+
675
+ def load_ssh_private_key(
676
+ data: utils.Buffer,
677
+ password: bytes | None,
678
+ backend: typing.Any = None,
679
+ *,
680
+ unsafe_skip_rsa_key_validation: bool = False,
681
+ ) -> SSHPrivateKeyTypes:
682
+ """Load private key from OpenSSH custom encoding."""
683
+ utils._check_byteslike("data", data)
684
+ if password is not None:
685
+ utils._check_bytes("password", password)
686
+
687
+ m = _PEM_RC.search(data)
688
+ if not m:
689
+ raise ValueError("Not OpenSSH private key format")
690
+ p1 = m.start(1)
691
+ p2 = m.end(1)
692
+ data = binascii.a2b_base64(memoryview(data)[p1:p2])
693
+ if not data.startswith(_SK_MAGIC):
694
+ raise ValueError("Not OpenSSH private key format")
695
+ data = memoryview(data)[len(_SK_MAGIC) :]
696
+
697
+ # parse header
698
+ ciphername, data = _get_sshstr(data)
699
+ kdfname, data = _get_sshstr(data)
700
+ kdfoptions, data = _get_sshstr(data)
701
+ nkeys, data = _get_u32(data)
702
+ if nkeys != 1:
703
+ raise ValueError("Only one key supported")
704
+
705
+ # load public key data
706
+ pubdata, data = _get_sshstr(data)
707
+ pub_key_type, pubdata = _get_sshstr(pubdata)
708
+ kformat = _lookup_kformat(pub_key_type)
709
+ pubfields, pubdata = kformat.get_public(pubdata)
710
+ _check_empty(pubdata)
711
+
712
+ if ciphername != _NONE or kdfname != _NONE:
713
+ ciphername_bytes = ciphername.tobytes()
714
+ if ciphername_bytes not in _SSH_CIPHERS:
715
+ raise UnsupportedAlgorithm(
716
+ f"Unsupported cipher: {ciphername_bytes!r}"
717
+ )
718
+ if kdfname != _BCRYPT:
719
+ raise UnsupportedAlgorithm(f"Unsupported KDF: {kdfname!r}")
720
+ blklen = _SSH_CIPHERS[ciphername_bytes].block_len
721
+ tag_len = _SSH_CIPHERS[ciphername_bytes].tag_len
722
+ # load secret data
723
+ edata, data = _get_sshstr(data)
724
+ # see https://bugzilla.mindrot.org/show_bug.cgi?id=3553 for
725
+ # information about how OpenSSH handles AEAD tags
726
+ if _SSH_CIPHERS[ciphername_bytes].is_aead:
727
+ tag = bytes(data)
728
+ if len(tag) != tag_len:
729
+ raise ValueError("Corrupt data: invalid tag length for cipher")
730
+ else:
731
+ _check_empty(data)
732
+ _check_block_size(edata, blklen)
733
+ salt, kbuf = _get_sshstr(kdfoptions)
734
+ rounds, kbuf = _get_u32(kbuf)
735
+ _check_empty(kbuf)
736
+ ciph = _init_cipher(ciphername_bytes, password, salt.tobytes(), rounds)
737
+ dec = ciph.decryptor()
738
+ edata = memoryview(dec.update(edata))
739
+ if _SSH_CIPHERS[ciphername_bytes].is_aead:
740
+ assert isinstance(dec, AEADDecryptionContext)
741
+ _check_empty(dec.finalize_with_tag(tag))
742
+ else:
743
+ # _check_block_size requires data to be a full block so there
744
+ # should be no output from finalize
745
+ _check_empty(dec.finalize())
746
+ else:
747
+ if password:
748
+ raise TypeError(
749
+ "Password was given but private key is not encrypted."
750
+ )
751
+ # load secret data
752
+ edata, data = _get_sshstr(data)
753
+ _check_empty(data)
754
+ blklen = 8
755
+ _check_block_size(edata, blklen)
756
+ ck1, edata = _get_u32(edata)
757
+ ck2, edata = _get_u32(edata)
758
+ if ck1 != ck2:
759
+ raise ValueError("Corrupt data: broken checksum")
760
+
761
+ # load per-key struct
762
+ key_type, edata = _get_sshstr(edata)
763
+ if key_type != pub_key_type:
764
+ raise ValueError("Corrupt data: key type mismatch")
765
+ private_key, edata = kformat.load_private(
766
+ edata,
767
+ pubfields,
768
+ unsafe_skip_rsa_key_validation=unsafe_skip_rsa_key_validation,
769
+ )
770
+ # We don't use the comment
771
+ _, edata = _get_sshstr(edata)
772
+
773
+ # yes, SSH does padding check *after* all other parsing is done.
774
+ # need to follow as it writes zero-byte padding too.
775
+ if edata != _PADDING[: len(edata)]:
776
+ raise ValueError("Corrupt data: invalid padding")
777
+
778
+ if isinstance(private_key, dsa.DSAPrivateKey):
779
+ warnings.warn(
780
+ "SSH DSA keys are deprecated and will be removed in a future "
781
+ "release.",
782
+ utils.DeprecatedIn40,
783
+ stacklevel=2,
784
+ )
785
+
786
+ return private_key
787
+
788
+
789
+ def _serialize_ssh_private_key(
790
+ private_key: SSHPrivateKeyTypes,
791
+ password: bytes,
792
+ encryption_algorithm: KeySerializationEncryption,
793
+ ) -> bytes:
794
+ """Serialize private key with OpenSSH custom encoding."""
795
+ utils._check_bytes("password", password)
796
+ if isinstance(private_key, dsa.DSAPrivateKey):
797
+ warnings.warn(
798
+ "SSH DSA key support is deprecated and will be "
799
+ "removed in a future release",
800
+ utils.DeprecatedIn40,
801
+ stacklevel=4,
802
+ )
803
+
804
+ key_type = _get_ssh_key_type(private_key)
805
+ kformat = _lookup_kformat(key_type)
806
+
807
+ # setup parameters
808
+ f_kdfoptions = _FragList()
809
+ if password:
810
+ ciphername = _DEFAULT_CIPHER
811
+ blklen = _SSH_CIPHERS[ciphername].block_len
812
+ kdfname = _BCRYPT
813
+ rounds = _DEFAULT_ROUNDS
814
+ if (
815
+ isinstance(encryption_algorithm, _KeySerializationEncryption)
816
+ and encryption_algorithm._kdf_rounds is not None
817
+ ):
818
+ rounds = encryption_algorithm._kdf_rounds
819
+ salt = os.urandom(16)
820
+ f_kdfoptions.put_sshstr(salt)
821
+ f_kdfoptions.put_u32(rounds)
822
+ ciph = _init_cipher(ciphername, password, salt, rounds)
823
+ else:
824
+ ciphername = kdfname = _NONE
825
+ blklen = 8
826
+ ciph = None
827
+ nkeys = 1
828
+ checkval = os.urandom(4)
829
+ comment = b""
830
+
831
+ # encode public and private parts together
832
+ f_public_key = _FragList()
833
+ f_public_key.put_sshstr(key_type)
834
+ kformat.encode_public(private_key.public_key(), f_public_key)
835
+
836
+ f_secrets = _FragList([checkval, checkval])
837
+ f_secrets.put_sshstr(key_type)
838
+ kformat.encode_private(private_key, f_secrets)
839
+ f_secrets.put_sshstr(comment)
840
+ f_secrets.put_raw(_PADDING[: blklen - (f_secrets.size() % blklen)])
841
+
842
+ # top-level structure
843
+ f_main = _FragList()
844
+ f_main.put_raw(_SK_MAGIC)
845
+ f_main.put_sshstr(ciphername)
846
+ f_main.put_sshstr(kdfname)
847
+ f_main.put_sshstr(f_kdfoptions)
848
+ f_main.put_u32(nkeys)
849
+ f_main.put_sshstr(f_public_key)
850
+ f_main.put_sshstr(f_secrets)
851
+
852
+ # copy result info bytearray
853
+ slen = f_secrets.size()
854
+ mlen = f_main.size()
855
+ buf = memoryview(bytearray(mlen + blklen))
856
+ f_main.render(buf)
857
+ ofs = mlen - slen
858
+
859
+ # encrypt in-place
860
+ if ciph is not None:
861
+ ciph.encryptor().update_into(buf[ofs:mlen], buf[ofs:])
862
+
863
+ return bytes(buf[:mlen])
864
+
865
+
866
+ SSHPublicKeyTypes = typing.Union[
867
+ ec.EllipticCurvePublicKey,
868
+ rsa.RSAPublicKey,
869
+ dsa.DSAPublicKey,
870
+ ed25519.Ed25519PublicKey,
871
+ ]
872
+
873
+ SSHCertPublicKeyTypes = typing.Union[
874
+ ec.EllipticCurvePublicKey,
875
+ rsa.RSAPublicKey,
876
+ ed25519.Ed25519PublicKey,
877
+ ]
878
+
879
+
880
+ class SSHCertificateType(enum.Enum):
881
+ USER = 1
882
+ HOST = 2
883
+
884
+
885
+ class SSHCertificate:
886
+ def __init__(
887
+ self,
888
+ _nonce: memoryview,
889
+ _public_key: SSHPublicKeyTypes,
890
+ _serial: int,
891
+ _cctype: int,
892
+ _key_id: memoryview,
893
+ _valid_principals: list[bytes],
894
+ _valid_after: int,
895
+ _valid_before: int,
896
+ _critical_options: dict[bytes, bytes],
897
+ _extensions: dict[bytes, bytes],
898
+ _sig_type: memoryview,
899
+ _sig_key: memoryview,
900
+ _inner_sig_type: memoryview,
901
+ _signature: memoryview,
902
+ _tbs_cert_body: memoryview,
903
+ _cert_key_type: bytes,
904
+ _cert_body: memoryview,
905
+ ):
906
+ self._nonce = _nonce
907
+ self._public_key = _public_key
908
+ self._serial = _serial
909
+ try:
910
+ self._type = SSHCertificateType(_cctype)
911
+ except ValueError:
912
+ raise ValueError("Invalid certificate type")
913
+ self._key_id = _key_id
914
+ self._valid_principals = _valid_principals
915
+ self._valid_after = _valid_after
916
+ self._valid_before = _valid_before
917
+ self._critical_options = _critical_options
918
+ self._extensions = _extensions
919
+ self._sig_type = _sig_type
920
+ self._sig_key = _sig_key
921
+ self._inner_sig_type = _inner_sig_type
922
+ self._signature = _signature
923
+ self._cert_key_type = _cert_key_type
924
+ self._cert_body = _cert_body
925
+ self._tbs_cert_body = _tbs_cert_body
926
+
927
+ @property
928
+ def nonce(self) -> bytes:
929
+ return bytes(self._nonce)
930
+
931
+ def public_key(self) -> SSHCertPublicKeyTypes:
932
+ # make mypy happy until we remove DSA support entirely and
933
+ # the underlying union won't have a disallowed type
934
+ return typing.cast(SSHCertPublicKeyTypes, self._public_key)
935
+
936
+ @property
937
+ def serial(self) -> int:
938
+ return self._serial
939
+
940
+ @property
941
+ def type(self) -> SSHCertificateType:
942
+ return self._type
943
+
944
+ @property
945
+ def key_id(self) -> bytes:
946
+ return bytes(self._key_id)
947
+
948
+ @property
949
+ def valid_principals(self) -> list[bytes]:
950
+ return self._valid_principals
951
+
952
+ @property
953
+ def valid_before(self) -> int:
954
+ return self._valid_before
955
+
956
+ @property
957
+ def valid_after(self) -> int:
958
+ return self._valid_after
959
+
960
+ @property
961
+ def critical_options(self) -> dict[bytes, bytes]:
962
+ return self._critical_options
963
+
964
+ @property
965
+ def extensions(self) -> dict[bytes, bytes]:
966
+ return self._extensions
967
+
968
+ def signature_key(self) -> SSHCertPublicKeyTypes:
969
+ sigformat = _lookup_kformat(self._sig_type)
970
+ signature_key, sigkey_rest = sigformat.load_public(self._sig_key)
971
+ _check_empty(sigkey_rest)
972
+ return signature_key
973
+
974
+ def public_bytes(self) -> bytes:
975
+ return (
976
+ bytes(self._cert_key_type)
977
+ + b" "
978
+ + binascii.b2a_base64(bytes(self._cert_body), newline=False)
979
+ )
980
+
981
+ def verify_cert_signature(self) -> None:
982
+ signature_key = self.signature_key()
983
+ if isinstance(signature_key, ed25519.Ed25519PublicKey):
984
+ signature_key.verify(
985
+ bytes(self._signature), bytes(self._tbs_cert_body)
986
+ )
987
+ elif isinstance(signature_key, ec.EllipticCurvePublicKey):
988
+ # The signature is encoded as a pair of big-endian integers
989
+ r, data = _get_mpint(self._signature)
990
+ s, data = _get_mpint(data)
991
+ _check_empty(data)
992
+ computed_sig = asym_utils.encode_dss_signature(r, s)
993
+ hash_alg = _get_ec_hash_alg(signature_key.curve)
994
+ signature_key.verify(
995
+ computed_sig, bytes(self._tbs_cert_body), ec.ECDSA(hash_alg)
996
+ )
997
+ else:
998
+ assert isinstance(signature_key, rsa.RSAPublicKey)
999
+ if self._inner_sig_type == _SSH_RSA:
1000
+ hash_alg = hashes.SHA1()
1001
+ elif self._inner_sig_type == _SSH_RSA_SHA256:
1002
+ hash_alg = hashes.SHA256()
1003
+ else:
1004
+ assert self._inner_sig_type == _SSH_RSA_SHA512
1005
+ hash_alg = hashes.SHA512()
1006
+ signature_key.verify(
1007
+ bytes(self._signature),
1008
+ bytes(self._tbs_cert_body),
1009
+ padding.PKCS1v15(),
1010
+ hash_alg,
1011
+ )
1012
+
1013
+
1014
+ def _get_ec_hash_alg(curve: ec.EllipticCurve) -> hashes.HashAlgorithm:
1015
+ if isinstance(curve, ec.SECP256R1):
1016
+ return hashes.SHA256()
1017
+ elif isinstance(curve, ec.SECP384R1):
1018
+ return hashes.SHA384()
1019
+ else:
1020
+ assert isinstance(curve, ec.SECP521R1)
1021
+ return hashes.SHA512()
1022
+
1023
+
1024
+ def _load_ssh_public_identity(
1025
+ data: utils.Buffer,
1026
+ _legacy_dsa_allowed=False,
1027
+ ) -> SSHCertificate | SSHPublicKeyTypes:
1028
+ utils._check_byteslike("data", data)
1029
+
1030
+ m = _SSH_PUBKEY_RC.match(data)
1031
+ if not m:
1032
+ raise ValueError("Invalid line format")
1033
+ key_type = orig_key_type = m.group(1)
1034
+ key_body = m.group(2)
1035
+ with_cert = False
1036
+ if key_type.endswith(_CERT_SUFFIX):
1037
+ with_cert = True
1038
+ key_type = key_type[: -len(_CERT_SUFFIX)]
1039
+ if key_type == _SSH_DSA and not _legacy_dsa_allowed:
1040
+ raise UnsupportedAlgorithm(
1041
+ "DSA keys aren't supported in SSH certificates"
1042
+ )
1043
+ kformat = _lookup_kformat(key_type)
1044
+
1045
+ try:
1046
+ rest = memoryview(binascii.a2b_base64(key_body))
1047
+ except (TypeError, binascii.Error):
1048
+ raise ValueError("Invalid format")
1049
+
1050
+ if with_cert:
1051
+ cert_body = rest
1052
+ inner_key_type, rest = _get_sshstr(rest)
1053
+ if inner_key_type != orig_key_type:
1054
+ raise ValueError("Invalid key format")
1055
+ if with_cert:
1056
+ nonce, rest = _get_sshstr(rest)
1057
+ public_key, rest = kformat.load_public(rest)
1058
+ if with_cert:
1059
+ serial, rest = _get_u64(rest)
1060
+ cctype, rest = _get_u32(rest)
1061
+ key_id, rest = _get_sshstr(rest)
1062
+ principals, rest = _get_sshstr(rest)
1063
+ valid_principals = []
1064
+ while principals:
1065
+ principal, principals = _get_sshstr(principals)
1066
+ valid_principals.append(bytes(principal))
1067
+ valid_after, rest = _get_u64(rest)
1068
+ valid_before, rest = _get_u64(rest)
1069
+ crit_options, rest = _get_sshstr(rest)
1070
+ critical_options = _parse_exts_opts(crit_options)
1071
+ exts, rest = _get_sshstr(rest)
1072
+ extensions = _parse_exts_opts(exts)
1073
+ # Get the reserved field, which is unused.
1074
+ _, rest = _get_sshstr(rest)
1075
+ sig_key_raw, rest = _get_sshstr(rest)
1076
+ sig_type, sig_key = _get_sshstr(sig_key_raw)
1077
+ if sig_type == _SSH_DSA and not _legacy_dsa_allowed:
1078
+ raise UnsupportedAlgorithm(
1079
+ "DSA signatures aren't supported in SSH certificates"
1080
+ )
1081
+ # Get the entire cert body and subtract the signature
1082
+ tbs_cert_body = cert_body[: -len(rest)]
1083
+ signature_raw, rest = _get_sshstr(rest)
1084
+ _check_empty(rest)
1085
+ inner_sig_type, sig_rest = _get_sshstr(signature_raw)
1086
+ # RSA certs can have multiple algorithm types
1087
+ if (
1088
+ sig_type == _SSH_RSA
1089
+ and inner_sig_type
1090
+ not in [_SSH_RSA_SHA256, _SSH_RSA_SHA512, _SSH_RSA]
1091
+ ) or (sig_type != _SSH_RSA and inner_sig_type != sig_type):
1092
+ raise ValueError("Signature key type does not match")
1093
+ signature, sig_rest = _get_sshstr(sig_rest)
1094
+ _check_empty(sig_rest)
1095
+ return SSHCertificate(
1096
+ nonce,
1097
+ public_key,
1098
+ serial,
1099
+ cctype,
1100
+ key_id,
1101
+ valid_principals,
1102
+ valid_after,
1103
+ valid_before,
1104
+ critical_options,
1105
+ extensions,
1106
+ sig_type,
1107
+ sig_key,
1108
+ inner_sig_type,
1109
+ signature,
1110
+ tbs_cert_body,
1111
+ orig_key_type,
1112
+ cert_body,
1113
+ )
1114
+ else:
1115
+ _check_empty(rest)
1116
+ return public_key
1117
+
1118
+
1119
+ def load_ssh_public_identity(
1120
+ data: utils.Buffer,
1121
+ ) -> SSHCertificate | SSHPublicKeyTypes:
1122
+ return _load_ssh_public_identity(data)
1123
+
1124
+
1125
+ def _parse_exts_opts(exts_opts: memoryview) -> dict[bytes, bytes]:
1126
+ result: dict[bytes, bytes] = {}
1127
+ last_name = None
1128
+ while exts_opts:
1129
+ name, exts_opts = _get_sshstr(exts_opts)
1130
+ bname: bytes = bytes(name)
1131
+ if bname in result:
1132
+ raise ValueError("Duplicate name")
1133
+ if last_name is not None and bname < last_name:
1134
+ raise ValueError("Fields not lexically sorted")
1135
+ value, exts_opts = _get_sshstr(exts_opts)
1136
+ if len(value) > 0:
1137
+ value, extra = _get_sshstr(value)
1138
+ if len(extra) > 0:
1139
+ raise ValueError("Unexpected extra data after value")
1140
+ result[bname] = bytes(value)
1141
+ last_name = bname
1142
+ return result
1143
+
1144
+
1145
+ def ssh_key_fingerprint(
1146
+ key: SSHPublicKeyTypes,
1147
+ hash_algorithm: hashes.MD5 | hashes.SHA1 | hashes.SHA256,
1148
+ ) -> bytes:
1149
+ if not isinstance(
1150
+ hash_algorithm,
1151
+ (hashes.MD5, hashes.SHA1, hashes.SHA256),
1152
+ ):
1153
+ raise TypeError("hash_algorithm must be either MD5, SHA1, or SHA256")
1154
+
1155
+ key_type = _get_ssh_key_type(key)
1156
+ kformat = _lookup_kformat(key_type)
1157
+
1158
+ f_pub = _FragList()
1159
+ f_pub.put_sshstr(key_type)
1160
+ kformat.encode_public(key, f_pub)
1161
+
1162
+ ssh_binary_data = f_pub.tobytes()
1163
+
1164
+ # Hash the binary data
1165
+ hash_obj = hashes.Hash(hash_algorithm)
1166
+ hash_obj.update(ssh_binary_data)
1167
+ return hash_obj.finalize()
1168
+
1169
+
1170
+ def load_ssh_public_key(
1171
+ data: utils.Buffer, backend: typing.Any = None
1172
+ ) -> SSHPublicKeyTypes:
1173
+ cert_or_key = _load_ssh_public_identity(data, _legacy_dsa_allowed=True)
1174
+ public_key: SSHPublicKeyTypes
1175
+ if isinstance(cert_or_key, SSHCertificate):
1176
+ public_key = cert_or_key.public_key()
1177
+ else:
1178
+ public_key = cert_or_key
1179
+
1180
+ if isinstance(public_key, dsa.DSAPublicKey):
1181
+ warnings.warn(
1182
+ "SSH DSA keys are deprecated and will be removed in a future "
1183
+ "release.",
1184
+ utils.DeprecatedIn40,
1185
+ stacklevel=2,
1186
+ )
1187
+ return public_key
1188
+
1189
+
1190
+ def serialize_ssh_public_key(public_key: SSHPublicKeyTypes) -> bytes:
1191
+ """One-line public key format for OpenSSH"""
1192
+ if isinstance(public_key, dsa.DSAPublicKey):
1193
+ warnings.warn(
1194
+ "SSH DSA key support is deprecated and will be "
1195
+ "removed in a future release",
1196
+ utils.DeprecatedIn40,
1197
+ stacklevel=4,
1198
+ )
1199
+ key_type = _get_ssh_key_type(public_key)
1200
+ kformat = _lookup_kformat(key_type)
1201
+
1202
+ f_pub = _FragList()
1203
+ f_pub.put_sshstr(key_type)
1204
+ kformat.encode_public(public_key, f_pub)
1205
+
1206
+ pub = binascii.b2a_base64(f_pub.tobytes()).strip()
1207
+ return b"".join([key_type, b" ", pub])
1208
+
1209
+
1210
+ SSHCertPrivateKeyTypes = typing.Union[
1211
+ ec.EllipticCurvePrivateKey,
1212
+ rsa.RSAPrivateKey,
1213
+ ed25519.Ed25519PrivateKey,
1214
+ ]
1215
+
1216
+
1217
+ # This is an undocumented limit enforced in the openssh codebase for sshd and
1218
+ # ssh-keygen, but it is undefined in the ssh certificates spec.
1219
+ _SSHKEY_CERT_MAX_PRINCIPALS = 256
1220
+
1221
+
1222
+ class SSHCertificateBuilder:
1223
+ def __init__(
1224
+ self,
1225
+ _public_key: SSHCertPublicKeyTypes | None = None,
1226
+ _serial: int | None = None,
1227
+ _type: SSHCertificateType | None = None,
1228
+ _key_id: bytes | None = None,
1229
+ _valid_principals: list[bytes] = [],
1230
+ _valid_for_all_principals: bool = False,
1231
+ _valid_before: int | None = None,
1232
+ _valid_after: int | None = None,
1233
+ _critical_options: list[tuple[bytes, bytes]] = [],
1234
+ _extensions: list[tuple[bytes, bytes]] = [],
1235
+ ):
1236
+ self._public_key = _public_key
1237
+ self._serial = _serial
1238
+ self._type = _type
1239
+ self._key_id = _key_id
1240
+ self._valid_principals = _valid_principals
1241
+ self._valid_for_all_principals = _valid_for_all_principals
1242
+ self._valid_before = _valid_before
1243
+ self._valid_after = _valid_after
1244
+ self._critical_options = _critical_options
1245
+ self._extensions = _extensions
1246
+
1247
+ def public_key(
1248
+ self, public_key: SSHCertPublicKeyTypes
1249
+ ) -> SSHCertificateBuilder:
1250
+ if not isinstance(
1251
+ public_key,
1252
+ (
1253
+ ec.EllipticCurvePublicKey,
1254
+ rsa.RSAPublicKey,
1255
+ ed25519.Ed25519PublicKey,
1256
+ ),
1257
+ ):
1258
+ raise TypeError("Unsupported key type")
1259
+ if self._public_key is not None:
1260
+ raise ValueError("public_key already set")
1261
+
1262
+ return SSHCertificateBuilder(
1263
+ _public_key=public_key,
1264
+ _serial=self._serial,
1265
+ _type=self._type,
1266
+ _key_id=self._key_id,
1267
+ _valid_principals=self._valid_principals,
1268
+ _valid_for_all_principals=self._valid_for_all_principals,
1269
+ _valid_before=self._valid_before,
1270
+ _valid_after=self._valid_after,
1271
+ _critical_options=self._critical_options,
1272
+ _extensions=self._extensions,
1273
+ )
1274
+
1275
+ def serial(self, serial: int) -> SSHCertificateBuilder:
1276
+ if not isinstance(serial, int):
1277
+ raise TypeError("serial must be an integer")
1278
+ if not 0 <= serial < 2**64:
1279
+ raise ValueError("serial must be between 0 and 2**64")
1280
+ if self._serial is not None:
1281
+ raise ValueError("serial already set")
1282
+
1283
+ return SSHCertificateBuilder(
1284
+ _public_key=self._public_key,
1285
+ _serial=serial,
1286
+ _type=self._type,
1287
+ _key_id=self._key_id,
1288
+ _valid_principals=self._valid_principals,
1289
+ _valid_for_all_principals=self._valid_for_all_principals,
1290
+ _valid_before=self._valid_before,
1291
+ _valid_after=self._valid_after,
1292
+ _critical_options=self._critical_options,
1293
+ _extensions=self._extensions,
1294
+ )
1295
+
1296
+ def type(self, type: SSHCertificateType) -> SSHCertificateBuilder:
1297
+ if not isinstance(type, SSHCertificateType):
1298
+ raise TypeError("type must be an SSHCertificateType")
1299
+ if self._type is not None:
1300
+ raise ValueError("type already set")
1301
+
1302
+ return SSHCertificateBuilder(
1303
+ _public_key=self._public_key,
1304
+ _serial=self._serial,
1305
+ _type=type,
1306
+ _key_id=self._key_id,
1307
+ _valid_principals=self._valid_principals,
1308
+ _valid_for_all_principals=self._valid_for_all_principals,
1309
+ _valid_before=self._valid_before,
1310
+ _valid_after=self._valid_after,
1311
+ _critical_options=self._critical_options,
1312
+ _extensions=self._extensions,
1313
+ )
1314
+
1315
+ def key_id(self, key_id: bytes) -> SSHCertificateBuilder:
1316
+ if not isinstance(key_id, bytes):
1317
+ raise TypeError("key_id must be bytes")
1318
+ if self._key_id is not None:
1319
+ raise ValueError("key_id already set")
1320
+
1321
+ return SSHCertificateBuilder(
1322
+ _public_key=self._public_key,
1323
+ _serial=self._serial,
1324
+ _type=self._type,
1325
+ _key_id=key_id,
1326
+ _valid_principals=self._valid_principals,
1327
+ _valid_for_all_principals=self._valid_for_all_principals,
1328
+ _valid_before=self._valid_before,
1329
+ _valid_after=self._valid_after,
1330
+ _critical_options=self._critical_options,
1331
+ _extensions=self._extensions,
1332
+ )
1333
+
1334
+ def valid_principals(
1335
+ self, valid_principals: list[bytes]
1336
+ ) -> SSHCertificateBuilder:
1337
+ if self._valid_for_all_principals:
1338
+ raise ValueError(
1339
+ "Principals can't be set because the cert is valid "
1340
+ "for all principals"
1341
+ )
1342
+ if (
1343
+ not all(isinstance(x, bytes) for x in valid_principals)
1344
+ or not valid_principals
1345
+ ):
1346
+ raise TypeError(
1347
+ "principals must be a list of bytes and can't be empty"
1348
+ )
1349
+ if self._valid_principals:
1350
+ raise ValueError("valid_principals already set")
1351
+
1352
+ if len(valid_principals) > _SSHKEY_CERT_MAX_PRINCIPALS:
1353
+ raise ValueError(
1354
+ "Reached or exceeded the maximum number of valid_principals"
1355
+ )
1356
+
1357
+ return SSHCertificateBuilder(
1358
+ _public_key=self._public_key,
1359
+ _serial=self._serial,
1360
+ _type=self._type,
1361
+ _key_id=self._key_id,
1362
+ _valid_principals=valid_principals,
1363
+ _valid_for_all_principals=self._valid_for_all_principals,
1364
+ _valid_before=self._valid_before,
1365
+ _valid_after=self._valid_after,
1366
+ _critical_options=self._critical_options,
1367
+ _extensions=self._extensions,
1368
+ )
1369
+
1370
+ def valid_for_all_principals(self):
1371
+ if self._valid_principals:
1372
+ raise ValueError(
1373
+ "valid_principals already set, can't set "
1374
+ "valid_for_all_principals"
1375
+ )
1376
+ if self._valid_for_all_principals:
1377
+ raise ValueError("valid_for_all_principals already set")
1378
+
1379
+ return SSHCertificateBuilder(
1380
+ _public_key=self._public_key,
1381
+ _serial=self._serial,
1382
+ _type=self._type,
1383
+ _key_id=self._key_id,
1384
+ _valid_principals=self._valid_principals,
1385
+ _valid_for_all_principals=True,
1386
+ _valid_before=self._valid_before,
1387
+ _valid_after=self._valid_after,
1388
+ _critical_options=self._critical_options,
1389
+ _extensions=self._extensions,
1390
+ )
1391
+
1392
+ def valid_before(self, valid_before: int | float) -> SSHCertificateBuilder:
1393
+ if not isinstance(valid_before, (int, float)):
1394
+ raise TypeError("valid_before must be an int or float")
1395
+ valid_before = int(valid_before)
1396
+ if valid_before < 0 or valid_before >= 2**64:
1397
+ raise ValueError("valid_before must [0, 2**64)")
1398
+ if self._valid_before is not None:
1399
+ raise ValueError("valid_before already set")
1400
+
1401
+ return SSHCertificateBuilder(
1402
+ _public_key=self._public_key,
1403
+ _serial=self._serial,
1404
+ _type=self._type,
1405
+ _key_id=self._key_id,
1406
+ _valid_principals=self._valid_principals,
1407
+ _valid_for_all_principals=self._valid_for_all_principals,
1408
+ _valid_before=valid_before,
1409
+ _valid_after=self._valid_after,
1410
+ _critical_options=self._critical_options,
1411
+ _extensions=self._extensions,
1412
+ )
1413
+
1414
+ def valid_after(self, valid_after: int | float) -> SSHCertificateBuilder:
1415
+ if not isinstance(valid_after, (int, float)):
1416
+ raise TypeError("valid_after must be an int or float")
1417
+ valid_after = int(valid_after)
1418
+ if valid_after < 0 or valid_after >= 2**64:
1419
+ raise ValueError("valid_after must [0, 2**64)")
1420
+ if self._valid_after is not None:
1421
+ raise ValueError("valid_after already set")
1422
+
1423
+ return SSHCertificateBuilder(
1424
+ _public_key=self._public_key,
1425
+ _serial=self._serial,
1426
+ _type=self._type,
1427
+ _key_id=self._key_id,
1428
+ _valid_principals=self._valid_principals,
1429
+ _valid_for_all_principals=self._valid_for_all_principals,
1430
+ _valid_before=self._valid_before,
1431
+ _valid_after=valid_after,
1432
+ _critical_options=self._critical_options,
1433
+ _extensions=self._extensions,
1434
+ )
1435
+
1436
+ def add_critical_option(
1437
+ self, name: bytes, value: bytes
1438
+ ) -> SSHCertificateBuilder:
1439
+ if not isinstance(name, bytes) or not isinstance(value, bytes):
1440
+ raise TypeError("name and value must be bytes")
1441
+ # This is O(n**2)
1442
+ if name in [name for name, _ in self._critical_options]:
1443
+ raise ValueError("Duplicate critical option name")
1444
+
1445
+ return SSHCertificateBuilder(
1446
+ _public_key=self._public_key,
1447
+ _serial=self._serial,
1448
+ _type=self._type,
1449
+ _key_id=self._key_id,
1450
+ _valid_principals=self._valid_principals,
1451
+ _valid_for_all_principals=self._valid_for_all_principals,
1452
+ _valid_before=self._valid_before,
1453
+ _valid_after=self._valid_after,
1454
+ _critical_options=[*self._critical_options, (name, value)],
1455
+ _extensions=self._extensions,
1456
+ )
1457
+
1458
+ def add_extension(
1459
+ self, name: bytes, value: bytes
1460
+ ) -> SSHCertificateBuilder:
1461
+ if not isinstance(name, bytes) or not isinstance(value, bytes):
1462
+ raise TypeError("name and value must be bytes")
1463
+ # This is O(n**2)
1464
+ if name in [name for name, _ in self._extensions]:
1465
+ raise ValueError("Duplicate extension name")
1466
+
1467
+ return SSHCertificateBuilder(
1468
+ _public_key=self._public_key,
1469
+ _serial=self._serial,
1470
+ _type=self._type,
1471
+ _key_id=self._key_id,
1472
+ _valid_principals=self._valid_principals,
1473
+ _valid_for_all_principals=self._valid_for_all_principals,
1474
+ _valid_before=self._valid_before,
1475
+ _valid_after=self._valid_after,
1476
+ _critical_options=self._critical_options,
1477
+ _extensions=[*self._extensions, (name, value)],
1478
+ )
1479
+
1480
+ def sign(self, private_key: SSHCertPrivateKeyTypes) -> SSHCertificate:
1481
+ if not isinstance(
1482
+ private_key,
1483
+ (
1484
+ ec.EllipticCurvePrivateKey,
1485
+ rsa.RSAPrivateKey,
1486
+ ed25519.Ed25519PrivateKey,
1487
+ ),
1488
+ ):
1489
+ raise TypeError("Unsupported private key type")
1490
+
1491
+ if self._public_key is None:
1492
+ raise ValueError("public_key must be set")
1493
+
1494
+ # Not required
1495
+ serial = 0 if self._serial is None else self._serial
1496
+
1497
+ if self._type is None:
1498
+ raise ValueError("type must be set")
1499
+
1500
+ # Not required
1501
+ key_id = b"" if self._key_id is None else self._key_id
1502
+
1503
+ # A zero length list is valid, but means the certificate
1504
+ # is valid for any principal of the specified type. We require
1505
+ # the user to explicitly set valid_for_all_principals to get
1506
+ # that behavior.
1507
+ if not self._valid_principals and not self._valid_for_all_principals:
1508
+ raise ValueError(
1509
+ "valid_principals must be set if valid_for_all_principals "
1510
+ "is False"
1511
+ )
1512
+
1513
+ if self._valid_before is None:
1514
+ raise ValueError("valid_before must be set")
1515
+
1516
+ if self._valid_after is None:
1517
+ raise ValueError("valid_after must be set")
1518
+
1519
+ if self._valid_after > self._valid_before:
1520
+ raise ValueError("valid_after must be earlier than valid_before")
1521
+
1522
+ # lexically sort our byte strings
1523
+ self._critical_options.sort(key=lambda x: x[0])
1524
+ self._extensions.sort(key=lambda x: x[0])
1525
+
1526
+ key_type = _get_ssh_key_type(self._public_key)
1527
+ cert_prefix = key_type + _CERT_SUFFIX
1528
+
1529
+ # Marshal the bytes to be signed
1530
+ nonce = os.urandom(32)
1531
+ kformat = _lookup_kformat(key_type)
1532
+ f = _FragList()
1533
+ f.put_sshstr(cert_prefix)
1534
+ f.put_sshstr(nonce)
1535
+ kformat.encode_public(self._public_key, f)
1536
+ f.put_u64(serial)
1537
+ f.put_u32(self._type.value)
1538
+ f.put_sshstr(key_id)
1539
+ fprincipals = _FragList()
1540
+ for p in self._valid_principals:
1541
+ fprincipals.put_sshstr(p)
1542
+ f.put_sshstr(fprincipals.tobytes())
1543
+ f.put_u64(self._valid_after)
1544
+ f.put_u64(self._valid_before)
1545
+ fcrit = _FragList()
1546
+ for name, value in self._critical_options:
1547
+ fcrit.put_sshstr(name)
1548
+ if len(value) > 0:
1549
+ foptval = _FragList()
1550
+ foptval.put_sshstr(value)
1551
+ fcrit.put_sshstr(foptval.tobytes())
1552
+ else:
1553
+ fcrit.put_sshstr(value)
1554
+ f.put_sshstr(fcrit.tobytes())
1555
+ fext = _FragList()
1556
+ for name, value in self._extensions:
1557
+ fext.put_sshstr(name)
1558
+ if len(value) > 0:
1559
+ fextval = _FragList()
1560
+ fextval.put_sshstr(value)
1561
+ fext.put_sshstr(fextval.tobytes())
1562
+ else:
1563
+ fext.put_sshstr(value)
1564
+ f.put_sshstr(fext.tobytes())
1565
+ f.put_sshstr(b"") # RESERVED FIELD
1566
+ # encode CA public key
1567
+ ca_type = _get_ssh_key_type(private_key)
1568
+ caformat = _lookup_kformat(ca_type)
1569
+ caf = _FragList()
1570
+ caf.put_sshstr(ca_type)
1571
+ caformat.encode_public(private_key.public_key(), caf)
1572
+ f.put_sshstr(caf.tobytes())
1573
+ # Sigs according to the rules defined for the CA's public key
1574
+ # (RFC4253 section 6.6 for ssh-rsa, RFC5656 for ECDSA,
1575
+ # and RFC8032 for Ed25519).
1576
+ if isinstance(private_key, ed25519.Ed25519PrivateKey):
1577
+ signature = private_key.sign(f.tobytes())
1578
+ fsig = _FragList()
1579
+ fsig.put_sshstr(ca_type)
1580
+ fsig.put_sshstr(signature)
1581
+ f.put_sshstr(fsig.tobytes())
1582
+ elif isinstance(private_key, ec.EllipticCurvePrivateKey):
1583
+ hash_alg = _get_ec_hash_alg(private_key.curve)
1584
+ signature = private_key.sign(f.tobytes(), ec.ECDSA(hash_alg))
1585
+ r, s = asym_utils.decode_dss_signature(signature)
1586
+ fsig = _FragList()
1587
+ fsig.put_sshstr(ca_type)
1588
+ fsigblob = _FragList()
1589
+ fsigblob.put_mpint(r)
1590
+ fsigblob.put_mpint(s)
1591
+ fsig.put_sshstr(fsigblob.tobytes())
1592
+ f.put_sshstr(fsig.tobytes())
1593
+
1594
+ else:
1595
+ assert isinstance(private_key, rsa.RSAPrivateKey)
1596
+ # Just like Golang, we're going to use SHA512 for RSA
1597
+ # https://cs.opensource.google/go/x/crypto/+/refs/tags/
1598
+ # v0.4.0:ssh/certs.go;l=445
1599
+ # RFC 8332 defines SHA256 and 512 as options
1600
+ fsig = _FragList()
1601
+ fsig.put_sshstr(_SSH_RSA_SHA512)
1602
+ signature = private_key.sign(
1603
+ f.tobytes(), padding.PKCS1v15(), hashes.SHA512()
1604
+ )
1605
+ fsig.put_sshstr(signature)
1606
+ f.put_sshstr(fsig.tobytes())
1607
+
1608
+ cert_data = binascii.b2a_base64(f.tobytes()).strip()
1609
+ # load_ssh_public_identity returns a union, but this is
1610
+ # guaranteed to be an SSHCertificate, so we cast to make
1611
+ # mypy happy.
1612
+ return typing.cast(
1613
+ SSHCertificate,
1614
+ load_ssh_public_identity(b"".join([cert_prefix, b" ", cert_data])),
1615
+ )
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
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
+
8
+ class InvalidToken(Exception):
9
+ pass
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 base64
8
+ import typing
9
+ from urllib.parse import quote, urlencode
10
+
11
+ from cryptography.hazmat.primitives import constant_time, hmac
12
+ from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512
13
+ from cryptography.hazmat.primitives.twofactor import InvalidToken
14
+ from cryptography.utils import Buffer
15
+
16
+ HOTPHashTypes = typing.Union[SHA1, SHA256, SHA512]
17
+
18
+
19
+ def _generate_uri(
20
+ hotp: HOTP,
21
+ type_name: str,
22
+ account_name: str,
23
+ issuer: str | None,
24
+ extra_parameters: list[tuple[str, int]],
25
+ ) -> str:
26
+ parameters = [
27
+ ("digits", hotp._length),
28
+ ("secret", base64.b32encode(hotp._key)),
29
+ ("algorithm", hotp._algorithm.name.upper()),
30
+ ]
31
+
32
+ if issuer is not None:
33
+ parameters.append(("issuer", issuer))
34
+
35
+ parameters.extend(extra_parameters)
36
+
37
+ label = (
38
+ f"{quote(issuer)}:{quote(account_name)}"
39
+ if issuer
40
+ else quote(account_name)
41
+ )
42
+ return f"otpauth://{type_name}/{label}?{urlencode(parameters)}"
43
+
44
+
45
+ class HOTP:
46
+ def __init__(
47
+ self,
48
+ key: Buffer,
49
+ length: int,
50
+ algorithm: HOTPHashTypes,
51
+ backend: typing.Any = None,
52
+ enforce_key_length: bool = True,
53
+ ) -> None:
54
+ if len(key) < 16 and enforce_key_length is True:
55
+ raise ValueError("Key length has to be at least 128 bits.")
56
+
57
+ if not isinstance(length, int):
58
+ raise TypeError("Length parameter must be an integer type.")
59
+
60
+ if length < 6 or length > 8:
61
+ raise ValueError("Length of HOTP has to be between 6 and 8.")
62
+
63
+ if not isinstance(algorithm, (SHA1, SHA256, SHA512)):
64
+ raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.")
65
+
66
+ self._key = key
67
+ self._length = length
68
+ self._algorithm = algorithm
69
+
70
+ def generate(self, counter: int) -> bytes:
71
+ if not isinstance(counter, int):
72
+ raise TypeError("Counter parameter must be an integer type.")
73
+
74
+ truncated_value = self._dynamic_truncate(counter)
75
+ hotp = truncated_value % (10**self._length)
76
+ return "{0:0{1}}".format(hotp, self._length).encode()
77
+
78
+ def verify(self, hotp: bytes, counter: int) -> None:
79
+ if not constant_time.bytes_eq(self.generate(counter), hotp):
80
+ raise InvalidToken("Supplied HOTP value does not match.")
81
+
82
+ def _dynamic_truncate(self, counter: int) -> int:
83
+ ctx = hmac.HMAC(self._key, self._algorithm)
84
+
85
+ try:
86
+ ctx.update(counter.to_bytes(length=8, byteorder="big"))
87
+ except OverflowError:
88
+ raise ValueError(f"Counter must be between 0 and {2**64 - 1}.")
89
+
90
+ hmac_value = ctx.finalize()
91
+
92
+ offset = hmac_value[len(hmac_value) - 1] & 0b1111
93
+ p = hmac_value[offset : offset + 4]
94
+ return int.from_bytes(p, byteorder="big") & 0x7FFFFFFF
95
+
96
+ def get_provisioning_uri(
97
+ self, account_name: str, counter: int, issuer: str | None
98
+ ) -> str:
99
+ return _generate_uri(
100
+ self, "hotp", account_name, issuer, [("counter", int(counter))]
101
+ )
.mcp-venv/lib/python3.13/site-packages/cryptography/hazmat/primitives/twofactor/totp.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 typing
8
+
9
+ from cryptography.hazmat.primitives import constant_time
10
+ from cryptography.hazmat.primitives.twofactor import InvalidToken
11
+ from cryptography.hazmat.primitives.twofactor.hotp import (
12
+ HOTP,
13
+ HOTPHashTypes,
14
+ _generate_uri,
15
+ )
16
+ from cryptography.utils import Buffer
17
+
18
+
19
+ class TOTP:
20
+ def __init__(
21
+ self,
22
+ key: Buffer,
23
+ length: int,
24
+ algorithm: HOTPHashTypes,
25
+ time_step: int,
26
+ backend: typing.Any = None,
27
+ enforce_key_length: bool = True,
28
+ ):
29
+ self._time_step = time_step
30
+ self._hotp = HOTP(
31
+ key, length, algorithm, enforce_key_length=enforce_key_length
32
+ )
33
+
34
+ def generate(self, time: int | float) -> bytes:
35
+ if not isinstance(time, (int, float)):
36
+ raise TypeError(
37
+ "Time parameter must be an integer type or float type."
38
+ )
39
+
40
+ counter = int(time / self._time_step)
41
+ return self._hotp.generate(counter)
42
+
43
+ def verify(self, totp: bytes, time: int) -> None:
44
+ if not constant_time.bytes_eq(self.generate(time), totp):
45
+ raise InvalidToken("Supplied TOTP value does not match.")
46
+
47
+ def get_provisioning_uri(
48
+ self, account_name: str, issuer: str | None
49
+ ) -> str:
50
+ return _generate_uri(
51
+ self._hotp,
52
+ "totp",
53
+ account_name,
54
+ issuer,
55
+ [("period", int(self._time_step))],
56
+ )
.mcp-venv/lib/python3.13/site-packages/cryptography/py.typed ADDED
File without changes
.mcp-venv/lib/python3.13/site-packages/cryptography/utils.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 enum
8
+ import sys
9
+ import types
10
+ import typing
11
+ import warnings
12
+ from collections.abc import Sequence
13
+
14
+
15
+ # We use a UserWarning subclass, instead of DeprecationWarning, because CPython
16
+ # decided deprecation warnings should be invisible by default.
17
+ class CryptographyDeprecationWarning(UserWarning):
18
+ pass
19
+
20
+
21
+ # Several APIs were deprecated with no specific end-of-life date because of the
22
+ # ubiquity of their use. They should not be removed until we agree on when that
23
+ # cycle ends.
24
+ DeprecatedIn36 = CryptographyDeprecationWarning
25
+ DeprecatedIn40 = CryptographyDeprecationWarning
26
+ DeprecatedIn41 = CryptographyDeprecationWarning
27
+ DeprecatedIn42 = CryptographyDeprecationWarning
28
+ DeprecatedIn43 = CryptographyDeprecationWarning
29
+ DeprecatedIn47 = CryptographyDeprecationWarning
30
+ DeprecatedIn50 = CryptographyDeprecationWarning
31
+
32
+
33
+ # If you're wondering why we don't use `Buffer`, it's because `Buffer` would
34
+ # be more accurately named: Bufferable. It means something which has an
35
+ # `__buffer__`. Which means you can't actually treat the result as a buffer
36
+ # (and do things like take a `len()`).
37
+ Buffer = typing.Union[bytes, bytearray, memoryview]
38
+
39
+
40
+ def _check_bytes(name: str, value: bytes) -> None:
41
+ if not isinstance(value, bytes):
42
+ raise TypeError(f"{name} must be bytes")
43
+
44
+
45
+ def _check_byteslike(name: str, value: Buffer) -> None:
46
+ if isinstance(value, (bytes, bytearray, memoryview)):
47
+ return
48
+ try:
49
+ memoryview(value)
50
+ except TypeError:
51
+ raise TypeError(f"{name} must be bytes-like")
52
+
53
+
54
+ def int_to_bytes(integer: int, length: int | None = None) -> bytes:
55
+ if length == 0:
56
+ raise ValueError("length argument can't be 0")
57
+ return integer.to_bytes(
58
+ length or (integer.bit_length() + 7) // 8 or 1, "big"
59
+ )
60
+
61
+
62
+ class InterfaceNotImplemented(Exception):
63
+ pass
64
+
65
+
66
+ class _DeprecatedValue:
67
+ def __init__(self, value: object, message: str, warning_class):
68
+ self.value = value
69
+ self.message = message
70
+ self.warning_class = warning_class
71
+
72
+
73
+ class _ModuleWithDeprecations(types.ModuleType):
74
+ def __init__(self, module: types.ModuleType):
75
+ super().__init__(module.__name__)
76
+ self.__dict__["_module"] = module
77
+
78
+ def __getattr__(self, name: str) -> typing.Any:
79
+ obj = getattr(self._module, name)
80
+ if isinstance(obj, _DeprecatedValue):
81
+ warnings.warn(obj.message, obj.warning_class, stacklevel=2)
82
+ obj = obj.value
83
+ else:
84
+ # Cache non-deprecated attributes in our own `__dict__` so that
85
+ # subsequent lookups are ordinary module attribute accesses and
86
+ # don't pay for this `__getattr__` (which would otherwise defeat
87
+ # CPython's LOAD_ATTR module caching for every attribute of the
88
+ # module). `__setattr__` and `__delattr__` keep the cache
89
+ # coherent.
90
+ self.__dict__[name] = obj
91
+ return obj
92
+
93
+ def __setattr__(self, attr: str, value: object) -> None:
94
+ if isinstance(value, _DeprecatedValue):
95
+ self.__dict__.pop(attr, None)
96
+ else:
97
+ self.__dict__[attr] = value
98
+ setattr(self._module, attr, value)
99
+
100
+ def __delattr__(self, attr: str) -> None:
101
+ obj = getattr(self._module, attr)
102
+ if isinstance(obj, _DeprecatedValue):
103
+ warnings.warn(obj.message, obj.warning_class, stacklevel=2)
104
+
105
+ self.__dict__.pop(attr, None)
106
+ delattr(self._module, attr)
107
+
108
+ def __dir__(self) -> Sequence[str]:
109
+ return ["_module", *dir(self._module)]
110
+
111
+
112
+ def deprecated(
113
+ value: object,
114
+ module_name: str,
115
+ message: str,
116
+ warning_class: type[Warning],
117
+ name: str | None = None,
118
+ ) -> _DeprecatedValue:
119
+ module = sys.modules[module_name]
120
+ if not isinstance(module, _ModuleWithDeprecations):
121
+ sys.modules[module_name] = module = _ModuleWithDeprecations(module)
122
+ dv = _DeprecatedValue(value, message, warning_class)
123
+ # Maintain backwards compatibility with `name is None` for pyOpenSSL.
124
+ if name is not None:
125
+ setattr(module, name, dv)
126
+ return dv
127
+
128
+
129
+ # Python 3.10 changed representation of enums. We use well-defined object
130
+ # representation and string representation from Python 3.9.
131
+ class Enum(enum.Enum):
132
+ def __repr__(self) -> str:
133
+ return f"<{self.__class__.__name__}.{self._name_}: {self._value_!r}>"
134
+
135
+ def __str__(self) -> str:
136
+ return f"{self.__class__.__name__}.{self._name_}"
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/__init__.py ADDED
@@ -0,0 +1,270 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.x509 import certificate_transparency, oid, verification
8
+ from cryptography.x509.base import (
9
+ Attribute,
10
+ AttributeNotFound,
11
+ Attributes,
12
+ Certificate,
13
+ CertificateBuilder,
14
+ CertificateRevocationList,
15
+ CertificateRevocationListBuilder,
16
+ CertificateSigningRequest,
17
+ CertificateSigningRequestBuilder,
18
+ InvalidVersion,
19
+ RevokedCertificate,
20
+ RevokedCertificateBuilder,
21
+ Version,
22
+ load_der_x509_certificate,
23
+ load_der_x509_crl,
24
+ load_der_x509_csr,
25
+ load_pem_x509_certificate,
26
+ load_pem_x509_certificates,
27
+ load_pem_x509_crl,
28
+ load_pem_x509_csr,
29
+ random_serial_number,
30
+ )
31
+ from cryptography.x509.extensions import (
32
+ AccessDescription,
33
+ Admission,
34
+ Admissions,
35
+ AuthorityInformationAccess,
36
+ AuthorityKeyIdentifier,
37
+ BasicConstraints,
38
+ CertificateIssuer,
39
+ CertificatePolicies,
40
+ CRLDistributionPoints,
41
+ CRLNumber,
42
+ CRLReason,
43
+ DeltaCRLIndicator,
44
+ DistributionPoint,
45
+ DuplicateExtension,
46
+ ExtendedKeyUsage,
47
+ Extension,
48
+ ExtensionNotFound,
49
+ Extensions,
50
+ ExtensionType,
51
+ FreshestCRL,
52
+ GeneralNames,
53
+ InhibitAnyPolicy,
54
+ InvalidityDate,
55
+ IssuerAlternativeName,
56
+ IssuingDistributionPoint,
57
+ KeyUsage,
58
+ MSCertificateTemplate,
59
+ NameConstraints,
60
+ NamingAuthority,
61
+ NoticeReference,
62
+ OCSPAcceptableResponses,
63
+ OCSPNoCheck,
64
+ OCSPNonce,
65
+ PolicyConstraints,
66
+ PolicyInformation,
67
+ PrecertificateSignedCertificateTimestamps,
68
+ PrecertPoison,
69
+ PrivateKeyUsagePeriod,
70
+ ProfessionInfo,
71
+ ReasonFlags,
72
+ SignedCertificateTimestamps,
73
+ SubjectAlternativeName,
74
+ SubjectInformationAccess,
75
+ SubjectKeyIdentifier,
76
+ TLSFeature,
77
+ TLSFeatureType,
78
+ UnrecognizedExtension,
79
+ UserNotice,
80
+ )
81
+ from cryptography.x509.general_name import (
82
+ DirectoryName,
83
+ DNSName,
84
+ GeneralName,
85
+ IPAddress,
86
+ OtherName,
87
+ RegisteredID,
88
+ RFC822Name,
89
+ UniformResourceIdentifier,
90
+ UnsupportedGeneralNameType,
91
+ )
92
+ from cryptography.x509.name import (
93
+ Name,
94
+ NameAttribute,
95
+ RelativeDistinguishedName,
96
+ )
97
+ from cryptography.x509.oid import (
98
+ AuthorityInformationAccessOID,
99
+ CertificatePoliciesOID,
100
+ CRLEntryExtensionOID,
101
+ ExtendedKeyUsageOID,
102
+ ExtensionOID,
103
+ NameOID,
104
+ ObjectIdentifier,
105
+ PublicKeyAlgorithmOID,
106
+ SignatureAlgorithmOID,
107
+ )
108
+
109
+ OID_AUTHORITY_INFORMATION_ACCESS = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
110
+ OID_AUTHORITY_KEY_IDENTIFIER = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
111
+ OID_BASIC_CONSTRAINTS = ExtensionOID.BASIC_CONSTRAINTS
112
+ OID_CERTIFICATE_POLICIES = ExtensionOID.CERTIFICATE_POLICIES
113
+ OID_CRL_DISTRIBUTION_POINTS = ExtensionOID.CRL_DISTRIBUTION_POINTS
114
+ OID_EXTENDED_KEY_USAGE = ExtensionOID.EXTENDED_KEY_USAGE
115
+ OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL
116
+ OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY
117
+ OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME
118
+ OID_KEY_USAGE = ExtensionOID.KEY_USAGE
119
+ OID_PRIVATE_KEY_USAGE_PERIOD = ExtensionOID.PRIVATE_KEY_USAGE_PERIOD
120
+ OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS
121
+ OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK
122
+ OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS
123
+ OID_POLICY_MAPPINGS = ExtensionOID.POLICY_MAPPINGS
124
+ OID_SUBJECT_ALTERNATIVE_NAME = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
125
+ OID_SUBJECT_DIRECTORY_ATTRIBUTES = ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES
126
+ OID_SUBJECT_INFORMATION_ACCESS = ExtensionOID.SUBJECT_INFORMATION_ACCESS
127
+ OID_SUBJECT_KEY_IDENTIFIER = ExtensionOID.SUBJECT_KEY_IDENTIFIER
128
+
129
+ OID_DSA_WITH_SHA1 = SignatureAlgorithmOID.DSA_WITH_SHA1
130
+ OID_DSA_WITH_SHA224 = SignatureAlgorithmOID.DSA_WITH_SHA224
131
+ OID_DSA_WITH_SHA256 = SignatureAlgorithmOID.DSA_WITH_SHA256
132
+ OID_ECDSA_WITH_SHA1 = SignatureAlgorithmOID.ECDSA_WITH_SHA1
133
+ OID_ECDSA_WITH_SHA224 = SignatureAlgorithmOID.ECDSA_WITH_SHA224
134
+ OID_ECDSA_WITH_SHA256 = SignatureAlgorithmOID.ECDSA_WITH_SHA256
135
+ OID_ECDSA_WITH_SHA384 = SignatureAlgorithmOID.ECDSA_WITH_SHA384
136
+ OID_ECDSA_WITH_SHA512 = SignatureAlgorithmOID.ECDSA_WITH_SHA512
137
+ OID_RSA_WITH_MD5 = SignatureAlgorithmOID.RSA_WITH_MD5
138
+ OID_RSA_WITH_SHA1 = SignatureAlgorithmOID.RSA_WITH_SHA1
139
+ OID_RSA_WITH_SHA224 = SignatureAlgorithmOID.RSA_WITH_SHA224
140
+ OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256
141
+ OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384
142
+ OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512
143
+ OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS
144
+
145
+ OID_COMMON_NAME = NameOID.COMMON_NAME
146
+ OID_COUNTRY_NAME = NameOID.COUNTRY_NAME
147
+ OID_DOMAIN_COMPONENT = NameOID.DOMAIN_COMPONENT
148
+ OID_DN_QUALIFIER = NameOID.DN_QUALIFIER
149
+ OID_EMAIL_ADDRESS = NameOID.EMAIL_ADDRESS
150
+ OID_GENERATION_QUALIFIER = NameOID.GENERATION_QUALIFIER
151
+ OID_GIVEN_NAME = NameOID.GIVEN_NAME
152
+ OID_LOCALITY_NAME = NameOID.LOCALITY_NAME
153
+ OID_ORGANIZATIONAL_UNIT_NAME = NameOID.ORGANIZATIONAL_UNIT_NAME
154
+ OID_ORGANIZATION_NAME = NameOID.ORGANIZATION_NAME
155
+ OID_PSEUDONYM = NameOID.PSEUDONYM
156
+ OID_SERIAL_NUMBER = NameOID.SERIAL_NUMBER
157
+ OID_STATE_OR_PROVINCE_NAME = NameOID.STATE_OR_PROVINCE_NAME
158
+ OID_SURNAME = NameOID.SURNAME
159
+ OID_TITLE = NameOID.TITLE
160
+
161
+ OID_CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH
162
+ OID_CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING
163
+ OID_EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION
164
+ OID_OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING
165
+ OID_SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH
166
+ OID_TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING
167
+
168
+ OID_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY
169
+ OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER
170
+ OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE
171
+
172
+ OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER
173
+ OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON
174
+ OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE
175
+
176
+ OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS
177
+ OID_OCSP = AuthorityInformationAccessOID.OCSP
178
+
179
+ __all__ = [
180
+ "OID_CA_ISSUERS",
181
+ "OID_OCSP",
182
+ "AccessDescription",
183
+ "Admission",
184
+ "Admissions",
185
+ "Attribute",
186
+ "AttributeNotFound",
187
+ "Attributes",
188
+ "AuthorityInformationAccess",
189
+ "AuthorityKeyIdentifier",
190
+ "BasicConstraints",
191
+ "CRLDistributionPoints",
192
+ "CRLNumber",
193
+ "CRLReason",
194
+ "Certificate",
195
+ "CertificateBuilder",
196
+ "CertificateIssuer",
197
+ "CertificatePolicies",
198
+ "CertificateRevocationList",
199
+ "CertificateRevocationListBuilder",
200
+ "CertificateSigningRequest",
201
+ "CertificateSigningRequestBuilder",
202
+ "DNSName",
203
+ "DeltaCRLIndicator",
204
+ "DirectoryName",
205
+ "DistributionPoint",
206
+ "DuplicateExtension",
207
+ "ExtendedKeyUsage",
208
+ "Extension",
209
+ "ExtensionNotFound",
210
+ "ExtensionType",
211
+ "Extensions",
212
+ "FreshestCRL",
213
+ "GeneralName",
214
+ "GeneralNames",
215
+ "IPAddress",
216
+ "InhibitAnyPolicy",
217
+ "InvalidVersion",
218
+ "InvalidityDate",
219
+ "IssuerAlternativeName",
220
+ "IssuingDistributionPoint",
221
+ "KeyUsage",
222
+ "MSCertificateTemplate",
223
+ "Name",
224
+ "NameAttribute",
225
+ "NameConstraints",
226
+ "NameOID",
227
+ "NamingAuthority",
228
+ "NoticeReference",
229
+ "OCSPAcceptableResponses",
230
+ "OCSPNoCheck",
231
+ "OCSPNonce",
232
+ "ObjectIdentifier",
233
+ "OtherName",
234
+ "PolicyConstraints",
235
+ "PolicyInformation",
236
+ "PrecertPoison",
237
+ "PrecertificateSignedCertificateTimestamps",
238
+ "PrivateKeyUsagePeriod",
239
+ "ProfessionInfo",
240
+ "PublicKeyAlgorithmOID",
241
+ "RFC822Name",
242
+ "ReasonFlags",
243
+ "RegisteredID",
244
+ "RelativeDistinguishedName",
245
+ "RevokedCertificate",
246
+ "RevokedCertificateBuilder",
247
+ "SignatureAlgorithmOID",
248
+ "SignedCertificateTimestamps",
249
+ "SubjectAlternativeName",
250
+ "SubjectInformationAccess",
251
+ "SubjectKeyIdentifier",
252
+ "TLSFeature",
253
+ "TLSFeatureType",
254
+ "UniformResourceIdentifier",
255
+ "UnrecognizedExtension",
256
+ "UnsupportedGeneralNameType",
257
+ "UserNotice",
258
+ "Version",
259
+ "certificate_transparency",
260
+ "load_der_x509_certificate",
261
+ "load_der_x509_crl",
262
+ "load_der_x509_csr",
263
+ "load_pem_x509_certificate",
264
+ "load_pem_x509_certificates",
265
+ "load_pem_x509_crl",
266
+ "load_pem_x509_csr",
267
+ "oid",
268
+ "random_serial_number",
269
+ "verification",
270
+ ]
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/base.py ADDED
@@ -0,0 +1,834 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 datetime
8
+ import os
9
+ import typing
10
+ from collections.abc import Iterable
11
+
12
+ from cryptography import utils
13
+ from cryptography.hazmat.bindings._rust import x509 as rust_x509
14
+ from cryptography.hazmat.primitives import hashes
15
+ from cryptography.hazmat.primitives.asymmetric import (
16
+ dsa,
17
+ ec,
18
+ ed448,
19
+ ed25519,
20
+ mldsa,
21
+ mlkem,
22
+ padding,
23
+ rsa,
24
+ x448,
25
+ x25519,
26
+ )
27
+ from cryptography.hazmat.primitives.asymmetric.types import (
28
+ CertificateIssuerPrivateKeyTypes,
29
+ CertificatePublicKeyTypes,
30
+ )
31
+ from cryptography.x509.extensions import (
32
+ Extension,
33
+ ExtensionType,
34
+ _make_sequence_methods,
35
+ )
36
+ from cryptography.x509.name import Name, _ASN1Type
37
+ from cryptography.x509.oid import ObjectIdentifier
38
+
39
+ _EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1)
40
+
41
+ # This must be kept in sync with sign.rs's list of allowable types in
42
+ # identify_hash_type
43
+ _AllowedHashTypes = typing.Union[
44
+ hashes.SHA224,
45
+ hashes.SHA256,
46
+ hashes.SHA384,
47
+ hashes.SHA512,
48
+ hashes.SHA3_224,
49
+ hashes.SHA3_256,
50
+ hashes.SHA3_384,
51
+ hashes.SHA3_512,
52
+ ]
53
+
54
+
55
+ class AttributeNotFound(Exception):
56
+ def __init__(self, msg: str, oid: ObjectIdentifier) -> None:
57
+ super().__init__(msg)
58
+ self.oid = oid
59
+
60
+
61
+ def _reject_duplicate_extension(
62
+ extension: Extension[ExtensionType],
63
+ extensions: list[Extension[ExtensionType]],
64
+ ) -> None:
65
+ # This is quadratic in the number of extensions
66
+ for e in extensions:
67
+ if e.oid == extension.oid:
68
+ raise ValueError("This extension has already been set.")
69
+
70
+
71
+ def _reject_duplicate_attribute(
72
+ oid: ObjectIdentifier,
73
+ attributes: list[tuple[ObjectIdentifier, bytes, int | None]],
74
+ ) -> None:
75
+ # This is quadratic in the number of attributes
76
+ for attr_oid, _, _ in attributes:
77
+ if attr_oid == oid:
78
+ raise ValueError("This attribute has already been set.")
79
+
80
+
81
+ def _convert_to_naive_utc_time(time: datetime.datetime) -> datetime.datetime:
82
+ """Normalizes a datetime to a naive datetime in UTC.
83
+
84
+ time -- datetime to normalize. Assumed to be in UTC if not timezone
85
+ aware.
86
+ """
87
+ if time.tzinfo is not None:
88
+ offset = time.utcoffset()
89
+ offset = offset if offset else datetime.timedelta()
90
+ return time.replace(tzinfo=None) - offset
91
+ else:
92
+ return time
93
+
94
+
95
+ class Attribute:
96
+ def __init__(
97
+ self,
98
+ oid: ObjectIdentifier,
99
+ value: bytes,
100
+ _type: int = _ASN1Type.UTF8String.value,
101
+ ) -> None:
102
+ self._oid = oid
103
+ self._value = value
104
+ self._type = _type
105
+
106
+ @property
107
+ def oid(self) -> ObjectIdentifier:
108
+ return self._oid
109
+
110
+ @property
111
+ def value(self) -> bytes:
112
+ return self._value
113
+
114
+ def __repr__(self) -> str:
115
+ return f"<Attribute(oid={self.oid}, value={self.value!r})>"
116
+
117
+ def __eq__(self, other: object) -> bool:
118
+ if not isinstance(other, Attribute):
119
+ return NotImplemented
120
+
121
+ return (
122
+ self.oid == other.oid
123
+ and self.value == other.value
124
+ and self._type == other._type
125
+ )
126
+
127
+ def __hash__(self) -> int:
128
+ return hash((self.oid, self.value, self._type))
129
+
130
+
131
+ class Attributes:
132
+ def __init__(
133
+ self,
134
+ attributes: Iterable[Attribute],
135
+ ) -> None:
136
+ self._attributes = list(attributes)
137
+
138
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_attributes")
139
+
140
+ def __repr__(self) -> str:
141
+ return f"<Attributes({self._attributes})>"
142
+
143
+ def get_attribute_for_oid(self, oid: ObjectIdentifier) -> Attribute:
144
+ for attr in self:
145
+ if attr.oid == oid:
146
+ return attr
147
+
148
+ raise AttributeNotFound(f"No {oid} attribute was found", oid)
149
+
150
+
151
+ class Version(utils.Enum):
152
+ v1 = 0
153
+ v3 = 2
154
+
155
+
156
+ class InvalidVersion(Exception):
157
+ def __init__(self, msg: str, parsed_version: int) -> None:
158
+ super().__init__(msg)
159
+ self.parsed_version = parsed_version
160
+
161
+
162
+ Certificate = rust_x509.Certificate
163
+ RevokedCertificate = rust_x509.RevokedCertificate
164
+
165
+
166
+ CertificateRevocationList = rust_x509.CertificateRevocationList
167
+ CertificateSigningRequest = rust_x509.CertificateSigningRequest
168
+
169
+
170
+ load_pem_x509_certificate = rust_x509.load_pem_x509_certificate
171
+ load_der_x509_certificate = rust_x509.load_der_x509_certificate
172
+
173
+ load_pem_x509_certificates = rust_x509.load_pem_x509_certificates
174
+
175
+ load_pem_x509_csr = rust_x509.load_pem_x509_csr
176
+ load_der_x509_csr = rust_x509.load_der_x509_csr
177
+
178
+ load_pem_x509_crl = rust_x509.load_pem_x509_crl
179
+ load_der_x509_crl = rust_x509.load_der_x509_crl
180
+
181
+
182
+ class CertificateSigningRequestBuilder:
183
+ def __init__(
184
+ self,
185
+ subject_name: Name | None = None,
186
+ extensions: list[Extension[ExtensionType]] = [],
187
+ attributes: list[tuple[ObjectIdentifier, bytes, int | None]] = [],
188
+ ):
189
+ """
190
+ Creates an empty X.509 certificate request (v1).
191
+ """
192
+ self._subject_name = subject_name
193
+ self._extensions = extensions
194
+ self._attributes = attributes
195
+
196
+ def subject_name(self, name: Name) -> CertificateSigningRequestBuilder:
197
+ """
198
+ Sets the certificate requestor's distinguished name.
199
+ """
200
+ if not isinstance(name, Name):
201
+ raise TypeError("Expecting x509.Name object.")
202
+ if self._subject_name is not None:
203
+ raise ValueError("The subject name may only be set once.")
204
+ return CertificateSigningRequestBuilder(
205
+ name, self._extensions, self._attributes
206
+ )
207
+
208
+ def add_extension(
209
+ self, extval: ExtensionType, critical: bool
210
+ ) -> CertificateSigningRequestBuilder:
211
+ """
212
+ Adds an X.509 extension to the certificate request.
213
+ """
214
+ if not isinstance(extval, ExtensionType):
215
+ raise TypeError("extension must be an ExtensionType")
216
+
217
+ extension = Extension(extval.oid, critical, extval)
218
+ _reject_duplicate_extension(extension, self._extensions)
219
+
220
+ return CertificateSigningRequestBuilder(
221
+ self._subject_name,
222
+ [*self._extensions, extension],
223
+ self._attributes,
224
+ )
225
+
226
+ def add_attribute(
227
+ self,
228
+ oid: ObjectIdentifier,
229
+ value: bytes,
230
+ *,
231
+ _tag: _ASN1Type | None = None,
232
+ ) -> CertificateSigningRequestBuilder:
233
+ """
234
+ Adds an X.509 attribute with an OID and associated value.
235
+ """
236
+ if not isinstance(oid, ObjectIdentifier):
237
+ raise TypeError("oid must be an ObjectIdentifier")
238
+
239
+ if not isinstance(value, bytes):
240
+ raise TypeError("value must be bytes")
241
+
242
+ if _tag is not None and not isinstance(_tag, _ASN1Type):
243
+ raise TypeError("tag must be _ASN1Type")
244
+
245
+ _reject_duplicate_attribute(oid, self._attributes)
246
+
247
+ if _tag is not None:
248
+ tag = _tag.value
249
+ else:
250
+ tag = None
251
+
252
+ return CertificateSigningRequestBuilder(
253
+ self._subject_name,
254
+ self._extensions,
255
+ [*self._attributes, (oid, value, tag)],
256
+ )
257
+
258
+ def sign(
259
+ self,
260
+ private_key: CertificateIssuerPrivateKeyTypes,
261
+ algorithm: _AllowedHashTypes | None,
262
+ backend: typing.Any = None,
263
+ *,
264
+ rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
265
+ ecdsa_deterministic: bool | None = None,
266
+ ) -> CertificateSigningRequest:
267
+ """
268
+ Signs the request using the requestor's private key.
269
+ """
270
+ if self._subject_name is None:
271
+ raise ValueError("A CertificateSigningRequest must have a subject")
272
+
273
+ if rsa_padding is not None:
274
+ if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
275
+ raise TypeError("Padding must be PSS or PKCS1v15")
276
+ if not isinstance(private_key, rsa.RSAPrivateKey):
277
+ raise TypeError("Padding is only supported for RSA keys")
278
+
279
+ if ecdsa_deterministic is not None:
280
+ if not isinstance(private_key, ec.EllipticCurvePrivateKey):
281
+ raise TypeError(
282
+ "Deterministic ECDSA is only supported for EC keys"
283
+ )
284
+
285
+ return rust_x509.create_x509_csr(
286
+ self,
287
+ private_key,
288
+ algorithm,
289
+ rsa_padding,
290
+ ecdsa_deterministic,
291
+ )
292
+
293
+
294
+ class CertificateBuilder:
295
+ _extensions: list[Extension[ExtensionType]]
296
+
297
+ def __init__(
298
+ self,
299
+ issuer_name: Name | None = None,
300
+ subject_name: Name | None = None,
301
+ public_key: CertificatePublicKeyTypes | None = None,
302
+ serial_number: int | None = None,
303
+ not_valid_before: datetime.datetime | None = None,
304
+ not_valid_after: datetime.datetime | None = None,
305
+ extensions: list[Extension[ExtensionType]] = [],
306
+ public_key_rsa_padding: type[padding.PSS] | None = None,
307
+ ) -> None:
308
+ self._version = Version.v3
309
+ self._issuer_name = issuer_name
310
+ self._subject_name = subject_name
311
+ self._public_key = public_key
312
+ self._serial_number = serial_number
313
+ self._not_valid_before = not_valid_before
314
+ self._not_valid_after = not_valid_after
315
+ self._extensions = extensions
316
+ self._public_key_rsa_padding = public_key_rsa_padding
317
+
318
+ def issuer_name(self, name: Name) -> CertificateBuilder:
319
+ """
320
+ Sets the CA's distinguished name.
321
+ """
322
+ if not isinstance(name, Name):
323
+ raise TypeError("Expecting x509.Name object.")
324
+ if self._issuer_name is not None:
325
+ raise ValueError("The issuer name may only be set once.")
326
+ return CertificateBuilder(
327
+ name,
328
+ self._subject_name,
329
+ self._public_key,
330
+ self._serial_number,
331
+ self._not_valid_before,
332
+ self._not_valid_after,
333
+ self._extensions,
334
+ self._public_key_rsa_padding,
335
+ )
336
+
337
+ def subject_name(self, name: Name) -> CertificateBuilder:
338
+ """
339
+ Sets the requestor's distinguished name.
340
+ """
341
+ if not isinstance(name, Name):
342
+ raise TypeError("Expecting x509.Name object.")
343
+ if self._subject_name is not None:
344
+ raise ValueError("The subject name may only be set once.")
345
+ return CertificateBuilder(
346
+ self._issuer_name,
347
+ name,
348
+ self._public_key,
349
+ self._serial_number,
350
+ self._not_valid_before,
351
+ self._not_valid_after,
352
+ self._extensions,
353
+ self._public_key_rsa_padding,
354
+ )
355
+
356
+ def public_key(
357
+ self,
358
+ key: CertificatePublicKeyTypes,
359
+ *,
360
+ rsa_padding: type[padding.PSS] | None = None,
361
+ ) -> CertificateBuilder:
362
+ """
363
+ Sets the requestor's public key (as found in the signing request).
364
+ """
365
+ if not isinstance(
366
+ key,
367
+ (
368
+ dsa.DSAPublicKey,
369
+ rsa.RSAPublicKey,
370
+ ec.EllipticCurvePublicKey,
371
+ ed25519.Ed25519PublicKey,
372
+ ed448.Ed448PublicKey,
373
+ mldsa.MLDSA44PublicKey,
374
+ mldsa.MLDSA65PublicKey,
375
+ mldsa.MLDSA87PublicKey,
376
+ mlkem.MLKEM768PublicKey,
377
+ mlkem.MLKEM1024PublicKey,
378
+ x25519.X25519PublicKey,
379
+ x448.X448PublicKey,
380
+ ),
381
+ ):
382
+ raise TypeError(
383
+ "Expecting one of DSAPublicKey, RSAPublicKey,"
384
+ " EllipticCurvePublicKey, Ed25519PublicKey,"
385
+ " Ed448PublicKey, MLDSA44PublicKey, MLDSA65PublicKey,"
386
+ " MLDSA87PublicKey, MLKEM768PublicKey, MLKEM1024PublicKey,"
387
+ " X25519PublicKey or X448PublicKey."
388
+ )
389
+ if rsa_padding is not None:
390
+ if rsa_padding is not padding.PSS:
391
+ raise TypeError(
392
+ "rsa_padding must be the PSS class, not an instance"
393
+ )
394
+ if not isinstance(key, rsa.RSAPublicKey):
395
+ raise TypeError(
396
+ "rsa_padding is only supported with RSA public keys"
397
+ )
398
+ if self._public_key is not None:
399
+ raise ValueError("The public key may only be set once.")
400
+ return CertificateBuilder(
401
+ self._issuer_name,
402
+ self._subject_name,
403
+ key,
404
+ self._serial_number,
405
+ self._not_valid_before,
406
+ self._not_valid_after,
407
+ self._extensions,
408
+ rsa_padding,
409
+ )
410
+
411
+ def serial_number(self, number: int) -> CertificateBuilder:
412
+ """
413
+ Sets the certificate serial number.
414
+ """
415
+ if not isinstance(number, int):
416
+ raise TypeError("Serial number must be of integral type.")
417
+ if self._serial_number is not None:
418
+ raise ValueError("The serial number may only be set once.")
419
+ if number <= 0:
420
+ raise ValueError("The serial number should be positive.")
421
+
422
+ # ASN.1 integers are always signed, so most significant bit must be
423
+ # zero.
424
+ if number.bit_length() >= 160: # As defined in RFC 5280
425
+ raise ValueError(
426
+ "The serial number should not be more than 159 bits."
427
+ )
428
+ return CertificateBuilder(
429
+ self._issuer_name,
430
+ self._subject_name,
431
+ self._public_key,
432
+ number,
433
+ self._not_valid_before,
434
+ self._not_valid_after,
435
+ self._extensions,
436
+ self._public_key_rsa_padding,
437
+ )
438
+
439
+ def not_valid_before(self, time: datetime.datetime) -> CertificateBuilder:
440
+ """
441
+ Sets the certificate activation time.
442
+ """
443
+ if not isinstance(time, datetime.datetime):
444
+ raise TypeError("Expecting datetime object.")
445
+ if self._not_valid_before is not None:
446
+ raise ValueError("The not valid before may only be set once.")
447
+ time = _convert_to_naive_utc_time(time)
448
+ if time < _EARLIEST_UTC_TIME:
449
+ raise ValueError(
450
+ "The not valid before date must be on or after"
451
+ " 1950 January 1)."
452
+ )
453
+ if self._not_valid_after is not None and time > self._not_valid_after:
454
+ raise ValueError(
455
+ "The not valid before date must be before the not valid after "
456
+ "date."
457
+ )
458
+ return CertificateBuilder(
459
+ self._issuer_name,
460
+ self._subject_name,
461
+ self._public_key,
462
+ self._serial_number,
463
+ time,
464
+ self._not_valid_after,
465
+ self._extensions,
466
+ self._public_key_rsa_padding,
467
+ )
468
+
469
+ def not_valid_after(self, time: datetime.datetime) -> CertificateBuilder:
470
+ """
471
+ Sets the certificate expiration time.
472
+ """
473
+ if not isinstance(time, datetime.datetime):
474
+ raise TypeError("Expecting datetime object.")
475
+ if self._not_valid_after is not None:
476
+ raise ValueError("The not valid after may only be set once.")
477
+ time = _convert_to_naive_utc_time(time)
478
+ if time < _EARLIEST_UTC_TIME:
479
+ raise ValueError(
480
+ "The not valid after date must be on or after 1950 January 1."
481
+ )
482
+ if (
483
+ self._not_valid_before is not None
484
+ and time < self._not_valid_before
485
+ ):
486
+ raise ValueError(
487
+ "The not valid after date must be after the not valid before "
488
+ "date."
489
+ )
490
+ return CertificateBuilder(
491
+ self._issuer_name,
492
+ self._subject_name,
493
+ self._public_key,
494
+ self._serial_number,
495
+ self._not_valid_before,
496
+ time,
497
+ self._extensions,
498
+ self._public_key_rsa_padding,
499
+ )
500
+
501
+ def add_extension(
502
+ self, extval: ExtensionType, critical: bool
503
+ ) -> CertificateBuilder:
504
+ """
505
+ Adds an X.509 extension to the certificate.
506
+ """
507
+ if not isinstance(extval, ExtensionType):
508
+ raise TypeError("extension must be an ExtensionType")
509
+
510
+ extension = Extension(extval.oid, critical, extval)
511
+ _reject_duplicate_extension(extension, self._extensions)
512
+
513
+ return CertificateBuilder(
514
+ self._issuer_name,
515
+ self._subject_name,
516
+ self._public_key,
517
+ self._serial_number,
518
+ self._not_valid_before,
519
+ self._not_valid_after,
520
+ [*self._extensions, extension],
521
+ self._public_key_rsa_padding,
522
+ )
523
+
524
+ def sign(
525
+ self,
526
+ private_key: CertificateIssuerPrivateKeyTypes,
527
+ algorithm: _AllowedHashTypes | None,
528
+ backend: typing.Any = None,
529
+ *,
530
+ rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
531
+ ecdsa_deterministic: bool | None = None,
532
+ ) -> Certificate:
533
+ """
534
+ Signs the certificate using the CA's private key.
535
+ """
536
+ if self._subject_name is None:
537
+ raise ValueError("A certificate must have a subject name")
538
+
539
+ if self._issuer_name is None:
540
+ raise ValueError("A certificate must have an issuer name")
541
+
542
+ if self._serial_number is None:
543
+ raise ValueError("A certificate must have a serial number")
544
+
545
+ if self._not_valid_before is None:
546
+ raise ValueError("A certificate must have a not valid before time")
547
+
548
+ if self._not_valid_after is None:
549
+ raise ValueError("A certificate must have a not valid after time")
550
+
551
+ if self._public_key is None:
552
+ raise ValueError("A certificate must have a public key")
553
+
554
+ if private_key is None:
555
+ raise TypeError("Need private key to sign certificate")
556
+
557
+ if rsa_padding is not None:
558
+ if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
559
+ raise TypeError("Padding must be PSS or PKCS1v15")
560
+ if not isinstance(private_key, rsa.RSAPrivateKey):
561
+ raise TypeError("Padding is only supported for RSA keys")
562
+
563
+ if ecdsa_deterministic is not None:
564
+ if not isinstance(private_key, ec.EllipticCurvePrivateKey):
565
+ raise TypeError(
566
+ "Deterministic ECDSA is only supported for EC keys"
567
+ )
568
+
569
+ return rust_x509.create_x509_certificate(
570
+ self,
571
+ private_key,
572
+ algorithm,
573
+ rsa_padding,
574
+ ecdsa_deterministic,
575
+ )
576
+
577
+ def create_unsigned(self) -> Certificate:
578
+ """
579
+ Creates an unsigned certificate, per RFC 9925.
580
+ """
581
+ if self._subject_name is None:
582
+ raise ValueError("A certificate must have a subject name")
583
+
584
+ if self._issuer_name is None:
585
+ raise ValueError("A certificate must have an issuer name")
586
+
587
+ if self._serial_number is None:
588
+ raise ValueError("A certificate must have a serial number")
589
+
590
+ if self._not_valid_before is None:
591
+ raise ValueError("A certificate must have a not valid before time")
592
+
593
+ if self._not_valid_after is None:
594
+ raise ValueError("A certificate must have a not valid after time")
595
+
596
+ if self._public_key is None:
597
+ raise ValueError("A certificate must have a public key")
598
+
599
+ return rust_x509.create_x509_certificate(
600
+ self,
601
+ private_key=None,
602
+ hash_algorithm=None,
603
+ rsa_padding=None,
604
+ ecdsa_deterministic=None,
605
+ )
606
+
607
+
608
+ class CertificateRevocationListBuilder:
609
+ _extensions: list[Extension[ExtensionType]]
610
+ _revoked_certificates: list[RevokedCertificate]
611
+
612
+ def __init__(
613
+ self,
614
+ issuer_name: Name | None = None,
615
+ last_update: datetime.datetime | None = None,
616
+ next_update: datetime.datetime | None = None,
617
+ extensions: list[Extension[ExtensionType]] = [],
618
+ revoked_certificates: list[RevokedCertificate] = [],
619
+ ):
620
+ self._issuer_name = issuer_name
621
+ self._last_update = last_update
622
+ self._next_update = next_update
623
+ self._extensions = extensions
624
+ self._revoked_certificates = revoked_certificates
625
+
626
+ def issuer_name(
627
+ self, issuer_name: Name
628
+ ) -> CertificateRevocationListBuilder:
629
+ if not isinstance(issuer_name, Name):
630
+ raise TypeError("Expecting x509.Name object.")
631
+ if self._issuer_name is not None:
632
+ raise ValueError("The issuer name may only be set once.")
633
+ return CertificateRevocationListBuilder(
634
+ issuer_name,
635
+ self._last_update,
636
+ self._next_update,
637
+ self._extensions,
638
+ self._revoked_certificates,
639
+ )
640
+
641
+ def last_update(
642
+ self, last_update: datetime.datetime
643
+ ) -> CertificateRevocationListBuilder:
644
+ if not isinstance(last_update, datetime.datetime):
645
+ raise TypeError("Expecting datetime object.")
646
+ if self._last_update is not None:
647
+ raise ValueError("Last update may only be set once.")
648
+ last_update = _convert_to_naive_utc_time(last_update)
649
+ if last_update < _EARLIEST_UTC_TIME:
650
+ raise ValueError(
651
+ "The last update date must be on or after 1950 January 1."
652
+ )
653
+ if self._next_update is not None and last_update > self._next_update:
654
+ raise ValueError(
655
+ "The last update date must be before the next update date."
656
+ )
657
+ return CertificateRevocationListBuilder(
658
+ self._issuer_name,
659
+ last_update,
660
+ self._next_update,
661
+ self._extensions,
662
+ self._revoked_certificates,
663
+ )
664
+
665
+ def next_update(
666
+ self, next_update: datetime.datetime
667
+ ) -> CertificateRevocationListBuilder:
668
+ if not isinstance(next_update, datetime.datetime):
669
+ raise TypeError("Expecting datetime object.")
670
+ if self._next_update is not None:
671
+ raise ValueError("Last update may only be set once.")
672
+ next_update = _convert_to_naive_utc_time(next_update)
673
+ if next_update < _EARLIEST_UTC_TIME:
674
+ raise ValueError(
675
+ "The last update date must be on or after 1950 January 1."
676
+ )
677
+ if self._last_update is not None and next_update < self._last_update:
678
+ raise ValueError(
679
+ "The next update date must be after the last update date."
680
+ )
681
+ return CertificateRevocationListBuilder(
682
+ self._issuer_name,
683
+ self._last_update,
684
+ next_update,
685
+ self._extensions,
686
+ self._revoked_certificates,
687
+ )
688
+
689
+ def add_extension(
690
+ self, extval: ExtensionType, critical: bool
691
+ ) -> CertificateRevocationListBuilder:
692
+ """
693
+ Adds an X.509 extension to the certificate revocation list.
694
+ """
695
+ if not isinstance(extval, ExtensionType):
696
+ raise TypeError("extension must be an ExtensionType")
697
+
698
+ extension = Extension(extval.oid, critical, extval)
699
+ _reject_duplicate_extension(extension, self._extensions)
700
+ return CertificateRevocationListBuilder(
701
+ self._issuer_name,
702
+ self._last_update,
703
+ self._next_update,
704
+ [*self._extensions, extension],
705
+ self._revoked_certificates,
706
+ )
707
+
708
+ def add_revoked_certificate(
709
+ self, revoked_certificate: RevokedCertificate
710
+ ) -> CertificateRevocationListBuilder:
711
+ """
712
+ Adds a revoked certificate to the CRL.
713
+ """
714
+ if not isinstance(revoked_certificate, RevokedCertificate):
715
+ raise TypeError("Must be an instance of RevokedCertificate")
716
+
717
+ return CertificateRevocationListBuilder(
718
+ self._issuer_name,
719
+ self._last_update,
720
+ self._next_update,
721
+ self._extensions,
722
+ [*self._revoked_certificates, revoked_certificate],
723
+ )
724
+
725
+ def sign(
726
+ self,
727
+ private_key: CertificateIssuerPrivateKeyTypes,
728
+ algorithm: _AllowedHashTypes | None,
729
+ backend: typing.Any = None,
730
+ *,
731
+ rsa_padding: padding.PSS | padding.PKCS1v15 | None = None,
732
+ ecdsa_deterministic: bool | None = None,
733
+ ) -> CertificateRevocationList:
734
+ if self._issuer_name is None:
735
+ raise ValueError("A CRL must have an issuer name")
736
+
737
+ if self._last_update is None:
738
+ raise ValueError("A CRL must have a last update time")
739
+
740
+ if self._next_update is None:
741
+ raise ValueError("A CRL must have a next update time")
742
+
743
+ if rsa_padding is not None:
744
+ if not isinstance(rsa_padding, (padding.PSS, padding.PKCS1v15)):
745
+ raise TypeError("Padding must be PSS or PKCS1v15")
746
+ if not isinstance(private_key, rsa.RSAPrivateKey):
747
+ raise TypeError("Padding is only supported for RSA keys")
748
+
749
+ if ecdsa_deterministic is not None:
750
+ if not isinstance(private_key, ec.EllipticCurvePrivateKey):
751
+ raise TypeError(
752
+ "Deterministic ECDSA is only supported for EC keys"
753
+ )
754
+
755
+ return rust_x509.create_x509_crl(
756
+ self,
757
+ private_key,
758
+ algorithm,
759
+ rsa_padding,
760
+ ecdsa_deterministic,
761
+ )
762
+
763
+
764
+ class RevokedCertificateBuilder:
765
+ def __init__(
766
+ self,
767
+ serial_number: int | None = None,
768
+ revocation_date: datetime.datetime | None = None,
769
+ extensions: list[Extension[ExtensionType]] = [],
770
+ ):
771
+ self._serial_number = serial_number
772
+ self._revocation_date = revocation_date
773
+ self._extensions = extensions
774
+
775
+ def serial_number(self, number: int) -> RevokedCertificateBuilder:
776
+ if not isinstance(number, int):
777
+ raise TypeError("Serial number must be of integral type.")
778
+ if self._serial_number is not None:
779
+ raise ValueError("The serial number may only be set once.")
780
+ if number <= 0:
781
+ raise ValueError("The serial number should be positive")
782
+
783
+ # ASN.1 integers are always signed, so most significant bit must be
784
+ # zero.
785
+ if number.bit_length() >= 160: # As defined in RFC 5280
786
+ raise ValueError(
787
+ "The serial number should not be more than 159 bits."
788
+ )
789
+ return RevokedCertificateBuilder(
790
+ number, self._revocation_date, self._extensions
791
+ )
792
+
793
+ def revocation_date(
794
+ self, time: datetime.datetime
795
+ ) -> RevokedCertificateBuilder:
796
+ if not isinstance(time, datetime.datetime):
797
+ raise TypeError("Expecting datetime object.")
798
+ if self._revocation_date is not None:
799
+ raise ValueError("The revocation date may only be set once.")
800
+ time = _convert_to_naive_utc_time(time)
801
+ if time < _EARLIEST_UTC_TIME:
802
+ raise ValueError(
803
+ "The revocation date must be on or after 1950 January 1."
804
+ )
805
+ return RevokedCertificateBuilder(
806
+ self._serial_number, time, self._extensions
807
+ )
808
+
809
+ def add_extension(
810
+ self, extval: ExtensionType, critical: bool
811
+ ) -> RevokedCertificateBuilder:
812
+ if not isinstance(extval, ExtensionType):
813
+ raise TypeError("extension must be an ExtensionType")
814
+
815
+ extension = Extension(extval.oid, critical, extval)
816
+ _reject_duplicate_extension(extension, self._extensions)
817
+ return RevokedCertificateBuilder(
818
+ self._serial_number,
819
+ self._revocation_date,
820
+ [*self._extensions, extension],
821
+ )
822
+
823
+ def build(self, backend: typing.Any = None) -> RevokedCertificate:
824
+ if self._serial_number is None:
825
+ raise ValueError("A revoked certificate must have a serial number")
826
+ if self._revocation_date is None:
827
+ raise ValueError(
828
+ "A revoked certificate must have a revocation date"
829
+ )
830
+ return rust_x509.create_revoked_certificate(self)
831
+
832
+
833
+ def random_serial_number() -> int:
834
+ return int.from_bytes(os.urandom(20), "big") >> 1
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/certificate_transparency.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography import utils
8
+ from cryptography.hazmat.bindings._rust import x509 as rust_x509
9
+
10
+
11
+ class LogEntryType(utils.Enum):
12
+ X509_CERTIFICATE = 0
13
+ PRE_CERTIFICATE = 1
14
+
15
+
16
+ class Version(utils.Enum):
17
+ v1 = 0
18
+
19
+
20
+ class SignatureAlgorithm(utils.Enum):
21
+ """
22
+ Signature algorithms that are valid for SCTs.
23
+
24
+ These are exactly the same as SignatureAlgorithm in RFC 5246 (TLS 1.2).
25
+
26
+ See: <https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.1.4.1>
27
+ """
28
+
29
+ ANONYMOUS = 0
30
+ RSA = 1
31
+ DSA = 2
32
+ ECDSA = 3
33
+
34
+
35
+ SignedCertificateTimestamp = rust_x509.Sct
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/extensions.py ADDED
@@ -0,0 +1,2533 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 _serialization, constant_time
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] # type: ignore[return-value,unused-ignore]
1562
+ return list(objs) # type: ignore[return-value,unused-ignore]
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
+ if self.full_name is not None:
2115
+ full_name: tuple[GeneralName, ...] | None = tuple(self.full_name)
2116
+ else:
2117
+ full_name = None
2118
+
2119
+ return hash(
2120
+ (
2121
+ full_name,
2122
+ self.relative_name,
2123
+ self.only_contains_user_certs,
2124
+ self.only_contains_ca_certs,
2125
+ self.only_some_reasons,
2126
+ self.indirect_crl,
2127
+ self.only_contains_attribute_certs,
2128
+ )
2129
+ )
2130
+
2131
+ @property
2132
+ def full_name(self) -> list[GeneralName] | None:
2133
+ return self._full_name
2134
+
2135
+ @property
2136
+ def relative_name(self) -> RelativeDistinguishedName | None:
2137
+ return self._relative_name
2138
+
2139
+ @property
2140
+ def only_contains_user_certs(self) -> bool:
2141
+ return self._only_contains_user_certs
2142
+
2143
+ @property
2144
+ def only_contains_ca_certs(self) -> bool:
2145
+ return self._only_contains_ca_certs
2146
+
2147
+ @property
2148
+ def only_some_reasons(
2149
+ self,
2150
+ ) -> frozenset[ReasonFlags] | None:
2151
+ return self._only_some_reasons
2152
+
2153
+ @property
2154
+ def indirect_crl(self) -> bool:
2155
+ return self._indirect_crl
2156
+
2157
+ @property
2158
+ def only_contains_attribute_certs(self) -> bool:
2159
+ return self._only_contains_attribute_certs
2160
+
2161
+ def public_bytes(self) -> bytes:
2162
+ return rust_x509.encode_extension_value(self)
2163
+
2164
+
2165
+ class MSCertificateTemplate(ExtensionType):
2166
+ oid = ExtensionOID.MS_CERTIFICATE_TEMPLATE
2167
+
2168
+ def __init__(
2169
+ self,
2170
+ template_id: ObjectIdentifier,
2171
+ major_version: int | None,
2172
+ minor_version: int | None,
2173
+ ) -> None:
2174
+ if not isinstance(template_id, ObjectIdentifier):
2175
+ raise TypeError("oid must be an ObjectIdentifier")
2176
+ self._template_id = template_id
2177
+ if (
2178
+ major_version is not None and not isinstance(major_version, int)
2179
+ ) or (
2180
+ minor_version is not None and not isinstance(minor_version, int)
2181
+ ):
2182
+ raise TypeError(
2183
+ "major_version and minor_version must be integers or None"
2184
+ )
2185
+ self._major_version = major_version
2186
+ self._minor_version = minor_version
2187
+
2188
+ @property
2189
+ def template_id(self) -> ObjectIdentifier:
2190
+ return self._template_id
2191
+
2192
+ @property
2193
+ def major_version(self) -> int | None:
2194
+ return self._major_version
2195
+
2196
+ @property
2197
+ def minor_version(self) -> int | None:
2198
+ return self._minor_version
2199
+
2200
+ def __repr__(self) -> str:
2201
+ return (
2202
+ f"<MSCertificateTemplate(template_id={self.template_id}, "
2203
+ f"major_version={self.major_version}, "
2204
+ f"minor_version={self.minor_version})>"
2205
+ )
2206
+
2207
+ def __eq__(self, other: object) -> bool:
2208
+ if not isinstance(other, MSCertificateTemplate):
2209
+ return NotImplemented
2210
+
2211
+ return (
2212
+ self.template_id == other.template_id
2213
+ and self.major_version == other.major_version
2214
+ and self.minor_version == other.minor_version
2215
+ )
2216
+
2217
+ def __hash__(self) -> int:
2218
+ return hash((self.template_id, self.major_version, self.minor_version))
2219
+
2220
+ def public_bytes(self) -> bytes:
2221
+ return rust_x509.encode_extension_value(self)
2222
+
2223
+
2224
+ class NamingAuthority:
2225
+ def __init__(
2226
+ self,
2227
+ id: ObjectIdentifier | None,
2228
+ url: str | None,
2229
+ text: str | None,
2230
+ ) -> None:
2231
+ if id is not None and not isinstance(id, ObjectIdentifier):
2232
+ raise TypeError("id must be an ObjectIdentifier")
2233
+
2234
+ if url is not None and not isinstance(url, str):
2235
+ raise TypeError("url must be a str")
2236
+
2237
+ if text is not None and not isinstance(text, str):
2238
+ raise TypeError("text must be a str")
2239
+
2240
+ self._id = id
2241
+ self._url = url
2242
+ self._text = text
2243
+
2244
+ @property
2245
+ def id(self) -> ObjectIdentifier | None:
2246
+ return self._id
2247
+
2248
+ @property
2249
+ def url(self) -> str | None:
2250
+ return self._url
2251
+
2252
+ @property
2253
+ def text(self) -> str | None:
2254
+ return self._text
2255
+
2256
+ def __repr__(self) -> str:
2257
+ return (
2258
+ f"<NamingAuthority("
2259
+ f"id={self.id}, url={self.url}, text={self.text})>"
2260
+ )
2261
+
2262
+ def __eq__(self, other: object) -> bool:
2263
+ if not isinstance(other, NamingAuthority):
2264
+ return NotImplemented
2265
+
2266
+ return (
2267
+ self.id == other.id
2268
+ and self.url == other.url
2269
+ and self.text == other.text
2270
+ )
2271
+
2272
+ def __hash__(self) -> int:
2273
+ return hash(
2274
+ (
2275
+ self.id,
2276
+ self.url,
2277
+ self.text,
2278
+ )
2279
+ )
2280
+
2281
+
2282
+ class ProfessionInfo:
2283
+ def __init__(
2284
+ self,
2285
+ naming_authority: NamingAuthority | None,
2286
+ profession_items: Iterable[str],
2287
+ profession_oids: Iterable[ObjectIdentifier] | None,
2288
+ registration_number: str | None,
2289
+ add_profession_info: bytes | None,
2290
+ ) -> None:
2291
+ if naming_authority is not None and not isinstance(
2292
+ naming_authority, NamingAuthority
2293
+ ):
2294
+ raise TypeError("naming_authority must be a NamingAuthority")
2295
+
2296
+ profession_items = list(profession_items)
2297
+ if not all(isinstance(item, str) for item in profession_items):
2298
+ raise TypeError(
2299
+ "Every item in the profession_items list must be a str"
2300
+ )
2301
+
2302
+ if profession_oids is not None:
2303
+ profession_oids = list(profession_oids)
2304
+ if not all(
2305
+ isinstance(oid, ObjectIdentifier) for oid in profession_oids
2306
+ ):
2307
+ raise TypeError(
2308
+ "Every item in the profession_oids list must be an "
2309
+ "ObjectIdentifier"
2310
+ )
2311
+
2312
+ if registration_number is not None and not isinstance(
2313
+ registration_number, str
2314
+ ):
2315
+ raise TypeError("registration_number must be a str")
2316
+
2317
+ if add_profession_info is not None and not isinstance(
2318
+ add_profession_info, bytes
2319
+ ):
2320
+ raise TypeError("add_profession_info must be bytes")
2321
+
2322
+ self._naming_authority = naming_authority
2323
+ self._profession_items = profession_items
2324
+ self._profession_oids = profession_oids
2325
+ self._registration_number = registration_number
2326
+ self._add_profession_info = add_profession_info
2327
+
2328
+ @property
2329
+ def naming_authority(self) -> NamingAuthority | None:
2330
+ return self._naming_authority
2331
+
2332
+ @property
2333
+ def profession_items(self) -> list[str]:
2334
+ return self._profession_items
2335
+
2336
+ @property
2337
+ def profession_oids(self) -> list[ObjectIdentifier] | None:
2338
+ return self._profession_oids
2339
+
2340
+ @property
2341
+ def registration_number(self) -> str | None:
2342
+ return self._registration_number
2343
+
2344
+ @property
2345
+ def add_profession_info(self) -> bytes | None:
2346
+ return self._add_profession_info
2347
+
2348
+ def __repr__(self) -> str:
2349
+ return (
2350
+ f"<ProfessionInfo(naming_authority={self.naming_authority}, "
2351
+ f"profession_items={self.profession_items}, "
2352
+ f"profession_oids={self.profession_oids}, "
2353
+ f"registration_number={self.registration_number}, "
2354
+ f"add_profession_info={self.add_profession_info!r})>"
2355
+ )
2356
+
2357
+ def __eq__(self, other: object) -> bool:
2358
+ if not isinstance(other, ProfessionInfo):
2359
+ return NotImplemented
2360
+
2361
+ return (
2362
+ self.naming_authority == other.naming_authority
2363
+ and self.profession_items == other.profession_items
2364
+ and self.profession_oids == other.profession_oids
2365
+ and self.registration_number == other.registration_number
2366
+ and self.add_profession_info == other.add_profession_info
2367
+ )
2368
+
2369
+ def __hash__(self) -> int:
2370
+ if self.profession_oids is not None:
2371
+ profession_oids = tuple(self.profession_oids)
2372
+ else:
2373
+ profession_oids = None
2374
+ return hash(
2375
+ (
2376
+ self.naming_authority,
2377
+ tuple(self.profession_items),
2378
+ profession_oids,
2379
+ self.registration_number,
2380
+ self.add_profession_info,
2381
+ )
2382
+ )
2383
+
2384
+
2385
+ class Admission:
2386
+ def __init__(
2387
+ self,
2388
+ admission_authority: GeneralName | None,
2389
+ naming_authority: NamingAuthority | None,
2390
+ profession_infos: Iterable[ProfessionInfo],
2391
+ ) -> None:
2392
+ if admission_authority is not None and not isinstance(
2393
+ admission_authority, GeneralName
2394
+ ):
2395
+ raise TypeError("admission_authority must be a GeneralName")
2396
+
2397
+ if naming_authority is not None and not isinstance(
2398
+ naming_authority, NamingAuthority
2399
+ ):
2400
+ raise TypeError("naming_authority must be a NamingAuthority")
2401
+
2402
+ profession_infos = list(profession_infos)
2403
+ if not all(
2404
+ isinstance(info, ProfessionInfo) for info in profession_infos
2405
+ ):
2406
+ raise TypeError(
2407
+ "Every item in the profession_infos list must be a "
2408
+ "ProfessionInfo"
2409
+ )
2410
+
2411
+ self._admission_authority = admission_authority
2412
+ self._naming_authority = naming_authority
2413
+ self._profession_infos = profession_infos
2414
+
2415
+ @property
2416
+ def admission_authority(self) -> GeneralName | None:
2417
+ return self._admission_authority
2418
+
2419
+ @property
2420
+ def naming_authority(self) -> NamingAuthority | None:
2421
+ return self._naming_authority
2422
+
2423
+ @property
2424
+ def profession_infos(self) -> list[ProfessionInfo]:
2425
+ return self._profession_infos
2426
+
2427
+ def __repr__(self) -> str:
2428
+ return (
2429
+ f"<Admission(admission_authority={self.admission_authority}, "
2430
+ f"naming_authority={self.naming_authority}, "
2431
+ f"profession_infos={self.profession_infos})>"
2432
+ )
2433
+
2434
+ def __eq__(self, other: object) -> bool:
2435
+ if not isinstance(other, Admission):
2436
+ return NotImplemented
2437
+
2438
+ return (
2439
+ self.admission_authority == other.admission_authority
2440
+ and self.naming_authority == other.naming_authority
2441
+ and self.profession_infos == other.profession_infos
2442
+ )
2443
+
2444
+ def __hash__(self) -> int:
2445
+ return hash(
2446
+ (
2447
+ self.admission_authority,
2448
+ self.naming_authority,
2449
+ tuple(self.profession_infos),
2450
+ )
2451
+ )
2452
+
2453
+
2454
+ class Admissions(ExtensionType):
2455
+ oid = ExtensionOID.ADMISSIONS
2456
+
2457
+ def __init__(
2458
+ self,
2459
+ authority: GeneralName | None,
2460
+ admissions: Iterable[Admission],
2461
+ ) -> None:
2462
+ if authority is not None and not isinstance(authority, GeneralName):
2463
+ raise TypeError("authority must be a GeneralName")
2464
+
2465
+ admissions = list(admissions)
2466
+ if not all(
2467
+ isinstance(admission, Admission) for admission in admissions
2468
+ ):
2469
+ raise TypeError(
2470
+ "Every item in the contents_of_admissions list must be an "
2471
+ "Admission"
2472
+ )
2473
+
2474
+ self._authority = authority
2475
+ self._admissions = admissions
2476
+
2477
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_admissions")
2478
+
2479
+ @property
2480
+ def authority(self) -> GeneralName | None:
2481
+ return self._authority
2482
+
2483
+ def __repr__(self) -> str:
2484
+ return (
2485
+ f"<Admissions(authority={self._authority}, "
2486
+ f"admissions={self._admissions})>"
2487
+ )
2488
+
2489
+ def __eq__(self, other: object) -> bool:
2490
+ if not isinstance(other, Admissions):
2491
+ return NotImplemented
2492
+
2493
+ return (
2494
+ self.authority == other.authority
2495
+ and self._admissions == other._admissions
2496
+ )
2497
+
2498
+ def __hash__(self) -> int:
2499
+ return hash((self.authority, tuple(self._admissions)))
2500
+
2501
+ def public_bytes(self) -> bytes:
2502
+ return rust_x509.encode_extension_value(self)
2503
+
2504
+
2505
+ class UnrecognizedExtension(ExtensionType):
2506
+ def __init__(self, oid: ObjectIdentifier, value: bytes) -> None:
2507
+ if not isinstance(oid, ObjectIdentifier):
2508
+ raise TypeError("oid must be an ObjectIdentifier")
2509
+ self._oid = oid
2510
+ self._value = value
2511
+
2512
+ @property
2513
+ def oid(self) -> ObjectIdentifier: # type: ignore[override]
2514
+ return self._oid
2515
+
2516
+ @property
2517
+ def value(self) -> bytes:
2518
+ return self._value
2519
+
2520
+ def __repr__(self) -> str:
2521
+ return f"<UnrecognizedExtension(oid={self.oid}, value={self.value!r})>"
2522
+
2523
+ def __eq__(self, other: object) -> bool:
2524
+ if not isinstance(other, UnrecognizedExtension):
2525
+ return NotImplemented
2526
+
2527
+ return self.oid == other.oid and self.value == other.value
2528
+
2529
+ def __hash__(self) -> int:
2530
+ return hash((self.oid, self.value))
2531
+
2532
+ def public_bytes(self) -> bytes:
2533
+ return self.value
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/general_name.py ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ipaddress
9
+ import typing
10
+ from email.utils import parseaddr
11
+
12
+ from cryptography.x509.name import Name
13
+ from cryptography.x509.oid import ObjectIdentifier
14
+
15
+ _IPAddressTypes = typing.Union[
16
+ ipaddress.IPv4Address,
17
+ ipaddress.IPv6Address,
18
+ ipaddress.IPv4Network,
19
+ ipaddress.IPv6Network,
20
+ ]
21
+
22
+
23
+ class UnsupportedGeneralNameType(Exception):
24
+ pass
25
+
26
+
27
+ class GeneralName(metaclass=abc.ABCMeta):
28
+ @property
29
+ @abc.abstractmethod
30
+ def value(self) -> typing.Any:
31
+ """
32
+ Return the value of the object
33
+ """
34
+
35
+
36
+ class RFC822Name(GeneralName):
37
+ def __init__(self, value: str) -> None:
38
+ if isinstance(value, str):
39
+ try:
40
+ value.encode("ascii")
41
+ except UnicodeEncodeError:
42
+ raise ValueError(
43
+ "RFC822Name values should be passed as an A-label string. "
44
+ "This means unicode characters should be encoded via "
45
+ "a library like idna."
46
+ )
47
+ else:
48
+ raise TypeError("value must be string")
49
+
50
+ name, address = parseaddr(value)
51
+ if name or not address:
52
+ # parseaddr has found a name (e.g. Name <email>) or the entire
53
+ # value is an empty string.
54
+ raise ValueError("Invalid rfc822name value")
55
+
56
+ self._value = value
57
+
58
+ @property
59
+ def value(self) -> str:
60
+ return self._value
61
+
62
+ @classmethod
63
+ def _init_without_validation(cls, value: str) -> RFC822Name:
64
+ instance = cls.__new__(cls)
65
+ instance._value = value
66
+ return instance
67
+
68
+ def __repr__(self) -> str:
69
+ return f"<RFC822Name(value={self.value!r})>"
70
+
71
+ def __eq__(self, other: object) -> bool:
72
+ if not isinstance(other, RFC822Name):
73
+ return NotImplemented
74
+
75
+ return self.value == other.value
76
+
77
+ def __hash__(self) -> int:
78
+ return hash(self.value)
79
+
80
+
81
+ class DNSName(GeneralName):
82
+ def __init__(self, value: str) -> None:
83
+ if isinstance(value, str):
84
+ try:
85
+ value.encode("ascii")
86
+ except UnicodeEncodeError:
87
+ raise ValueError(
88
+ "DNSName values should be passed as an A-label string. "
89
+ "This means unicode characters should be encoded via "
90
+ "a library like idna."
91
+ )
92
+ else:
93
+ raise TypeError("value must be string")
94
+
95
+ self._value = value
96
+
97
+ @property
98
+ def value(self) -> str:
99
+ return self._value
100
+
101
+ @classmethod
102
+ def _init_without_validation(cls, value: str) -> DNSName:
103
+ instance = cls.__new__(cls)
104
+ instance._value = value
105
+ return instance
106
+
107
+ def __repr__(self) -> str:
108
+ return f"<DNSName(value={self.value!r})>"
109
+
110
+ def __eq__(self, other: object) -> bool:
111
+ if not isinstance(other, DNSName):
112
+ return NotImplemented
113
+
114
+ return self.value == other.value
115
+
116
+ def __hash__(self) -> int:
117
+ return hash(self.value)
118
+
119
+
120
+ class UniformResourceIdentifier(GeneralName):
121
+ def __init__(self, value: str) -> None:
122
+ if isinstance(value, str):
123
+ try:
124
+ value.encode("ascii")
125
+ except UnicodeEncodeError:
126
+ raise ValueError(
127
+ "URI values should be passed as an A-label string. "
128
+ "This means unicode characters should be encoded via "
129
+ "a library like idna."
130
+ )
131
+ else:
132
+ raise TypeError("value must be string")
133
+
134
+ self._value = value
135
+
136
+ @property
137
+ def value(self) -> str:
138
+ return self._value
139
+
140
+ @classmethod
141
+ def _init_without_validation(cls, value: str) -> UniformResourceIdentifier:
142
+ instance = cls.__new__(cls)
143
+ instance._value = value
144
+ return instance
145
+
146
+ def __repr__(self) -> str:
147
+ return f"<UniformResourceIdentifier(value={self.value!r})>"
148
+
149
+ def __eq__(self, other: object) -> bool:
150
+ if not isinstance(other, UniformResourceIdentifier):
151
+ return NotImplemented
152
+
153
+ return self.value == other.value
154
+
155
+ def __hash__(self) -> int:
156
+ return hash(self.value)
157
+
158
+
159
+ class DirectoryName(GeneralName):
160
+ def __init__(self, value: Name) -> None:
161
+ if not isinstance(value, Name):
162
+ raise TypeError("value must be a Name")
163
+
164
+ self._value = value
165
+
166
+ @property
167
+ def value(self) -> Name:
168
+ return self._value
169
+
170
+ def __repr__(self) -> str:
171
+ return f"<DirectoryName(value={self.value})>"
172
+
173
+ def __eq__(self, other: object) -> bool:
174
+ if not isinstance(other, DirectoryName):
175
+ return NotImplemented
176
+
177
+ return self.value == other.value
178
+
179
+ def __hash__(self) -> int:
180
+ return hash(self.value)
181
+
182
+
183
+ class RegisteredID(GeneralName):
184
+ def __init__(self, value: ObjectIdentifier) -> None:
185
+ if not isinstance(value, ObjectIdentifier):
186
+ raise TypeError("value must be an ObjectIdentifier")
187
+
188
+ self._value = value
189
+
190
+ @property
191
+ def value(self) -> ObjectIdentifier:
192
+ return self._value
193
+
194
+ def __repr__(self) -> str:
195
+ return f"<RegisteredID(value={self.value})>"
196
+
197
+ def __eq__(self, other: object) -> bool:
198
+ if not isinstance(other, RegisteredID):
199
+ return NotImplemented
200
+
201
+ return self.value == other.value
202
+
203
+ def __hash__(self) -> int:
204
+ return hash(self.value)
205
+
206
+
207
+ class IPAddress(GeneralName):
208
+ def __init__(self, value: _IPAddressTypes) -> None:
209
+ if not isinstance(
210
+ value,
211
+ (
212
+ ipaddress.IPv4Address,
213
+ ipaddress.IPv6Address,
214
+ ipaddress.IPv4Network,
215
+ ipaddress.IPv6Network,
216
+ ),
217
+ ):
218
+ raise TypeError(
219
+ "value must be an instance of ipaddress.IPv4Address, "
220
+ "ipaddress.IPv6Address, ipaddress.IPv4Network, or "
221
+ "ipaddress.IPv6Network"
222
+ )
223
+
224
+ self._value = value
225
+
226
+ @property
227
+ def value(self) -> _IPAddressTypes:
228
+ return self._value
229
+
230
+ def _packed(self) -> bytes:
231
+ if isinstance(
232
+ self.value, (ipaddress.IPv4Address, ipaddress.IPv6Address)
233
+ ):
234
+ return self.value.packed
235
+ else:
236
+ return (
237
+ self.value.network_address.packed + self.value.netmask.packed
238
+ )
239
+
240
+ def __repr__(self) -> str:
241
+ return f"<IPAddress(value={self.value})>"
242
+
243
+ def __eq__(self, other: object) -> bool:
244
+ if not isinstance(other, IPAddress):
245
+ return NotImplemented
246
+
247
+ return self.value == other.value
248
+
249
+ def __hash__(self) -> int:
250
+ return hash(self.value)
251
+
252
+
253
+ class OtherName(GeneralName):
254
+ def __init__(self, type_id: ObjectIdentifier, value: bytes) -> None:
255
+ if not isinstance(type_id, ObjectIdentifier):
256
+ raise TypeError("type_id must be an ObjectIdentifier")
257
+ if not isinstance(value, bytes):
258
+ raise TypeError("value must be a binary string")
259
+
260
+ self._type_id = type_id
261
+ self._value = value
262
+
263
+ @property
264
+ def type_id(self) -> ObjectIdentifier:
265
+ return self._type_id
266
+
267
+ @property
268
+ def value(self) -> bytes:
269
+ return self._value
270
+
271
+ def __repr__(self) -> str:
272
+ return f"<OtherName(type_id={self.type_id}, value={self.value!r})>"
273
+
274
+ def __eq__(self, other: object) -> bool:
275
+ if not isinstance(other, OtherName):
276
+ return NotImplemented
277
+
278
+ return self.type_id == other.type_id and self.value == other.value
279
+
280
+ def __hash__(self) -> int:
281
+ return hash((self.type_id, self.value))
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/name.py ADDED
@@ -0,0 +1,489 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 binascii
8
+ import re
9
+ import sys
10
+ import typing
11
+ import warnings
12
+ from collections.abc import Iterable, Iterator
13
+
14
+ from cryptography import utils
15
+ from cryptography.hazmat.bindings._rust import x509 as rust_x509
16
+ from cryptography.x509.oid import NameOID, ObjectIdentifier
17
+
18
+
19
+ class _ASN1Type(utils.Enum):
20
+ BitString = 3
21
+ OctetString = 4
22
+ UTF8String = 12
23
+ NumericString = 18
24
+ PrintableString = 19
25
+ T61String = 20
26
+ IA5String = 22
27
+ UTCTime = 23
28
+ GeneralizedTime = 24
29
+ VisibleString = 26
30
+ UniversalString = 28
31
+ BMPString = 30
32
+
33
+
34
+ _ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type}
35
+ _NAMEOID_DEFAULT_TYPE: dict[ObjectIdentifier, _ASN1Type] = {
36
+ NameOID.COUNTRY_NAME: _ASN1Type.PrintableString,
37
+ NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString,
38
+ NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString,
39
+ NameOID.DN_QUALIFIER: _ASN1Type.PrintableString,
40
+ NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String,
41
+ NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String,
42
+ }
43
+
44
+ # Type alias
45
+ _OidNameMap = typing.Mapping[ObjectIdentifier, str]
46
+ _NameOidMap = typing.Mapping[str, ObjectIdentifier]
47
+
48
+ #: Short attribute names from RFC 4514:
49
+ #: https://tools.ietf.org/html/rfc4514#page-7
50
+ _NAMEOID_TO_NAME: _OidNameMap = {
51
+ NameOID.COMMON_NAME: "CN",
52
+ NameOID.LOCALITY_NAME: "L",
53
+ NameOID.STATE_OR_PROVINCE_NAME: "ST",
54
+ NameOID.ORGANIZATION_NAME: "O",
55
+ NameOID.ORGANIZATIONAL_UNIT_NAME: "OU",
56
+ NameOID.COUNTRY_NAME: "C",
57
+ NameOID.STREET_ADDRESS: "STREET",
58
+ NameOID.DOMAIN_COMPONENT: "DC",
59
+ NameOID.USER_ID: "UID",
60
+ }
61
+ _NAME_TO_NAMEOID = {v: k for k, v in _NAMEOID_TO_NAME.items()}
62
+
63
+ _NAMEOID_LENGTH_LIMIT = {
64
+ NameOID.COUNTRY_NAME: (2, 2),
65
+ NameOID.JURISDICTION_COUNTRY_NAME: (2, 2),
66
+ NameOID.COMMON_NAME: (1, 64),
67
+ }
68
+
69
+
70
+ def _escape_dn_value(val: str | bytes) -> str:
71
+ """Escape special characters in RFC4514 Distinguished Name value."""
72
+
73
+ if not val:
74
+ return ""
75
+
76
+ # RFC 4514 Section 2.4 defines the value as being the # (U+0023) character
77
+ # followed by the hexadecimal encoding of the octets.
78
+ if isinstance(val, bytes):
79
+ return "#" + binascii.hexlify(val).decode("utf8")
80
+
81
+ # See https://tools.ietf.org/html/rfc4514#section-2.4
82
+ val = val.replace("\\", "\\\\")
83
+ val = val.replace('"', '\\"')
84
+ val = val.replace("+", "\\+")
85
+ val = val.replace(",", "\\,")
86
+ val = val.replace(";", "\\;")
87
+ val = val.replace("<", "\\<")
88
+ val = val.replace(">", "\\>")
89
+ val = val.replace("\0", "\\00")
90
+
91
+ if val[0] == "#" or (val[0] == " " and len(val) > 1):
92
+ val = "\\" + val
93
+ if val[-1] == " ":
94
+ val = val[:-1] + "\\ "
95
+
96
+ return val
97
+
98
+
99
+ def _unescape_dn_value(val: str) -> str:
100
+ if not val:
101
+ return ""
102
+
103
+ # See https://tools.ietf.org/html/rfc4514#section-3
104
+
105
+ # special = escaped / SPACE / SHARP / EQUALS
106
+ # escaped = DQUOTE / PLUS / COMMA / SEMI / LANGLE / RANGLE
107
+ def sub(m):
108
+ val = m.group(0)
109
+ # Special character escape
110
+ if len(val) == 2:
111
+ return val[1:]
112
+
113
+ # Unicode string of hex
114
+ return binascii.unhexlify(val.replace("\\", "")).decode()
115
+
116
+ return _RFC4514NameParser._PAIR_MULTI_RE.sub(sub, val)
117
+
118
+
119
+ NameAttributeValueType = typing.TypeVar(
120
+ "NameAttributeValueType",
121
+ typing.Union[str, bytes],
122
+ str,
123
+ bytes,
124
+ covariant=True,
125
+ )
126
+
127
+
128
+ class NameAttribute(typing.Generic[NameAttributeValueType]):
129
+ def __init__(
130
+ self,
131
+ oid: ObjectIdentifier,
132
+ value: NameAttributeValueType,
133
+ _type: _ASN1Type | None = None,
134
+ *,
135
+ _validate: bool = True,
136
+ ) -> None:
137
+ if not isinstance(oid, ObjectIdentifier):
138
+ raise TypeError(
139
+ "oid argument must be an ObjectIdentifier instance."
140
+ )
141
+ if _type == _ASN1Type.BitString:
142
+ if oid != NameOID.X500_UNIQUE_IDENTIFIER:
143
+ raise TypeError(
144
+ "oid must be X500_UNIQUE_IDENTIFIER for BitString type."
145
+ )
146
+ if not isinstance(value, bytes):
147
+ raise TypeError("value must be bytes for BitString")
148
+ elif not isinstance(value, str):
149
+ raise TypeError("value argument must be a str")
150
+
151
+ length_limits = _NAMEOID_LENGTH_LIMIT.get(oid)
152
+ if length_limits is not None:
153
+ min_length, max_length = length_limits
154
+ assert isinstance(value, str)
155
+ c_len = len(value.encode("utf8"))
156
+ if c_len < min_length or c_len > max_length:
157
+ msg = (
158
+ f"Attribute's length must be >= {min_length} and "
159
+ f"<= {max_length}, but it was {c_len}"
160
+ )
161
+ if _validate is True:
162
+ raise ValueError(msg)
163
+ else:
164
+ warnings.warn(msg, stacklevel=2)
165
+
166
+ # The appropriate ASN1 string type varies by OID and is defined across
167
+ # multiple RFCs including 2459, 3280, and 5280. In general UTF8String
168
+ # is preferred (2459), but 3280 and 5280 specify several OIDs with
169
+ # alternate types. This means when we see the sentinel value we need
170
+ # to look up whether the OID has a non-UTF8 type. If it does, set it
171
+ # to that. Otherwise, UTF8!
172
+ if _type is None:
173
+ _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String)
174
+
175
+ if not isinstance(_type, _ASN1Type):
176
+ raise TypeError("_type must be from the _ASN1Type enum")
177
+
178
+ self._oid = oid
179
+ self._value: NameAttributeValueType = value
180
+ self._type: _ASN1Type = _type
181
+
182
+ @property
183
+ def oid(self) -> ObjectIdentifier:
184
+ return self._oid
185
+
186
+ @property
187
+ def value(self) -> NameAttributeValueType:
188
+ return self._value
189
+
190
+ @property
191
+ def rfc4514_attribute_name(self) -> str:
192
+ """
193
+ The short attribute name (for example "CN") if available,
194
+ otherwise the OID dotted string.
195
+ """
196
+ return _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string)
197
+
198
+ def rfc4514_string(
199
+ self, attr_name_overrides: _OidNameMap | None = None
200
+ ) -> str:
201
+ """
202
+ Format as RFC4514 Distinguished Name string.
203
+
204
+ Use short attribute name if available, otherwise fall back to OID
205
+ dotted string.
206
+ """
207
+ attr_name = (
208
+ attr_name_overrides.get(self.oid) if attr_name_overrides else None
209
+ )
210
+ if attr_name is None:
211
+ attr_name = self.rfc4514_attribute_name
212
+
213
+ return f"{attr_name}={_escape_dn_value(self.value)}"
214
+
215
+ def __eq__(self, other: object) -> bool:
216
+ if not isinstance(other, NameAttribute):
217
+ return NotImplemented
218
+
219
+ return self.oid == other.oid and self.value == other.value
220
+
221
+ def __hash__(self) -> int:
222
+ return hash((self.oid, self.value))
223
+
224
+ def __repr__(self) -> str:
225
+ return f"<NameAttribute(oid={self.oid}, value={self.value!r})>"
226
+
227
+
228
+ class RelativeDistinguishedName:
229
+ def __init__(self, attributes: Iterable[NameAttribute[str | bytes]]):
230
+ attributes = list(attributes)
231
+ if not attributes:
232
+ raise ValueError("a relative distinguished name cannot be empty")
233
+ if not all(isinstance(x, NameAttribute) for x in attributes):
234
+ raise TypeError("attributes must be an iterable of NameAttribute")
235
+
236
+ # Keep list and frozenset to preserve attribute order where it matters
237
+ self._attributes = attributes
238
+ self._attribute_set = frozenset(attributes)
239
+
240
+ if len(self._attribute_set) != len(attributes):
241
+ raise ValueError("duplicate attributes are not allowed")
242
+
243
+ def get_attributes_for_oid(
244
+ self,
245
+ oid: ObjectIdentifier,
246
+ ) -> list[NameAttribute[str | bytes]]:
247
+ return [i for i in self if i.oid == oid]
248
+
249
+ def rfc4514_string(
250
+ self, attr_name_overrides: _OidNameMap | None = None
251
+ ) -> str:
252
+ """
253
+ Format as RFC4514 Distinguished Name string.
254
+
255
+ Within each RDN, attributes are joined by '+', although that is rarely
256
+ used in certificates.
257
+ """
258
+ return "+".join(
259
+ attr.rfc4514_string(attr_name_overrides)
260
+ for attr in self._attributes
261
+ )
262
+
263
+ def __eq__(self, other: object) -> bool:
264
+ if not isinstance(other, RelativeDistinguishedName):
265
+ return NotImplemented
266
+
267
+ return self._attribute_set == other._attribute_set
268
+
269
+ def __hash__(self) -> int:
270
+ return hash(self._attribute_set)
271
+
272
+ def __iter__(self) -> Iterator[NameAttribute[str | bytes]]:
273
+ return iter(self._attributes)
274
+
275
+ def __len__(self) -> int:
276
+ return len(self._attributes)
277
+
278
+ def __repr__(self) -> str:
279
+ return f"<RelativeDistinguishedName({self.rfc4514_string()})>"
280
+
281
+
282
+ class Name:
283
+ @typing.overload
284
+ def __init__(
285
+ self, attributes: Iterable[NameAttribute[str | bytes]]
286
+ ) -> None: ...
287
+
288
+ @typing.overload
289
+ def __init__(
290
+ self, attributes: Iterable[RelativeDistinguishedName]
291
+ ) -> None: ...
292
+
293
+ def __init__(
294
+ self,
295
+ attributes: Iterable[
296
+ NameAttribute[str | bytes] | RelativeDistinguishedName
297
+ ],
298
+ ) -> None:
299
+ attributes = list(attributes)
300
+ if all(isinstance(x, NameAttribute) for x in attributes):
301
+ self._attributes = [
302
+ RelativeDistinguishedName([typing.cast(NameAttribute, x)])
303
+ for x in attributes
304
+ ]
305
+ elif all(isinstance(x, RelativeDistinguishedName) for x in attributes):
306
+ self._attributes = typing.cast(
307
+ list[RelativeDistinguishedName], attributes
308
+ )
309
+ else:
310
+ raise TypeError(
311
+ "attributes must be a list of NameAttribute"
312
+ " or a list RelativeDistinguishedName"
313
+ )
314
+
315
+ @classmethod
316
+ def from_rfc4514_string(
317
+ cls,
318
+ data: str,
319
+ attr_name_overrides: _NameOidMap | None = None,
320
+ ) -> Name:
321
+ return _RFC4514NameParser(data, attr_name_overrides or {}).parse()
322
+
323
+ @classmethod
324
+ def from_bytes(cls, data: bytes) -> Name:
325
+ """
326
+ Parse a DER encoded X.509 name (the inverse of ``public_bytes``).
327
+ """
328
+ return rust_x509.parse_name_bytes(data)
329
+
330
+ def rfc4514_string(
331
+ self, attr_name_overrides: _OidNameMap | None = None
332
+ ) -> str:
333
+ """
334
+ Format as RFC4514 Distinguished Name string.
335
+ For example 'CN=foobar.com,O=Foo Corp,C=US'
336
+
337
+ An X.509 name is a two-level structure: a list of sets of attributes.
338
+ Each list element is separated by ',' and within each list element, set
339
+ elements are separated by '+'. The latter is almost never used in
340
+ real world certificates. According to RFC4514 section 2.1 the
341
+ RDNSequence must be reversed when converting to string representation.
342
+ """
343
+ return ",".join(
344
+ attr.rfc4514_string(attr_name_overrides)
345
+ for attr in reversed(self._attributes)
346
+ )
347
+
348
+ def get_attributes_for_oid(
349
+ self,
350
+ oid: ObjectIdentifier,
351
+ ) -> list[NameAttribute[str | bytes]]:
352
+ return [i for i in self if i.oid == oid]
353
+
354
+ @property
355
+ def rdns(self) -> list[RelativeDistinguishedName]:
356
+ return self._attributes
357
+
358
+ def public_bytes(self, backend: typing.Any = None) -> bytes:
359
+ return rust_x509.encode_name_bytes(self)
360
+
361
+ def __eq__(self, other: object) -> bool:
362
+ if not isinstance(other, Name):
363
+ return NotImplemented
364
+
365
+ return self._attributes == other._attributes
366
+
367
+ def __hash__(self) -> int:
368
+ # TODO: this is relatively expensive, if this looks like a bottleneck
369
+ # for you, consider optimizing!
370
+ return hash(tuple(self._attributes))
371
+
372
+ def __iter__(self) -> Iterator[NameAttribute[str | bytes]]:
373
+ for rdn in self._attributes:
374
+ yield from rdn
375
+
376
+ def __len__(self) -> int:
377
+ return sum(len(rdn) for rdn in self._attributes)
378
+
379
+ def __repr__(self) -> str:
380
+ return f"<Name({self.rfc4514_string()})>"
381
+
382
+
383
+ class _RFC4514NameParser:
384
+ _OID_RE = re.compile(r"(0|([1-9]\d*))(\.(0|([1-9]\d*)))+")
385
+ _DESCR_RE = re.compile(r"[a-zA-Z][a-zA-Z\d-]*")
386
+
387
+ _ESCAPE_SPECIAL = r"[\\ #=\"\+,;<>]"
388
+ _ESCAPE_HEX = r"[\da-zA-Z]{2}"
389
+ _PAIR = rf"\\({_ESCAPE_SPECIAL}|{_ESCAPE_HEX})"
390
+ _PAIR_MULTI_RE = re.compile(rf"(\\{_ESCAPE_SPECIAL})|((\\{_ESCAPE_HEX})+)")
391
+ _LUTF1 = r"[\x01-\x1f\x21\x24-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]"
392
+ _SUTF1 = r"[\x01-\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]"
393
+ _TUTF1 = r"[\x01-\x1F\x21\x23-\x2A\x2D-\x3A\x3D\x3F-\x5B\x5D-\x7F]"
394
+ _UTFMB = rf"[\x80-{chr(sys.maxunicode)}]"
395
+ _LEADCHAR = rf"{_LUTF1}|{_UTFMB}"
396
+ _STRINGCHAR = rf"{_SUTF1}|{_UTFMB}"
397
+ _TRAILCHAR = rf"{_TUTF1}|{_UTFMB}"
398
+ _STRING_RE = re.compile(
399
+ rf"""
400
+ (
401
+ ({_LEADCHAR}|{_PAIR})
402
+ (
403
+ ({_STRINGCHAR}|{_PAIR})*
404
+ ({_TRAILCHAR}|{_PAIR})
405
+ )?
406
+ )?
407
+ """,
408
+ re.VERBOSE,
409
+ )
410
+ _HEXSTRING_RE = re.compile(r"#([\da-zA-Z]{2})+")
411
+
412
+ def __init__(self, data: str, attr_name_overrides: _NameOidMap) -> None:
413
+ self._data = data
414
+ self._idx = 0
415
+
416
+ self._attr_name_overrides = attr_name_overrides
417
+
418
+ def _has_data(self) -> bool:
419
+ return self._idx < len(self._data)
420
+
421
+ def _peek(self) -> str | None:
422
+ if self._has_data():
423
+ return self._data[self._idx]
424
+ return None
425
+
426
+ def _read_char(self, ch: str) -> None:
427
+ if self._peek() != ch:
428
+ raise ValueError
429
+ self._idx += 1
430
+
431
+ def _read_re(self, pat) -> str:
432
+ match = pat.match(self._data, pos=self._idx)
433
+ if match is None:
434
+ raise ValueError
435
+ val = match.group()
436
+ self._idx += len(val)
437
+ return val
438
+
439
+ def parse(self) -> Name:
440
+ """
441
+ Parses the `data` string and converts it to a Name.
442
+
443
+ According to RFC4514 section 2.1 the RDNSequence must be
444
+ reversed when converting to string representation. So, when
445
+ we parse it, we need to reverse again to get the RDNs on the
446
+ correct order.
447
+ """
448
+
449
+ if not self._has_data():
450
+ return Name([])
451
+
452
+ rdns = [self._parse_rdn()]
453
+
454
+ while self._has_data():
455
+ self._read_char(",")
456
+ rdns.append(self._parse_rdn())
457
+
458
+ return Name(reversed(rdns))
459
+
460
+ def _parse_rdn(self) -> RelativeDistinguishedName:
461
+ nas = [self._parse_na()]
462
+ while self._peek() == "+":
463
+ self._read_char("+")
464
+ nas.append(self._parse_na())
465
+
466
+ return RelativeDistinguishedName(nas)
467
+
468
+ def _parse_na(self) -> NameAttribute[str]:
469
+ try:
470
+ oid_value = self._read_re(self._OID_RE)
471
+ except ValueError:
472
+ name = self._read_re(self._DESCR_RE)
473
+ oid = self._attr_name_overrides.get(
474
+ name, _NAME_TO_NAMEOID.get(name)
475
+ )
476
+ if oid is None:
477
+ raise ValueError
478
+ else:
479
+ oid = ObjectIdentifier(oid_value)
480
+
481
+ self._read_char("=")
482
+ if self._peek() == "#":
483
+ value = self._read_re(self._HEXSTRING_RE)
484
+ value = binascii.unhexlify(value[1:]).decode()
485
+ else:
486
+ raw_value = self._read_re(self._STRING_RE)
487
+ value = _unescape_dn_value(raw_value)
488
+
489
+ return NameAttribute(oid, value)
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/ocsp.py ADDED
@@ -0,0 +1,379 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 datetime
8
+ from collections.abc import Iterable
9
+
10
+ from cryptography import utils, x509
11
+ from cryptography.hazmat.bindings._rust import ocsp
12
+ from cryptography.hazmat.primitives import hashes
13
+ from cryptography.hazmat.primitives.asymmetric.types import (
14
+ CertificateIssuerPrivateKeyTypes,
15
+ )
16
+ from cryptography.x509.base import _reject_duplicate_extension
17
+
18
+
19
+ class OCSPResponderEncoding(utils.Enum):
20
+ HASH = "By Hash"
21
+ NAME = "By Name"
22
+
23
+
24
+ class OCSPResponseStatus(utils.Enum):
25
+ SUCCESSFUL = 0
26
+ MALFORMED_REQUEST = 1
27
+ INTERNAL_ERROR = 2
28
+ TRY_LATER = 3
29
+ SIG_REQUIRED = 5
30
+ UNAUTHORIZED = 6
31
+
32
+
33
+ _ALLOWED_HASHES = (
34
+ hashes.SHA1,
35
+ hashes.SHA224,
36
+ hashes.SHA256,
37
+ hashes.SHA384,
38
+ hashes.SHA512,
39
+ )
40
+
41
+
42
+ def _verify_algorithm(algorithm: hashes.HashAlgorithm) -> None:
43
+ if not isinstance(algorithm, _ALLOWED_HASHES):
44
+ raise ValueError(
45
+ "Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512"
46
+ )
47
+
48
+
49
+ class OCSPCertStatus(utils.Enum):
50
+ GOOD = 0
51
+ REVOKED = 1
52
+ UNKNOWN = 2
53
+
54
+
55
+ class _SingleResponse:
56
+ def __init__(
57
+ self,
58
+ resp: tuple[x509.Certificate, x509.Certificate] | None,
59
+ resp_hash: tuple[bytes, bytes, int] | None,
60
+ algorithm: hashes.HashAlgorithm,
61
+ cert_status: OCSPCertStatus,
62
+ this_update: datetime.datetime,
63
+ next_update: datetime.datetime | None,
64
+ revocation_time: datetime.datetime | None,
65
+ revocation_reason: x509.ReasonFlags | None,
66
+ ):
67
+ _verify_algorithm(algorithm)
68
+ if not isinstance(this_update, datetime.datetime):
69
+ raise TypeError("this_update must be a datetime object")
70
+ if next_update is not None and not isinstance(
71
+ next_update, datetime.datetime
72
+ ):
73
+ raise TypeError("next_update must be a datetime object or None")
74
+
75
+ self._resp = resp
76
+ self._resp_hash = resp_hash
77
+ self._algorithm = algorithm
78
+ self._this_update = this_update
79
+ self._next_update = next_update
80
+
81
+ if not isinstance(cert_status, OCSPCertStatus):
82
+ raise TypeError(
83
+ "cert_status must be an item from the OCSPCertStatus enum"
84
+ )
85
+ if cert_status is not OCSPCertStatus.REVOKED:
86
+ if revocation_time is not None:
87
+ raise ValueError(
88
+ "revocation_time can only be provided if the certificate "
89
+ "is revoked"
90
+ )
91
+ if revocation_reason is not None:
92
+ raise ValueError(
93
+ "revocation_reason can only be provided if the certificate"
94
+ " is revoked"
95
+ )
96
+ else:
97
+ if not isinstance(revocation_time, datetime.datetime):
98
+ raise TypeError("revocation_time must be a datetime object")
99
+
100
+ if revocation_reason is not None and not isinstance(
101
+ revocation_reason, x509.ReasonFlags
102
+ ):
103
+ raise TypeError(
104
+ "revocation_reason must be an item from the ReasonFlags "
105
+ "enum or None"
106
+ )
107
+
108
+ self._cert_status = cert_status
109
+ self._revocation_time = revocation_time
110
+ self._revocation_reason = revocation_reason
111
+
112
+
113
+ OCSPRequest = ocsp.OCSPRequest
114
+ OCSPResponse = ocsp.OCSPResponse
115
+ OCSPSingleResponse = ocsp.OCSPSingleResponse
116
+
117
+
118
+ class OCSPRequestBuilder:
119
+ def __init__(
120
+ self,
121
+ request: tuple[
122
+ x509.Certificate, x509.Certificate, hashes.HashAlgorithm
123
+ ]
124
+ | None = None,
125
+ request_hash: tuple[bytes, bytes, int, hashes.HashAlgorithm]
126
+ | None = None,
127
+ extensions: list[x509.Extension[x509.ExtensionType]] = [],
128
+ ) -> None:
129
+ self._request = request
130
+ self._request_hash = request_hash
131
+ self._extensions = extensions
132
+
133
+ def add_certificate(
134
+ self,
135
+ cert: x509.Certificate,
136
+ issuer: x509.Certificate,
137
+ algorithm: hashes.HashAlgorithm,
138
+ ) -> OCSPRequestBuilder:
139
+ if self._request is not None or self._request_hash is not None:
140
+ raise ValueError("Only one certificate can be added to a request")
141
+
142
+ _verify_algorithm(algorithm)
143
+ if not isinstance(cert, x509.Certificate) or not isinstance(
144
+ issuer, x509.Certificate
145
+ ):
146
+ raise TypeError("cert and issuer must be a Certificate")
147
+
148
+ return OCSPRequestBuilder(
149
+ (cert, issuer, algorithm), self._request_hash, self._extensions
150
+ )
151
+
152
+ def add_certificate_by_hash(
153
+ self,
154
+ issuer_name_hash: bytes,
155
+ issuer_key_hash: bytes,
156
+ serial_number: int,
157
+ algorithm: hashes.HashAlgorithm,
158
+ ) -> OCSPRequestBuilder:
159
+ if self._request is not None or self._request_hash is not None:
160
+ raise ValueError("Only one certificate can be added to a request")
161
+
162
+ if not isinstance(serial_number, int):
163
+ raise TypeError("serial_number must be an integer")
164
+
165
+ _verify_algorithm(algorithm)
166
+ utils._check_bytes("issuer_name_hash", issuer_name_hash)
167
+ utils._check_bytes("issuer_key_hash", issuer_key_hash)
168
+ if algorithm.digest_size != len(
169
+ issuer_name_hash
170
+ ) or algorithm.digest_size != len(issuer_key_hash):
171
+ raise ValueError(
172
+ "issuer_name_hash and issuer_key_hash must be the same length "
173
+ "as the digest size of the algorithm"
174
+ )
175
+
176
+ return OCSPRequestBuilder(
177
+ self._request,
178
+ (issuer_name_hash, issuer_key_hash, serial_number, algorithm),
179
+ self._extensions,
180
+ )
181
+
182
+ def add_extension(
183
+ self, extval: x509.ExtensionType, critical: bool
184
+ ) -> OCSPRequestBuilder:
185
+ if not isinstance(extval, x509.ExtensionType):
186
+ raise TypeError("extension must be an ExtensionType")
187
+
188
+ extension = x509.Extension(extval.oid, critical, extval)
189
+ _reject_duplicate_extension(extension, self._extensions)
190
+
191
+ return OCSPRequestBuilder(
192
+ self._request, self._request_hash, [*self._extensions, extension]
193
+ )
194
+
195
+ def build(self) -> OCSPRequest:
196
+ if self._request is None and self._request_hash is None:
197
+ raise ValueError("You must add a certificate before building")
198
+
199
+ return ocsp.create_ocsp_request(self)
200
+
201
+
202
+ class OCSPResponseBuilder:
203
+ def __init__(
204
+ self,
205
+ response: _SingleResponse | None = None,
206
+ responder_id: tuple[x509.Certificate, OCSPResponderEncoding]
207
+ | None = None,
208
+ certs: list[x509.Certificate] | None = None,
209
+ extensions: list[x509.Extension[x509.ExtensionType]] = [],
210
+ ):
211
+ self._response = response
212
+ self._responder_id = responder_id
213
+ self._certs = certs
214
+ self._extensions = extensions
215
+
216
+ def add_response(
217
+ self,
218
+ cert: x509.Certificate,
219
+ issuer: x509.Certificate,
220
+ algorithm: hashes.HashAlgorithm,
221
+ cert_status: OCSPCertStatus,
222
+ this_update: datetime.datetime,
223
+ next_update: datetime.datetime | None,
224
+ revocation_time: datetime.datetime | None,
225
+ revocation_reason: x509.ReasonFlags | None,
226
+ ) -> OCSPResponseBuilder:
227
+ if self._response is not None:
228
+ raise ValueError("Only one response per OCSPResponse.")
229
+
230
+ if not isinstance(cert, x509.Certificate) or not isinstance(
231
+ issuer, x509.Certificate
232
+ ):
233
+ raise TypeError("cert and issuer must be a Certificate")
234
+
235
+ singleresp = _SingleResponse(
236
+ (cert, issuer),
237
+ None,
238
+ algorithm,
239
+ cert_status,
240
+ this_update,
241
+ next_update,
242
+ revocation_time,
243
+ revocation_reason,
244
+ )
245
+ return OCSPResponseBuilder(
246
+ singleresp,
247
+ self._responder_id,
248
+ self._certs,
249
+ self._extensions,
250
+ )
251
+
252
+ def add_response_by_hash(
253
+ self,
254
+ issuer_name_hash: bytes,
255
+ issuer_key_hash: bytes,
256
+ serial_number: int,
257
+ algorithm: hashes.HashAlgorithm,
258
+ cert_status: OCSPCertStatus,
259
+ this_update: datetime.datetime,
260
+ next_update: datetime.datetime | None,
261
+ revocation_time: datetime.datetime | None,
262
+ revocation_reason: x509.ReasonFlags | None,
263
+ ) -> OCSPResponseBuilder:
264
+ if self._response is not None:
265
+ raise ValueError("Only one response per OCSPResponse.")
266
+
267
+ if not isinstance(serial_number, int):
268
+ raise TypeError("serial_number must be an integer")
269
+
270
+ utils._check_bytes("issuer_name_hash", issuer_name_hash)
271
+ utils._check_bytes("issuer_key_hash", issuer_key_hash)
272
+ _verify_algorithm(algorithm)
273
+ if algorithm.digest_size != len(
274
+ issuer_name_hash
275
+ ) or algorithm.digest_size != len(issuer_key_hash):
276
+ raise ValueError(
277
+ "issuer_name_hash and issuer_key_hash must be the same length "
278
+ "as the digest size of the algorithm"
279
+ )
280
+
281
+ singleresp = _SingleResponse(
282
+ None,
283
+ (issuer_name_hash, issuer_key_hash, serial_number),
284
+ algorithm,
285
+ cert_status,
286
+ this_update,
287
+ next_update,
288
+ revocation_time,
289
+ revocation_reason,
290
+ )
291
+ return OCSPResponseBuilder(
292
+ singleresp,
293
+ self._responder_id,
294
+ self._certs,
295
+ self._extensions,
296
+ )
297
+
298
+ def responder_id(
299
+ self, encoding: OCSPResponderEncoding, responder_cert: x509.Certificate
300
+ ) -> OCSPResponseBuilder:
301
+ if self._responder_id is not None:
302
+ raise ValueError("responder_id can only be set once")
303
+ if not isinstance(responder_cert, x509.Certificate):
304
+ raise TypeError("responder_cert must be a Certificate")
305
+ if not isinstance(encoding, OCSPResponderEncoding):
306
+ raise TypeError(
307
+ "encoding must be an element from OCSPResponderEncoding"
308
+ )
309
+
310
+ return OCSPResponseBuilder(
311
+ self._response,
312
+ (responder_cert, encoding),
313
+ self._certs,
314
+ self._extensions,
315
+ )
316
+
317
+ def certificates(
318
+ self, certs: Iterable[x509.Certificate]
319
+ ) -> OCSPResponseBuilder:
320
+ if self._certs is not None:
321
+ raise ValueError("certificates may only be set once")
322
+ certs = list(certs)
323
+ if len(certs) == 0:
324
+ raise ValueError("certs must not be an empty list")
325
+ if not all(isinstance(x, x509.Certificate) for x in certs):
326
+ raise TypeError("certs must be a list of Certificates")
327
+ return OCSPResponseBuilder(
328
+ self._response,
329
+ self._responder_id,
330
+ certs,
331
+ self._extensions,
332
+ )
333
+
334
+ def add_extension(
335
+ self, extval: x509.ExtensionType, critical: bool
336
+ ) -> OCSPResponseBuilder:
337
+ if not isinstance(extval, x509.ExtensionType):
338
+ raise TypeError("extension must be an ExtensionType")
339
+
340
+ extension = x509.Extension(extval.oid, critical, extval)
341
+ _reject_duplicate_extension(extension, self._extensions)
342
+
343
+ return OCSPResponseBuilder(
344
+ self._response,
345
+ self._responder_id,
346
+ self._certs,
347
+ [*self._extensions, extension],
348
+ )
349
+
350
+ def sign(
351
+ self,
352
+ private_key: CertificateIssuerPrivateKeyTypes,
353
+ algorithm: hashes.HashAlgorithm | None,
354
+ ) -> OCSPResponse:
355
+ if self._response is None:
356
+ raise ValueError("You must add a response before signing")
357
+ if self._responder_id is None:
358
+ raise ValueError("You must add a responder_id before signing")
359
+
360
+ return ocsp.create_ocsp_response(
361
+ OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm
362
+ )
363
+
364
+ @classmethod
365
+ def build_unsuccessful(
366
+ cls, response_status: OCSPResponseStatus
367
+ ) -> OCSPResponse:
368
+ if not isinstance(response_status, OCSPResponseStatus):
369
+ raise TypeError(
370
+ "response_status must be an item from OCSPResponseStatus"
371
+ )
372
+ if response_status is OCSPResponseStatus.SUCCESSFUL:
373
+ raise ValueError("response_status cannot be SUCCESSFUL")
374
+
375
+ return ocsp.create_ocsp_response(response_status, None, None, None)
376
+
377
+
378
+ load_der_ocsp_request = ocsp.load_der_ocsp_request
379
+ load_der_ocsp_response = ocsp.load_der_ocsp_response
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/oid.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ from cryptography.hazmat._oid import (
8
+ AttributeOID,
9
+ AuthorityInformationAccessOID,
10
+ CertificatePoliciesOID,
11
+ CRLEntryExtensionOID,
12
+ ExtendedKeyUsageOID,
13
+ ExtensionOID,
14
+ NameOID,
15
+ ObjectIdentifier,
16
+ OCSPExtensionOID,
17
+ OtherNameFormOID,
18
+ PublicKeyAlgorithmOID,
19
+ SignatureAlgorithmOID,
20
+ SubjectInformationAccessOID,
21
+ )
22
+
23
+ __all__ = [
24
+ "AttributeOID",
25
+ "AuthorityInformationAccessOID",
26
+ "CRLEntryExtensionOID",
27
+ "CertificatePoliciesOID",
28
+ "ExtendedKeyUsageOID",
29
+ "ExtensionOID",
30
+ "NameOID",
31
+ "OCSPExtensionOID",
32
+ "ObjectIdentifier",
33
+ "OtherNameFormOID",
34
+ "PublicKeyAlgorithmOID",
35
+ "SignatureAlgorithmOID",
36
+ "SubjectInformationAccessOID",
37
+ ]
.mcp-venv/lib/python3.13/site-packages/cryptography/x509/verification.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 typing
8
+
9
+ from cryptography.hazmat.bindings._rust import x509 as rust_x509
10
+ from cryptography.x509.general_name import DNSName, IPAddress
11
+
12
+ __all__ = [
13
+ "ClientVerifier",
14
+ "Criticality",
15
+ "ExtensionPolicy",
16
+ "Policy",
17
+ "PolicyBuilder",
18
+ "ServerVerifier",
19
+ "Store",
20
+ "Subject",
21
+ "VerificationError",
22
+ "VerifiedClient",
23
+ ]
24
+
25
+ Store = rust_x509.Store
26
+ Subject = typing.Union[DNSName, IPAddress]
27
+ VerifiedClient = rust_x509.VerifiedClient
28
+ ClientVerifier = rust_x509.ClientVerifier
29
+ ServerVerifier = rust_x509.ServerVerifier
30
+ PolicyBuilder = rust_x509.PolicyBuilder
31
+ Policy = rust_x509.Policy
32
+ ExtensionPolicy = rust_x509.ExtensionPolicy
33
+ Criticality = rust_x509.Criticality
34
+ VerificationError = rust_x509.VerificationError
.mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/INSTALLER ADDED
@@ -0,0 +1 @@
 
 
1
+ pip
.mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/METADATA ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Metadata-Version: 2.4
2
+ Name: h11
3
+ Version: 0.16.0
4
+ Summary: A pure-Python, bring-your-own-I/O implementation of HTTP/1.1
5
+ Home-page: https://github.com/python-hyper/h11
6
+ Author: Nathaniel J. Smith
7
+ Author-email: njs@pobox.com
8
+ License: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: Implementation :: CPython
13
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Internet :: WWW/HTTP
22
+ Classifier: Topic :: System :: Networking
23
+ Requires-Python: >=3.8
24
+ License-File: LICENSE.txt
25
+ Dynamic: author
26
+ Dynamic: author-email
27
+ Dynamic: classifier
28
+ Dynamic: description
29
+ Dynamic: home-page
30
+ Dynamic: license
31
+ Dynamic: license-file
32
+ Dynamic: requires-python
33
+ Dynamic: summary
34
+
35
+ h11
36
+ ===
37
+
38
+ .. image:: https://travis-ci.org/python-hyper/h11.svg?branch=master
39
+ :target: https://travis-ci.org/python-hyper/h11
40
+ :alt: Automated test status
41
+
42
+ .. image:: https://codecov.io/gh/python-hyper/h11/branch/master/graph/badge.svg
43
+ :target: https://codecov.io/gh/python-hyper/h11
44
+ :alt: Test coverage
45
+
46
+ .. image:: https://readthedocs.org/projects/h11/badge/?version=latest
47
+ :target: http://h11.readthedocs.io/en/latest/?badge=latest
48
+ :alt: Documentation Status
49
+
50
+ This is a little HTTP/1.1 library written from scratch in Python,
51
+ heavily inspired by `hyper-h2 <https://hyper-h2.readthedocs.io/>`_.
52
+
53
+ It's a "bring-your-own-I/O" library; h11 contains no IO code
54
+ whatsoever. This means you can hook h11 up to your favorite network
55
+ API, and that could be anything you want: synchronous, threaded,
56
+ asynchronous, or your own implementation of `RFC 6214
57
+ <https://tools.ietf.org/html/rfc6214>`_ -- h11 won't judge you.
58
+ (Compare this to the current state of the art, where every time a `new
59
+ network API <https://trio.readthedocs.io/>`_ comes along then someone
60
+ gets to start over reimplementing the entire HTTP protocol from
61
+ scratch.) Cory Benfield made an `excellent blog post describing the
62
+ benefits of this approach
63
+ <https://lukasa.co.uk/2015/10/The_New_Hyper/>`_, or if you like video
64
+ then here's his `PyCon 2016 talk on the same theme
65
+ <https://www.youtube.com/watch?v=7cC3_jGwl_U>`_.
66
+
67
+ This also means that h11 is not immediately useful out of the box:
68
+ it's a toolkit for building programs that speak HTTP, not something
69
+ that could directly replace ``requests`` or ``twisted.web`` or
70
+ whatever. But h11 makes it much easier to implement something like
71
+ ``requests`` or ``twisted.web``.
72
+
73
+ At a high level, working with h11 goes like this:
74
+
75
+ 1) First, create an ``h11.Connection`` object to track the state of a
76
+ single HTTP/1.1 connection.
77
+
78
+ 2) When you read data off the network, pass it to
79
+ ``conn.receive_data(...)``; you'll get back a list of objects
80
+ representing high-level HTTP "events".
81
+
82
+ 3) When you want to send a high-level HTTP event, create the
83
+ corresponding "event" object and pass it to ``conn.send(...)``;
84
+ this will give you back some bytes that you can then push out
85
+ through the network.
86
+
87
+ For example, a client might instantiate and then send a
88
+ ``h11.Request`` object, then zero or more ``h11.Data`` objects for the
89
+ request body (e.g., if this is a POST), and then a
90
+ ``h11.EndOfMessage`` to indicate the end of the message. Then the
91
+ server would then send back a ``h11.Response``, some ``h11.Data``, and
92
+ its own ``h11.EndOfMessage``. If either side violates the protocol,
93
+ you'll get a ``h11.ProtocolError`` exception.
94
+
95
+ h11 is suitable for implementing both servers and clients, and has a
96
+ pleasantly symmetric API: the events you send as a client are exactly
97
+ the ones that you receive as a server and vice-versa.
98
+
99
+ `Here's an example of a tiny HTTP client
100
+ <https://github.com/python-hyper/h11/blob/master/examples/basic-client.py>`_
101
+
102
+ It also has `a fine manual <https://h11.readthedocs.io/>`_.
103
+
104
+ FAQ
105
+ ---
106
+
107
+ *Whyyyyy?*
108
+
109
+ I wanted to play with HTTP in `Curio
110
+ <https://curio.readthedocs.io/en/latest/tutorial.html>`__ and `Trio
111
+ <https://trio.readthedocs.io>`__, which at the time didn't have any
112
+ HTTP libraries. So I thought, no big deal, Python has, like, a dozen
113
+ different implementations of HTTP, surely I can find one that's
114
+ reusable. I didn't find one, but I did find Cory's call-to-arms
115
+ blog-post. So I figured, well, fine, if I have to implement HTTP from
116
+ scratch, at least I can make sure no-one *else* has to ever again.
117
+
118
+ *Should I use it?*
119
+
120
+ Maybe. You should be aware that it's a very young project. But, it's
121
+ feature complete and has an exhaustive test-suite and complete docs,
122
+ so the next step is for people to try using it and see how it goes
123
+ :-). If you do then please let us know -- if nothing else we'll want
124
+ to talk to you before making any incompatible changes!
125
+
126
+ *What are the features/limitations?*
127
+
128
+ Roughly speaking, it's trying to be a robust, complete, and non-hacky
129
+ implementation of the first "chapter" of the HTTP/1.1 spec: `RFC 7230:
130
+ HTTP/1.1 Message Syntax and Routing
131
+ <https://tools.ietf.org/html/rfc7230>`_. That is, it mostly focuses on
132
+ implementing HTTP at the level of taking bytes on and off the wire,
133
+ and the headers related to that, and tries to be anal about spec
134
+ conformance. It doesn't know about higher-level concerns like URL
135
+ routing, conditional GETs, cross-origin cookie policies, or content
136
+ negotiation. But it does know how to take care of framing,
137
+ cross-version differences in keep-alive handling, and the "obsolete
138
+ line folding" rule, so you can focus your energies on the hard /
139
+ interesting parts for your application, and it tries to support the
140
+ full specification in the sense that any useful HTTP/1.1 conformant
141
+ application should be able to use h11.
142
+
143
+ It's pure Python, and has no dependencies outside of the standard
144
+ library.
145
+
146
+ It has a test suite with 100.0% coverage for both statements and
147
+ branches.
148
+
149
+ Currently it supports Python 3 (testing on 3.8-3.12) and PyPy 3.
150
+ The last Python 2-compatible version was h11 0.11.x.
151
+ (Originally it had a Cython wrapper for `http-parser
152
+ <https://github.com/nodejs/http-parser>`_ and a beautiful nested state
153
+ machine implemented with ``yield from`` to postprocess the output. But
154
+ I had to take these out -- the new *parser* needs fewer lines-of-code
155
+ than the old *parser wrapper*, is written in pure Python, uses no
156
+ exotic language syntax, and has more features. It's sad, really; that
157
+ old state machine was really slick. I just need a few sentences here
158
+ to mourn that.)
159
+
160
+ I don't know how fast it is. I haven't benchmarked or profiled it yet,
161
+ so it's probably got a few pointless hot spots, and I've been trying
162
+ to err on the side of simplicity and robustness instead of
163
+ micro-optimization. But at the architectural level I tried hard to
164
+ avoid fundamentally bad decisions, e.g., I believe that all the
165
+ parsing algorithms remain linear-time even in the face of pathological
166
+ input like slowloris, and there are no byte-by-byte loops. (I also
167
+ believe that it maintains bounded memory usage in the face of
168
+ arbitrary/pathological input.)
169
+
170
+ The whole library is ~800 lines-of-code. You can read and understand
171
+ the whole thing in less than an hour. Most of the energy invested in
172
+ this so far has been spent on trying to keep things simple by
173
+ minimizing special-cases and ad hoc state manipulation; even though it
174
+ is now quite small and simple, I'm still annoyed that I haven't
175
+ figured out how to make it even smaller and simpler. (Unfortunately,
176
+ HTTP does not lend itself to simplicity.)
177
+
178
+ The API is ~feature complete and I don't expect the general outlines
179
+ to change much, but you can't judge an API's ergonomics until you
180
+ actually document and use it, so I'd expect some changes in the
181
+ details.
182
+
183
+ *How do I try it?*
184
+
185
+ .. code-block:: sh
186
+
187
+ $ pip install h11
188
+ $ git clone git@github.com:python-hyper/h11
189
+ $ cd h11/examples
190
+ $ python basic-client.py
191
+
192
+ and go from there.
193
+
194
+ *License?*
195
+
196
+ MIT
197
+
198
+ *Code of conduct?*
199
+
200
+ Contributors are requested to follow our `code of conduct
201
+ <https://github.com/python-hyper/h11/blob/master/CODE_OF_CONDUCT.md>`_ in
202
+ all project spaces.
.mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/RECORD ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ h11-0.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
2
+ h11-0.16.0.dist-info/METADATA,sha256=KPMmCYrAn8unm48YD5YIfIQf4kViFct7hyqcfVzRnWQ,8348
3
+ h11-0.16.0.dist-info/RECORD,,
4
+ h11-0.16.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
5
+ h11-0.16.0.dist-info/licenses/LICENSE.txt,sha256=N9tbuFkm2yikJ6JYZ_ELEjIAOuob5pzLhRE4rbjm82E,1124
6
+ h11-0.16.0.dist-info/top_level.txt,sha256=F7dC4jl3zeh8TGHEPaWJrMbeuoWbS379Gwdi-Yvdcis,4
7
+ h11/__init__.py,sha256=iO1KzkSO42yZ6ffg-VMgbx_ZVTWGUY00nRYEWn-s3kY,1507
8
+ h11/__pycache__/__init__.cpython-313.pyc,,
9
+ h11/__pycache__/_abnf.cpython-313.pyc,,
10
+ h11/__pycache__/_connection.cpython-313.pyc,,
11
+ h11/__pycache__/_events.cpython-313.pyc,,
12
+ h11/__pycache__/_headers.cpython-313.pyc,,
13
+ h11/__pycache__/_readers.cpython-313.pyc,,
14
+ h11/__pycache__/_receivebuffer.cpython-313.pyc,,
15
+ h11/__pycache__/_state.cpython-313.pyc,,
16
+ h11/__pycache__/_util.cpython-313.pyc,,
17
+ h11/__pycache__/_version.cpython-313.pyc,,
18
+ h11/__pycache__/_writers.cpython-313.pyc,,
19
+ h11/_abnf.py,sha256=ybixr0xsupnkA6GFAyMubuXF6Tc1lb_hF890NgCsfNc,4815
20
+ h11/_connection.py,sha256=k9YRVf6koZqbttBW36xSWaJpWdZwa-xQVU9AHEo9DuI,26863
21
+ h11/_events.py,sha256=I97aXoal1Wu7dkL548BANBUCkOIbe-x5CioYA9IBY14,11792
22
+ h11/_headers.py,sha256=P7D-lBNxHwdLZPLimmYwrPG-9ZkjElvvJZJdZAgSP-4,10412
23
+ h11/_readers.py,sha256=a4RypORUCC3d0q_kxPuBIM7jTD8iLt5X91TH0FsduN4,8590
24
+ h11/_receivebuffer.py,sha256=xrspsdsNgWFxRfQcTXxR8RrdjRXXTK0Io5cQYWpJ1Ws,5252
25
+ h11/_state.py,sha256=_5LG_BGR8FCcFQeBPH-TMHgm_-B-EUcWCnQof_9XjFE,13231
26
+ h11/_util.py,sha256=LWkkjXyJaFlAy6Lt39w73UStklFT5ovcvo0TkY7RYuk,4888
27
+ h11/_version.py,sha256=GVSsbPSPDcOuF6ptfIiXnVJoaEm3ygXbMnqlr_Giahw,686
28
+ h11/_writers.py,sha256=oFKm6PtjeHfbj4RLX7VB7KDc1gIY53gXG3_HR9ltmTA,5081
29
+ h11/py.typed,sha256=sow9soTwP9T_gEAQSVh7Gb8855h04Nwmhs2We-JRgZM,7
.mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/WHEEL ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (78.1.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
.mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/licenses/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Nathaniel J. Smith <njs@pobox.com> and other contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
.mcp-venv/lib/python3.13/site-packages/h11-0.16.0.dist-info/top_level.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ h11
.mcp-venv/lib/python3.13/site-packages/h11/__init__.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # A highish-level implementation of the HTTP/1.1 wire protocol (RFC 7230),
2
+ # containing no networking code at all, loosely modelled on hyper-h2's generic
3
+ # implementation of HTTP/2 (and in particular the h2.connection.H2Connection
4
+ # class). There's still a bunch of subtle details you need to get right if you
5
+ # want to make this actually useful, because it doesn't implement all the
6
+ # semantics to check that what you're asking to write to the wire is sensible,
7
+ # but at least it gets you out of dealing with the wire itself.
8
+
9
+ from h11._connection import Connection, NEED_DATA, PAUSED
10
+ from h11._events import (
11
+ ConnectionClosed,
12
+ Data,
13
+ EndOfMessage,
14
+ Event,
15
+ InformationalResponse,
16
+ Request,
17
+ Response,
18
+ )
19
+ from h11._state import (
20
+ CLIENT,
21
+ CLOSED,
22
+ DONE,
23
+ ERROR,
24
+ IDLE,
25
+ MIGHT_SWITCH_PROTOCOL,
26
+ MUST_CLOSE,
27
+ SEND_BODY,
28
+ SEND_RESPONSE,
29
+ SERVER,
30
+ SWITCHED_PROTOCOL,
31
+ )
32
+ from h11._util import LocalProtocolError, ProtocolError, RemoteProtocolError
33
+ from h11._version import __version__
34
+
35
+ PRODUCT_ID = "python-h11/" + __version__
36
+
37
+
38
+ __all__ = (
39
+ "Connection",
40
+ "NEED_DATA",
41
+ "PAUSED",
42
+ "ConnectionClosed",
43
+ "Data",
44
+ "EndOfMessage",
45
+ "Event",
46
+ "InformationalResponse",
47
+ "Request",
48
+ "Response",
49
+ "CLIENT",
50
+ "CLOSED",
51
+ "DONE",
52
+ "ERROR",
53
+ "IDLE",
54
+ "MUST_CLOSE",
55
+ "SEND_BODY",
56
+ "SEND_RESPONSE",
57
+ "SERVER",
58
+ "SWITCHED_PROTOCOL",
59
+ "ProtocolError",
60
+ "LocalProtocolError",
61
+ "RemoteProtocolError",
62
+ )
.mcp-venv/lib/python3.13/site-packages/h11/_abnf.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # We use native strings for all the re patterns, to take advantage of string
2
+ # formatting, and then convert to bytestrings when compiling the final re
3
+ # objects.
4
+
5
+ # https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#whitespace
6
+ # OWS = *( SP / HTAB )
7
+ # ; optional whitespace
8
+ OWS = r"[ \t]*"
9
+
10
+ # https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.token.separators
11
+ # token = 1*tchar
12
+ #
13
+ # tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
14
+ # / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
15
+ # / DIGIT / ALPHA
16
+ # ; any VCHAR, except delimiters
17
+ token = r"[-!#$%&'*+.^_`|~0-9a-zA-Z]+"
18
+
19
+ # https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#header.fields
20
+ # field-name = token
21
+ field_name = token
22
+
23
+ # The standard says:
24
+ #
25
+ # field-value = *( field-content / obs-fold )
26
+ # field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
27
+ # field-vchar = VCHAR / obs-text
28
+ # obs-fold = CRLF 1*( SP / HTAB )
29
+ # ; obsolete line folding
30
+ # ; see Section 3.2.4
31
+ #
32
+ # https://tools.ietf.org/html/rfc5234#appendix-B.1
33
+ #
34
+ # VCHAR = %x21-7E
35
+ # ; visible (printing) characters
36
+ #
37
+ # https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#rule.quoted-string
38
+ # obs-text = %x80-FF
39
+ #
40
+ # However, the standard definition of field-content is WRONG! It disallows
41
+ # fields containing a single visible character surrounded by whitespace,
42
+ # e.g. "foo a bar".
43
+ #
44
+ # See: https://www.rfc-editor.org/errata_search.php?rfc=7230&eid=4189
45
+ #
46
+ # So our definition of field_content attempts to fix it up...
47
+ #
48
+ # Also, we allow lots of control characters, because apparently people assume
49
+ # that they're legal in practice (e.g., google analytics makes cookies with
50
+ # \x01 in them!):
51
+ # https://github.com/python-hyper/h11/issues/57
52
+ # We still don't allow NUL or whitespace, because those are often treated as
53
+ # meta-characters and letting them through can lead to nasty issues like SSRF.
54
+ vchar = r"[\x21-\x7e]"
55
+ vchar_or_obs_text = r"[^\x00\s]"
56
+ field_vchar = vchar_or_obs_text
57
+ field_content = r"{field_vchar}+(?:[ \t]+{field_vchar}+)*".format(**globals())
58
+
59
+ # We handle obs-fold at a different level, and our fixed-up field_content
60
+ # already grows to swallow the whole value, so ? instead of *
61
+ field_value = r"({field_content})?".format(**globals())
62
+
63
+ # header-field = field-name ":" OWS field-value OWS
64
+ header_field = (
65
+ r"(?P<field_name>{field_name})"
66
+ r":"
67
+ r"{OWS}"
68
+ r"(?P<field_value>{field_value})"
69
+ r"{OWS}".format(**globals())
70
+ )
71
+
72
+ # https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#request.line
73
+ #
74
+ # request-line = method SP request-target SP HTTP-version CRLF
75
+ # method = token
76
+ # HTTP-version = HTTP-name "/" DIGIT "." DIGIT
77
+ # HTTP-name = %x48.54.54.50 ; "HTTP", case-sensitive
78
+ #
79
+ # request-target is complicated (see RFC 7230 sec 5.3) -- could be path, full
80
+ # URL, host+port (for connect), or even "*", but in any case we are guaranteed
81
+ # that it contists of the visible printing characters.
82
+ method = token
83
+ request_target = r"{vchar}+".format(**globals())
84
+ http_version = r"HTTP/(?P<http_version>[0-9]\.[0-9])"
85
+ request_line = (
86
+ r"(?P<method>{method})"
87
+ r" "
88
+ r"(?P<target>{request_target})"
89
+ r" "
90
+ r"{http_version}".format(**globals())
91
+ )
92
+
93
+ # https://svn.tools.ietf.org/svn/wg/httpbis/specs/rfc7230.html#status.line
94
+ #
95
+ # status-line = HTTP-version SP status-code SP reason-phrase CRLF
96
+ # status-code = 3DIGIT
97
+ # reason-phrase = *( HTAB / SP / VCHAR / obs-text )
98
+ status_code = r"[0-9]{3}"
99
+ reason_phrase = r"([ \t]|{vchar_or_obs_text})*".format(**globals())
100
+ status_line = (
101
+ r"{http_version}"
102
+ r" "
103
+ r"(?P<status_code>{status_code})"
104
+ # However, there are apparently a few too many servers out there that just
105
+ # leave out the reason phrase:
106
+ # https://github.com/scrapy/scrapy/issues/345#issuecomment-281756036
107
+ # https://github.com/seanmonstar/httparse/issues/29
108
+ # so make it optional. ?: is a non-capturing group.
109
+ r"(?: (?P<reason>{reason_phrase}))?".format(**globals())
110
+ )
111
+
112
+ HEXDIG = r"[0-9A-Fa-f]"
113
+ # Actually
114
+ #
115
+ # chunk-size = 1*HEXDIG
116
+ #
117
+ # but we impose an upper-limit to avoid ridiculosity. len(str(2**64)) == 20
118
+ chunk_size = r"({HEXDIG}){{1,20}}".format(**globals())
119
+ # Actually
120
+ #
121
+ # chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
122
+ #
123
+ # but we aren't parsing the things so we don't really care.
124
+ chunk_ext = r";.*"
125
+ chunk_header = (
126
+ r"(?P<chunk_size>{chunk_size})"
127
+ r"(?P<chunk_ext>{chunk_ext})?"
128
+ r"{OWS}\r\n".format(
129
+ **globals()
130
+ ) # Even though the specification does not allow for extra whitespaces,
131
+ # we are lenient with trailing whitespaces because some servers on the wild use it.
132
+ )