Skip to content

Commit 22b9b07

Browse files
committed
GH-827: known_hosts: skip and log invalid lines
Previous code would throw an exception on the first error encountered.
1 parent c10dbcd commit 22b9b07

3 files changed

Lines changed: 33 additions & 8 deletions

File tree

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
* [GH-807](https://github.com/apache/mina-sshd/issues/807) Handle "verified" flag for sk-* keys
3333
* [GH-809](https://github.com/apache/mina-sshd/pull/809) Fix server-side authentication for FIDO/U2F sk-* keys with flags in `authorized_keys`
34+
* [GH-827](https://github.com/apache/mina-sshd/pull/827) Don't fail on invalid `known_hosts` lines; log and skip them
3435

3536
## New Features
3637

sshd-common/src/main/java/org/apache/sshd/client/config/hosts/KnownHostEntry.java

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import java.io.InputStream;
2525
import java.io.InputStreamReader;
2626
import java.io.Reader;
27-
import java.io.StreamCorruptedException;
2827
import java.net.URL;
2928
import java.nio.charset.StandardCharsets;
3029
import java.nio.file.Files;
@@ -34,13 +33,14 @@
3433
import java.util.Collections;
3534
import java.util.List;
3635

37-
import org.apache.sshd.common.config.ConfigFileReaderSupport;
3836
import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
3937
import org.apache.sshd.common.config.keys.PublicKeyEntry;
4038
import org.apache.sshd.common.util.GenericUtils;
4139
import org.apache.sshd.common.util.ValidateUtils;
4240
import org.apache.sshd.common.util.io.input.NoCloseInputStream;
4341
import org.apache.sshd.common.util.io.input.NoCloseReader;
42+
import org.slf4j.Logger;
43+
import org.slf4j.LoggerFactory;
4444

4545
/**
4646
* Contains a representation of an entry in the <code>known_hosts</code> file
@@ -59,6 +59,8 @@ public class KnownHostEntry extends HostPatternsHolder {
5959
*/
6060
public static final String STD_HOSTS_FILENAME = "known_hosts";
6161

62+
private static final Logger LOG = LoggerFactory.getLogger(KnownHostEntry.class);
63+
6264
private static final class LazyDefaultConfigFileHolder {
6365
private static final Path HOSTS_FILE = PublicKeyEntry.getDefaultKeysFolderPath().resolve(STD_HOSTS_FILENAME);
6466

@@ -183,7 +185,7 @@ public static List<KnownHostEntry> readKnownHostEntries(BufferedReader rdr) thro
183185
continue;
184186
}
185187

186-
int pos = line.indexOf(ConfigFileReaderSupport.COMMENT_CHAR);
188+
int pos = line.indexOf(PublicKeyEntry.COMMENT_CHAR);
187189
if (pos == 0) {
188190
continue;
189191
}
@@ -203,9 +205,8 @@ public static List<KnownHostEntry> readKnownHostEntries(BufferedReader rdr) thro
203205
entries = new ArrayList<>();
204206
}
205207
entries.add(entry);
206-
} catch (RuntimeException | Error e) { // TODO consider consulting a user callback
207-
throw new StreamCorruptedException("Failed (" + e.getClass().getSimpleName() + ") to parse line #"
208-
+ lineNumber + " '" + line + "': " + e.getMessage());
208+
} catch (RuntimeException e) { // TODO consider consulting a user callback
209+
LOG.warn("Invalid known_hosts line #" + lineNumber + " '" + line + "': " + e.getMessage());
209210
}
210211
}
211212

@@ -217,13 +218,16 @@ public static List<KnownHostEntry> readKnownHostEntries(BufferedReader rdr) thro
217218
}
218219

219220
public static KnownHostEntry parseKnownHostEntry(String line) {
220-
return parseKnownHostEntry(GenericUtils.isEmpty(line) ? null : new KnownHostEntry(), line);
221+
return GenericUtils.isEmpty(line) ? null : parseKnownHostEntry(new KnownHostEntry(), line);
221222
}
222223

223224
public static <E extends KnownHostEntry> E parseKnownHostEntry(E entry, String data) {
225+
if (data == null) {
226+
return null;
227+
}
224228
String line = GenericUtils.replaceWhitespaceAndTrim(data);
225229
if (GenericUtils.isEmpty(line) || (line.charAt(0) == PublicKeyEntry.COMMENT_CHAR)) {
226-
return entry;
230+
return null;
227231
}
228232

229233
entry.setConfigLine(line);
@@ -254,6 +258,9 @@ public static <E extends KnownHostEntry> E parseKnownHostEntry(E entry, String d
254258
}
255259
AuthorizedKeyEntry key = PublicKeyEntry.parsePublicKeyEntry(new AuthorizedKeyEntry(),
256260
ValidateUtils.checkNotNullAndNotEmpty(line, "No valid key entry recovered from line=%s", data));
261+
if (key == null) {
262+
return null;
263+
}
257264
entry.setKeyEntry(key);
258265
return entry;
259266
}

sshd-core/src/test/java/org/apache/sshd/client/keyverifier/KnownHostsUnsupportedKeysTest.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,23 @@ void unknownExistingKey() throws Exception {
7070
assertTrue(invokeVerifier(verifier, new SshdSocketAddress("127.0.0.1", 2222), key));
7171
}
7272

73+
@Test
74+
void invalidLineIgnored() throws Exception {
75+
Path knownHosts = tmp.resolve("known_hosts");
76+
String entry
77+
= "[127.0.0.1]:2222 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCbZVVpqEHGLNWMqMeyU1VbWb91XteoamVcgpy4yxNVbZffb5IDdbo1ons/y9KAhcub6LZeLrvXzVUZbXCZiUkg=";
78+
List<String> lines = new ArrayList<>();
79+
lines.add(entry + entry);
80+
lines.add(entry);
81+
Files.write(knownHosts, lines);
82+
KnownHostsServerKeyVerifier verifier = new KnownHostsServerKeyVerifier(RejectAllServerKeyVerifier.INSTANCE, knownHosts);
83+
KnownHostEntry knownHost = KnownHostEntry.parseKnownHostEntry(lines.get(1));
84+
AuthorizedKeyEntry keyEntry = knownHost.getKeyEntry();
85+
assertNotNull(keyEntry);
86+
PublicKey key = keyEntry.resolvePublicKey(null, PublicKeyEntryResolver.FAILING);
87+
assertTrue(invokeVerifier(verifier, new SshdSocketAddress("127.0.0.1", 2222), key));
88+
}
89+
7390
@Test
7491
void unknownNewKey() throws Exception {
7592
KeyPair kp = CommonTestSupportUtils.generateKeyPair(KeyUtils.RSA_ALGORITHM, 1024);

0 commit comments

Comments
 (0)