-
Notifications
You must be signed in to change notification settings - Fork 602
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Lean on Config.keyAlgorithms choosing between rsa-sha2-* and ssh-rsa (#…
…742) * Improve SshdContainer: log `docker build` to stdout, don't wait too long if container exited * Fix #740: Lean on Config.keyAlgorithms choosing between rsa-sha2-* and ssh-rsa Previously, there was a heuristic that was choosing rsa-sha2-512 after receiving a host key of type RSA. It didn't work well when a server doesn't have an RSA host key. OpenSSH 8.8 introduced a breaking change: it removed ssh-rsa from the default list of supported public key signature algorithms. SSHJ was unable to connect to OpenSSH 8.8 server if the server has an EcDSA or Ed25519 host key. Current behaviour behaves the same as OpenSSH 8.8 client does. SSHJ doesn't try to determine rsa-sha2-* support on the fly. Instead, it looks only on `Config.getKeyAlgorithms()`, which may or may not contain ssh-rsa and rsa-sha2-* in any order. Sorry, this commit mostly reverts changes from #607. * Introduce ConfigImpl.prioritizeSshRsaKeyAlgorithm to deal with broken backward compatibility Co-authored-by: Jeroen van Erp <jeroen@hierynomus.com>
- Loading branch information
1 parent
d8697c2
commit 624747c
Showing
13 changed files
with
332 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
159 changes: 159 additions & 0 deletions
159
src/itest/groovy/com/hierynomus/sshj/RsaShaKeySignatureTest.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
/* | ||
* Copyright (C)2009 - SSHJ Contributors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.hierynomus.sshj | ||
|
||
import com.hierynomus.sshj.key.KeyAlgorithms | ||
import net.schmizz.sshj.Config | ||
import net.schmizz.sshj.DefaultConfig | ||
import org.testcontainers.images.builder.dockerfile.DockerfileBuilder | ||
import spock.lang.Specification | ||
import spock.lang.Unroll | ||
|
||
import java.nio.file.Paths | ||
|
||
/** | ||
* Checks that SSHJ is able to work with OpenSSH 8.8, which removed ssh-rsa signature from the default setup. | ||
*/ | ||
class RsaShaKeySignatureTest extends Specification { | ||
private static final Map<String, KeyAlgorithms.Factory> SSH_HOST_KEYS_AND_FACTORIES = [ | ||
'ssh_host_ecdsa_256_key': KeyAlgorithms.ECDSASHANistp256(), | ||
'ssh_host_ecdsa_384_key': KeyAlgorithms.ECDSASHANistp384(), | ||
'ssh_host_ecdsa_521_key': KeyAlgorithms.ECDSASHANistp521(), | ||
'ssh_host_ed25519_384_key': KeyAlgorithms.EdDSA25519(), | ||
'ssh_host_rsa_2048_key': KeyAlgorithms.RSASHA512(), | ||
] | ||
|
||
private static void dockerfileBuilder(DockerfileBuilder it, String hostKey, String pubkeyAcceptedAlgorithms) { | ||
it.from("archlinux:base") | ||
it.run('yes | pacman -Sy core/openssh' + | ||
' && (' + | ||
' V=$(echo $(/usr/sbin/sshd -h 2>&1) | grep -o \'OpenSSH_[0-9][0-9]*[.][0-9][0-9]*p[0-9]\');' + | ||
' if [[ "$V" < OpenSSH_8.8p1 ]]; then' + | ||
' echo $V is too old 1>&2;' + | ||
' exit 1;' + | ||
' fi' + | ||
')' + | ||
' && set -o pipefail ' + | ||
' && useradd --create-home sshj' + | ||
' && echo \"sshj:ultrapassword\" | chpasswd') | ||
it.add("authorized_keys", "/home/sshj/.ssh/") | ||
it.add(hostKey, '/etc/ssh/') | ||
it.run('chmod go-rwx /etc/ssh/ssh_host_*' + | ||
' && chown -R sshj /home/sshj/.ssh' + | ||
' && chmod -R go-rwx /home/sshj/.ssh') | ||
it.expose(22) | ||
|
||
def cmd = [ | ||
'/usr/sbin/sshd', | ||
'-D', | ||
'-e', | ||
'-f', '/dev/null', | ||
'-o', 'LogLevel=DEBUG2', | ||
'-o', "HostKey=/etc/ssh/$hostKey", | ||
] | ||
if (pubkeyAcceptedAlgorithms != null) { | ||
cmd += ['-o', "PubkeyAcceptedAlgorithms=$pubkeyAcceptedAlgorithms"] | ||
} | ||
it.cmd(cmd as String[]) | ||
} | ||
|
||
private static SshdContainer makeSshdContainer(String hostKey, String pubkeyAcceptedAlgorithms) { | ||
return new SshdContainer(new SshdContainer.DebugLoggingImageFromDockerfile() | ||
.withFileFromPath("authorized_keys", Paths.get("src/itest/docker-image/authorized_keys")) | ||
.withFileFromPath(hostKey, Paths.get("src/itest/docker-image/test-container/host_keys/$hostKey")) | ||
.withDockerfileFromBuilder { | ||
dockerfileBuilder(it, hostKey, pubkeyAcceptedAlgorithms) | ||
}) | ||
} | ||
|
||
@Unroll | ||
def "connect to a server with host key #hostKey that does not support ssh-rsa"() { | ||
given: | ||
SshdContainer sshd = makeSshdContainer(hostKey, "rsa-sha2-512,rsa-sha2-256,ssh-ed25519") | ||
sshd.start() | ||
|
||
and: | ||
Config config = new DefaultConfig() | ||
config.keyAlgorithms = [ | ||
KeyAlgorithms.RSASHA512(), | ||
KeyAlgorithms.RSASHA256(), | ||
SSH_HOST_KEYS_AND_FACTORIES[hostKey], | ||
] | ||
|
||
when: | ||
def sshClient = sshd.getConnectedClient(config) | ||
sshClient.authPublickey("sshj", "src/itest/resources/keyfiles/id_rsa_opensshv1") | ||
|
||
then: | ||
sshClient.isAuthenticated() | ||
|
||
cleanup: | ||
sshClient?.disconnect() | ||
sshd.stop() | ||
|
||
where: | ||
hostKey << SSH_HOST_KEYS_AND_FACTORIES.keySet() | ||
} | ||
|
||
@Unroll | ||
def "connect to a default server with host key #hostKey using a default config"() { | ||
given: | ||
SshdContainer sshd = makeSshdContainer(hostKey, null) | ||
sshd.start() | ||
|
||
when: | ||
def sshClient = sshd.getConnectedClient() | ||
sshClient.authPublickey("sshj", "src/itest/resources/keyfiles/id_rsa_opensshv1") | ||
|
||
then: | ||
sshClient.isAuthenticated() | ||
|
||
cleanup: | ||
sshClient?.disconnect() | ||
sshd.stop() | ||
|
||
where: | ||
hostKey << SSH_HOST_KEYS_AND_FACTORIES.keySet() | ||
} | ||
|
||
@Unroll | ||
def "connect to a server with host key #hostkey that supports only ssh-rsa"() { | ||
given: | ||
SshdContainer sshd = makeSshdContainer(hostKey, "ssh-rsa,ssh-ed25519") | ||
sshd.start() | ||
|
||
and: | ||
Config config = new DefaultConfig() | ||
config.keyAlgorithms = [ | ||
KeyAlgorithms.SSHRSA(), | ||
SSH_HOST_KEYS_AND_FACTORIES[hostKey], | ||
] | ||
|
||
when: | ||
def sshClient = sshd.getConnectedClient(config) | ||
sshClient.authPublickey("sshj", "src/itest/resources/keyfiles/id_rsa_opensshv1") | ||
|
||
then: | ||
sshClient.isAuthenticated() | ||
|
||
cleanup: | ||
sshClient.disconnect() | ||
sshd.stop() | ||
|
||
where: | ||
hostKey << SSH_HOST_KEYS_AND_FACTORIES.keySet() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.