Open mgattinger opened 5 years ago
You can run:
ssh-keyscan -t ed25519 localhost
You can add that line to your ~/.ssh/known_hosts
file.
As @mgattinger, I'm very interested that sshj uses RSA when ed25519 fingerprint is not found in known hosts. It could be a fallback: if ed25519 fingerprint is not found, then sshj looks for RSA fingerprint, and if not found, DSA fingerprint.
That would be very helpful. In my known_hosts, I have only RSA fingerprints. And if I remove the fingerprint, and do a new ssh connexion (using putty), rsa fingerprint is added (not ed25519) to know_hosts file.
Finally, if I do "ssh-keyscan -t ed25519 localhost", I get the following error:
unknown key type ed25519
So please, consider to fix this issue.
Same issue still exists with 0.30.0
@fbaligand : Just to clarify, when you issue:
ssh-keyscan -t ed25519 localhost
is localhost
the target running ssh software?
Hi,
"localhost" is not my target running ssh software, but just an example host.
That said, if I do ssh-keyscan -t ed25519 my-remote-ssh-server
(that is a VM), I get the same error.
Though I do this test on a quite "classic" linux OS: RHEL.
when initiating a ssh connection, the host key is only sent once. so the client says, i want to verify using key types (algorithms) A, B, C. server then looks at its keys and uses the key that matches the leftmost proposal of the client. e.g. if it has key types A and B, it will always choose A.
the problem with sshj is that it always sends the whole list of algorithms, starting with Ed25519, regardless of what keys it has. so if the client only knows server's RSA key and the server has both RSA and Ed25519 keys, sshj will fail to connect. is this the issue?
unknown key type ed25519
i think this is a problem with your ssh-keyscan
, perhaps it's too old? try running it from another device maybe
Well, after some tests, on RHEL 6, ed25519 key type is not recognized, but it works fine on RHEL 7.
That said, the point of this issue is that sshj works in all cases and recognizes RSA key types.
So it would be great if sshj searches for ed25519 key type in known_hosts
file, and if not found, searches for rsa key type, and ideally if still not found, searches for dsa key type
Thank you @oakkitten for the explanations. It allowed me to limit to RSA and now it works.
DefaultConfig conf = new DefaultConfig();
conf.setSignatureFactories(new SignatureRSA.Factory());
SSHClient ssh = new SSHClient(conf);
This is makes it very hard to imagine using SSHJ in production. It seems the above solution is OBE, there is no DefaultConfig.setSignatureFactories now.
By looping threw making each type of key the first choice, I am able to connect to all the hosts I have tried so far. You have to do extra work to keep SSHJ from killing your thread.
This is in Scala, I'm sure you can figure out how to do the same in java.
Logging is LOUD! There are a lot of messages generated doing this, so logback.xml is worth while, even then some are ERRORs.
val algs: List[Factory.Named[KeyAlgorithm]] = List(
KeyAlgorithms.ECDSASHANistp256(),
KeyAlgorithms.ECDSASHANistp521(),
KeyAlgorithms.ECDSASHANistp384(),
KeyAlgorithms.SSHRSA(),
KeyAlgorithms.RSASHA256(),
KeyAlgorithms.RSASHA512(),
KeyAlgorithms.EdDSA25519(),
KeyAlgorithms.SSHRSACertV01(),
KeyAlgorithms.SSHDSSCertV01(),
KeyAlgorithms.SSHDSA()
)
/**
*
* @param hostname -- host to connect to
* @return -- The authenticated SSHClient or None if no authentication succeeds
*/
def makeConnection(hostname: String, user: String): Option[SSHClient] = {
var result: Option[SSHClient] = None
for {alg <- algs if result.isEmpty} {
val test = new Thread(() => {
try {
val conf = new DefaultConfig
conf.setKeyAlgorithms(List(alg).asJava)
val ssh = new SSHClient(conf)
ssh.loadKnownHosts()
ssh.connect(hostname)
ssh.authPublickey(user)
if (ssh.isAuthenticated) {
result = Some(ssh)
}
} catch {
case tx: TransportException if tx.getDisconnectReason != DisconnectReason.HOST_KEY_NOT_VERIFIABLE =>
throw tx
}
})
test.start()
test.join()
}
result
}
The same error here with me, but found this: https://github.com/hierynomus/sshj/issues/635
Then I've added this before connecting:
ssh.addHostKeyVerifier(new PromiscuousVerifier());
It was enough to solve!
I'm new to sshj and I try to solve the following problem of verifying the identity of the host to connect to. The host is an SSH server that only provides its public key using the ssh-rsa host key algorithm (and not the ssh-ed25519 algorithm, too).
I use the following code to do the verification:
PublicKey publicKey = new Buffer.PlainBuffer(Base64.decode("...")).readPublicKey(); sshClient.addHostKeyVerifier(SecurityUtils.getFingerprint(publicKey));
whereas "..." contains the public key that can be listed requested from the host using the command ssh-keyscan -t rsa.
The SSHClient uses the default configuration.
If I run this code on my machine (in this case the target host is the localhost), I get the following exception: ERROR n.s.s.t.KeyExchanger - Disconnecting because none of the configured Host key verifiers ([net.schmizz.sshj.transport.verification.FingerprintVerifier$1@73f0d46f]) could verify 'ssh-ed25519' host key with fingerprint ca:5f:e9:2b:79:58:5c:0e:a5:b3:28:b5:51:9a:54:d2 for localhost:22 ERROR n.s.s.t.TransportImpl - Dying because - Could not verify> woke to: net.schmizz.sshj.transport.TransportException: [HOST_KEY_NOT_VERIFIABLE] Could not verify
ssh-ed25519
host key with fingerprint...
forlocalhost
on port 22 net.schmizz.sshj.transport.TransportException: Could not verifyssh-ed25519
host key with fingerprint...
forlocalhost
on port 22 at net.schmizz.sshj.transport.KeyExchanger.verifyHost(KeyExchanger.java:211) at net.schmizz.sshj.transport.KeyExchanger.handle(KeyExchanger.java:365) at net.schmizz.sshj.transport.TransportImpl.handle(TransportImpl.java:503) at net.schmizz.sshj.transport.Decoder.decodeMte(Decoder.java:159) at net.schmizz.sshj.transport.Decoder.decode(Decoder.java:79) at net.schmizz.sshj.transport.Decoder.received(Decoder.java:231) at net.schmizz.sshj.transport.Reader.run(Reader.java:59) ERROR n.s.c.Promise - <ssh-ed25519
host key with fingerprint...
forlocalhost
on port 22I wonder why sshj still wants to use ssh-ed25519 for verification as the method KeyType.fromKey(publicKey) prints ssh-rsa.
I know that I can use sshClient.addHostKeyVerifier(new PromiscuousVerifier()); to circumvent the problem, but that is not the solution I'm looking for.
So the question is how I can verify the host key if I only have an RSA ciphered public key of the host?
I found out, that if I use an explicit DefaultConfiguation like this: DefaultConfig defaultConfig = new DefaultConfig(); defaultConfig.setSignatureFactories(new SignatureRSA.Factory()); and pass this to the constructor of the SSHClient the exception disappears.
I do not understand why the default configuration which consists of several preregistered signature factories (and the factory above is already present) will not work as expected. I suppose that all registered signature factories are used to verify the hosts public key. To me this looks like an error.
BTW: I'm using version 0.27.0 of sshj.
Kind regards, Marcus