You are connecting to an OpenSSH server using an RSA private key and the following error is displayed:
1 |
USERNAME@HOST: Permission denied (publickey,password). |
You check the OpenSSH server logs and find the following entry:
1 |
userauth_pubkey: signature algorithm ssh-rsa not in PubkeyAcceptedAlgorithms [preauth] |
You are not able to authenticate with the SSH server.
Paramiko
Your program is using the Paramiko SSH library. Paramiko will throw an exception:
1 |
paramiko.ssh_exception.IncompatiblePeer: Incompatible ssh peer (no acceptable host key) |
What does the error mean?
SSH today supports three RSA signature algorithms:
- ssh-rsa
- rsa-sha2-256
- rsa-sha2-512
The original signature algorithm supported only ssh-rsa. That signature used SHA-1. The hash algorithm SHA-1 is considered weak/broken today, so SHA-1 was replaced with SHA-2. The SSH key types rsa-sha2-256 and rsa-sha2-512 replaced ssh-rsa. The OpenSSH server disabled the ssh-rsa signature algorithm in version 8.8 on 2021-09-26.
The SHA-1 signature algorithm is defined in RFC4253 Section 6.6.
The SHA-2 signature algorithms are defined in RFC8332.
The server error message means that the client is using RSA keys with SHA-1 signatures and the signature algorithm has been disabled in the SSH server.
The SSH client is older than version 8.8 and the OpenSSH server is version 8.8 or newer.
SSH Key Type Confusion
The OpenSSH team decided to keep the key type name ssh-rsa, even after deprecating the signature algorithm with the same name. I guess this would break other features such as the authorized_keys file, the known_hosts file, SSH server fingerprint programs, and more. Their goal was probably to keep the blast radius from this change as small as possible.
The critical point is the word ssh-rsa is used in several contexts. It can mean the SSH key type and the SSH signature algorithm. Same name but very different meanings:
- ssh-rsa is used as the SSH Key Type e.g the type of public key cryptography (RSA, DSA, ECDSA, EdDSA).
- ssh-rsa is used as the SSH Signature Algorithm e.g. the protocol used during key exchanges (RSA+SHA-1, RSA+SHA-2).
Solutions:
- If you are using the SSH client program, upgrade the client to be at the same version or newer than the SSH server. Support for rsa-sha2-256 and rsa-sha2-512 was released in version 8.8 (2021-09-26).
- If you are using an SSH library, upgrade the library.
- For example, the Python Paramiko library did not support rsa-sha2-256 and rsa-sha2-512 until version 2.9.0 (2021-12-23). Older versions of Paramiko would fail to connect to OpenSSH server version 8.8 or newer when using RSA keys. Older libraries used SHA-1 for the signature algorithm instead of SHA-2.
- Enable ssh-rsa in the OpenSSH server. This is not recommended for security reasons.
- Edit the
sshd_config
file. For Debian-based systems:/etc/ssh/sshd_config
. - Add the following line:
- PubkeyAcceptedKeyTypes=+ssh-rsa
- Edit the
Verify that your SSH server does not support ssh-rsa
The SSH client that is part of the OpenSSH tool suite has several useful command line options.
This option declares the SSH key types that the SSH client will use:
- -o PubkeyAcceptedKeyTypes=ssh-rsa
This option disables asking for a password:
- -o PasswordAuthentication=no
Combine those options and connect to your SSH server. If ssh-rsa is supported the connection will succeed. That means the server is vulnerable to attack. Review the server’s configuration and disable ssh-rsa if possible. If not, upgrade the server to a version that supports RSA+SHA-2.
1 |
ssh -o PubkeyAcceptedKeyTypes=ssh-rsa -o PasswordAuthentication=no -i /path/to/private.key USERNAME@HOST |
Paramiko
The following Python program will also generate the same error but with a different exception message. If this program succeeds, the SSH server is vulnerable.
1 |
paramiko.ssh_exception.IncompatiblePeer: Incompatible ssh peer (no acceptable host key) |
force_rsa_error.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import sys import logging from paramiko import Transport logging.basicConfig() logging.getLogger("paramiko").setLevel(logging.CRITICAL) # logging.getLogger("paramiko").setLevel(logging.DEBUG) if len(sys.argv) < 2: print("Error: missing hostname") sys.exit(1) hostname = sys.argv[1] key_type = "ssh-rsa" if len(sys.argv) >= 3: key_type = sys.argv[2] t = Transport((hostname, 22)) if key_type is not None: t.get_security_options().key_types = [key_type] t.start_client() k = t.get_remote_server_key() print(f"{hostname} {k.get_name()} {k.get_base64()}") t.close() |
Run the program:
1 |
python force_rsa_error.py HOST |
An exception is thrown:
1 |
paramiko.ssh_exception.IncompatiblePeer: Incompatible ssh peer (no acceptable host key) |
Solution:
Change this line:
1 |
key_type = "ssh-rsa" |
Change the key_type
to the support signature algorithm rsa-sha2-256
:
1 |
key_type = "rsa-sha2-256" |
The program supports a third command line argument which you can use to change the key_type for testing:
1 |
python force_rsa_error.py HOST rsa-sha2-256 |
On success the program prints the SSH fingerprint:
1 |
HOST ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCGVePmwn+3YIl6R3azQmgzYERtGQZMPBPJMdlEM3D+sAHBOZaetAx7RUYymZ5sz5kBVlHpIbg7ChGzTkuf+GzL0YOpQ9NoMpu6Cw3rzYF2cnyk5WmxUO+fa/hWw51ugEoZ2+t6GEgqMkhhkwGnFS+gsWhEzGoJa62A0P8qV5BILo/NztuKK55RNMiMqoAczW7kx/LlQYoNR1DHsppewmYenB1YqvJqZJT1Q1SBiA2s5TGoqnLEU7NBySfPYRznV9cWcrQwhtw6Hciwl0O5SBHRqraG7tetWiVoqOhRY1GGzsDo5w6SIBUm97P8SIlocBe+KJE6b/lE4+dyj7k7RkOqtqbSQHZKxiNVN99ou7cEZfwIAl1PONI1TrPJ4h5vsNZnozj17Yr/T+VzEAGx88jM0HHJa3UEdt+xlyma+l0mNtr3Nl2NdKR/LLDOIKgDjGLznNczVJ3k6m3PjHMSzgiU10WdjfWEfU/LB9vEVd0F6fO39AsLFZck5mcyUQCSHEU= |
Summary
Once you understand the error message, the solution becomes obvious. An important point to mention is that the problem is caused by a security fix. The SHA-1 security risk is very dangerous today. Under More Information, I provide a couple of article links.
Unless required, do not enable ssh-rsa by modifying the OpenSSH server configuration file with this change: PubkeyAcceptedKeyTypes=+ssh-rsa
. If you do, roll out client updates as soon as possible and disable ssh-rsa.
More Information
- Other articles I have written about SSH
- OpenSSH version 8.8 release notes
- This release disables RSA signatures using the SHA-1 hash algorithm
by default. This change has been made as the SHA-1 hash algorithm is
cryptographically broken, and it is possible to create chosen-prefix
hash collisions for <USD$50K.
- This release disables RSA signatures using the SHA-1 hash algorithm
- SHA-1 is a Shambles
- OpenSSH to deprecate SHA-1 logins due to security risk
- Paramiko release notes 2.9.0 2021-12-23
- Client verification of server host key during key exchange will now prefer rsa-sha2-512, rsa-sha2-256, and legacy ssh-rsa algorithms, in that order, instead of just ssh-rsa.
I design software for enterprise-class systems and data centers. My background is 30+ years in storage (SCSI, FC, iSCSI, disk arrays, imaging) virtualization. 20+ years in identity, security, and forensics.
For the past 14+ years, I have been working in the cloud (AWS, Azure, Google, Alibaba, IBM, Oracle) designing hybrid and multi-cloud software solutions. I am an MVP/GDE with several.
Leave a Reply