From b6e2800560dbf7348dcc1965e9069863ef96e4f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C5=A1a=20=C5=BDivkov?= Date: Thu, 4 Oct 2018 14:08:41 +0200 Subject: [PATCH] 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 --- .../transport/JschConfigSessionFactory.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java index eab3b3c0c..4e712a556 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2018, Sasa Zivkov * Copyright (C) 2016, Mark Ingram * Copyright (C) 2009, Constantine Plotnikov * 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 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);