Skip to content

Commit 148f182

Browse files
committed
Remove deprecated DSS/DSSKey support and upgrade to paramiko 3.0+
This commit removes support for the deprecated DSA (DSS) key algorithm, which was removed in paramiko 3.0. DSS has been obsolete and insecure for over a decade and was removed from OpenSSH. Changes made: - Updated paramiko dependency from >=2.7.2 to >=3.0.0 in setup.py - Removed paramiko.DSSKey references from sshtunnel.py: * Removed 'dsa': paramiko.DSSKey from paramiko_key_types dict * Removed paramiko.DSSKey from key_types tuple - Updated documentation to reflect RSA/ECDSA support only: * Updated docstrings in sshtunnel.py * Updated CLI help text * Updated README.rst * Updated CLAUDE.md to mention Ed25519 support - Removed SSH_DSS test constant from tests/test_forwarder.py - Removed 'ssh-dss' from FINGERPRINTS test dict - Updated all test assertions to use SSH_RSA instead of SSH_DSS All existing tests pass with paramiko 4.0.0. Fixes: pahaz#299 (module 'paramiko' has no attribute 'DSSKey') Based on community proposals: pahaz#300, pahaz#301, pahaz#304 Tested with: - paramiko 4.0.0 (latest) - All argument parsing tests pass - All key-related tests pass
1 parent 78a3b12 commit 148f182

File tree

5 files changed

+11
-14
lines changed

5 files changed

+11
-14
lines changed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ Logger naming convention: `'sshtunnel.SSHTunnelForwarder'`
257257

258258
2. **Authentication Methods**
259259
- Password authentication
260-
- Private key files (RSA/DSS/ECDSA)
260+
- Private key files (RSA/ECDSA/Ed25519)
261261
- SSH agent support (can be disabled)
262262
- Password-protected private keys
263263

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,9 +255,9 @@ CLI usage
255255
-k SSH_HOST_KEY, --ssh_host_key SSH_HOST_KEY
256256
Gateway's host key
257257
-K KEY_FILE, --private_key_file KEY_FILE
258-
RSA/DSS/ECDSA private key file
258+
RSA/ECDSA private key file
259259
-S KEY_PASSWORD, --private_key_password KEY_PASSWORD
260-
RSA/DSS/ECDSA private key password
260+
RSA/ECDSA private key password
261261
-t, --threaded Allow concurrent connections to each tunnel
262262
-v, --verbose Increase output verbosity (default: ERROR)
263263
-V, --version Show version number and quit

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@
9797
# requirements files see:
9898
# https://packaging.python.org/en/latest/requirements.html
9999
install_requires=[
100-
'paramiko>=2.7.2',
100+
'paramiko>=3.0.0',
101101
],
102102

103103
# List additional groups of dependencies here (e.g. development

sshtunnel.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,6 @@ def get_keys(logger=None, host_pkey_directories=None, allow_agent=False):
10901090
host_pkey_directories = [DEFAULT_SSH_DIRECTORY]
10911091

10921092
paramiko_key_types = {'rsa': paramiko.RSAKey,
1093-
'dsa': paramiko.DSSKey,
10941093
'ecdsa': paramiko.ECDSAKey}
10951094
if hasattr(paramiko, 'Ed25519Key'):
10961095
# NOQA: new in paramiko>=2.2: http://docs.paramiko.org/en/stable/api/keys.html#module-paramiko.ed25519key
@@ -1286,7 +1285,7 @@ def read_private_key_file(pkey_file,
12861285
12871286
Arguments:
12881287
pkey_file (str):
1289-
File containing a private key (RSA, DSS or ECDSA)
1288+
File containing a private key (RSA or ECDSA)
12901289
Keyword Arguments:
12911290
pkey_password (Optional[str]):
12921291
Password to decrypt the private key
@@ -1295,7 +1294,7 @@ def read_private_key_file(pkey_file,
12951294
paramiko.Pkey
12961295
"""
12971296
ssh_pkey = None
1298-
key_types = (paramiko.RSAKey, paramiko.DSSKey, paramiko.ECDSAKey)
1297+
key_types = (paramiko.RSAKey, paramiko.ECDSAKey)
12991298
if hasattr(paramiko, 'Ed25519Key'):
13001299
# NOQA: new in paramiko>=2.2: http://docs.paramiko.org/en/stable/api/keys.html#module-paramiko.ed25519key
13011300
key_types += (paramiko.Ed25519Key, )
@@ -1806,15 +1805,15 @@ def _parse_arguments(args=None):
18061805
dest='ssh_private_key',
18071806
metavar='KEY_FILE',
18081807
type=str,
1809-
help='RSA/DSS/ECDSA private key file'
1808+
help='RSA/ECDSA private key file'
18101809
)
18111810

18121811
parser.add_argument(
18131812
'-S', '--private_key_password',
18141813
dest='ssh_private_key_password',
18151814
metavar='KEY_PASSWORD',
18161815
type=str,
1817-
help='RSA/DSS/ECDSA private key password'
1816+
help='RSA/ECDSA private key password'
18181817
)
18191818

18201819
parser.add_argument(

tests/test_forwarder.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,9 @@ def capture_stdout_stderr():
8181

8282
SSH_USERNAME = get_random_string()
8383
SSH_PASSWORD = get_random_string()
84-
SSH_DSS = b'\x44\x78\xf0\xb9\xa2\x3c\xc5\x18\x20\x09\xff\x75\x5b\xc1\xd2\x6c'
8584
SSH_RSA = b'\x60\x73\x38\x44\xcb\x51\x86\x65\x7f\xde\xda\xa2\x2b\x5a\x57\xd5'
8685
ECDSA = b'\x25\x19\xeb\x55\xe6\xa1\x47\xff\x4f\x38\xd2\x75\x6f\xa5\xd5\x60'
8786
FINGERPRINTS = {
88-
'ssh-dss': SSH_DSS,
8987
'ssh-rsa': SSH_RSA,
9088
'ecdsa-sha2-nistp256': ECDSA,
9189
}
@@ -1202,7 +1200,7 @@ def test_parse_arguments_short(self):
12021200
'-P={0}'.format(SSH_PASSWORD), # GW password
12031201
'-R', '10.0.0.1:8080', '10.0.0.2:8080', # remote bind list
12041202
'-L', ':8081', ':8082', # local bind list
1205-
'-k={0}'.format(SSH_DSS), # hostkey
1203+
'-k={0}'.format(SSH_RSA), # hostkey
12061204
'-K={0}'.format(__file__), # pkey file
12071205
'-S={0}'.format(SSH_PASSWORD), # pkey password
12081206
'-t', # concurrent connections (threaded)
@@ -1232,7 +1230,7 @@ def test_parse_arguments_long(self):
12321230
'--password={0}'.format(SSH_PASSWORD), # GW password
12331231
'--remote_bind_address', '10.0.0.1:8080', '10.0.0.2:8080',
12341232
'--local_bind_address', ':8081', ':8082', # local bind list
1235-
'--ssh_host_key={0}'.format(SSH_DSS), # hostkey
1233+
'--ssh_host_key={0}'.format(SSH_RSA), # hostkey
12361234
'--private_key_file={0}'.format(__file__), # pkey file
12371235
'--private_key_password={0}'.format(SSH_PASSWORD),
12381236
'--threaded', # concurrent connections (threaded)
@@ -1254,7 +1252,7 @@ def _test_parser(self, parser):
12541252
[('10.0.0.1', 8080), ('10.0.0.2', 8080)])
12551253
self.assertListEqual(parser['local_bind_addresses'],
12561254
[('', 8081), ('', 8082)])
1257-
self.assertEqual(parser['ssh_host_key'], str(SSH_DSS))
1255+
self.assertEqual(parser['ssh_host_key'], str(SSH_RSA))
12581256
self.assertEqual(parser['ssh_private_key'], __file__)
12591257
self.assertEqual(parser['ssh_private_key_password'], SSH_PASSWORD)
12601258
self.assertTrue(parser['threaded'])

0 commit comments

Comments
 (0)