diff --git a/src/main/java/net/schmizz/sshj/ConfigImpl.java b/src/main/java/net/schmizz/sshj/ConfigImpl.java index 836f2161..8220c561 100644 --- a/src/main/java/net/schmizz/sshj/ConfigImpl.java +++ b/src/main/java/net/schmizz/sshj/ConfigImpl.java @@ -188,4 +188,27 @@ public boolean isVerifyHostKeyCertificates() { public void setVerifyHostKeyCertificates(boolean value) { verifyHostKeyCertificates = value; } + + /** + * Modern servers neglect the key algorithm ssh-rsa. OpenSSH 8.8 even dropped its support by default in favour + * of rsa-sha2-*. However, there are legacy servers like Apache SSHD that don't support the newer replacements + * for ssh-rsa. + * + * If ssh-rsa factory is in {@link #getKeyAlgorithms()}, this methods makes ssh-rsa key algorithm more preferred + * than any of rsa-sha2-*. Otherwise, nothing happens. + */ + public void prioritizeSshRsaKeyAlgorithm() { + for (int sshRsaIndex = 0; sshRsaIndex < keyAlgorithms.size(); ++ sshRsaIndex) { + if ("ssh-rsa".equals(keyAlgorithms.get(sshRsaIndex).getName())) { + for (int i = 0; i < sshRsaIndex; ++i) { + final String algo = keyAlgorithms.get(i).getName(); + if ("rsa-sha2-256".equals(algo) || "rsa-sha2-512".equals(algo)) { + keyAlgorithms.add(i, keyAlgorithms.remove(sshRsaIndex)); + break; + } + } + break; + } + } + } } diff --git a/src/test/groovy/com/hierynomus/sshj/userauth/keyprovider/FileKeyProviderSpec.groovy b/src/test/groovy/com/hierynomus/sshj/userauth/keyprovider/FileKeyProviderSpec.groovy index 06b48af6..90ecb3ec 100644 --- a/src/test/groovy/com/hierynomus/sshj/userauth/keyprovider/FileKeyProviderSpec.groovy +++ b/src/test/groovy/com/hierynomus/sshj/userauth/keyprovider/FileKeyProviderSpec.groovy @@ -43,10 +43,7 @@ class FileKeyProviderSpec extends Specification { // `fixture` is backed by Apache SSHD server. Looks like it doesn't support rsa-sha2-512 public key signature. // Changing the default config to prioritize the former default implementation of RSA signature. def config = new DefaultConfig() - def sshRsaFactory = config.keyAlgorithms.find {it.name == "ssh-rsa" } - if (sshRsaFactory == null) - throw new IllegalStateException("ssh-rsa was removed from the default config, the test should be refactored") - config.keyAlgorithms = [sshRsaFactory] + config.keyAlgorithms.grep { it != sshRsaFactory } + config.prioritizeSshRsaKeyAlgorithm() and: SSHClient client = fixture.setupClient(config) diff --git a/src/test/groovy/net/schmizz/sshj/ConfigImplSpec.groovy b/src/test/groovy/net/schmizz/sshj/ConfigImplSpec.groovy new file mode 100644 index 00000000..ca078138 --- /dev/null +++ b/src/test/groovy/net/schmizz/sshj/ConfigImplSpec.groovy @@ -0,0 +1,72 @@ +package net.schmizz.sshj + +import com.hierynomus.sshj.key.KeyAlgorithms +import spock.lang.Specification + +class ConfigImplSpec extends Specification { + static def ECDSA = KeyAlgorithms.ECDSASHANistp521() + static def ED25519 = KeyAlgorithms.EdDSA25519() + static def RSA_SHA_256 = KeyAlgorithms.RSASHA256() + static def RSA_SHA_512 = KeyAlgorithms.RSASHA512() + static def SSH_RSA = KeyAlgorithms.SSHRSA() + + def "prioritizeSshRsaKeyAlgorithm does nothing if there is no ssh-rsa"() { + given: + def config = new DefaultConfig() + config.keyAlgorithms = [RSA_SHA_512, ED25519] + + when: + config.prioritizeSshRsaKeyAlgorithm() + + then: + config.keyAlgorithms == [RSA_SHA_512, ED25519] + } + + def "prioritizeSshRsaKeyAlgorithm does nothing if there is no rsa-sha2-any"() { + given: + def config = new DefaultConfig() + config.keyAlgorithms = [ED25519, SSH_RSA, ECDSA] + + when: + config.prioritizeSshRsaKeyAlgorithm() + + then: + config.keyAlgorithms == [ED25519, SSH_RSA, ECDSA] + } + + def "prioritizeSshRsaKeyAlgorithm does nothing if ssh-rsa already has higher priority"() { + given: + def config = new DefaultConfig() + config.keyAlgorithms = [ED25519, SSH_RSA, RSA_SHA_512, ECDSA] + + when: + config.prioritizeSshRsaKeyAlgorithm() + + then: + config.keyAlgorithms == [ED25519, SSH_RSA, RSA_SHA_512, ECDSA] + } + + def "prioritizeSshRsaKeyAlgorithm prioritizes ssh-rsa if there is one rsa-sha2-any is prioritized"() { + given: + def config = new DefaultConfig() + config.keyAlgorithms = [ED25519, RSA_SHA_512, ECDSA, SSH_RSA] + + when: + config.prioritizeSshRsaKeyAlgorithm() + + then: + config.keyAlgorithms == [ED25519, SSH_RSA, RSA_SHA_512, ECDSA] + } + + def "prioritizeSshRsaKeyAlgorithm prioritizes ssh-rsa if there are two rsa-sha2-any is prioritized"() { + given: + def config = new DefaultConfig() + config.keyAlgorithms = [ED25519, RSA_SHA_512, ECDSA, RSA_SHA_256, SSH_RSA] + + when: + config.prioritizeSshRsaKeyAlgorithm() + + then: + config.keyAlgorithms == [ED25519, SSH_RSA, RSA_SHA_512, ECDSA, RSA_SHA_256] + } +}