ssh: Prefer algorithms of the known host keys

JSch prefers ssh-rsa key type. When the remote server supports ssh-rsa
key type then this key type will be used even if the known_hosts file
contains a host key for that host, but with different key type.
This caused an unexpected UnknownHostKey error.

To fix the issue first scan the known_hosts, the HostKeyRepository in
JSch API, for any already existing host keys for the target host and
modify the default session settings to prefer their algorithms. However,
do this only if there is no HostKeyAlgorithms setting active.

Change-Id: I236df2a860ddd9289a0a820ddf09c2dea3673d36
This commit is contained in:
Saša Živkov 2018-10-04 14:08:41 +02:00
parent 6dd50d2e1b
commit b6e2800560
1 changed files with 42 additions and 0 deletions

View File

@ -1,4 +1,5 @@
/*
* Copyright (C) 2018, Sasa Zivkov <sasa.zivkov@sap.com>
* Copyright (C) 2016, Mark Ingram <markdingram@gmail.com>
* Copyright (C) 2009, Constantine Plotnikov <constantine.plotnikov@gmail.com>
* Copyright (C) 2008-2009, Google Inc.
@ -49,6 +50,10 @@
package org.eclipse.jgit.transport;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static org.eclipse.jgit.transport.OpenSshConfig.SSH_PORT;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@ -59,9 +64,11 @@
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText;
@ -71,6 +78,8 @@
import com.jcraft.jsch.ConfigRepository;
import com.jcraft.jsch.ConfigRepository.Config;
import com.jcraft.jsch.HostKey;
import com.jcraft.jsch.HostKeyRepository;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
@ -224,6 +233,9 @@ Session createSession(CredentialsProvider credentialsProvider,
credentialsProvider));
}
safeConfig(session, hc.getConfig());
if (hc.getConfig().getValue("HostKeyAlgorithms") == null) { //$NON-NLS-1$
setPreferredKeyTypesOrder(session);
}
configure(hc, session);
return session;
}
@ -239,6 +251,36 @@ private void safeConfig(Session session, Config cfg) {
"CheckSignatures"); //$NON-NLS-1$
}
private static void setPreferredKeyTypesOrder(Session session) {
HostKeyRepository hkr = session.getHostKeyRepository();
List<String> known = Stream.of(hkr.getHostKey(hostName(session), null))
.map(HostKey::getType)
.collect(toList());
if (!known.isEmpty()) {
String serverHostKey = "server_host_key"; //$NON-NLS-1$
String current = session.getConfig(serverHostKey);
if (current == null) {
session.setConfig(serverHostKey, String.join(",", known)); //$NON-NLS-1$
return;
}
String knownFirst = Stream.concat(
known.stream(),
Stream.of(current.split(",")) //$NON-NLS-1$
.filter(s -> !known.contains(s)))
.collect(joining(",")); //$NON-NLS-1$
session.setConfig(serverHostKey, knownFirst);
}
}
private static String hostName(Session s) {
if (s.getPort() == SSH_PORT) {
return s.getHost();
}
return String.format("[%s]:%d", s.getHost(), s.getPort()); //$NON-NLS-1$
}
private void copyConfigValueToSession(Session session, Config cfg,
String from, String to) {
String value = cfg.getValue(from);