asyncssh 2.17.0__tar.gz → 2.18.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {asyncssh-2.17.0 → asyncssh-2.18.0}/.github/workflows/run_tests.yml +3 -1
- {asyncssh-2.17.0/asyncssh.egg-info → asyncssh-2.18.0}/PKG-INFO +15 -9
- {asyncssh-2.17.0 → asyncssh-2.18.0}/README.rst +3 -4
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/__init__.py +11 -10
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/agent.py +15 -23
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/agent_win32.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/asn1.py +11 -11
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/auth.py +36 -31
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/auth_keys.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/channel.py +66 -42
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/compression.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/config.py +11 -12
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/connection.py +129 -98
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/__init__.py +15 -4
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/cipher.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/ec.py +10 -9
- asyncssh-2.18.0/asyncssh/crypto/pq.py +103 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/umac.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/x509.py +4 -4
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/ecdsa.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/gss_win32.py +4 -4
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/kex.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/kex_dh.py +63 -52
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/kex_rsa.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/known_hosts.py +11 -11
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/listener.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/logging.py +7 -7
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/misc.py +86 -15
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/packet.py +11 -10
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/process.py +6 -5
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/public_key.py +24 -25
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/saslprep.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/scp.py +25 -19
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/sftp.py +221 -98
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/sk.py +6 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/version.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/x11.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0/asyncssh.egg-info}/PKG-INFO +15 -9
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh.egg-info/SOURCES.txt +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/api.rst +8 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/changes.rst +71 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/callback_client.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/callback_math_server.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/chat_server.py +4 -4
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/editor.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/gather_results.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/listening_client.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/local_forwarding_client2.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/math_server.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/show_environment.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/show_terminal.py +6 -7
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/simple_cert_server.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/simple_keyed_server.py +4 -4
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/simple_server.py +14 -10
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/stream_listening_client.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/pkcs11_stub.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/server.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_agent.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_auth.py +15 -6
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_auth_keys.py +3 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_channel.py +170 -26
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_config.py +6 -6
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_connection.py +48 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_connection_auth.py +24 -3
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_forward.py +10 -14
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_kex.py +104 -89
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_known_hosts.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_logging.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_pkcs11.py +4 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_process.py +15 -20
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_public_key.py +62 -65
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_saslprep.py +5 -5
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_sftp.py +85 -62
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_sk.py +10 -7
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_stream.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_tuntap.py +0 -4
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_x509.py +1 -1
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/util.py +16 -2
- asyncssh-2.17.0/asyncssh/crypto/sntrup.py +0 -88
- {asyncssh-2.17.0 → asyncssh-2.18.0}/.coveragerc +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/.gitignore +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/.readthedocs.yaml +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/CONTRIBUTING.rst +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/COPYRIGHT +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/LICENSE +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/MANIFEST.in +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/agent_unix.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/constants.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/chacha.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/dh.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/dsa.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/ec_params.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/ed.py +2 -2
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/kdf.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/misc.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/crypto/rsa.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/dsa.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/eddsa.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/editor.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/encryption.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/forward.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/gss.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/gss_unix.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/keysign.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/mac.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/pattern.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/pbe.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/pkcs11.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/py.typed +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/rsa.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/session.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/sk_ecdsa.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/sk_eddsa.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/socks.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/stream.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/subprocess.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh/tuntap.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh.egg-info/dependency_links.txt +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh.egg-info/requires.txt +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/asyncssh.egg-info/top_level.txt +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/_templates/sidebarbottom.html +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/_templates/sidebartop.html +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/conf.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/contributing.rst +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/index.rst +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/requirements.txt +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/rftheme/layout.html +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/rftheme/static/rftheme.css_t +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/rftheme/theme.conf +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/docs/rtd-req.txt +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/callback_client2.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/callback_client3.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/check_exit_status.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/chroot_sftp_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/direct_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/direct_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/local_forwarding_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/local_forwarding_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/math_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/redirect_input.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/redirect_local_pipe.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/redirect_remote_pipe.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/redirect_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/remote_forwarding_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/remote_forwarding_client2.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/remote_forwarding_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/reverse_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/reverse_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/scp_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/set_environment.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/set_terminal.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/sftp_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/simple_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/simple_scp_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/simple_sftp_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/stream_direct_client.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/examples/stream_direct_server.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/mypy.ini +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/pylintrc +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/setup.cfg +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/setup.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/__init__.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/gss_stub.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/gssapi_stub.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/keysign_stub.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/sk_stub.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/sspi_stub.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_asn1.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_compression.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_editor.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_encryption.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_mac.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_packet.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_subprocess.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tests/test_x11.py +0 -0
- {asyncssh-2.17.0 → asyncssh-2.18.0}/tox.ini +0 -0
|
@@ -38,7 +38,7 @@ jobs:
|
|
|
38
38
|
|
|
39
39
|
runs-on: ${{ matrix.os }}
|
|
40
40
|
env:
|
|
41
|
-
liboqs_version: '0.
|
|
41
|
+
liboqs_version: '0.10.1'
|
|
42
42
|
nettle_version: nettle_3.8.1_release_20220727
|
|
43
43
|
|
|
44
44
|
steps:
|
|
@@ -130,6 +130,7 @@ jobs:
|
|
|
130
130
|
with:
|
|
131
131
|
name: coverage-${{ matrix.os }}-${{ matrix.python-version }}
|
|
132
132
|
path: asyncssh/.coverage.*
|
|
133
|
+
include-hidden-files: true
|
|
133
134
|
retention-days: 1
|
|
134
135
|
|
|
135
136
|
merge-coverage:
|
|
@@ -142,6 +143,7 @@ jobs:
|
|
|
142
143
|
with:
|
|
143
144
|
name: coverage
|
|
144
145
|
pattern: coverage-*
|
|
146
|
+
include-hidden-files: true
|
|
145
147
|
|
|
146
148
|
report-coverage:
|
|
147
149
|
name: Report coverage
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: asyncssh
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.18.0
|
|
4
4
|
Summary: AsyncSSH: Asynchronous SSHv2 client and server library
|
|
5
5
|
Home-page: http://asyncssh.timeheart.net
|
|
6
6
|
Author: Ron Frederick
|
|
@@ -27,14 +27,23 @@ Classifier: Topic :: Security :: Cryptography
|
|
|
27
27
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
28
|
Classifier: Topic :: System :: Networking
|
|
29
29
|
Requires-Python: >= 3.6
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Requires-Dist: cryptography>=39.0
|
|
32
|
+
Requires-Dist: typing_extensions>=4.0.0
|
|
30
33
|
Provides-Extra: bcrypt
|
|
34
|
+
Requires-Dist: bcrypt>=3.1.3; extra == "bcrypt"
|
|
31
35
|
Provides-Extra: fido2
|
|
36
|
+
Requires-Dist: fido2>=0.9.2; extra == "fido2"
|
|
32
37
|
Provides-Extra: gssapi
|
|
38
|
+
Requires-Dist: gssapi>=1.2.0; extra == "gssapi"
|
|
33
39
|
Provides-Extra: libnacl
|
|
40
|
+
Requires-Dist: libnacl>=1.4.2; extra == "libnacl"
|
|
34
41
|
Provides-Extra: pkcs11
|
|
35
|
-
|
|
42
|
+
Requires-Dist: python-pkcs11>=0.7.0; extra == "pkcs11"
|
|
43
|
+
Provides-Extra: pyopenssl
|
|
44
|
+
Requires-Dist: pyOpenSSL>=23.0.0; extra == "pyopenssl"
|
|
36
45
|
Provides-Extra: pywin32
|
|
37
|
-
|
|
46
|
+
Requires-Dist: pywin32>=227; extra == "pywin32"
|
|
38
47
|
|
|
39
48
|
.. image:: https://readthedocs.org/projects/asyncssh/badge/?version=latest
|
|
40
49
|
:target: https://asyncssh.readthedocs.io/en/latest/?badge=latest
|
|
@@ -95,8 +104,7 @@ Features
|
|
|
95
104
|
* Byte and string based I/O with settable encoding
|
|
96
105
|
* A variety of `key exchange`__, `encryption`__, and `MAC`__ algorithms
|
|
97
106
|
|
|
98
|
-
* Including
|
|
99
|
-
sntrup761x25519-sha512\@openssh.com
|
|
107
|
+
* Including post-quantum kex algorithms ML-KEM and SNTRUP
|
|
100
108
|
|
|
101
109
|
* Support for `gzip compression`__
|
|
102
110
|
|
|
@@ -140,7 +148,7 @@ License
|
|
|
140
148
|
|
|
141
149
|
This package is released under the following terms:
|
|
142
150
|
|
|
143
|
-
Copyright (c) 2013-
|
|
151
|
+
Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
|
|
144
152
|
|
|
145
153
|
This program and the accompanying materials are made available under
|
|
146
154
|
the terms of the Eclipse Public License v2.0 which accompanies this
|
|
@@ -197,7 +205,7 @@ functionality:
|
|
|
197
205
|
|
|
198
206
|
* Install liboqs from https://github.com/open-quantum-safe/liboqs
|
|
199
207
|
if you want support for the OpenSSH post-quantum key exchange
|
|
200
|
-
|
|
208
|
+
algorithms based on ML-KEM and SNTRUP.
|
|
201
209
|
|
|
202
210
|
* Install libsodium from https://github.com/jedisct1/libsodium
|
|
203
211
|
and libnacl from https://pypi.python.org/pypi/libnacl if you have
|
|
@@ -267,5 +275,3 @@ Three mailing lists are available for AsyncSSH:
|
|
|
267
275
|
__ http://groups.google.com/d/forum/asyncssh-announce
|
|
268
276
|
__ http://groups.google.com/d/forum/asyncssh-dev
|
|
269
277
|
__ http://groups.google.com/d/forum/asyncssh-users
|
|
270
|
-
|
|
271
|
-
|
|
@@ -57,8 +57,7 @@ Features
|
|
|
57
57
|
* Byte and string based I/O with settable encoding
|
|
58
58
|
* A variety of `key exchange`__, `encryption`__, and `MAC`__ algorithms
|
|
59
59
|
|
|
60
|
-
* Including
|
|
61
|
-
sntrup761x25519-sha512\@openssh.com
|
|
60
|
+
* Including post-quantum kex algorithms ML-KEM and SNTRUP
|
|
62
61
|
|
|
63
62
|
* Support for `gzip compression`__
|
|
64
63
|
|
|
@@ -102,7 +101,7 @@ License
|
|
|
102
101
|
|
|
103
102
|
This package is released under the following terms:
|
|
104
103
|
|
|
105
|
-
Copyright (c) 2013-
|
|
104
|
+
Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
|
|
106
105
|
|
|
107
106
|
This program and the accompanying materials are made available under
|
|
108
107
|
the terms of the Eclipse Public License v2.0 which accompanies this
|
|
@@ -159,7 +158,7 @@ functionality:
|
|
|
159
158
|
|
|
160
159
|
* Install liboqs from https://github.com/open-quantum-safe/liboqs
|
|
161
160
|
if you want support for the OpenSSH post-quantum key exchange
|
|
162
|
-
|
|
161
|
+
algorithms based on ML-KEM and SNTRUP.
|
|
163
162
|
|
|
164
163
|
* Install libsodium from https://github.com/jedisct1/libsodium
|
|
165
164
|
and libnacl from https://pypi.python.org/pypi/libnacl if you have
|
|
@@ -109,7 +109,7 @@ from .sftp import SFTPByteRangeLockRefused, SFTPDeletePending
|
|
|
109
109
|
from .sftp import SFTPFileCorrupt, SFTPOwnerInvalid, SFTPGroupInvalid
|
|
110
110
|
from .sftp import SFTPNoMatchingByteRangeLock
|
|
111
111
|
from .sftp import SFTPConnectionLost, SFTPOpUnsupported
|
|
112
|
-
from .sftp import SFTPAttrs, SFTPVFSAttrs, SFTPName
|
|
112
|
+
from .sftp import SFTPAttrs, SFTPVFSAttrs, SFTPName, SFTPLimits
|
|
113
113
|
from .sftp import SEEK_SET, SEEK_CUR, SEEK_END
|
|
114
114
|
|
|
115
115
|
from .stream import SSHSocketSessionFactory, SSHServerSessionFactory
|
|
@@ -122,6 +122,7 @@ from .subprocess import SSHSubprocessProtocol, SSHSubprocessTransport
|
|
|
122
122
|
from . import sk_eddsa, sk_ecdsa, eddsa, ecdsa, rsa, dsa, kex_dh, kex_rsa
|
|
123
123
|
|
|
124
124
|
__all__ = [
|
|
125
|
+
'__author__', '__author_email__', '__url__', '__version__',
|
|
125
126
|
'BreakReceived', 'BytesOrStr', 'ChannelListenError',
|
|
126
127
|
'ChannelOpenError', 'CompressionError', 'ConfigParseError',
|
|
127
128
|
'ConnectionLost', 'DEVNULL', 'DataType', 'DisconnectError', 'Error',
|
|
@@ -136,15 +137,15 @@ __all__ = [
|
|
|
136
137
|
'SFTPDirNotEmpty', 'SFTPEOFError', 'SFTPError', 'SFTPFailure',
|
|
137
138
|
'SFTPFileAlreadyExists', 'SFTPFileCorrupt', 'SFTPFileIsADirectory',
|
|
138
139
|
'SFTPGroupInvalid', 'SFTPInvalidFilename', 'SFTPInvalidHandle',
|
|
139
|
-
'SFTPInvalidParameter', '
|
|
140
|
-
'
|
|
141
|
-
'
|
|
142
|
-
'
|
|
143
|
-
'
|
|
144
|
-
'SFTPServerFactory', 'SFTPUnknownPrincipal', 'SFTPVFSAttrs',
|
|
145
|
-
'SFTPWriteProtect', '
|
|
146
|
-
'
|
|
147
|
-
'SSHClientConnection', 'SSHClientConnectionOptions',
|
|
140
|
+
'SFTPInvalidParameter', 'SFTPLimits', 'SFTPLinkLoop', 'SFTPLockConflict',
|
|
141
|
+
'SFTPName', 'SFTPNoConnection', 'SFTPNoMatchingByteRangeLock',
|
|
142
|
+
'SFTPNoMedia', 'SFTPNoSpaceOnFilesystem', 'SFTPNoSuchFile',
|
|
143
|
+
'SFTPNoSuchPath', 'SFTPNotADirectory', 'SFTPOpUnsupported',
|
|
144
|
+
'SFTPOwnerInvalid', 'SFTPPermissionDenied', 'SFTPQuotaExceeded',
|
|
145
|
+
'SFTPServer', 'SFTPServerFactory', 'SFTPUnknownPrincipal', 'SFTPVFSAttrs',
|
|
146
|
+
'SFTPWriteProtect', 'SSHAcceptHandler', 'SSHAcceptor', 'SSHAgentClient',
|
|
147
|
+
'SSHAgentKeyPair', 'SSHAuthorizedKeys', 'SSHCertificate', 'SSHClient',
|
|
148
|
+
'SSHClientChannel', 'SSHClientConnection', 'SSHClientConnectionOptions',
|
|
148
149
|
'SSHClientProcess', 'SSHClientSession', 'SSHCompletedProcess',
|
|
149
150
|
'SSHForwarder', 'SSHKey', 'SSHKeyPair', 'SSHKnownHosts',
|
|
150
151
|
'SSHLineEditorChannel', 'SSHListener', 'SSHReader', 'SSHServer',
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"""SSH agent client"""
|
|
22
22
|
|
|
23
23
|
import asyncio
|
|
24
|
-
import errno
|
|
25
24
|
import os
|
|
26
25
|
import sys
|
|
27
26
|
from types import TracebackType
|
|
@@ -58,17 +57,10 @@ class AgentWriter(Protocol):
|
|
|
58
57
|
"""Wait for the connection to the SSH agent to close"""
|
|
59
58
|
|
|
60
59
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
from .agent_unix import open_agent
|
|
66
|
-
except ImportError as _exc: # pragma: no cover
|
|
67
|
-
async def open_agent(agent_path: str) -> \
|
|
68
|
-
Tuple[AgentReader, AgentWriter]:
|
|
69
|
-
"""Dummy function if we're unable to import agent support"""
|
|
70
|
-
|
|
71
|
-
raise OSError(errno.ENOENT, 'Agent support unavailable: %s' % str(_exc))
|
|
60
|
+
if sys.platform == 'win32': # pragma: no cover
|
|
61
|
+
from .agent_win32 import open_agent
|
|
62
|
+
else:
|
|
63
|
+
from .agent_unix import open_agent
|
|
72
64
|
|
|
73
65
|
|
|
74
66
|
class _SupportsOpenAgentConnection(Protocol):
|
|
@@ -260,7 +252,7 @@ class SSHAgentClient:
|
|
|
260
252
|
|
|
261
253
|
resplen = int.from_bytes((await reader.readexactly(4)), 'big')
|
|
262
254
|
|
|
263
|
-
resp = SSHPacket(
|
|
255
|
+
resp = SSHPacket(await reader.readexactly(resplen))
|
|
264
256
|
resptype = resp.get_byte()
|
|
265
257
|
|
|
266
258
|
return resptype, resp
|
|
@@ -306,7 +298,7 @@ class SSHAgentClient:
|
|
|
306
298
|
resp.check_end()
|
|
307
299
|
return result
|
|
308
300
|
else:
|
|
309
|
-
raise ValueError('Unknown SSH agent response:
|
|
301
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
310
302
|
|
|
311
303
|
async def sign(self, key_blob: bytes, data: bytes,
|
|
312
304
|
flags: int = 0) -> bytes:
|
|
@@ -323,7 +315,7 @@ class SSHAgentClient:
|
|
|
323
315
|
elif resptype == SSH_AGENT_FAILURE:
|
|
324
316
|
raise ValueError('Unable to sign with requested key')
|
|
325
317
|
else:
|
|
326
|
-
raise ValueError('Unknown SSH agent response:
|
|
318
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
327
319
|
|
|
328
320
|
async def add_keys(self, keylist: KeyPairListArg = (),
|
|
329
321
|
passphrase: Optional[str] = None,
|
|
@@ -405,7 +397,7 @@ class SSHAgentClient:
|
|
|
405
397
|
if not ignore_failures:
|
|
406
398
|
raise ValueError('Unable to add key')
|
|
407
399
|
else:
|
|
408
|
-
raise ValueError('Unknown SSH agent response:
|
|
400
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
409
401
|
|
|
410
402
|
async def add_smartcard_keys(self, provider: str,
|
|
411
403
|
pin: Optional[str] = None,
|
|
@@ -446,7 +438,7 @@ class SSHAgentClient:
|
|
|
446
438
|
elif resptype == SSH_AGENT_FAILURE:
|
|
447
439
|
raise ValueError('Unable to add keys')
|
|
448
440
|
else:
|
|
449
|
-
raise ValueError('Unknown SSH agent response:
|
|
441
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
450
442
|
|
|
451
443
|
async def remove_keys(self, keylist: Sequence[SSHKeyPair]) -> None:
|
|
452
444
|
"""Remove a key stored in the agent
|
|
@@ -469,7 +461,7 @@ class SSHAgentClient:
|
|
|
469
461
|
elif resptype == SSH_AGENT_FAILURE:
|
|
470
462
|
raise ValueError('Key not found')
|
|
471
463
|
else:
|
|
472
|
-
raise ValueError('Unknown SSH agent response:
|
|
464
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
473
465
|
|
|
474
466
|
async def remove_smartcard_keys(self, provider: str,
|
|
475
467
|
pin: Optional[str] = None) -> None:
|
|
@@ -495,7 +487,7 @@ class SSHAgentClient:
|
|
|
495
487
|
elif resptype == SSH_AGENT_FAILURE:
|
|
496
488
|
raise ValueError('Keys not found')
|
|
497
489
|
else:
|
|
498
|
-
raise ValueError('Unknown SSH agent response:
|
|
490
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
499
491
|
|
|
500
492
|
async def remove_all(self) -> None:
|
|
501
493
|
"""Remove all keys stored in the agent
|
|
@@ -512,7 +504,7 @@ class SSHAgentClient:
|
|
|
512
504
|
elif resptype == SSH_AGENT_FAILURE:
|
|
513
505
|
raise ValueError('Unable to remove all keys')
|
|
514
506
|
else:
|
|
515
|
-
raise ValueError('Unknown SSH agent response:
|
|
507
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
516
508
|
|
|
517
509
|
async def lock(self, passphrase: str) -> None:
|
|
518
510
|
"""Lock the agent using the specified passphrase
|
|
@@ -536,7 +528,7 @@ class SSHAgentClient:
|
|
|
536
528
|
elif resptype == SSH_AGENT_FAILURE:
|
|
537
529
|
raise ValueError('Unable to lock SSH agent')
|
|
538
530
|
else:
|
|
539
|
-
raise ValueError('Unknown SSH agent response:
|
|
531
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
540
532
|
|
|
541
533
|
async def unlock(self, passphrase: str) -> None:
|
|
542
534
|
"""Unlock the agent using the specified passphrase
|
|
@@ -560,7 +552,7 @@ class SSHAgentClient:
|
|
|
560
552
|
elif resptype == SSH_AGENT_FAILURE:
|
|
561
553
|
raise ValueError('Unable to unlock SSH agent')
|
|
562
554
|
else:
|
|
563
|
-
raise ValueError('Unknown SSH agent response:
|
|
555
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
564
556
|
|
|
565
557
|
async def query_extensions(self) -> Sequence[str]:
|
|
566
558
|
"""Return a list of extensions supported by the agent
|
|
@@ -589,7 +581,7 @@ class SSHAgentClient:
|
|
|
589
581
|
elif resptype == SSH_AGENT_FAILURE:
|
|
590
582
|
return []
|
|
591
583
|
else:
|
|
592
|
-
raise ValueError('Unknown SSH agent response:
|
|
584
|
+
raise ValueError(f'Unknown SSH agent response: {resptype}')
|
|
593
585
|
|
|
594
586
|
def close(self) -> None:
|
|
595
587
|
"""Close the SSH agent connection
|
|
@@ -78,7 +78,7 @@ class _PageantTransport:
|
|
|
78
78
|
"""Transport to connect to Pageant agent on Windows"""
|
|
79
79
|
|
|
80
80
|
def __init__(self) -> None:
|
|
81
|
-
self._mapname = '
|
|
81
|
+
self._mapname = f'{_AGENT_NAME}{win32api.GetCurrentThreadId():08x}'
|
|
82
82
|
|
|
83
83
|
try:
|
|
84
84
|
self._mapfile = mmapfile.mmapfile('', self._mapname,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2013-
|
|
1
|
+
# Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
|
|
2
2
|
#
|
|
3
3
|
# This program and the accompanying materials are made available under
|
|
4
4
|
# the terms of the Eclipse Public License v2.0 which accompanies this
|
|
@@ -169,8 +169,8 @@ class RawDERObject:
|
|
|
169
169
|
self.content = content
|
|
170
170
|
|
|
171
171
|
def __repr__(self) -> str:
|
|
172
|
-
return
|
|
173
|
-
|
|
172
|
+
return f'RawDERObject({_asn1_class[self.asn1_class]}, ' \
|
|
173
|
+
f'{self.tag}, {self.content!r})'
|
|
174
174
|
|
|
175
175
|
def __eq__(self, other: object) -> bool:
|
|
176
176
|
if not isinstance(other, RawDERObject): # pragma: no cover
|
|
@@ -213,10 +213,10 @@ class TaggedDERObject:
|
|
|
213
213
|
|
|
214
214
|
def __repr__(self) -> str:
|
|
215
215
|
if self.asn1_class == CONTEXT_SPECIFIC:
|
|
216
|
-
return 'TaggedDERObject(
|
|
216
|
+
return f'TaggedDERObject({self.tag}, {self.value!r})'
|
|
217
217
|
else:
|
|
218
|
-
return
|
|
219
|
-
|
|
218
|
+
return f'TaggedDERObject({_asn1_class[self.asn1_class]}, ' \
|
|
219
|
+
f'{self.tag}, {self.value!r})'
|
|
220
220
|
|
|
221
221
|
def __eq__(self, other: object) -> bool:
|
|
222
222
|
if not isinstance(other, TaggedDERObject): # pragma: no cover
|
|
@@ -469,7 +469,7 @@ class BitString(DERType):
|
|
|
469
469
|
return result
|
|
470
470
|
|
|
471
471
|
def __repr__(self) -> str:
|
|
472
|
-
return "BitString('
|
|
472
|
+
return f"BitString('{self}')"
|
|
473
473
|
|
|
474
474
|
def __eq__(self, other: object) -> bool:
|
|
475
475
|
if not isinstance(other, BitString): # pragma: no cover
|
|
@@ -508,10 +508,10 @@ class IA5String(DERType):
|
|
|
508
508
|
self.value = value
|
|
509
509
|
|
|
510
510
|
def __str__(self) -> str:
|
|
511
|
-
return
|
|
511
|
+
return self.value.decode('ascii')
|
|
512
512
|
|
|
513
513
|
def __repr__(self) -> str:
|
|
514
|
-
return 'IA5String(
|
|
514
|
+
return f'IA5String({self.value!r})'
|
|
515
515
|
|
|
516
516
|
def __eq__(self, other: object) -> bool: # pragma: no cover
|
|
517
517
|
if not isinstance(other, IA5String):
|
|
@@ -569,7 +569,7 @@ class ObjectIdentifier(DERType):
|
|
|
569
569
|
return self.value
|
|
570
570
|
|
|
571
571
|
def __repr__(self) -> str:
|
|
572
|
-
return "ObjectIdentifier('
|
|
572
|
+
return f"ObjectIdentifier('{self.value}')"
|
|
573
573
|
|
|
574
574
|
def __eq__(self, other: object) -> bool:
|
|
575
575
|
if not isinstance(other, ObjectIdentifier): # pragma: no cover
|
|
@@ -685,7 +685,7 @@ def der_encode(value: object) -> bytes:
|
|
|
685
685
|
identifier = cls.identifier
|
|
686
686
|
content = cls.encode(value)
|
|
687
687
|
else:
|
|
688
|
-
raise ASN1EncodeError('Cannot DER encode type
|
|
688
|
+
raise ASN1EncodeError(f'Cannot DER encode type {t.__name__}')
|
|
689
689
|
|
|
690
690
|
length = len(content)
|
|
691
691
|
if length < 0x80:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2013-
|
|
1
|
+
# Copyright (c) 2013-2024 by Ron Frederick <ronf@timeheart.net> and others.
|
|
2
2
|
#
|
|
3
3
|
# This program and the accompanying materials are made available under
|
|
4
4
|
# the terms of the Eclipse Public License v2.0 which accompanies this
|
|
@@ -27,6 +27,7 @@ from .constants import DEFAULT_LANG
|
|
|
27
27
|
from .gss import GSSBase, GSSError
|
|
28
28
|
from .logging import SSHLogger
|
|
29
29
|
from .misc import ProtocolError, PasswordChangeRequired, get_symbol_names
|
|
30
|
+
from .misc import run_in_executor
|
|
30
31
|
from .packet import Boolean, String, UInt32, SSHPacket, SSHPacketHandler
|
|
31
32
|
from .public_key import SigningKey
|
|
32
33
|
from .saslprep import saslprep, SASLPrepError
|
|
@@ -158,7 +159,7 @@ class _ClientGSSKexAuth(ClientAuth):
|
|
|
158
159
|
await self.send_request(key=self._conn.get_gss_context(),
|
|
159
160
|
trivial=False)
|
|
160
161
|
else:
|
|
161
|
-
self._conn.try_next_auth()
|
|
162
|
+
self._conn.try_next_auth(next_method=True)
|
|
162
163
|
|
|
163
164
|
|
|
164
165
|
class _ClientGSSMICAuth(ClientAuth):
|
|
@@ -180,10 +181,10 @@ class _ClientGSSMICAuth(ClientAuth):
|
|
|
180
181
|
|
|
181
182
|
self._gss = self._conn.get_gss_context()
|
|
182
183
|
self._gss.reset()
|
|
183
|
-
mechs = b''.join(
|
|
184
|
+
mechs = b''.join(String(mech) for mech in self._gss.mechs)
|
|
184
185
|
await self.send_request(UInt32(len(self._gss.mechs)), mechs)
|
|
185
186
|
else:
|
|
186
|
-
self._conn.try_next_auth()
|
|
187
|
+
self._conn.try_next_auth(next_method=True)
|
|
187
188
|
|
|
188
189
|
def _finish(self) -> None:
|
|
189
190
|
"""Finish client GSS MIC authentication"""
|
|
@@ -199,8 +200,8 @@ class _ClientGSSMICAuth(ClientAuth):
|
|
|
199
200
|
else:
|
|
200
201
|
self.send_packet(MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE)
|
|
201
202
|
|
|
202
|
-
def _process_response(self, _pkttype: int, _pktid: int,
|
|
203
|
-
|
|
203
|
+
async def _process_response(self, _pkttype: int, _pktid: int,
|
|
204
|
+
packet: SSHPacket) -> None:
|
|
204
205
|
"""Process a GSS response from the server"""
|
|
205
206
|
|
|
206
207
|
mech = packet.get_string()
|
|
@@ -212,7 +213,7 @@ class _ClientGSSMICAuth(ClientAuth):
|
|
|
212
213
|
raise ProtocolError('Mechanism mismatch')
|
|
213
214
|
|
|
214
215
|
try:
|
|
215
|
-
token = self._gss.step
|
|
216
|
+
token = await run_in_executor(self._gss.step)
|
|
216
217
|
assert token is not None
|
|
217
218
|
|
|
218
219
|
self.send_packet(MSG_USERAUTH_GSSAPI_TOKEN, String(token))
|
|
@@ -223,10 +224,10 @@ class _ClientGSSMICAuth(ClientAuth):
|
|
|
223
224
|
if exc.token:
|
|
224
225
|
self.send_packet(MSG_USERAUTH_GSSAPI_ERRTOK, String(exc.token))
|
|
225
226
|
|
|
226
|
-
self._conn.try_next_auth()
|
|
227
|
+
self._conn.try_next_auth(next_method=True)
|
|
227
228
|
|
|
228
|
-
def _process_token(self, _pkttype: int, _pktid: int,
|
|
229
|
-
|
|
229
|
+
async def _process_token(self, _pkttype: int, _pktid: int,
|
|
230
|
+
packet: SSHPacket) -> None:
|
|
230
231
|
"""Process a GSS token from the server"""
|
|
231
232
|
|
|
232
233
|
token: Optional[bytes] = packet.get_string()
|
|
@@ -235,7 +236,7 @@ class _ClientGSSMICAuth(ClientAuth):
|
|
|
235
236
|
assert self._gss is not None
|
|
236
237
|
|
|
237
238
|
try:
|
|
238
|
-
token = self._gss.step
|
|
239
|
+
token = await run_in_executor(self._gss.step, token)
|
|
239
240
|
|
|
240
241
|
if token:
|
|
241
242
|
self.send_packet(MSG_USERAUTH_GSSAPI_TOKEN, String(token))
|
|
@@ -246,7 +247,7 @@ class _ClientGSSMICAuth(ClientAuth):
|
|
|
246
247
|
if exc.token:
|
|
247
248
|
self.send_packet(MSG_USERAUTH_GSSAPI_ERRTOK, String(exc.token))
|
|
248
249
|
|
|
249
|
-
self._conn.try_next_auth()
|
|
250
|
+
self._conn.try_next_auth(next_method=True)
|
|
250
251
|
|
|
251
252
|
def _process_error(self, _pkttype: int, _pktid: int,
|
|
252
253
|
packet: SSHPacket) -> None:
|
|
@@ -261,8 +262,8 @@ class _ClientGSSMICAuth(ClientAuth):
|
|
|
261
262
|
self.logger.debug1('GSS error from server: %s', msg)
|
|
262
263
|
self._got_error = True
|
|
263
264
|
|
|
264
|
-
def _process_error_token(self, _pkttype: int, _pktid: int,
|
|
265
|
-
|
|
265
|
+
async def _process_error_token(self, _pkttype: int, _pktid: int,
|
|
266
|
+
packet: SSHPacket) -> None:
|
|
266
267
|
"""Process a GSS error token from the server"""
|
|
267
268
|
|
|
268
269
|
token = packet.get_string()
|
|
@@ -271,7 +272,7 @@ class _ClientGSSMICAuth(ClientAuth):
|
|
|
271
272
|
assert self._gss is not None
|
|
272
273
|
|
|
273
274
|
try:
|
|
274
|
-
self._gss.step
|
|
275
|
+
await run_in_executor(self._gss.step, token)
|
|
275
276
|
except GSSError as exc:
|
|
276
277
|
if not self._got_error: # pragma: no cover
|
|
277
278
|
self.logger.debug1('GSS error from server: %s', str(exc))
|
|
@@ -294,7 +295,7 @@ class _ClientHostBasedAuth(ClientAuth):
|
|
|
294
295
|
await self._conn.host_based_auth_requested()
|
|
295
296
|
|
|
296
297
|
if keypair is None:
|
|
297
|
-
self._conn.try_next_auth()
|
|
298
|
+
self._conn.try_next_auth(next_method=True)
|
|
298
299
|
return
|
|
299
300
|
|
|
300
301
|
self.logger.debug1('Trying host based auth of user %s on host %s '
|
|
@@ -322,7 +323,7 @@ class _ClientPublicKeyAuth(ClientAuth):
|
|
|
322
323
|
self._keypair = await self._conn.public_key_auth_requested()
|
|
323
324
|
|
|
324
325
|
if self._keypair is None:
|
|
325
|
-
self._conn.try_next_auth()
|
|
326
|
+
self._conn.try_next_auth(next_method=True)
|
|
326
327
|
return
|
|
327
328
|
|
|
328
329
|
self.logger.debug1('Trying public key auth with %s key',
|
|
@@ -340,10 +341,14 @@ class _ClientPublicKeyAuth(ClientAuth):
|
|
|
340
341
|
self.logger.debug1('Signing request with %s key',
|
|
341
342
|
self._keypair.algorithm)
|
|
342
343
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
344
|
+
try:
|
|
345
|
+
await self.send_request(Boolean(True),
|
|
346
|
+
String(self._keypair.algorithm),
|
|
347
|
+
String(self._keypair.public_data),
|
|
348
|
+
key=self._keypair, trivial=False)
|
|
349
|
+
except ValueError as exc:
|
|
350
|
+
self.logger.debug1('Public key auth failed: %s', str(exc))
|
|
351
|
+
self._conn.try_next_auth()
|
|
347
352
|
|
|
348
353
|
def _process_public_key_ok(self, _pkttype: int, _pktid: int,
|
|
349
354
|
packet: SSHPacket) -> None:
|
|
@@ -377,7 +382,7 @@ class _ClientKbdIntAuth(ClientAuth):
|
|
|
377
382
|
submethods = await self._conn.kbdint_auth_requested()
|
|
378
383
|
|
|
379
384
|
if submethods is None:
|
|
380
|
-
self._conn.try_next_auth()
|
|
385
|
+
self._conn.try_next_auth(next_method=True)
|
|
381
386
|
return
|
|
382
387
|
|
|
383
388
|
self.logger.debug1('Trying keyboard-interactive auth')
|
|
@@ -393,7 +398,7 @@ class _ClientKbdIntAuth(ClientAuth):
|
|
|
393
398
|
lang, prompts)
|
|
394
399
|
|
|
395
400
|
if responses is None:
|
|
396
|
-
self._conn.try_next_auth()
|
|
401
|
+
self._conn.try_next_auth(next_method=True)
|
|
397
402
|
return
|
|
398
403
|
|
|
399
404
|
self.send_packet(MSG_USERAUTH_INFO_RESPONSE, UInt32(len(responses)),
|
|
@@ -454,7 +459,7 @@ class _ClientPasswordAuth(ClientAuth):
|
|
|
454
459
|
password = await self._conn.password_auth_requested()
|
|
455
460
|
|
|
456
461
|
if password is None:
|
|
457
|
-
self._conn.try_next_auth()
|
|
462
|
+
self._conn.try_next_auth(next_method=True)
|
|
458
463
|
return
|
|
459
464
|
|
|
460
465
|
self.logger.debug1('Trying password auth')
|
|
@@ -469,7 +474,7 @@ class _ClientPasswordAuth(ClientAuth):
|
|
|
469
474
|
|
|
470
475
|
if result == NotImplemented:
|
|
471
476
|
# Password change not supported - move on to the next auth method
|
|
472
|
-
self._conn.try_next_auth()
|
|
477
|
+
self._conn.try_next_auth(next_method=True)
|
|
473
478
|
return
|
|
474
479
|
|
|
475
480
|
self.logger.debug1('Trying to chsnge password')
|
|
@@ -649,15 +654,15 @@ class _ServerGSSMICAuth(ServerAuth):
|
|
|
649
654
|
else:
|
|
650
655
|
self.send_failure()
|
|
651
656
|
|
|
652
|
-
def _process_token(self, _pkttype: int, _pktid: int,
|
|
653
|
-
|
|
657
|
+
async def _process_token(self, _pkttype: int, _pktid: int,
|
|
658
|
+
packet: SSHPacket) -> None:
|
|
654
659
|
"""Process a GSS token from the client"""
|
|
655
660
|
|
|
656
661
|
token: Optional[bytes] = packet.get_string()
|
|
657
662
|
packet.check_end()
|
|
658
663
|
|
|
659
664
|
try:
|
|
660
|
-
token = self._gss.step
|
|
665
|
+
token = await run_in_executor(self._gss.step, token)
|
|
661
666
|
|
|
662
667
|
if token:
|
|
663
668
|
self.send_packet(MSG_USERAUTH_GSSAPI_TOKEN, String(token))
|
|
@@ -682,15 +687,15 @@ class _ServerGSSMICAuth(ServerAuth):
|
|
|
682
687
|
else:
|
|
683
688
|
self.send_failure()
|
|
684
689
|
|
|
685
|
-
def _process_error_token(self, _pkttype: int, _pktid: int,
|
|
686
|
-
|
|
690
|
+
async def _process_error_token(self, _pkttype: int, _pktid: int,
|
|
691
|
+
packet: SSHPacket) -> None:
|
|
687
692
|
"""Process a GSS error token from the client"""
|
|
688
693
|
|
|
689
694
|
token = packet.get_string()
|
|
690
695
|
packet.check_end()
|
|
691
696
|
|
|
692
697
|
try:
|
|
693
|
-
self._gss.step
|
|
698
|
+
await run_in_executor(self._gss.step, token)
|
|
694
699
|
except GSSError as exc:
|
|
695
700
|
self.logger.debug1('GSS error from client: %s', str(exc))
|
|
696
701
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) 2015-
|
|
1
|
+
# Copyright (c) 2015-2024 by Ron Frederick <ronf@timeheart.net> and others.
|
|
2
2
|
#
|
|
3
3
|
# This program and the accompanying materials are made available under
|
|
4
4
|
# the terms of the Eclipse Public License v2.0 which accompanies this
|
|
@@ -120,8 +120,8 @@ class _SSHAuthorizedKeyEntry:
|
|
|
120
120
|
host = host[1:-1]
|
|
121
121
|
|
|
122
122
|
port = None if port_str == '*' else int(port_str)
|
|
123
|
-
except:
|
|
124
|
-
raise ValueError('Illegal permitopen value:
|
|
123
|
+
except ValueError:
|
|
124
|
+
raise ValueError(f'Illegal permitopen value: {value}') from None
|
|
125
125
|
|
|
126
126
|
permitted_opens = cast(Set[Tuple[str, Optional[int]]],
|
|
127
127
|
self.options.setdefault(option, set()))
|