Browse Source

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
tags/v5.1.3.201810200350-r
Saša Živkov 5 years ago
parent
commit
b6e2800560

+ 42
- 0
org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java 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.ConnectException;
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 org.slf4j.LoggerFactory;

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 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory {
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 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory {
"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);

Loading…
Cancel
Save