diff options
-rw-r--r-- | paramiko/transport.py | 28 | ||||
-rw-r--r-- | tests/test_transport.py | 31 |
2 files changed, 59 insertions, 0 deletions
diff --git a/paramiko/transport.py b/paramiko/transport.py index 71d2b4f1..dfee9afc 100644 --- a/paramiko/transport.py +++ b/paramiko/transport.py @@ -145,6 +145,9 @@ class Transport(threading.Thread, ClosingContextManager): # These tuples of algorithm identifiers are in preference order; do not # reorder without reason! + # NOTE: if you need to modify these, we suggest leveraging the + # `disable_algorithms` constructor argument (also available in SSHClient) + # instead of monkeypatching or subclassing. _preferred_ciphers = ( "aes128-ctr", "aes192-ctr", @@ -485,6 +488,9 @@ class Transport(threading.Thread, ClosingContextManager): # how long (seconds) to wait for the auth response. self.auth_timeout = 30 + # Note change from verb to plural noun. + self.disabled_algorithms = disable_algorithms + # server mode: self.server_mode = False self.server_object = None @@ -493,6 +499,28 @@ class Transport(threading.Thread, ClosingContextManager): self.server_accept_cv = threading.Condition(self.lock) self.subsystem_table = {} + def _filter_algorithm(self, type_): + default = getattr(self, "_preferred_{}".format(type_)) + return tuple( + x for x in default if x not in self.disabled_algorithms[type_] + ) + + @property + def preferred_ciphers(self): + return self._filter_algorithm("ciphers") + + @property + def preferred_macs(self): + return self._filter_algorithm("macs") + + @property + def preferred_keys(self): + return self._filter_algorithm("keys") + + @property + def preferred_kex(self): + return self._filter_algorithm("kex") + def __repr__(self): """ Returns a string representation of this object, for debugging. diff --git a/tests/test_transport.py b/tests/test_transport.py index ad267e28..f4e824d0 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -1102,3 +1102,34 @@ class TransportTest(unittest.TestCase): assert not self.ts.auth_handler.authenticated # Real fix's behavior self._expect_unimplemented() + + +class AlgorithmDisablingTests(unittest.TestCase): + def test_preferred_lists_default_to_private_attribute_contents(self): + t = Transport(sock=Mock()) + assert t.preferred_ciphers == t._preferred_ciphers + assert t.preferred_macs == t._preferred_macs + assert t.preferred_keys == t._preferred_keys + assert t.preferred_kex == t._preferred_kex + + def test_preferred_lists_filter_disabled_algorithms(self): + t = Transport( + sock=Mock(), + disable_algorithms={ + "ciphers": ["aes128-cbc"], + "macs": ["hmac-md5"], + "keys": ["ssh-dss"], + "kex": ["diffie-hellman-group14-sha256"], + }, + ) + assert "aes128-cbc" in t._preferred_ciphers + assert "aes128-cbc" not in t.preferred_ciphers + assert "hmac-md5" in t._preferred_macs + assert "hmac-md5" not in t.preferred_macs + assert "ssh-dss" in t._preferred_keys + assert "ssh-dss" not in t.preferred_keys + assert "diffie-hellman-group14-sha256" in t._preferred_kex + assert "diffie-hellman-group14-sha256" not in t.preferred_kex + + # TODO: a bunch of busywork proving all prior uses of ._preferred_x are now + # using .preferred_x :( |