Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-asyncssh for openSUSE:Factory checked in at 2023-07-03 17:42:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-asyncssh (Old) and /work/SRC/openSUSE:Factory/.python-asyncssh.new.13546 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-asyncssh" Mon Jul 3 17:42:14 2023 rev:23 rq:1096323 version:2.13.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-asyncssh/python-asyncssh.changes 2023-03-07 16:50:43.277706757 +0100 +++ /work/SRC/openSUSE:Factory/.python-asyncssh.new.13546/python-asyncssh.changes 2023-07-03 17:42:15.224530767 +0200 @@ -1,0 +2,19 @@ +Sat Jul 1 20:43:24 UTC 2023 - Dirk Müller <dmuel...@suse.com> + +- update to 2.13.2: + * Fixed an issue with host-based authentication when using + proxy_command, allowing it to be used if the caller + explicitly specifies client_host. + * Improved handling of signature algorithms for OpenSSH + certificates so that RSA SHA-2 signatures will work with + both older and newer versions of OpenSSH. + * Worked around an issue with some Cisco SSH implementations + generating invalid "ignore" packets. + * Fixed unit tests to avoid errors when cryptography's version + of * OpenSSL disables support for SHA-1 signatures. + * Fixed unit tests to avoid errors when the filesystem enforces + that filenames be valid UTF-8 strings. + * Added documentation about which config options apply when + passing a string as a tunnel argument. + +------------------------------------------------------------------- Old: ---- asyncssh-2.13.1.tar.gz New: ---- asyncssh-2.13.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-asyncssh.spec ++++++ --- /var/tmp/diff_new_pack.Xpov4R/_old 2023-07-03 17:42:15.948535029 +0200 +++ /var/tmp/diff_new_pack.Xpov4R/_new 2023-07-03 17:42:15.956535077 +0200 @@ -19,7 +19,7 @@ %define skip_python2 1 %define skip_python36 1 Name: python-asyncssh -Version: 2.13.1 +Version: 2.13.2 Release: 0 Summary: Asynchronous SSHv2 client and server library License: EPL-2.0 OR GPL-2.0-or-later ++++++ asyncssh-2.13.1.tar.gz -> asyncssh-2.13.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/PKG-INFO new/asyncssh-2.13.2/PKG-INFO --- old/asyncssh-2.13.1/PKG-INFO 2023-02-19 00:03:44.881586800 +0100 +++ new/asyncssh-2.13.2/PKG-INFO 2023-06-22 05:08:52.759388400 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: asyncssh -Version: 2.13.1 +Version: 2.13.2 Summary: AsyncSSH: Asynchronous SSHv2 client and server library Home-page: http://asyncssh.timeheart.net Author: Ron Frederick @@ -35,6 +35,15 @@ Provides-Extra: pywin32 License-File: LICENSE +.. image:: https://readthedocs.org/projects/asyncssh/badge/?version=latest + :target: https://asyncssh.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://img.shields.io/pypi/v/asyncssh.svg + :target: https://pypi.python.org/pypi/asyncssh/ + :alt: AsyncSSH PyPI Project + + AsyncSSH: Asynchronous SSH for Python ===================================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/README.rst new/asyncssh-2.13.2/README.rst --- old/asyncssh-2.13.1/README.rst 2022-08-11 02:01:29.000000000 +0200 +++ new/asyncssh-2.13.2/README.rst 2023-06-22 04:57:39.000000000 +0200 @@ -1,3 +1,12 @@ +.. image:: https://readthedocs.org/projects/asyncssh/badge/?version=latest + :target: https://asyncssh.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://img.shields.io/pypi/v/asyncssh.svg + :target: https://pypi.python.org/pypi/asyncssh/ + :alt: AsyncSSH PyPI Project + + AsyncSSH: Asynchronous SSH for Python ===================================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/channel.py new/asyncssh-2.13.2/asyncssh/channel.py --- old/asyncssh-2.13.1/asyncssh/channel.py 2023-02-18 23:52:45.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/channel.py 2023-06-22 04:57:39.000000000 +0200 @@ -1007,7 +1007,7 @@ This method can be called to resume delivery of incoming data which was suspended by a call to :meth:`pause_reading`. As soon as this method is called, any buffered data will be delivered - immediately. A pending end-of-file notication may also be + immediately. A pending end-of-file notification may also be delivered if one was queued while reading was paused. """ @@ -1042,7 +1042,7 @@ This method returns the command the client requested to execute when the session was opened, if any. If the client did not request that a command be executed, this method - will return `None`. On the server, alls to this method + will return `None`. On the server, calls to this method should only be made after :meth:`session_started <SSHServerSession.session_started>` has been called on the :class:`SSHServerSession`. When using the stream-based API, @@ -1829,7 +1829,7 @@ forwarding, this method returns `None`. :returns: A `str` containing the X11 display or `None` if - X11 fowarding was not requested + X11 forwarding was not requested """ @@ -1845,7 +1845,7 @@ `None`. :returns: A `str` containing the ssh-agent socket path or - `None` if agent fowarding was not requested + `None` if agent forwarding was not requested """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/client.py new/asyncssh-2.13.2/asyncssh/client.py --- old/asyncssh-2.13.1/asyncssh/client.py 2022-01-23 17:15:42.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/client.py 2023-06-22 04:57:39.000000000 +0200 @@ -216,7 +216,7 @@ """Authentication was completed successfully This method is called when authentication has completed - succesfully. Applications may use this method to create + successfully. Applications may use this method to create whatever client sessions and direct TCP/IP or UNIX domain connections are needed and/or set up listeners for incoming TCP/IP or UNIX domain connections coming from the server. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/connection.py new/asyncssh-2.13.2/asyncssh/connection.py --- old/asyncssh-2.13.1/asyncssh/connection.py 2023-02-18 23:52:45.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/connection.py 2023-06-22 04:57:39.000000000 +0200 @@ -664,7 +664,7 @@ This class in a wrapper around an :class:`asyncio.Server` listener which provides the ability to update the the set of SSH client or - server connection options associated wtih that listener. This is + server connection options associated with that listener. This is accomplished by calling the :meth:`update` method, which takes the same keyword arguments as the :class:`SSHClientConnectionOptions` and :class:`SSHServerConnectionOptions` classes. @@ -1988,10 +1988,11 @@ packet: SSHPacket) -> None: """Process an ignore message""" - # pylint: disable=no-self-use - - _ = packet.get_string() # data - packet.check_end() + # Work around missing payload bytes in an ignore message + # in some Cisco SSH servers + if b'Cisco' not in self._server_version: # pragma: no branch + _ = packet.get_string() # data + packet.check_end() def _process_unimplemented(self, _pkttype: int, _pktid: int, packet: SSHPacket) -> None: @@ -2544,7 +2545,7 @@ """Forcibly close the SSH connection This method closes the SSH connection immediately, without - waiting for pending operations to complete and wihtout sending + waiting for pending operations to complete and without sending an explicit SSH disconnect message. Buffered data waiting to be sent will be lost and no more data will be received. When the the connection is closed, :meth:`connection_lost() @@ -3073,6 +3074,7 @@ self._client_keys: List[SSHKeyPair] = \ list(options.client_keys) if options.client_keys else [] + self._saved_rsa_key: Optional[_ClientHostKey] = None if options.preferred_auth != (): self._preferred_auth = [method.encode('ascii') for method in @@ -3313,24 +3315,39 @@ if not self._host_based_auth: return None, '', '' + key: Optional[_ClientHostKey] + while True: - try: - key: Optional[_ClientHostKey] = self._client_host_keys.pop(0) - except IndexError: - key = None - break + if self._saved_rsa_key: + key = self._saved_rsa_key + key.algorithm = key.sig_algorithm + b'-cert-...@openssh.com' + self._saved_rsa_key = None + else: + try: + key = self._client_host_keys.pop(0) + except IndexError: + key = None + break assert key is not None if self._choose_signature_alg(key): + if key.algorithm == b'ssh-rsa-cert-...@openssh.com' and \ + key.sig_algorithm != b'ssh-rsa': + self._saved_rsa_key = key + break client_host = self._options.client_host if client_host is None: - client_host, _ = await self._loop.getnameinfo( - cast(SockAddr, self.get_extra_info('sockname')), - socket.NI_NUMERICSERV) + sockname = self.get_extra_info('sockname') + + if sockname: + client_host, _ = await self._loop.getnameinfo( + cast(SockAddr, sockname), socket.NI_NUMERICSERV) + else: + client_host = '' # Add a trailing '.' to the client host to be compatible with # ssh-keysign from OpenSSH @@ -3377,10 +3394,33 @@ self._client_keys = list(load_keypairs(result)) - keypair = self._client_keys.pop(0) + # OpenSSH versions before 7.8 didn't support RSA SHA-2 + # signature names in certificate key types, requiring the + # use of ssh-rsa-cert-...@openssh.com as the key type even + # when using SHA-2 signatures. However, OpenSSL 8.8 and + # later reject ssh-rsa-cert-...@openssh.com as a key type + # by default, requiring that the RSA SHA-2 version of the key + # type be used. This makes it difficult to use RSA keys with + # certificates without knowing the version of the remote + # server and which key types it will accept. + # + # The code below works around this by trying multiple key + # types during public key and host-based authentication when + # using SHA-2 signatures with RSA keys signed by certificates. + + if self._saved_rsa_key: + key = self._saved_rsa_key + key.algorithm = key.sig_algorithm + b'-cert-...@openssh.com' + self._saved_rsa_key = None + else: + key = self._client_keys.pop(0) + + if self._choose_signature_alg(key): + if key.algorithm == b'ssh-rsa-cert-...@openssh.com' and \ + key.sig_algorithm != b'ssh-rsa': + self._saved_rsa_key = key - if self._choose_signature_alg(keypair): - return keypair + return key async def password_auth_requested(self) -> Optional[str]: """Return a password to authenticate with""" @@ -5182,7 +5222,7 @@ self._keepalive_interval = options.keepalive_interval def choose_server_host_key(self, - peer_host_key_algs: Sequence[bytes]) -> bool: + peer_host_key_algs: Sequence[bytes]) -> bool: """Choose the server host key to use Given a list of host key algorithms supported by the client, @@ -6723,7 +6763,7 @@ :param password_auth: (optional) Whether or not to allow password authentication. By default, password authentication is enabled if a password is specified - or if callbacks to provide a password are made availble. + or if callbacks to provide a password are made available. :param gss_host: (optional) The principal name to use for the host in GSS key exchange and authentication. If not specified, this value will be the same @@ -6913,7 +6953,7 @@ :param config: (optional) Paths to OpenSSH client configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. .. note:: Specifying configuration files when creating an @@ -7372,7 +7412,7 @@ client connected from. :param authorized_client_keys: (optional) A list of authorized user and CA public keys which should be - trusted for certifcate-based client public key authentication. + trusted for certificate-based client public key authentication. :param x509_trusted_certs: (optional) A list of certificates which should be trusted for X.509 client certificate authentication. If this argument is explicitly set @@ -7562,7 +7602,7 @@ :param config: (optional) Paths to OpenSSH server configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. .. note:: Specifying configuration files when creating an @@ -7850,7 +7890,7 @@ :param config: (optional) Paths to OpenSSH client configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. If no paths are specified and no config paths were set when constructing the `options` argument (if any), an attempt will be made to load the @@ -7904,7 +7944,7 @@ :param config: (optional) Paths to OpenSSH server configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. By default, no OpenSSH configuration files will be loaded. See :ref:`SupportedServerConfigOptions` for details on what @@ -7985,6 +8025,17 @@ [user@]host[:port] may also be specified, in which case a connection will first be made to that host and it will then be used as a tunnel. + + .. note:: When specifying tunnel as a string, any config + options in the call will apply only when opening + the connection inside the tunnel. The tunnel + itself will be opened with default configuration + settings or settings in the default config file. + To get more control of config settings used to + open the tunnel, :func:`connect` can be called + explicitly, and the resulting client connection + can be passed as the tunnel argument. + :param family: (optional) The address family to use when creating the socket. By default, the address family is automatically selected based on the host. @@ -7999,7 +8050,7 @@ :param config: (optional) Paths to OpenSSH client configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. If no paths are specified and no config paths were set when constructing the `options` argument (if any), an attempt will be made to load the @@ -8080,6 +8131,17 @@ [user@]host[:port] may also be specified, in which case a connection will first be made to that host and it will then be used as a tunnel. + + .. note:: When specifying tunnel as a string, any config + options in the call will apply only when opening + the connection inside the tunnel. The tunnel + itself will be opened with default configuration + settings or settings in the default config file. + To get more control of config settings used to + open the tunnel, :func:`connect` can be called + explicitly, and the resulting client connection + can be passed as the tunnel argument. + :param family: (optional) The address family to use when creating the socket. By default, the address family is automatically selected based on the host. @@ -8094,7 +8156,7 @@ :param config: (optional) Paths to OpenSSH server configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. By default, no OpenSSH configuration files will be loaded. See :ref:`SupportedServerConfigOptions` for details on what @@ -8166,6 +8228,17 @@ [user@]host[:port] may also be specified, in which case a connection will first be made to that host and it will then be used as a tunnel. + + .. note:: When specifying tunnel as a string, any config + options in the call will apply only when opening + the connection inside the tunnel. The tunnel + itself will be opened with default configuration + settings or settings in the default config file. + To get more control of config settings used to + open the tunnel, :func:`connect` can be called + explicitly, and the resulting client connection + can be passed as the tunnel argument. + :param family: (optional) The address family to use when creating the server. By default, the address families are automatically selected based on the host. @@ -8200,7 +8273,7 @@ :param config: (optional) Paths to OpenSSH server configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. By default, no OpenSSH configuration files will be loaded. See :ref:`SupportedServerConfigOptions` for details on what @@ -8289,6 +8362,17 @@ [user@]host[:port] may also be specified, in which case a connection will first be made to that host and it will then be used as a tunnel. + + .. note:: When specifying tunnel as a string, any config + options in the call will apply only when opening + the connection inside the tunnel. The tunnel + itself will be opened with default configuration + settings or settings in the default config file. + To get more control of config settings used to + open the tunnel, :func:`connect` can be called + explicitly, and the resulting client connection + can be passed as the tunnel argument. + :param family: (optional) The address family to use when creating the server. By default, the address families are automatically selected based on the host. @@ -8322,7 +8406,7 @@ :param config: (optional) Paths to OpenSSH client configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. If no paths are specified and no config paths were set when constructing the `options` argument (if any), an attempt will be made to load the @@ -8459,6 +8543,17 @@ [user@]host[:port] may also be specified, in which case a connection will first be made to that host and it will then be used as a tunnel. + + .. note:: When specifying tunnel as a string, any config + options in the call will apply only when opening + the connection inside the tunnel. The tunnel + itself will be opened with default configuration + settings or settings in the default config file. + To get more control of config settings used to + open the tunnel, :func:`connect` can be called + explicitly, and the resulting client connection + can be passed as the tunnel argument. + :param proxy_command: (optional) A string or list of strings specifying a command and arguments to run to make a connection to the SSH server. Data will be @@ -8489,7 +8584,7 @@ :param config: (optional) Paths to OpenSSH client configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. If no paths are specified and no config paths were set when constructing the `options` argument (if any), an attempt will be made to load the @@ -8590,6 +8685,17 @@ [user@]host[:port] may also be specified, in which case a connection will first be made to that host and it will then be used as a tunnel. + + .. note:: When specifying tunnel as a string, any config + options in the call will apply only when opening + the connection inside the tunnel. The tunnel + itself will be opened with default configuration + settings or settings in the default config file. + To get more control of config settings used to + open the tunnel, :func:`connect` can be called + explicitly, and the resulting client connection + can be passed as the tunnel argument. + :param proxy_command: (optional) A string or list of strings specifying a command and arguments to run to make a connection to the SSH server. Data will be @@ -8620,7 +8726,7 @@ :param config: (optional) Paths to OpenSSH client configuration files to load. This configuration will be used as a fallback to override the - defaults for settings which are not explcitly specified using + defaults for settings which are not explicitly specified using AsyncSSH's configuration options. If no paths are specified and no config paths were set when constructing the `options` argument (if any), an attempt will be made to load the diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/crypto/x509.py new/asyncssh-2.13.2/asyncssh/crypto/x509.py --- old/asyncssh-2.13.1/asyncssh/crypto/x509.py 2022-06-04 17:22:17.000000000 +0200 +++ new/asyncssh-2.13.2/asyncssh/crypto/x509.py 2023-06-22 04:57:39.000000000 +0200 @@ -55,11 +55,9 @@ _nscomment_oid = x509.ObjectIdentifier('2.16.840.1.113730.1.13') -_datetime_min = datetime.utcfromtimestamp(0).replace(microsecond=1, - tzinfo=timezone.utc) +_datetime_min = datetime.fromtimestamp(0, timezone.utc).replace(microsecond=1) -_datetime_32bit_max = datetime.utcfromtimestamp(2**31 - 1).replace( - tzinfo=timezone.utc) +_datetime_32bit_max = datetime.fromtimestamp(2**31 - 1, timezone.utc) if sys.platform == 'win32': # pragma: no cover # Windows' datetime.max is year 9999, but timestamps that large don't work @@ -75,12 +73,13 @@ return _datetime_min else: try: - return datetime.utcfromtimestamp(t).replace(tzinfo=timezone.utc) + return datetime.fromtimestamp(t, timezone.utc) except (OSError, OverflowError): try: # Work around a bug in cryptography which shows up on # systems with a small time_t. - datetime.utcfromtimestamp(_datetime_max.timestamp() - 1) + datetime.fromtimestamp(_datetime_max.timestamp() - 1, + timezone.utc) return _datetime_max except (OSError, OverflowError): # pragma: no cover return _datetime_32bit_max diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/editor.py new/asyncssh-2.13.2/asyncssh/editor.py --- old/asyncssh-2.13.1/asyncssh/editor.py 2022-08-11 02:01:29.000000000 +0200 +++ new/asyncssh-2.13.2/asyncssh/editor.py 2023-06-22 04:57:39.000000000 +0200 @@ -745,7 +745,7 @@ this class is wrapped around the channel, providing the caller with the ability to enable and disable input line editing and echoing. - .. note:: Line editing is only available when a psuedo-terminal + .. note:: Line editing is only available when a pseudo-terminal is requested on the server channel and the character encoding on the channel is not set to `None`. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/encryption.py new/asyncssh-2.13.2/asyncssh/encryption.py --- old/asyncssh-2.13.1/asyncssh/encryption.py 2022-01-23 17:15:42.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/encryption.py 2023-06-22 04:57:39.000000000 +0200 @@ -48,7 +48,7 @@ @classmethod def get_mac_params(cls, mac_alg: bytes) -> Tuple[int, int, bool]: - """Get paramaters of the MAC algorithm used with this encryption""" + """Get parameters of the MAC algorithm used with this encryption""" return get_mac_params(mac_alg) @@ -163,7 +163,7 @@ @classmethod def get_mac_params(cls, mac_alg: bytes) -> Tuple[int, int, bool]: - """Get paramaters of the MAC algorithm used with this encryption""" + """Get parameters of the MAC algorithm used with this encryption""" return 0, 16, True @@ -202,7 +202,7 @@ @classmethod def get_mac_params(cls, mac_alg: bytes) -> Tuple[int, int, bool]: - """Get paramaters of the MAC algorithm used with this encryption""" + """Get parameters of the MAC algorithm used with this encryption""" return 0, 16, True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/pkcs11.py new/asyncssh-2.13.2/asyncssh/pkcs11.py --- old/asyncssh-2.13.1/asyncssh/pkcs11.py 2023-02-18 23:52:45.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/pkcs11.py 2023-06-22 04:57:39.000000000 +0200 @@ -100,7 +100,7 @@ class SSHPKCS11Session: - """Work around PKCS#11 sesssions not supporting simultaneous opens""" + """Work around PKCS#11 sessions not supporting simultaneous opens""" _sessions: _SessionMap = {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/public_key.py new/asyncssh-2.13.2/asyncssh/public_key.py --- old/asyncssh-2.13.1/asyncssh/public_key.py 2023-02-18 23:52:45.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/public_key.py 2023-06-22 04:57:39.000000000 +0200 @@ -70,6 +70,7 @@ _PubKeyAlgMap = Dict[bytes, Type['SSHKey']] _CertAlgMap = Dict[bytes, Tuple[Optional[Type['SSHKey']], Type['SSHCertificate']]] +_CertSigAlgMap = Dict[bytes, bytes] _CertVersionMap = Dict[Tuple[bytes, int], Tuple[bytes, Type['SSHOpenSSHCertificate']]] @@ -128,6 +129,7 @@ _public_key_alg_map: _PubKeyAlgMap = {} _certificate_alg_map: _CertAlgMap = {} +_certificate_sig_alg_map: _CertSigAlgMap = {} _certificate_version_map: _CertVersionMap = {} _pem_map: _PEMMap = {} _pkcs8_oid_map: _PKCS8OIDMap = {} @@ -238,6 +240,7 @@ algorithm: bytes = b'' sig_algorithms: Sequence[bytes] = () + cert_algorithms: Sequence[bytes] = () x509_algorithms: Sequence[bytes] = () all_sig_algorithms: Set[bytes] = set() default_x509_hash: str = '' @@ -647,7 +650,7 @@ comment: DefTuple[_Comment] = ()) -> 'SSHOpenSSHCertificate': """Generate a new SSH user certificate - This method returns an SSH user certifcate with the requested + This method returns an SSH user certificate with the requested attributes signed by this private key. :param user_key: @@ -766,7 +769,7 @@ 'SSHOpenSSHCertificate': """Generate a new SSH host certificate - This method returns an SSH host certifcate with the requested + This method returns an SSH host certificate with the requested attributes signed by this private key. :param host_key: @@ -827,7 +830,7 @@ comment: DefTuple[_Comment] = ()) -> 'SSHX509Certificate': """Generate a new X.509 user certificate - This method returns an X.509 user certifcate with the requested + This method returns an X.509 user certificate with the requested attributes signed by this private key. :param user_key: @@ -898,7 +901,7 @@ comment: DefTuple[_Comment] = ()) -> 'SSHX509Certificate': """Generate a new X.509 host certificate - This method returns a X.509 host certifcate with the requested + This method returns an X.509 host certificate with the requested attributes signed by this private key. :param host_key: @@ -969,7 +972,7 @@ 'SSHX509Certificate': """Generate a new X.509 CA certificate - This method returns a X.509 CA certifcate with the requested + This method returns an X.509 CA certificate with the requested attributes signed by this private key. :param ca_key: @@ -1557,7 +1560,8 @@ signing_key: SSHKey, serial: int, cert_type: int, key_id: str, valid_after: int, valid_before: int, comment: _Comment): - super().__init__(algorithm, key.sig_algorithms, (algorithm,), + super().__init__(algorithm, key.sig_algorithms, + key.cert_algorithms or (algorithm,), key, data, comment) self.principals = principals @@ -2183,6 +2187,11 @@ def set_sig_algorithm(self, sig_algorithm: bytes) -> None: """Set the signature algorithm to use when signing data""" + try: + sig_algorithm = _certificate_sig_alg_map[sig_algorithm] + except KeyError: + pass + self.sig_algorithm = sig_algorithm if not self._cert: @@ -2192,11 +2201,6 @@ cert = cast('SSHX509CertificateChain', self._cert) self.public_data = cert.adjust_public_data(sig_algorithm) - else: - if sig_algorithm.endswith(b'@openssh.com'): - sig_algorithm = sig_algorithm[:-12] - - self.algorithm = sig_algorithm + b'-cert-...@openssh.com' def sign(self, data: bytes) -> bytes: """Sign a block of data with this private key""" @@ -2924,6 +2928,8 @@ _certificate_alg_map[cert_algorithm] = (key_handler, cert_handler) + _certificate_sig_alg_map[cert_algorithm] = algorithm + _certificate_version_map[algorithm, version] = \ (cert_algorithm, cert_handler) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/rsa.py new/asyncssh-2.13.2/asyncssh/rsa.py --- old/asyncssh-2.13.1/asyncssh/rsa.py 2023-02-18 23:52:45.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/rsa.py 2023-06-22 04:57:39.000000000 +0200 @@ -59,6 +59,9 @@ b'ssh-rsa-sha...@ssh.com', b'ssh-rsa-sha...@ssh.com', b'ssh-rsa-sha...@ssh.com', b'ssh-rsa-sha...@ssh.com', b'ssh-rsa') + cert_sig_algorithms = (b'rsa-sha2-256', b'rsa-sha2-512', b'ssh-rsa') + cert_algorithms = tuple(alg + b'-cert-...@openssh.com' + for alg in cert_sig_algorithms) x509_sig_algorithms = (b'rsa2048-sha256', b'ssh-rsa') x509_algorithms = tuple(b'x509v3-' + alg for alg in x509_sig_algorithms) all_sig_algorithms = set(x509_sig_algorithms + sig_algorithms) @@ -265,7 +268,7 @@ register_public_key_alg(b'ssh-rsa', RSAKey, True) -for _alg in (b'rsa-sha2-256', b'rsa-sha2-512', b'ssh-rsa'): +for _alg in RSAKey.cert_sig_algorithms: register_certificate_alg(1, _alg, _alg + b'-cert-...@openssh.com', RSAKey, SSHOpenSSHCertificateV01, True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/server.py new/asyncssh-2.13.2/asyncssh/server.py --- old/asyncssh-2.13.1/asyncssh/server.py 2022-01-23 17:15:42.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/server.py 2023-06-22 04:57:39.000000000 +0200 @@ -148,7 +148,7 @@ """Authentication was completed successfully This method is called when authentication has completed - succesfully. Applications may use this method to perform + successfully. Applications may use this method to perform processing based on the authenticated username or options in the authorized keys list or certificate associated with the user before any sessions are opened or forwarding requests @@ -575,7 +575,7 @@ authentication is supported. Applications wishing to support it must have this method return `True` and implement :meth:`get_kbdint_challenge` and :meth:`validate_kbdint_response` - to generate the apporiate challenges and validate the responses + to generate the appropriate challenges and validate the responses for the user being authenticated. By default, this method returns `NotImplemented` tying @@ -677,7 +677,7 @@ If blocking operations need to be performed before the session can be created, a coroutine which returns an :class:`SSHServerSession` object can be returned instead of - the session iself. This can be either returned directly or as + the session itself. This can be either returned directly or as a part of a tuple with an :class:`SSHServerChannel` object. To reject this request, this method should return `False` @@ -742,7 +742,7 @@ If blocking operations need to be performed before the session can be created, a coroutine which returns an :class:`SSHTCPSession` object can be returned instead of - the session iself. This can be either returned directly or as + the session itself. This can be either returned directly or as a part of a tuple with an :class:`SSHTCPChannel` object. By default, all connection requests are rejected. @@ -857,7 +857,7 @@ If blocking operations need to be performed before the session can be created, a coroutine which returns an :class:`SSHUNIXSession` object can be returned instead of - the session iself. This can be either returned directly or as + the session itself. This can be either returned directly or as a part of a tuple with an :class:`SSHUNIXChannel` object. By default, all connection requests are rejected. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/session.py new/asyncssh-2.13.2/asyncssh/session.py --- old/asyncssh-2.13.1/asyncssh/session.py 2022-01-23 17:15:42.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/session.py 2023-06-22 04:57:39.000000000 +0200 @@ -262,7 +262,7 @@ def pty_requested(self, term_type: str, term_size: Tuple[int, int, int, int], term_modes: Mapping[int, int]) -> bool: - """A psuedo-terminal has been requested + """A pseudo-terminal has been requested This method is called when the client sends a request to allocate a pseudo-terminal with the requested terminal type, size, and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/sftp.py new/asyncssh-2.13.2/asyncssh/sftp.py --- old/asyncssh-2.13.1/asyncssh/sftp.py 2023-02-18 23:52:45.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/sftp.py 2023-06-22 04:57:39.000000000 +0200 @@ -601,7 +601,7 @@ class _SFTPParallelIO(Generic[_T]): """Parallelize I/O requests on files - This class issues parallel read and wite requests on files. + This class issues parallel read and write requests on files. """ @@ -1313,11 +1313,11 @@ class SFTPInvalidParameter(SFTPError): """SFTP invalid parameter (SFTPv6+) - This exception is raised when paramters in a request are + This exception is raised when parameters in a request are out of range or incompatible with one another. :param reason: - Details about the invalid paramter + Details about the invalid parameter :param lang: (optional) The language the reason is in :type reason: `str` @@ -3059,7 +3059,7 @@ if offset is None: offset = self._offset - # If self._offset is None, we're appending and haven't seeked + # If self._offset is None, we're appending and haven't sought # backward in the file since the last write, so there's no # data to return @@ -3132,7 +3132,7 @@ if offset is None: offset = self._offset - # If self._offset is None, we're appending and haven't seeked + # If self._offset is None, we're appending and haven't sought # backward in the file since the last write, so there's no # data to return @@ -4379,7 +4379,7 @@ Most applications should be able to use this method regardless of the version of the SFTP protocol negotiated with the SFTP server. A conversion from the pflags_or_mode values to the - SFTPv5/v6 flag values will happen automaitcally. However, if + SFTPv5/v6 flag values will happen automatically. However, if an application wishes to set flags only available in SFTPv5/v6, the :meth:`open56` method may be used to specify these flags explicitly. @@ -4973,7 +4973,7 @@ .. note:: By default, this version of rename will not overwrite the new path if it already exists. However, this can be controlled using the `flags` argument, - available in SFTPv5 and later. Whan a connection + available in SFTPv5 and later. When a connection is negotiated to use an earliler version of SFTP and `flags` is set, this method will attempt to fall back to the OpenSSH "posix-rename" extension @@ -5392,7 +5392,7 @@ # Supported SFTPv5/v6 open flags _supported_open_flags = FXF_ACCESS_DISPOSITION | FXF_APPEND_DATA - # Supported SFTPv5/v6 desired accesss flags + # Supported SFTPv5/v6 desired access flags _supported_access_mask = ACE4_READ_DATA | ACE4_WRITE_DATA | \ ACE4_APPEND_DATA | ACE4_READ_ATTRIBUTES | \ ACE4_WRITE_ATTRIBUTES @@ -6373,7 +6373,7 @@ .. note:: Any method can optionally be defined as a coroutine if that method needs to perform - blocking opertions to determine its result. + blocking operations to determine its result. The `chan` object provided here is the :class:`SSHServerChannel` instance this SFTP server is associated with. It can be queried to diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/subprocess.py new/asyncssh-2.13.2/asyncssh/subprocess.py --- old/asyncssh-2.13.1/asyncssh/subprocess.py 2023-02-18 23:52:45.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/subprocess.py 2023-06-22 04:57:39.000000000 +0200 @@ -134,7 +134,7 @@ transport: 'SSHSubprocessTransport[AnyStr]') -> None: """Called when a remote process is successfully started - This method is called when a a remote process is successfully + This method is called when a remote process is successfully started. The transport parameter should be stored if needed for later use. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh/version.py new/asyncssh-2.13.2/asyncssh/version.py --- old/asyncssh-2.13.1/asyncssh/version.py 2023-02-18 23:52:53.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh/version.py 2023-06-22 04:57:55.000000000 +0200 @@ -26,4 +26,4 @@ __url__ = 'http://asyncssh.timeheart.net' -__version__ = '2.13.1' +__version__ = '2.13.2' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/asyncssh.egg-info/PKG-INFO new/asyncssh-2.13.2/asyncssh.egg-info/PKG-INFO --- old/asyncssh-2.13.1/asyncssh.egg-info/PKG-INFO 2023-02-19 00:03:44.000000000 +0100 +++ new/asyncssh-2.13.2/asyncssh.egg-info/PKG-INFO 2023-06-22 05:08:52.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: asyncssh -Version: 2.13.1 +Version: 2.13.2 Summary: AsyncSSH: Asynchronous SSHv2 client and server library Home-page: http://asyncssh.timeheart.net Author: Ron Frederick @@ -35,6 +35,15 @@ Provides-Extra: pywin32 License-File: LICENSE +.. image:: https://readthedocs.org/projects/asyncssh/badge/?version=latest + :target: https://asyncssh.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +.. image:: https://img.shields.io/pypi/v/asyncssh.svg + :target: https://pypi.python.org/pypi/asyncssh/ + :alt: AsyncSSH PyPI Project + + AsyncSSH: Asynchronous SSH for Python ===================================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/docs/api.rst new/asyncssh-2.13.2/docs/api.rst --- old/asyncssh-2.13.1/docs/api.rst 2022-12-27 22:30:36.000000000 +0100 +++ new/asyncssh-2.13.2/docs/api.rst 2023-06-22 04:57:39.000000000 +0200 @@ -1357,7 +1357,7 @@ Instead of passing tuples of keys and certificates or relying on file naming conventions for certificates, you also have the option of -providing a list of keys and a seperate list of certificates. In this +providing a list of keys and a separate list of certificates. In this case, AsyncSSH will automatically match up the keys with their associated certificates when they are present. @@ -1413,7 +1413,7 @@ To specify a subject name pattern instead of a specific certificate, base64-encoded certificate data should be replaced with the string -'Subject:' followed by a a comma-separated list of X.509 relative +'Subject:' followed by a comma-separated list of X.509 relative distinguished name components. AsyncSSH extends the PKIX-SSH syntax to also support matching on a @@ -2184,9 +2184,9 @@ Supported Algorithms ==================== -Algorithms can be specified as either an list of exact algorithm names +Algorithms can be specified as either a list of exact algorithm names or as a string of comma-separated algorithm names that may optionally -include wildcards. A '*' in a name matches zero or more characters and +include wildcards. An '*' in a name matches zero or more characters and a '?' matches exactly one character. When specifying algorithms as a string, it can also be prefixed with '^' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/docs/changes.rst new/asyncssh-2.13.2/docs/changes.rst --- old/asyncssh-2.13.1/docs/changes.rst 2023-02-18 23:58:25.000000000 +0100 +++ new/asyncssh-2.13.2/docs/changes.rst 2023-06-22 04:59:01.000000000 +0200 @@ -3,6 +3,31 @@ Change Log ========== +Release 2.13.2 (21 Jun 2023) +---------------------------- + +* Fixed an issue with host-based authentication when using proxy_command, + allowing it to be used if the caller explicitly specifies client_host. + Thanks go to GitHub user yuqingm7 for reporting this issue. + +* Improved handling of signature algorithms for OpenSSH certificates + so that RSA SHA-2 signatures will work with both older and newer + versions of OpenSSH. + +* Worked around an issue with some Cisco SSH implementations generating + invalid "ignore" packets. Thanks go to Jost Luebbe for reporting and + helping to debug this issue. + +* Fixed unit tests to avoid errors when cryptography's version of + OpenSSL disables support for SHA-1 signatures. + +* Fixed unit tests to avoid errors when the filesystem enforces that + filenames be valid UTF-8 strings. Thanks go to Robert Schütz and + Martin Weinelt for reporting this issue. + +* Added documentation about which config options apply when passing + a string as a tunnel argument. + Release 2.13.1 (18 Feb 2023) ---------------------------- @@ -100,7 +125,7 @@ * Updated default for "ignore_encrypted" client connection option to ignore encrypted keys specified in an OpenSSH config file when no - passphrase is provided, similar to what was previosuly done for + passphrase is provided, similar to what was previously done for keys with default names. * Fixed an issue when using an SSH agent with RSA keys and an X.509 @@ -343,7 +368,7 @@ * Fixed a couple of issues related to sending SSH_EXT_INFO messages. * Fixed an issue with using SSHAcceptor as an async context manager. - Thanks go to Paulo Costa for reporing this. + Thanks go to Paulo Costa for reporting this. * Fixed an issue where a tunnel wasn't always cleaned up properly when creating a remote listener. @@ -463,7 +488,7 @@ 0.8.1. * Fixed problem with setting config options with percent substitutions - to 'none'. Percent subsitution should not be performed in this case. + to 'none'. Percent substitution should not be performed in this case. Thanks go to Yuqing Miao for finding and reporting this issue! * Fixed return type of filenames in SFTPClient scandir() and readlink() @@ -956,7 +981,7 @@ * Added channel, connection, and env properties to SFTPServer instances, so connection and channel information can be used to influence the SFTP server's behavior. Previously, connection information was made - avaiable through the constructor, but channel and environment + available through the constructor, but channel and environment information was not. Now, all of these are available as properties on the SFTPServer instance without the need to explicitly store anything in a custom constructor. @@ -1319,7 +1344,7 @@ * Updated key and certificate comment handling to be less sensitive to the encoding of non-ASCII characters. The get_comment() and set_comment() - functions now take an optional encoding paramter, defaulting to UTF-8 + functions now take an optional encoding parameter, defaulting to UTF-8 but allowing for others encodings. There's also a get_comment_bytes() function to get the comment data as bytes without performing Unicode decoding. @@ -1568,7 +1593,7 @@ these signature algorithms. * Added new load_keypairs and load_public_keys API functions which - support expicitly loading keys using the same syntax that was + support explicitly loading keys using the same syntax that was previously available for specifying client_keys, authorized_client_keys, and server_host_keys arguments when creating SSH clients and servers. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/docs/index.rst new/asyncssh-2.13.2/docs/index.rst --- old/asyncssh-2.13.1/docs/index.rst 2022-03-26 23:53:06.000000000 +0100 +++ new/asyncssh-2.13.2/docs/index.rst 2023-06-22 04:57:39.000000000 +0200 @@ -38,7 +38,7 @@ receive binary data, you can set the encoding to `None` when the session is opened to make read and write operate on bytes instead. Alternate encodings can also be selected to change how strings are -convered to and from bytes. +converted to and from bytes. To check against a different set of server host keys, they can be provided in the known_hosts argument when the connection is opened: @@ -435,7 +435,7 @@ receive binary data, you can set the encoding to `None` when the session is opened to make read and write operate on bytes instead. Alternate encodings can also be selected to change how strings are -convered to and from bytes. +converted to and from bytes. .. include:: ../examples/simple_server.py :literal: @@ -512,7 +512,7 @@ applications like the one above, AsyncSSH defaults to providing basic line editing for server sessions which request a pseudo-terminal. -When thise line editor is enabled, it defaults to delivering input to +When this line editor is enabled, it defaults to delivering input to the application a line at a time. Applications can switch between line and character at a time input using the :meth:`set_line_mode() <SSHLineEditorChannel.set_line_mode>` method. Also, when in line diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/keysign_stub.py new/asyncssh-2.13.2/tests/keysign_stub.py --- old/asyncssh-2.13.1/tests/keysign_stub.py 2021-07-02 15:28:16.000000000 +0200 +++ new/asyncssh-2.13.2/tests/keysign_stub.py 2023-06-22 04:57:39.000000000 +0200 @@ -48,7 +48,7 @@ elif version == 1: return b'', b'invalid request' else: - skey = asyncssh.load_keypairs('skey')[0] + skey = asyncssh.load_keypairs('skey_ecdsa')[0] sig = skey.sign(data) return String(Byte(KEYSIGN_VERSION) + String(sig)), b'' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/server.py new/asyncssh-2.13.2/tests/server.py --- old/asyncssh-2.13.1/tests/server.py 2022-08-11 02:01:29.000000000 +0200 +++ new/asyncssh-2.13.2/tests/server.py 2023-06-22 04:57:39.000000000 +0200 @@ -131,11 +131,14 @@ skey_ecdsa.write_private_key('skey_ecdsa') skey_ecdsa.write_public_key('skey_ecdsa.pub') - skey_cert = skey.generate_host_certificate(skey, 'name', - principals=['127.0.0.1', - 'localhost']) + skey_cert = skey.generate_host_certificate( + skey, 'name', principals=['127.0.0.1', 'localhost']) skey_cert.write_certificate('skey-cert.pub') + skey_ecdsa_cert = skey_ecdsa.generate_host_certificate( + skey_ecdsa, 'name', principals=['127.0.0.1', 'localhost']) + skey_ecdsa_cert.write_certificate('skey_ecdsa-cert.pub') + exp_cert = skey.generate_host_certificate(skey, 'name', valid_after='-2d', valid_before='-1d') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/test_auth.py new/asyncssh-2.13.2/tests/test_auth.py --- old/asyncssh-2.13.1/tests/test_auth.py 2022-06-04 17:22:17.000000000 +0200 +++ new/asyncssh-2.13.2/tests/test_auth.py 2023-06-22 04:57:39.000000000 +0200 @@ -517,7 +517,7 @@ async def test_hostbased_auth(self): """Unit test host-based authentication""" - hkey = get_test_key('ssh-rsa') + hkey = get_test_key('ecdsa-sha2-nistp256') cert = hkey.generate_host_certificate(hkey, 'host') with self.subTest('Host-based auth not available'): @@ -541,7 +541,7 @@ async def test_publickey_auth(self): """Unit test public key authentication""" - ckey = get_test_key('ssh-rsa') + ckey = get_test_key('ecdsa-sha2-nistp256') cert = ckey.generate_user_certificate(ckey, 'name') with self.subTest('Public key auth not available'): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/test_connection.py new/asyncssh-2.13.2/tests/test_connection.py --- old/asyncssh-2.13.1/tests/test_connection.py 2022-08-11 02:01:29.000000000 +0200 +++ new/asyncssh-2.13.2/tests/test_connection.py 2023-06-22 04:57:39.000000000 +0200 @@ -25,7 +25,6 @@ import os from pathlib import Path import socket -import subprocess import sys import unittest from unittest.mock import patch @@ -51,17 +50,10 @@ from .server import Server, ServerTestCase -from .util import asynctest, gss_available, patch_gss, run +from .util import asynctest, gss_available, nc_available, patch_gss from .util import patch_getnameinfo, x509_available -try: - run('which nc') - _nc_available = True -except subprocess.CalledProcessError: # pragma: no cover - _nc_available = False - - class _CheckAlgsClientConnection(asyncssh.SSHClientConnection): """Test specification of encryption algorithms""" @@ -421,7 +413,7 @@ @asynctest async def test_connect_encrypted_key(self): - """Test connecting with encrytped client key and no passphrase""" + """Test connecting with encrypted client key and no passphrase""" async with self.connect(client_keys='ckey_encrypted', ignore_encrypted=True): @@ -609,7 +601,7 @@ with self.assertRaises(OSError): await asyncssh.get_server_host_key('\xff') - @unittest.skipUnless(_nc_available, 'Netcat not available') + @unittest.skipUnless(nc_available, 'Netcat not available') @asynctest async def test_get_server_host_key_proxy(self): """Test retrieving a server host key using proxy command""" @@ -621,12 +613,12 @@ self.assertEqual(key, keylist[0]) - @unittest.skipUnless(_nc_available, 'Netcat not available') + @unittest.skipUnless(nc_available, 'Netcat not available') @asynctest async def test_get_server_host_key_proxy_failure(self): """Test failure retrieving a server host key using proxy command""" - # Leave out arguments to 'nc' to trigger a faliure + # Leave out arguments to 'nc' to trigger a failure proxy_command = 'nc' with self.assertRaises((OSError, asyncssh.ConnectionLost)): @@ -866,7 +858,7 @@ @asynctest async def test_duplicate_encryption_algs(self): - """Test connecting with an duplicated encryption algorithm""" + """Test connecting with a duplicated encryption algorithm""" with patch('asyncssh.connection.SSHClientConnection', _CheckAlgsClientConnection): @@ -1624,7 +1616,7 @@ async with self.run_server(sock): pass - @unittest.skipUnless(_nc_available, 'Netcat not available') + @unittest.skipUnless(nc_available, 'Netcat not available') @asynctest async def test_connect_reverse_proxy(self): """Test reverse direction SSH connection with proxy command""" @@ -1788,14 +1780,14 @@ @asynctest async def test_connect_x509_untrusted_self(self): - """Test connecting with untrusted X.509 self-signed certficate""" + """Test connecting with untrusted X.509 self-signed certificate""" with self.assertRaises(asyncssh.HostKeyNotVerifiable): await self.connect(x509_trusted_certs='root_ca_cert.pem') @asynctest async def test_connect_x509_revoked_self(self): - """Test connecting with revoked X.509 self-signed certficate""" + """Test connecting with revoked X.509 self-signed certificate""" with self.assertRaises(asyncssh.HostKeyNotVerifiable): await self.connect(known_hosts=([], [], [], ['root_ca_cert.pem'], @@ -1991,11 +1983,9 @@ return _ValidateHostKeyClient(host_key='skey.pub') - algs = [asyncssh.read_public_key('skey.pub').get_algorithm()] - - conn, _ = await self.create_connection(client_factory, - known_hosts=([], [], []), - server_host_key_algs=algs) + conn, _ = await self.create_connection( + client_factory, known_hosts=([], [], []), + server_host_key_algs=['rsa-sha2-256']) async with conn: pass diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/test_connection_auth.py new/asyncssh-2.13.2/tests/test_connection_auth.py --- old/asyncssh-2.13.1/tests/test_connection_auth.py 2022-08-11 02:01:29.000000000 +0200 +++ new/asyncssh-2.13.2/tests/test_connection_auth.py 2023-06-22 04:57:39.000000000 +0200 @@ -26,6 +26,8 @@ from unittest.mock import patch +from cryptography.exceptions import UnsupportedAlgorithm + import asyncssh from asyncssh.misc import async_context_manager, write_file from asyncssh.packet import String @@ -34,7 +36,7 @@ from .keysign_stub import create_subprocess_exec_stub from .server import Server, ServerTestCase from .util import asynctest, gss_available, patch_getnameinfo, patch_gss -from .util import make_certificate, x509_available +from .util import make_certificate, nc_available, x509_available class _FailValidateHostSSHServerConnection(asyncssh.SSHServerConnection): @@ -658,6 +660,17 @@ self.assertEqual(auth_methods, ['hostbased']) + @unittest.skipUnless(nc_available, 'Netcat not available') + @asynctest + async def test_get_server_auth_methods_no_sockname(self): + """Test getting auth methods from the test server""" + + proxy_command = ('nc', str(self._server_addr), str(self._server_port)) + + with self.assertRaises(asyncssh.PermissionDenied): + await self.connect(username='user', client_host_keys='skey', + proxy_command=proxy_command) + @asynctest async def test_client_host_auth(self): """Test connecting with host-based authentication""" @@ -709,7 +722,7 @@ async def test_client_host_signature_algs(self): """Test host based authentication with specific signature algorithms""" - for alg in ('ssh-rsa', 'rsa-sha2-256', 'rsa-sha2-512'): + for alg in ('rsa-sha2-256', 'rsa-sha2-512'): async with self.connect(username='user', client_host_keys='skey', client_username='user', signature_algs=[alg]): @@ -728,8 +741,12 @@ with patch('asyncssh.connection.SSHConnection._get_ext_info_kex_alg', skip_ext_info): - async with self.connect(username='user', client_host_keys='skey', - client_username='user'): + try: + async with self.connect(username='user', + client_host_keys='skey', + client_username='user'): + pass + except UnsupportedAlgorithm: # pragma: no cover pass @asynctest @@ -889,8 +906,8 @@ async def start_server(cls): """Start an SSH server which supports host-based authentication""" - return await cls.create_server(_HostBasedServer, - known_client_hosts='known_hosts') + return await cls.create_server( + _HostBasedServer, known_client_hosts=(['skey_ecdsa.pub'], [], [])) @async_context_manager async def _connect_keysign(self, client_host_keysign=True, @@ -902,7 +919,7 @@ with patch('asyncssh.keysign._DEFAULT_KEYSIGN_DIRS', keysign_dirs): with patch('asyncssh.public_key._DEFAULT_HOST_KEY_DIRS', ['.']): with patch('asyncssh.public_key._DEFAULT_HOST_KEY_FILES', - ['skey', 'xxx']): + ['skey_ecdsa', 'xxx']): return await self.connect( username='user', client_host_keysign=client_host_keysign, @@ -927,7 +944,7 @@ async def test_keysign_explicit_host_keys(self): """Test ssh-keysign with explicit host public keys""" - async with self._connect_keysign(client_host_keys='skey.pub'): + async with self._connect_keysign(client_host_keys='skey_ecdsa.pub'): pass @asynctest @@ -1022,9 +1039,12 @@ async def test_host_signature_alg_fallback(self): """Test fall back to default host key signature algorithm""" - async with self.connect(username='ckey', client_host_keys='skey', - client_username='user', - signature_algs=['rsa-sha2-256', 'ssh-rsa']): + try: + async with self.connect(username='ckey', client_host_keys='skey', + client_username='user', + signature_algs=['rsa-sha2-256', 'ssh-rsa']): + pass + except UnsupportedAlgorithm: # pragma: no cover pass @@ -1209,7 +1229,7 @@ async def test_public_key_signature_algs(self): """Test public key authentication with specific signature algorithms""" - for alg in ('ssh-rsa', 'rsa-sha2-256', 'rsa-sha2-512'): + for alg in ('rsa-sha2-256', 'rsa-sha2-512'): async with self.connect(username='ckey', agent_path=None, client_keys='ckey', signature_algs=[alg]): pass @@ -1227,8 +1247,11 @@ with patch('asyncssh.connection.SSHConnection._get_ext_info_kex_alg', skip_ext_info): - async with self.connect(username='ckey', client_keys='ckey', - agent_path=None): + try: + async with self.connect(username='ckey', client_keys='ckey', + agent_path=None): + pass + except UnsupportedAlgorithm: # pragma: no cover pass @asynctest @@ -1949,7 +1972,7 @@ pass @asynctest - async def test_kbdint_auth_callback_faliure(self): + async def test_kbdint_auth_callback_failure(self): """Test failure connecting with keyboard-interactive auth callback""" with self.assertRaises(asyncssh.PermissionDenied): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/test_kex.py new/asyncssh-2.13.2/tests/test_kex.py --- old/asyncssh-2.13.1/tests/test_kex.py 2022-08-11 02:01:29.000000000 +0200 +++ new/asyncssh-2.13.2/tests/test_kex.py 2023-06-22 04:57:39.000000000 +0200 @@ -211,7 +211,7 @@ if gss_host and 'no_host_key' in gss_host: self._server_host_key = None else: - priv_key = get_test_key('ssh-rsa') + priv_key = get_test_key('ecdsa-sha2-nistp256') self._server_host_key = asyncssh.load_keypairs(priv_key)[0] def connection_lost(self, exc): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/test_known_hosts.py new/asyncssh-2.13.2/tests/test_known_hosts.py --- old/asyncssh-2.13.1/tests/test_known_hosts.py 2022-06-04 17:22:17.000000000 +0200 +++ new/asyncssh-2.13.2/tests/test_known_hosts.py 2023-06-22 04:57:39.000000000 +0200 @@ -234,12 +234,12 @@ self.check_match(b'@cert-authority xxx\n') def test_invalid_key(self): - """Test for line with invaid key""" + """Test for line with invalid key""" self.check_match(b'xxx yyy\n', ([], [], [], [], [], [], [])) def test_invalid_marker(self): - """Test for line with invaid marker""" + """Test for line with invalid marker""" with self.assertRaises(ValueError): self.check_match(b'@xxx yyy zzz\n') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/test_public_key.py new/asyncssh-2.13.2/tests/test_public_key.py --- old/asyncssh-2.13.1/tests/test_public_key.py 2023-02-18 23:52:45.000000000 +0100 +++ new/asyncssh-2.13.2/tests/test_public_key.py 2023-06-22 04:57:39.000000000 +0200 @@ -36,6 +36,8 @@ import sys import unittest +from cryptography.exceptions import UnsupportedAlgorithm + import asyncssh from asyncssh.asn1 import der_encode, BitString, ObjectIdentifier @@ -1277,26 +1279,30 @@ for sig_alg in keypair.sig_algorithms: with self.subTest('Good signature', sig_alg=sig_alg): - keypair.set_sig_algorithm(sig_alg) - sig = keypair.sign(data) - - with self.subTest('Good signature'): - self.assertTrue(self.pubkey.verify(data, sig)) - - badsig = bytearray(sig) - badsig[-1] ^= 0xff - badsig = bytes(badsig) - - with self.subTest('Bad signature'): - self.assertFalse(self.pubkey.verify(data, badsig)) + try: + keypair.set_sig_algorithm(sig_alg) + sig = keypair.sign(data) + + with self.subTest('Good signature'): + self.assertTrue(self.pubkey.verify(data, sig)) + + badsig = bytearray(sig) + badsig[-1] ^= 0xff + badsig = bytes(badsig) + + with self.subTest('Bad signature'): + self.assertFalse(self.pubkey.verify(data, + badsig)) + except UnsupportedAlgorithm: # pragma: no cover + pass with self.subTest('Missing signature'): self.assertFalse(self.pubkey.verify( - data, String(self.pubkey.algorithm))) + data, String(self.pubkey.sig_algorithms[0]))) with self.subTest('Empty signature'): self.assertFalse(self.pubkey.verify( - data, String(self.pubkey.algorithm) + String(b''))) + data, String(self.pubkey.sig_algorithms[0]) + String(b''))) with self.subTest('Sign with bad algorithm'): with self.assertRaises(ValueError): @@ -1308,7 +1314,7 @@ with self.subTest('Sign with public key'): with self.assertRaises(ValueError): - self.pubkey.sign(data, self.pubkey.algorithm) + self.pubkey.sign(data, self.pubkey.sig_algorithms[0]) def check_set_certificate(self): """Check setting certificate on existing keypair""" @@ -2245,7 +2251,7 @@ self.assertEqual(bool(get_x509_certificate_algs()), x509_available) def test_public_key_algorithm_mismatch(self): - """Test algorihm mismatch in SSH public key""" + """Test algorithm mismatch in SSH public key""" privkey = get_test_key('ssh-rsa') keydata = privkey.export_public_key('openssh') @@ -2266,7 +2272,7 @@ pkcs1_decrypt(b'', b'AES-128-CBC', os.urandom(16), 'x') def test_ec_explicit(self): - """Test EC certificate with explcit parameters""" + """Test EC certificate with explicit parameters""" if _openssl_available: # pragma: no branch for curve in ('secp256r1', 'secp384r1', 'secp521r1'): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/test_sftp.py new/asyncssh-2.13.2/tests/test_sftp.py --- old/asyncssh-2.13.1/tests/test_sftp.py 2022-08-11 02:01:29.000000000 +0200 +++ new/asyncssh-2.13.2/tests/test_sftp.py 2023-06-22 04:57:39.000000000 +0200 @@ -868,7 +868,7 @@ for method in ('get', 'put', 'copy', 'mget', 'mput', 'mcopy'): with self.subTest(method=method): - with self.assertRaises((FileNotFoundError, SFTPNoSuchFile, + with self.assertRaises((OSError, SFTPNoSuchFile, SFTPFailure, UnicodeDecodeError)): await getattr(sftp, method)(b'\xff') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/asyncssh-2.13.1/tests/util.py new/asyncssh-2.13.2/tests/util.py --- old/asyncssh-2.13.1/tests/util.py 2022-12-27 22:30:36.000000000 +0100 +++ new/asyncssh-2.13.2/tests/util.py 2023-06-22 04:57:39.000000000 +0200 @@ -24,6 +24,7 @@ import binascii import functools import os +import shutil import subprocess import sys import tempfile @@ -33,7 +34,14 @@ from cryptography.hazmat.backends.openssl import backend -# pylint: disable=unused-import +from asyncssh.gss import gss_available +from asyncssh.logging import logger +from asyncssh.misc import ConnectionLost, SignalReceived +from asyncssh.packet import Byte, String, UInt32, UInt64 +from asyncssh.public_key import generate_private_key + + +# pylint: disable=ungrouped-imports, unused-import try: import bcrypt @@ -41,6 +49,8 @@ except ImportError: # pragma: no cover bcrypt_available = False +nc_available = bool(shutil.which('nc')) + try: import uvloop uvloop_available = True @@ -53,14 +63,7 @@ except ImportError: # pragma: no cover x509_available = False -# pylint: enable=unused-import - -from asyncssh.gss import gss_available -from asyncssh.logging import logger -from asyncssh.misc import ConnectionLost, SignalReceived -from asyncssh.packet import Byte, String, UInt32, UInt64 -from asyncssh.public_key import generate_private_key - +# pylint: enable=ungrouped-imports, unused-import # pylint: disable=no-member