diff options
-rw-r--r-- | .travis.yml | 19 | ||||
-rw-r--r-- | paramiko/ecdsakey.py | 4 | ||||
-rw-r--r-- | paramiko/hostkeys.py | 6 | ||||
-rw-r--r-- | paramiko/kex_ecdh_nist.py | 37 | ||||
-rw-r--r-- | setup.py | 2 | ||||
-rw-r--r-- | sites/www/changelog.rst | 25 | ||||
-rw-r--r-- | tests/test_kex.py | 12 |
7 files changed, 79 insertions, 26 deletions
diff --git a/.travis.yml b/.travis.yml index a2820666..41c074bb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,3 +1,4 @@ +dist: xenial language: python sudo: false cache: @@ -8,26 +9,28 @@ python: - "3.4" - "3.5" - "3.6" - - "3.7-dev" - - "pypy-5.6.0" + - "3.7" + - "3.8-dev" + - "pypy" + - "pypy3" matrix: allow_failures: - - python: "3.7-dev" + - python: "3.8-dev" # Explicitly test against our oldest supported cryptography.io, in addition # to whatever the latest default is. include: - python: 2.7 - env: "CRYPTO_BEFORE=2.6" - - python: 3.6 - env: "CRYPTO_BEFORE=2.6" + env: "OLDEST_CRYPTO=2.5" + - python: 3.7 + env: "OLDEST_CRYPTO=2.5" install: # Ensure modern pip/etc to avoid some issues w/ older worker environs - pip install pip==9.0.1 setuptools==36.6.0 # Grab a specific version of Cryptography if desired. Doing this before other # installations ensures we don't have to do any downgrading/overriding. - | - if [[ -n "$CRYPTO_BEFORE" ]]; then - pip install "cryptography<${CRYPTO_BEFORE}" + if [[ -n "$OLDEST_CRYPTO" ]]; then + pip install "cryptography==${OLDEST_CRYPTO}" fi # Self-install for setup.py-driven deps - pip install -e . diff --git a/paramiko/ecdsakey.py b/paramiko/ecdsakey.py index b73a969e..353c5f9e 100644 --- a/paramiko/ecdsakey.py +++ b/paramiko/ecdsakey.py @@ -160,12 +160,12 @@ class ECDSAKey(PKey): pointinfo = msg.get_binary() try: - numbers = ec.EllipticCurvePublicNumbers.from_encoded_point( + key = ec.EllipticCurvePublicKey.from_encoded_point( self.ecdsa_curve.curve_class(), pointinfo ) + self.verifying_key = key except ValueError: raise SSHException("Invalid public key") - self.verifying_key = numbers.public_key(backend=default_backend()) @classmethod def supported_key_format_identifiers(cls): diff --git a/paramiko/hostkeys.py b/paramiko/hostkeys.py index f31b8819..d0660cc8 100644 --- a/paramiko/hostkeys.py +++ b/paramiko/hostkeys.py @@ -19,8 +19,12 @@ import binascii import os +import sys -from collections import MutableMapping +if sys.version_info[:2] >= (3, 3): + from collections.abc import MutableMapping +else: + from collections import MutableMapping from hashlib import sha1 from hmac import HMAC diff --git a/paramiko/kex_ecdh_nist.py b/paramiko/kex_ecdh_nist.py index 1d87442a..ad5c9c79 100644 --- a/paramiko/kex_ecdh_nist.py +++ b/paramiko/kex_ecdh_nist.py @@ -9,6 +9,7 @@ from paramiko.py3compat import byte_chr, long from paramiko.ssh_exception import SSHException from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives import serialization from binascii import hexlify _MSG_KEXECDH_INIT, _MSG_KEXECDH_REPLY = range(30, 32) @@ -36,7 +37,12 @@ class KexNistp256: m = Message() m.add_byte(c_MSG_KEXECDH_INIT) # SEC1: V2.0 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion - m.add_string(self.Q_C.public_numbers().encode_point()) + m.add_string( + self.Q_C.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint, + ) + ) self.transport._send_message(m) self.transport._expect_packet(_MSG_KEXECDH_REPLY) @@ -58,11 +64,11 @@ class KexNistp256: def _parse_kexecdh_init(self, m): Q_C_bytes = m.get_string() - self.Q_C = ec.EllipticCurvePublicNumbers.from_encoded_point( + self.Q_C = ec.EllipticCurvePublicKey.from_encoded_point( self.curve, Q_C_bytes ) K_S = self.transport.get_server_key().asbytes() - K = self.P.exchange(ec.ECDH(), self.Q_C.public_key(default_backend())) + K = self.P.exchange(ec.ECDH(), self.Q_C) K = long(hexlify(K), 16) # compute exchange hash hm = Message() @@ -75,7 +81,12 @@ class KexNistp256: hm.add_string(K_S) hm.add_string(Q_C_bytes) # SEC1: V2.0 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion - hm.add_string(self.Q_S.public_numbers().encode_point()) + hm.add_string( + self.Q_S.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint, + ) + ) hm.add_mpint(long(K)) H = self.hash_algo(hm.asbytes()).digest() self.transport._set_K_H(K, H) @@ -84,7 +95,12 @@ class KexNistp256: m = Message() m.add_byte(c_MSG_KEXECDH_REPLY) m.add_string(K_S) - m.add_string(self.Q_S.public_numbers().encode_point()) + m.add_string( + self.Q_S.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint, + ) + ) m.add_string(sig) self.transport._send_message(m) self.transport._activate_outbound() @@ -92,11 +108,11 @@ class KexNistp256: def _parse_kexecdh_reply(self, m): K_S = m.get_string() Q_S_bytes = m.get_string() - self.Q_S = ec.EllipticCurvePublicNumbers.from_encoded_point( + self.Q_S = ec.EllipticCurvePublicKey.from_encoded_point( self.curve, Q_S_bytes ) sig = m.get_binary() - K = self.P.exchange(ec.ECDH(), self.Q_S.public_key(default_backend())) + K = self.P.exchange(ec.ECDH(), self.Q_S) K = long(hexlify(K), 16) # compute exchange hash and verify signature hm = Message() @@ -108,7 +124,12 @@ class KexNistp256: ) hm.add_string(K_S) # SEC1: V2.0 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion - hm.add_string(self.Q_C.public_numbers().encode_point()) + hm.add_string( + self.Q_C.public_bytes( + serialization.Encoding.X962, + serialization.PublicFormat.UncompressedPoint, + ) + ) hm.add_string(Q_S_bytes) hm.add_mpint(K) self.transport._set_K_H(K, self.hash_algo(hm.asbytes()).digest()) @@ -70,6 +70,8 @@ setup( "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", ], install_requires=["bcrypt>=3.1.3", "cryptography>=2.5", "pynacl>=1.0.1"], ) diff --git a/sites/www/changelog.rst b/sites/www/changelog.rst index ff87bfbb..032edb44 100644 --- a/sites/www/changelog.rst +++ b/sites/www/changelog.rst @@ -2,6 +2,29 @@ Changelog ========= +- :support:`1379` (also :issue:`1369`) Raise Cryptography dependency + requirement to version 2.5 (from 1.5) and update some deprecated uses of its + API. + + This removes a bunch of warnings of the style + ``CryptographyDeprecationWarning: encode_point has been deprecated on + EllipticCurvePublicNumbers and will be removed in a future version. Please + use EllipticCurvePublicKey.public_bytes to obtain both compressed and + uncompressed point encoding`` and similar, which users who had eventually + upgraded to Cryptography 2.x would encounter. + + .. warning:: + This change is backwards incompatible **if** you are unable to upgrade your + version of Cryptography. Please see `Cryptography's own changelog + <https://cryptography.io/en/latest/changelog/>`_ for details on what may + change when you upgrade; for the most part the only changes involved + dropping older Python versions (such as 2.6, 3.3, or some PyPy editions) + which Paramiko itself has already dropped. + +- :support:`1378 backported` Add support for the modern (as of Python 3.3) + import location of ``MutableMapping`` (used in host key management) to avoid + the old location becoming deprecated in Python 3.8. Thanks to Josh Karpel for + catch & patch. - :release:`2.4.2 <2018-09-18>` - :release:`2.3.3 <2018-09-18>` - :release:`2.2.4 <2018-09-18>` @@ -95,7 +118,7 @@ Changelog - :support:`1100` Updated the test suite & related docs/metadata/config to be compatible with pytest instead of using the old, custom, crufty unittest-based ``test.py``. - + This includes marking known-slow tests (mostly the SFTP ones) so they can be filtered out by ``inv test``'s default behavior; as well as other minor tweaks to test collection and/or display (for example, GSSAPI tests are diff --git a/tests/test_kex.py b/tests/test_kex.py index 62512beb..d42355a1 100644 --- a/tests/test_kex.py +++ b/tests/test_kex.py @@ -42,20 +42,20 @@ def dummy_urandom(n): def dummy_generate_key_pair(obj): private_key_value = 94761803665136558137557783047955027733968423115106677159790289642479432803037 public_key_numbers = "042bdab212fa8ba1b7c843301682a4db424d307246c7e1e6083c41d9ca7b098bf30b3d63e2ec6278488c135360456cc054b3444ecc45998c08894cbc1370f5f989" - public_key_numbers_obj = ec.EllipticCurvePublicNumbers.from_encoded_point( + public_key_numbers_obj = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256R1(), unhexlify(public_key_numbers) - ) + ).public_numbers() obj.P = ec.EllipticCurvePrivateNumbers( private_value=private_key_value, public_numbers=public_key_numbers_obj ).private_key(default_backend()) if obj.transport.server_mode: - obj.Q_S = ec.EllipticCurvePublicNumbers.from_encoded_point( + obj.Q_S = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256R1(), unhexlify(public_key_numbers) - ).public_key(default_backend()) + ) return - obj.Q_C = ec.EllipticCurvePublicNumbers.from_encoded_point( + obj.Q_C = ec.EllipticCurvePublicKey.from_encoded_point( ec.SECP256R1(), unhexlify(public_key_numbers) - ).public_key(default_backend()) + ) class FakeKey(object): |