summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorPaul Howarth <paul@city-fan.org>2022-03-20 21:09:54 +0000
committerPaul Howarth <paul@city-fan.org>2022-03-20 21:09:54 +0000
commitd4ff3dd430f6358b98dd104a4eb51bbc2a7ce844 (patch)
tree2c677e80d1a6c192760de5f2cb4017c4a9c17c50 /tests
parent361a60d44a00e469d8ff6e84519ae5afcbaa7e9f (diff)
downloadparamiko-d4ff3dd430f6358b98dd104a4eb51bbc2a7ce844.tar.gz
Skip tests requiring sha1 signing if the backend doesn't support that
Red Hat Enterprise Linux 9 will have SHA-1 signatures disabled by default. It is likely that SHA-1 signatures will disappear elsewhere over time too. This change detects if sha1 signatures are not supported by the backend and skips tests that rely on that functionality. This is a workaround for #2004. It would be good to reduce the reliance of the test suite on sha1 signatures except in the cases where that is explicitly being tested, and the markers added here give a decent starting point for seeing where to change things.
Diffstat (limited to 'tests')
-rw-r--r--tests/test_client.py24
-rw-r--r--tests/test_pkey.py9
-rw-r--r--tests/test_transport.py7
-rw-r--r--tests/util.py28
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
+