diff options
Diffstat (limited to 'paramiko/transport.py')
-rw-r--r-- | paramiko/transport.py | 154 |
1 files changed, 72 insertions, 82 deletions
diff --git a/paramiko/transport.py b/paramiko/transport.py index 7ff40933..bab23fa1 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -58,6 +58,7 @@ from paramiko.ed25519key import Ed25519Key from paramiko.kex_gex import KexGex, KexGexSHA256 from paramiko.kex_group1 import KexGroup1 from paramiko.kex_group14 import KexGroup14 +from paramiko.kex_ecdh_nist import KexNistp256, KexNistp384, KexNistp521 from paramiko.kex_gss import KexGSSGex, KexGSSGroup1, KexGSSGroup14 from paramiko.message import Message from paramiko.packet import Packetizer, NeedRekeyException @@ -73,7 +74,6 @@ from paramiko.ssh_exception import ( from paramiko.util import retry_on_signal, ClosingContextManager, clamp_value - # for thread cleanup _active_threads = [] @@ -109,31 +109,35 @@ class Transport(threading.Thread, ClosingContextManager): 'aes192-ctr', 'aes256-ctr', 'aes128-cbc', - 'blowfish-cbc', 'aes192-cbc', 'aes256-cbc', + 'blowfish-cbc', '3des-cbc', - 'arcfour128', - 'arcfour256', ) _preferred_macs = ( 'hmac-sha2-256', 'hmac-sha2-512', + 'hmac-sha1', 'hmac-md5', 'hmac-sha1-96', 'hmac-md5-96', - 'hmac-sha1', ) _preferred_keys = ( 'ssh-ed25519', + 'ecdsa-sha2-nistp256', + 'ecdsa-sha2-nistp384', + 'ecdsa-sha2-nistp521', 'ssh-rsa', 'ssh-dss', - ) + tuple(ECDSAKey.supported_key_format_identifiers()) + ) _preferred_kex = ( - 'diffie-hellman-group1-sha1', - 'diffie-hellman-group14-sha1', - 'diffie-hellman-group-exchange-sha1', + 'ecdh-sha2-nistp256', + 'ecdh-sha2-nistp384', + 'ecdh-sha2-nistp521', 'diffie-hellman-group-exchange-sha256', + 'diffie-hellman-group-exchange-sha1', + 'diffie-hellman-group14-sha1', + 'diffie-hellman-group1-sha1', ) _preferred_compression = ('none',) @@ -186,18 +190,6 @@ class Transport(threading.Thread, ClosingContextManager): 'block-size': 8, 'key-size': 24 }, - 'arcfour128': { - 'class': algorithms.ARC4, - 'mode': None, - 'block-size': 8, - 'key-size': 16 - }, - 'arcfour256': { - 'class': algorithms.ARC4, - 'mode': None, - 'block-size': 8, - 'key-size': 32 - }, } @@ -214,6 +206,8 @@ class Transport(threading.Thread, ClosingContextManager): 'ssh-rsa': RSAKey, 'ssh-dss': DSSKey, 'ecdsa-sha2-nistp256': ECDSAKey, + 'ecdsa-sha2-nistp384': ECDSAKey, + 'ecdsa-sha2-nistp521': ECDSAKey, 'ssh-ed25519': Ed25519Key, } @@ -224,7 +218,10 @@ class Transport(threading.Thread, ClosingContextManager): 'diffie-hellman-group-exchange-sha256': KexGexSHA256, 'gss-group1-sha1-toWM5Slw5Ew8Mqkay+al2g==': KexGSSGroup1, 'gss-group14-sha1-toWM5Slw5Ew8Mqkay+al2g==': KexGSSGroup14, - 'gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==': KexGSSGex + 'gss-gex-sha1-toWM5Slw5Ew8Mqkay+al2g==': KexGSSGex, + 'ecdh-sha2-nistp256': KexNistp256, + 'ecdh-sha2-nistp384': KexNistp384, + 'ecdh-sha2-nistp521': KexNistp521, } _compression_info = { @@ -290,7 +287,6 @@ class Transport(threading.Thread, ClosingContextManager): arguments. """ self.active = False - self._sshclient = None if isinstance(sock, string_types): # convert "host:port" into (host, port) @@ -324,14 +320,9 @@ class Transport(threading.Thread, ClosingContextManager): threading.Thread.__init__(self) self.setDaemon(True) self.sock = sock - # Python < 2.3 doesn't have the settimeout method - RogerB - try: - # we set the timeout so we can check self.active periodically to - # see if we should bail. socket.timeout exception is never - # propagated. - self.sock.settimeout(self._active_check_timeout) - except AttributeError: - pass + # we set the timeout so we can check self.active periodically to + # see if we should bail. socket.timeout exception is never propagated. + self.sock.settimeout(self._active_check_timeout) # negotiated crypto parameters self.packetizer = Packetizer(sock) @@ -400,6 +391,8 @@ class Transport(threading.Thread, ClosingContextManager): # how long (seconds) to wait for the handshake to finish after SSH # banner sent. self.handshake_timeout = 15 + # how long (seconds) to wait for the auth response. + self.auth_timeout = 30 # server mode: self.server_mode = False @@ -459,7 +452,6 @@ class Transport(threading.Thread, ClosingContextManager): :param str gss_host: The targets name in the kerberos database Default: The name of the host to connect to - :rtype: Void """ # We need the FQDN to get this working with SSPI self.gss_host = socket.getfqdn(gss_host) @@ -495,8 +487,9 @@ class Transport(threading.Thread, ClosingContextManager): :param float timeout: a timeout, in seconds, for SSH2 session negotiation (optional) - :raises SSHException: if negotiation fails (and no ``event`` was passed - in) + :raises: + `.SSHException` -- if negotiation fails (and no ``event`` was + passed in) """ self.active = True if event is not None: @@ -560,8 +553,9 @@ class Transport(threading.Thread, ClosingContextManager): an object used to perform authentication and create `channels <.Channel>` - :raises SSHException: if negotiation fails (and no ``event`` was passed - in) + :raises: + `.SSHException` -- if negotiation fails (and no ``event`` was + passed in) """ if server is None: server = ServerInterface() @@ -663,9 +657,6 @@ class Transport(threading.Thread, ClosingContextManager): Transport._modulus_pack = None return False - def set_sshclient(self, sshclient): - self._sshclient = sshclient - def close(self): """ Close this session, and any open channels that are tied to it. @@ -676,7 +667,6 @@ class Transport(threading.Thread, ClosingContextManager): for chan in list(self._channels.values()): chan._unlink() self.sock.close() - self._sshclient = None def get_remote_server_key(self): """ @@ -687,7 +677,7 @@ class Transport(threading.Thread, ClosingContextManager): string)``. You can get the same effect by calling `.PKey.get_name` for the key type, and ``str(key)`` for the key string. - :raises SSHException: if no session is currently active. + :raises: `.SSHException` -- if no session is currently active. :return: public key (`.PKey`) of the remote server """ @@ -727,7 +717,8 @@ class Transport(threading.Thread, ClosingContextManager): :return: a new `.Channel` - :raises SSHException: if the request is rejected or the session ends + :raises: + `.SSHException` -- if the request is rejected or the session ends prematurely .. versionchanged:: 1.13.4/1.14.3/1.15.3 @@ -750,7 +741,8 @@ class Transport(threading.Thread, ClosingContextManager): x11 port, ie. 6010) :return: a new `.Channel` - :raises SSHException: if the request is rejected or the session ends + :raises: + `.SSHException` -- if the request is rejected or the session ends prematurely """ return self.open_channel('x11', src_addr=src_addr) @@ -764,7 +756,7 @@ class Transport(threading.Thread, ClosingContextManager): :return: a new `.Channel` - :raises SSHException: + :raises: `.SSHException` -- if the request is rejected or the session ends prematurely """ return self.open_channel('auth-agent@openssh.com') @@ -816,7 +808,8 @@ class Transport(threading.Thread, ClosingContextManager): :return: a new `.Channel` on success - :raises SSHException: if the request is rejected, the session ends + :raises: + `.SSHException` -- if the request is rejected, the session ends prematurely or there is a timeout openning a channel .. versionchanged:: 1.15 @@ -903,7 +896,8 @@ class Transport(threading.Thread, ClosingContextManager): :return: the port number (`int`) allocated by the server - :raises SSHException: if the server refused the TCP forward request + :raises: + `.SSHException` -- if the server refused the TCP forward request """ if not self.active: raise SSHException('SSH session not active') @@ -977,8 +971,9 @@ class Transport(threading.Thread, ClosingContextManager): traffic both ways as the two sides swap keys and do computations. This method returns when the session has switched to new keys. - :raises SSHException: if the key renegotiation failed (which causes the - session to end) + :raises: + `.SSHException` -- if the key renegotiation failed (which causes + the session to end) """ self.completion_event = threading.Event() self._send_kex_init() @@ -1119,7 +1114,7 @@ class Transport(threading.Thread, ClosingContextManager): :param bool gss_deleg_creds: Whether to delegate GSS-API client credentials. - :raises SSHException: if the SSH2 negotiation fails, the host key + :raises: `.SSHException` -- if the SSH2 negotiation fails, the host key supplied by the server is incorrect, or authentication fails. """ if hostkey is not None: @@ -1193,7 +1188,7 @@ class Transport(threading.Thread, ClosingContextManager): passed to the `.SubsystemHandler` constructor later. :param str name: name of the subsystem. - :param class handler: + :param handler: subclass of `.SubsystemHandler` that handles this subsystem. """ try: @@ -1254,9 +1249,11 @@ class Transport(threading.Thread, ClosingContextManager): `list` of auth types permissible for the next stage of authentication (normally empty) - :raises BadAuthenticationType: if "none" authentication isn't allowed + :raises: + `.BadAuthenticationType` -- if "none" authentication isn't allowed by the server for this user - :raises SSHException: if the authentication failed due to a network + :raises: + `.SSHException` -- if the authentication failed due to a network error .. versionadded:: 1.5 @@ -1307,11 +1304,13 @@ class Transport(threading.Thread, ClosingContextManager): `list` of auth types permissible for the next stage of authentication (normally empty) - :raises BadAuthenticationType: if password authentication isn't + :raises: + `.BadAuthenticationType` -- if password authentication isn't allowed by the server for this user (and no event was passed in) - :raises AuthenticationException: if the authentication failed (and no + :raises: + `.AuthenticationException` -- if the authentication failed (and no event was passed in) - :raises SSHException: if there was a network error + :raises: `.SSHException` -- if there was a network error """ if (not self.active) or (not self.initial_kex_done): # we should never try to send the password unless we're on a secure @@ -1376,11 +1375,13 @@ class Transport(threading.Thread, ClosingContextManager): `list` of auth types permissible for the next stage of authentication (normally empty) - :raises BadAuthenticationType: if public-key authentication isn't + :raises: + `.BadAuthenticationType` -- if public-key authentication isn't allowed by the server for this user (and no event was passed in) - :raises AuthenticationException: if the authentication failed (and no + :raises: + `.AuthenticationException` -- if the authentication failed (and no event was passed in) - :raises SSHException: if there was a network error + :raises: `.SSHException` -- if there was a network error """ if (not self.active) or (not self.initial_kex_done): # we should never try to authenticate unless we're on a secure link @@ -1432,10 +1433,10 @@ class Transport(threading.Thread, ClosingContextManager): `list` of auth types permissible for the next stage of authentication (normally empty). - :raises BadAuthenticationType: if public-key authentication isn't + :raises: `.BadAuthenticationType` -- if public-key authentication isn't allowed by the server for this user - :raises AuthenticationException: if the authentication failed - :raises SSHException: if there was a network error + :raises: `.AuthenticationException` -- if the authentication failed + :raises: `.SSHException` -- if there was a network error .. versionadded:: 1.5 """ @@ -1480,11 +1481,12 @@ class Transport(threading.Thread, ClosingContextManager): :return: list of auth types permissible for the next stage of authentication (normally empty) :rtype: list - :raise BadAuthenticationType: if gssapi-with-mic isn't + :raises: `.BadAuthenticationType` -- if gssapi-with-mic isn't allowed by the server (and no event was passed in) - :raise AuthenticationException: if the authentication failed (and no + :raises: + `.AuthenticationException` -- if the authentication failed (and no event was passed in) - :raise SSHException: if there was a network error + :raises: `.SSHException` -- if there was a network error """ if (not self.active) or (not self.initial_kex_done): # we should never try to authenticate unless we're on a secure link @@ -1504,12 +1506,12 @@ class Transport(threading.Thread, ClosingContextManager): :returns: a `list` of auth types permissible for the next stage of authentication (normally empty) - :raises BadAuthenticationType: + :raises: `.BadAuthenticationType` -- if GSS-API Key Exchange was not performed (and no event was passed in) - :raises AuthenticationException: + :raises: `.AuthenticationException` -- if the authentication failed (and no event was passed in) - :raises SSHException: if there was a network error + :raises: `.SSHException` -- if there was a network error """ if (not self.active) or (not self.initial_kex_done): # we should never try to authenticate unless we're on a secure link @@ -1731,21 +1733,6 @@ class Transport(threading.Thread, ClosingContextManager): def _get_cipher(self, name, key, iv, operation): if name not in self._cipher_info: raise SSHException('Unknown client cipher ' + name) - if name in ('arcfour128', 'arcfour256'): - # arcfour cipher - cipher = Cipher( - self._cipher_info[name]['class'](key), - None, - backend=default_backend() - ) - if operation is self._ENCRYPT: - engine = cipher.encryptor() - else: - engine = cipher.decryptor() - # as per RFC 4345, the first 1536 bytes of keystream - # generated by the cipher MUST be discarded - engine.encrypt(" " * 1536) - return engine else: cipher = Cipher( self._cipher_info[name]['class'](key), @@ -2113,6 +2100,9 @@ class Transport(threading.Thread, ClosingContextManager): self.host_key_type = agreed_keys[0] if self.server_mode and (self.get_server_key() is None): raise SSHException('Incompatible ssh peer (can\'t match requested host key type)') # noqa + self._log_agreement( + 'HostKey', agreed_keys[0], agreed_keys[0] + ) if self.server_mode: agreed_local_ciphers = list(filter( |