diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_client.py | 24 | ||||
-rw-r--r-- | tests/test_pkey.py | 9 | ||||
-rw-r--r-- | tests/test_transport.py | 7 | ||||
-rw-r--r-- | tests/util.py | 28 |
4 files changed, 64 insertions, 4 deletions
diff --git a/tests/test_client.py b/tests/test_client.py index 10132aae..a0a321ce 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -41,13 +41,17 @@ from paramiko import SSHClient from paramiko.pkey import PublicBlob from paramiko.ssh_exception import SSHException, AuthenticationException -from .util import _support, slow +from .util import _support, sha1_signing_unsupported, slow requires_gss_auth = unittest.skipUnless( paramiko.GSS_AUTH_AVAILABLE, "GSS auth not available" ) +requires_sha1_signing = unittest.skipIf( + sha1_signing_unsupported(), "SHA-1 signing not supported" +) + FINGERPRINTS = { "ssh-dss": b"\x44\x78\xf0\xb9\xa2\x3c\xc5\x18\x20\x09\xff\x75\x5b\xc1\xd2\x6c", # noqa "ssh-rsa": b"\x60\x73\x38\x44\xcb\x51\x86\x65\x7f\xde\xda\xa2\x2b\x5a\x57\xd5", # noqa @@ -235,33 +239,39 @@ class ClientTest(unittest.TestCase): class SSHClientTest(ClientTest): + @requires_sha1_signing def test_client(self): """ verify that the SSHClient stuff works too. """ self._test_connection(password="pygmalion") + @requires_sha1_signing def test_client_dsa(self): """ verify that SSHClient works with a DSA key. """ self._test_connection(key_filename=_support("test_dss.key")) + @requires_sha1_signing def test_client_rsa(self): """ verify that SSHClient works with an RSA key. """ self._test_connection(key_filename=_support("test_rsa.key")) + @requires_sha1_signing def test_client_ecdsa(self): """ verify that SSHClient works with an ECDSA key. """ self._test_connection(key_filename=_support("test_ecdsa_256.key")) + @requires_sha1_signing def test_client_ed25519(self): self._test_connection(key_filename=_support("test_ed25519.key")) + @requires_sha1_signing def test_multiple_key_files(self): """ verify that SSHClient accepts and tries multiple key files. @@ -293,6 +303,7 @@ class SSHClientTest(ClientTest): self.tearDown() self.setUp() + @requires_sha1_signing def test_multiple_key_files_failure(self): """ Expect failure when multiple keys in play and none are accepted @@ -306,6 +317,7 @@ class SSHClientTest(ClientTest): allowed_keys=["ecdsa-sha2-nistp256"], ) + @requires_sha1_signing def test_certs_allowed_as_key_filename_values(self): # NOTE: giving cert path here, not key path. (Key path test is below. # They're similar except for which path is given; the expected auth and @@ -319,6 +331,7 @@ class SSHClientTest(ClientTest): public_blob=PublicBlob.from_file(cert_path), ) + @requires_sha1_signing def test_certs_implicitly_loaded_alongside_key_filename_keys(self): # NOTE: a regular test_connection() w/ test_rsa.key would incidentally # test this (because test_xxx.key-cert.pub exists) but incidental tests @@ -469,6 +482,7 @@ class SSHClientTest(ClientTest): kwargs = dict(self.connect_kwargs, banner_timeout=0.5) self.assertRaises(paramiko.SSHException, self.tc.connect, **kwargs) + @requires_sha1_signing def test_auth_trickledown(self): """ Failed key auth doesn't prevent subsequent pw auth from succeeding @@ -489,6 +503,7 @@ class SSHClientTest(ClientTest): ) self._test_connection(**kwargs) + @requires_sha1_signing @slow def test_auth_timeout(self): """ @@ -591,6 +606,7 @@ class SSHClientTest(ClientTest): host_key = paramiko.ECDSAKey.generate() self._client_host_key_bad(host_key) + @requires_sha1_signing def test_host_key_negotiation_2(self): host_key = paramiko.RSAKey.generate(2048) self._client_host_key_bad(host_key) @@ -598,6 +614,7 @@ class SSHClientTest(ClientTest): def test_host_key_negotiation_3(self): self._client_host_key_good(paramiko.ECDSAKey, "test_ecdsa_256.key") + @requires_sha1_signing def test_host_key_negotiation_4(self): self._client_host_key_good(paramiko.RSAKey, "test_rsa.key") @@ -681,6 +698,7 @@ class PasswordPassphraseTests(ClientTest): # instead of suffering a real connection cycle. # TODO: in that case, move the below to be part of an integration suite? + @requires_sha1_signing def test_password_kwarg_works_for_password_auth(self): # Straightforward / duplicate of earlier basic password test. self._test_connection(password="pygmalion") @@ -688,10 +706,12 @@ class PasswordPassphraseTests(ClientTest): # TODO: more granular exception pending #387; should be signaling "no auth # methods available" because no key and no password @raises(SSHException) + @requires_sha1_signing def test_passphrase_kwarg_not_used_for_password_auth(self): # Using the "right" password in the "wrong" field shouldn't work. self._test_connection(passphrase="pygmalion") + @requires_sha1_signing def test_passphrase_kwarg_used_for_key_passphrase(self): # Straightforward again, with new passphrase kwarg. self._test_connection( @@ -699,6 +719,7 @@ class PasswordPassphraseTests(ClientTest): passphrase="television", ) + @requires_sha1_signing def test_password_kwarg_used_for_passphrase_when_no_passphrase_kwarg_given( self ): # noqa @@ -709,6 +730,7 @@ class PasswordPassphraseTests(ClientTest): ) @raises(AuthenticationException) # TODO: more granular + @requires_sha1_signing def test_password_kwarg_not_used_for_passphrase_when_passphrase_kwarg_given( # noqa self ): diff --git a/tests/test_pkey.py b/tests/test_pkey.py index ed62da21..6eac35a0 100644 --- a/tests/test_pkey.py +++ b/tests/test_pkey.py @@ -44,9 +44,13 @@ from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateNumbers from mock import patch, Mock import pytest -from .util import _support, is_low_entropy +from .util import _support, is_low_entropy, sha1_signing_unsupported +requires_sha1_signing = unittest.skipIf( + sha1_signing_unsupported(), "SHA-1 signing not supported" +) + # from openssh's ssh-keygen PUB_RSA = "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA049W6geFpmsljTwfvI1UmKWWJPNFI74+vNKTk4dmzkQY2yAMs6FhlvhlI8ysU4oj71ZsRYMecHbBbxdN79+JRFVYTKaLqjwGENeTd+yv4q+V2PvZv3fLnzApI3l7EJCqhWwJUHJ1jAkZzqDx0tyOL4uoZpww3nmE0kb3y21tH4c=" # noqa PUB_DSS = "ssh-dss AAAAB3NzaC1kc3MAAACBAOeBpgNnfRzr/twmAQRu2XwWAp3CFtrVnug6s6fgwj/oLjYbVtjAy6pl/h0EKCWx2rf1IetyNsTxWrniA9I6HeDj65X1FyDkg6g8tvCnaNB8Xp/UUhuzHuGsMIipRxBxw9LF608EqZcj1E3ytktoW5B5OcjrkEoz3xG7C+rpIjYvAAAAFQDwz4UnmsGiSNu5iqjn3uTzwUpshwAAAIEAkxfFeY8P2wZpDjX0MimZl5wkoFQDL25cPzGBuB4OnB8NoUk/yjAHIIpEShw8V+LzouMK5CTJQo5+Ngw3qIch/WgRmMHy4kBq1SsXMjQCte1So6HBMvBPIW5SiMTmjCfZZiw4AYHK+B/JaOwaG9yRg2Ejg4Ok10+XFDxlqZo8Y+wAAACARmR7CCPjodxASvRbIyzaVpZoJ/Z6x7dAumV+ysrV1BVYd0lYukmnjO1kKBWApqpH1ve9XDQYN8zgxM4b16L21kpoWQnZtXrY3GZ4/it9kUgyB7+NwacIBlXa8cMDL7Q/69o0d54U0X/NeX5QxuYR6OMJlrkQB7oiW/P/1mwjQgE=" # noqa @@ -136,7 +140,6 @@ x1234 = b"\x01\x02\x03\x04" TEST_KEY_BYTESTR_2 = "\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01#\x00\x00\x00\x81\x00\xd3\x8fV\xea\x07\x85\xa6k%\x8d<\x1f\xbc\x8dT\x98\xa5\x96$\xf3E#\xbe>\xbc\xd2\x93\x93\x87f\xceD\x18\xdb \x0c\xb3\xa1a\x96\xf8e#\xcc\xacS\x8a#\xefVlE\x83\x1epv\xc1o\x17M\xef\xdf\x89DUXL\xa6\x8b\xaa<\x06\x10\xd7\x93w\xec\xaf\xe2\xaf\x95\xd8\xfb\xd9\xbfw\xcb\x9f0)#y{\x10\x90\xaa\x85l\tPru\x8c\t\x19\xce\xa0\xf1\xd2\xdc\x8e/\x8b\xa8f\x9c0\xdey\x84\xd2F\xf7\xcbmm\x1f\x87" # noqa TEST_KEY_BYTESTR_3 = "\x00\x00\x00\x07ssh-rsa\x00\x00\x00\x01#\x00\x00\x00\x00ӏV\x07k%<\x1fT$E#>ғfD\x18 \x0cae#̬S#VlE\x1epvo\x17M߉DUXL<\x06\x10דw\u2bd5ٿw˟0)#y{\x10l\tPru\t\x19Π\u070e/f0yFmm\x1f" # noqa - class KeyTest(unittest.TestCase): def setUp(self): pass @@ -256,6 +259,7 @@ class KeyTest(unittest.TestCase): pub = RSAKey(data=key.asbytes()) self.assertTrue(pub.verify_ssh_sig(b"ice weasels", msg)) + @requires_sha1_signing def test_sign_and_verify_ssh_rsa(self): self._sign_and_verify_rsa("ssh-rsa", SIGNED_RSA) @@ -280,6 +284,7 @@ class KeyTest(unittest.TestCase): pub = DSSKey(data=key.asbytes()) self.assertTrue(pub.verify_ssh_sig(b"ice weasels", msg)) + @requires_sha1_signing def test_generate_rsa(self): key = RSAKey.generate(1024) msg = key.sign_ssh_data(b"jerri blank") diff --git a/tests/test_transport.py b/tests/test_transport.py index a9262f3d..8124f129 100644 --- a/tests/test_transport.py +++ b/tests/test_transport.py @@ -61,7 +61,7 @@ from paramiko.common import ( from paramiko.py3compat import bytes, byte_chr from paramiko.message import Message -from .util import needs_builtin, _support, slow +from .util import needs_builtin, _support, sha1_signing_unsupported, slow from .loop import LoopSocket @@ -77,6 +77,9 @@ Note: An SSH banner may eventually appear. Maybe. """ +requires_sha1_signing = unittest.skipIf( + sha1_signing_unsupported(), "SHA-1 signing not supported" +) class NullServer(ServerInterface): paranoid_did_password = False @@ -1283,6 +1286,7 @@ class TestSHA2SignatureKeyExchange(unittest.TestCase): # are new tests in test_pkey.py which use known signature blobs to prove # the SHA2 family was in fact used! + @requires_sha1_signing def test_base_case_ssh_rsa_still_used_as_fallback(self): # Prove that ssh-rsa is used if either, or both, participants have SHA2 # algorithms disabled @@ -1405,6 +1409,7 @@ class TestSHA2SignaturePubkeys(unittest.TestCase): ) as (tc, ts, err): assert isinstance(err, AuthenticationException) + @requires_sha1_signing def test_ssh_rsa_still_used_when_sha2_disabled(self): privkey = RSAKey.from_private_key_file(_support("test_rsa.key")) # NOTE: this works because key obj comparison uses public bytes diff --git a/tests/util.py b/tests/util.py index 1355ce8a..69df87f5 100644 --- a/tests/util.py +++ b/tests/util.py @@ -9,6 +9,9 @@ import pytest from paramiko.py3compat import builtins, PY2 from paramiko.ssh_gss import GSS_AUTH_AVAILABLE +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import padding, rsa tests_dir = dirname(realpath(__file__)) @@ -144,3 +147,28 @@ def is_low_entropy(): # I don't see a way to tell internally if the hash seed was set this # way, but env should be plenty sufficient, this is only for testing. return is_32bit and os.environ.get("PYTHONHASHSEED", None) == "0" + + +def sha1_signing_unsupported(): + """ + This is used to skip tests in environments where SHA-1 signing is + not supported by the backend. + """ + private_key = rsa.generate_private_key( + public_exponent=65537, + key_size=2048, + ) + message = b"Some dummy text" + try: + signature = private_key.sign( + message, + padding.PSS( + mgf=padding.MGF1(hashes.SHA1()), + salt_length=padding.PSS.MAX_LENGTH + ), + hashes.SHA1() + ) + return False + except UnsupportedAlgorithm as e: + return e._reason is _Reasons.UNSUPPORTED_HASH + |