Skip to content

Commit 8776500

Browse files
committed
Merge pull request #201 from iterate-ch/feature/algorithms-verifier
Add option for client to verify negotiated key exchange algorithms.
2 parents 9706526 + a747db8 commit 8776500

File tree

5 files changed

+69
-3
lines changed

5 files changed

+69
-3
lines changed

src/main/java/net/schmizz/sshj/SSHClient.java

+13-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import net.schmizz.sshj.transport.compression.DelayedZlibCompression;
4040
import net.schmizz.sshj.transport.compression.NoneCompression;
4141
import net.schmizz.sshj.transport.compression.ZlibCompression;
42+
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
4243
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
4344
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
4445
import net.schmizz.sshj.userauth.UserAuth;
@@ -158,10 +159,19 @@ public SSHClient(Config config) {
158159
* Add a {@link HostKeyVerifier} which will be invoked for verifying host key during connection establishment and
159160
* future key exchanges.
160161
*
161-
* @param hostKeyVerifier {@link HostKeyVerifier} instance
162+
* @param verifier {@link HostKeyVerifier} instance
162163
*/
163-
public void addHostKeyVerifier(HostKeyVerifier hostKeyVerifier) {
164-
trans.addHostKeyVerifier(hostKeyVerifier);
164+
public void addHostKeyVerifier(HostKeyVerifier verifier) {
165+
trans.addHostKeyVerifier(verifier);
166+
}
167+
168+
/**
169+
* Add a {@link AlgorithmsVerifier} which will be invoked for verifying negotiated algorithms.
170+
*
171+
* @param verifier {@link AlgorithmsVerifier} instance
172+
*/
173+
public void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
174+
trans.addAlgorithmsVerifier(verifier);
165175
}
166176

167177
/**

src/main/java/net/schmizz/sshj/transport/KeyExchanger.java

+15
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
import net.schmizz.sshj.transport.kex.KeyExchange;
3434
import net.schmizz.sshj.transport.mac.MAC;
3535
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
36+
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
37+
3638
import org.slf4j.Logger;
3739
import org.slf4j.LoggerFactory;
3840

@@ -68,6 +70,8 @@ private static enum Expected {
6870
*/
6971
private final Queue<HostKeyVerifier> hostVerifiers = new LinkedList<HostKeyVerifier>();
7072

73+
private final Queue<AlgorithmsVerifier> algorithmVerifiers = new LinkedList<AlgorithmsVerifier>();
74+
7175
private final AtomicBoolean kexOngoing = new AtomicBoolean();
7276

7377
/** What we are expecting from the next packet */
@@ -108,6 +112,10 @@ synchronized void addHostKeyVerifier(HostKeyVerifier hkv) {
108112
hostVerifiers.add(hkv);
109113
}
110114

115+
synchronized void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
116+
algorithmVerifiers.add(verifier);
117+
}
118+
111119
/**
112120
* Returns the session identifier computed during key exchange.
113121
*
@@ -218,6 +226,13 @@ private void gotKexInit(SSHPacket buf)
218226
final Proposal serverProposal = new Proposal(buf);
219227
negotiatedAlgs = clientProposal.negotiate(serverProposal);
220228
log.debug("Negotiated algorithms: {}", negotiatedAlgs);
229+
for(AlgorithmsVerifier v: algorithmVerifiers) {
230+
log.debug("Trying to verify algorithms with {}", v);
231+
if(!v.verify(negotiatedAlgs)) {
232+
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED,
233+
"Failed to verify negotiated algorithms `" + negotiatedAlgs + "`");
234+
}
235+
}
221236
kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(),
222237
negotiatedAlgs.getKeyExchangeAlgorithm());
223238
try {

src/main/java/net/schmizz/sshj/transport/Transport.java

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import net.schmizz.sshj.common.DisconnectReason;
2121
import net.schmizz.sshj.common.SSHPacket;
2222
import net.schmizz.sshj.common.SSHPacketHandler;
23+
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
2324
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
2425

2526
import java.io.InputStream;
@@ -51,6 +52,13 @@ void init(String host, int port, InputStream in, OutputStream out)
5152
*/
5253
void addHostKeyVerifier(HostKeyVerifier hkv);
5354

55+
/**
56+
* Adds the specified verifier.
57+
*
58+
* @param verifier The verifier to call with negotiated algorithms
59+
*/
60+
void addAlgorithmsVerifier(AlgorithmsVerifier verifier);
61+
5462
/**
5563
* Do key exchange and algorithm negotiation. This can be the initial one or for algorithm renegotiation.
5664
*

src/main/java/net/schmizz/sshj/transport/TransportImpl.java

+6
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import net.schmizz.sshj.common.Message;
2828
import net.schmizz.sshj.common.SSHException;
2929
import net.schmizz.sshj.common.SSHPacket;
30+
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
3031
import net.schmizz.sshj.transport.verification.HostKeyVerifier;
3132
import org.slf4j.Logger;
3233
import org.slf4j.LoggerFactory;
@@ -235,6 +236,11 @@ public void addHostKeyVerifier(HostKeyVerifier hkv) {
235236
kexer.addHostKeyVerifier(hkv);
236237
}
237238

239+
@Override
240+
public void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
241+
kexer.addAlgorithmsVerifier(verifier);
242+
}
243+
238244
@Override
239245
public void doKex()
240246
throws TransportException {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright 2009 sshj contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package net.schmizz.sshj.transport.verification;
17+
18+
import net.schmizz.sshj.transport.NegotiatedAlgorithms;
19+
20+
public interface AlgorithmsVerifier {
21+
22+
/**
23+
* Callback is invoked when algorithms have been negotiated between client and server.
24+
* @return False to interrupt the connection
25+
*/
26+
boolean verify(NegotiatedAlgorithms algorithms);
27+
}

0 commit comments

Comments
 (0)