summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJeff Forcier <jeff@bitprophet.org>2017-06-06 13:26:43 -0700
committerJeff Forcier <jeff@bitprophet.org>2017-06-06 13:26:43 -0700
commit63dd0e2c2aa2413dd1032de5b2be5b9cc46dac2b (patch)
tree5dd1b9bd36792759d412ed8a2780681cf1b952c8
parentc1233679c448b445ec991710d259eec0a9f64b61 (diff)
parent1c88acaac8afd7d0dbf0062bcabff1795a4a729f (diff)
Merge branch 'master' into 983-int
-rw-r--r--paramiko/client.py17
-rw-r--r--paramiko/transport.py30
-rw-r--r--sites/www/changelog.rst12
-rw-r--r--tests/test_client.py17
4 files changed, 36 insertions, 40 deletions
diff --git a/paramiko/client.py b/paramiko/client.py
index 689f84b1..08fe69d4 100644
--- a/paramiko/client.py
+++ b/paramiko/client.py
@@ -22,6 +22,7 @@ SSH client & key policies
from binascii import hexlify
import getpass
+import inspect
import os
import socket
import warnings
@@ -170,16 +171,10 @@ class SSHClient (ClosingContextManager):
Specifically:
- * A **policy** is an instance of a "policy class", namely some subclass
- of `.MissingHostKeyPolicy` such as `.RejectPolicy` (the default),
- `.AutoAddPolicy`, `.WarningPolicy`, or a user-created subclass.
-
- .. note::
- This method takes class **instances**, not **classes** themselves.
- Thus it must be called as e.g.
- ``.set_missing_host_key_policy(WarningPolicy())`` and *not*
- ``.set_missing_host_key_policy(WarningPolicy)``.
-
+ * A **policy** is a "policy class" (or instance thereof), namely some
+ subclass of `.MissingHostKeyPolicy` such as `.RejectPolicy` (the
+ default), `.AutoAddPolicy`, `.WarningPolicy`, or a user-created
+ subclass.
* A host key is **known** when it appears in the client object's cached
host keys structures (those manipulated by `load_system_host_keys`
and/or `load_host_keys`).
@@ -188,6 +183,8 @@ class SSHClient (ClosingContextManager):
the policy to use when receiving a host key from a
previously-unknown server
"""
+ if inspect.isclass(policy):
+ policy = policy()
self._policy = policy
def _families_and_addresses(self, hostname, port):
diff --git a/paramiko/transport.py b/paramiko/transport.py
index b6200933..688e09e7 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -74,7 +74,6 @@ from paramiko.ssh_exception import (
from paramiko.util import retry_on_signal, ClosingContextManager, clamp_value
-
# for thread cleanup
_active_threads = []
@@ -114,8 +113,6 @@ class Transport(threading.Thread, ClosingContextManager):
'aes192-cbc',
'aes256-cbc',
'3des-cbc',
- 'arcfour128',
- 'arcfour256',
)
_preferred_macs = (
'hmac-sha2-256',
@@ -193,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
- },
}
@@ -1756,21 +1741,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),
diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst
index 3f45334d..2e09a5c3 100644
--- a/sites/www/changelog.rst
+++ b/sites/www/changelog.rst
@@ -2,6 +2,18 @@
Changelog
=========
+* :bug:`-` (partial application of :issue:`983`) Move ``sha1`` above the
+ now-arguably-broken ``md5`` in the list of preferred MAC algorithms, as an
+ incremental security improvement for users whose target systems offer both.
+ Credit: Pierce Lopez.
+* :bug:`667` The RC4/arcfour family of ciphers has been broken since version
+ 2.0; but since the algorithm is now known to be completely insecure, we are
+ opting to remove support outright instead of fixing it. Thanks to Alex Gaynor
+ for catch & patch.
+* :feature:`857` Allow `SSHClient.set_missing_host_key_policy
+ <paramiko.client.SSHClient.set_missing_host_key_policy>` to accept policy
+ classes _or_ instances, instead of only instances, thus fixing a
+ long-standing gotcha for unaware users.
* :feature:`951` Add support for ECDH key exchange (kex), specifically the
algorithms ``ecdh-sha2-nistp256``, ``ecdh-sha2-nistp384``, and
``ecdh-sha2-nistp521``. Thanks to Shashank Veerapaneni for the patch.
diff --git a/tests/test_client.py b/tests/test_client.py
index a340be00..3a9001e2 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -418,3 +418,20 @@ class SSHClientTest (unittest.TestCase):
'Expected original SSHException in exception')
else:
self.assertFalse(False, 'SSHException was not thrown.')
+
+
+ def test_missing_key_policy_accepts_classes_or_instances(self):
+ """
+ Client.missing_host_key_policy() can take classes or instances.
+ """
+ # AN ACTUAL UNIT TEST?! GOOD LORD
+ # (But then we have to test a private API...meh.)
+ client = paramiko.SSHClient()
+ # Default
+ assert isinstance(client._policy, paramiko.RejectPolicy)
+ # Hand in an instance (classic behavior)
+ client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ assert isinstance(client._policy, paramiko.AutoAddPolicy)
+ # Hand in just the class (new behavior)
+ client.set_missing_host_key_policy(paramiko.AutoAddPolicy)
+ assert isinstance(client._policy, paramiko.AutoAddPolicy)