Skip to content

Commit a0ef7a5

Browse files
committed
Host certificates: check both public keys for not being revoked
It could be that the certificate is perfectly valid, but the certified host key is listed itself as being revoked.
1 parent b11c159 commit a0ef7a5

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

sshd-core/src/main/java/org/apache/sshd/client/keyverifier/KnownHostsServerKeyVerifier.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,18 @@ protected boolean acceptKnownHostEntries(
298298
.filter(e -> isCert == "cert-authority".equals(e.getHostEntry().getMarker()))
299299
.collect(Collectors.toList());
300300
if (!keyMatches.isEmpty()) {
301+
if (serverKey instanceof OpenSshCertificate) {
302+
// Also check whether the certified key has been revoked.
303+
PublicKey certifiedKey = ((OpenSshCertificate) serverKey).getCertPubKey();
304+
String certKeyType = KeyUtils.getKeyType(certifiedKey);
305+
if (hostMatches.stream() //
306+
.filter(entry -> certKeyType.equals(entry.getHostEntry().getKeyEntry().getKeyType()))
307+
.filter(k -> KeyUtils.compareKeys(k.getServerKey(), certifiedKey))
308+
.anyMatch(entry -> "revoked".equals(entry.getHostEntry().getMarker()))) {
309+
handleRevokedKey(clientSession, remoteAddress, certifiedKey);
310+
return false;
311+
}
312+
}
301313
return true;
302314
}
303315

@@ -306,7 +318,8 @@ protected boolean acceptKnownHostEntries(
306318
}
307319

308320
Optional<HostEntryPair> anyNonRevokedMatch = hostMatches.stream()
309-
.filter(k -> !"revoked".equals(k.getHostEntry().getMarker()))
321+
.filter(k -> !"revoked".equals(k.getHostEntry().getMarker())
322+
&& !"cert-authority".equals(k.getHostEntry().getMarker()))
310323
.findAny();
311324

312325
if (!anyNonRevokedMatch.isPresent()) {

sshd-core/src/test/java/org/apache/sshd/common/signature/KnownHostsCertificateTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.nio.file.Files;
2222
import java.nio.file.Path;
23+
import java.nio.file.StandardOpenOption;
2324
import java.security.KeyPair;
2425
import java.util.Arrays;
2526
import java.util.Collections;
@@ -199,4 +200,24 @@ void testHostCertificateWithWildcardSucceeds(String principals) throws Exception
199200
s.auth().verify(AUTH_TIMEOUT);
200201
}
201202
}
203+
204+
@Test
205+
void testHostCertificateWithRejectedHostKeyFails() throws Exception {
206+
initKeys(KeyUtils.EC_ALGORITHM, 256, KeyUtils.EC_ALGORITHM, 256, "ecdsa-sha2-nistp256", "cert-authority");
207+
Path knownHosts = tmp.resolve("known_hosts");
208+
StringBuilder line = new StringBuilder();
209+
line.append("@revoked ");
210+
line.append("[localhost]:").append(port).append(",[127.0.0.1]:").append(port).append(' ');
211+
line.append(PublicKeyEntry.toString(hostKey.getPublic()));
212+
line.append('\n');
213+
Files.write(knownHosts, Collections.singletonList(line.toString()), StandardOpenOption.APPEND);
214+
client.setServerKeyVerifier(new KnownHostsServerKeyVerifier(AcceptAllServerKeyVerifier.INSTANCE, knownHosts));
215+
assertThrows(SshException.class, () -> {
216+
try (ClientSession s = client.connect(getCurrentTestName(), TEST_LOCALHOST, port).verify(CONNECT_TIMEOUT)
217+
.getSession()) {
218+
s.addPasswordIdentity(getCurrentTestName());
219+
s.auth().verify(AUTH_TIMEOUT);
220+
}
221+
});
222+
}
202223
}

0 commit comments

Comments
 (0)