Merge pull request #201 from iterate-ch/feature/algorithms-verifier

Add option for client to verify negotiated key exchange algorithms.
This commit is contained in:
Jeroen van Erp
2015-06-16 15:50:06 +02:00
5 changed files with 69 additions and 3 deletions

View File

@@ -39,6 +39,7 @@ import net.schmizz.sshj.transport.TransportImpl;
import net.schmizz.sshj.transport.compression.DelayedZlibCompression; import net.schmizz.sshj.transport.compression.DelayedZlibCompression;
import net.schmizz.sshj.transport.compression.NoneCompression; import net.schmizz.sshj.transport.compression.NoneCompression;
import net.schmizz.sshj.transport.compression.ZlibCompression; import net.schmizz.sshj.transport.compression.ZlibCompression;
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
import net.schmizz.sshj.transport.verification.HostKeyVerifier; import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts; import net.schmizz.sshj.transport.verification.OpenSSHKnownHosts;
import net.schmizz.sshj.userauth.UserAuth; import net.schmizz.sshj.userauth.UserAuth;
@@ -158,10 +159,19 @@ public class SSHClient
* Add a {@link HostKeyVerifier} which will be invoked for verifying host key during connection establishment and * Add a {@link HostKeyVerifier} which will be invoked for verifying host key during connection establishment and
* future key exchanges. * future key exchanges.
* *
* @param hostKeyVerifier {@link HostKeyVerifier} instance * @param verifier {@link HostKeyVerifier} instance
*/ */
public void addHostKeyVerifier(HostKeyVerifier hostKeyVerifier) { public void addHostKeyVerifier(HostKeyVerifier verifier) {
trans.addHostKeyVerifier(hostKeyVerifier); trans.addHostKeyVerifier(verifier);
}
/**
* Add a {@link AlgorithmsVerifier} which will be invoked for verifying negotiated algorithms.
*
* @param verifier {@link AlgorithmsVerifier} instance
*/
public void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
trans.addAlgorithmsVerifier(verifier);
} }
/** /**

View File

@@ -33,6 +33,8 @@ import net.schmizz.sshj.transport.digest.Digest;
import net.schmizz.sshj.transport.kex.KeyExchange; import net.schmizz.sshj.transport.kex.KeyExchange;
import net.schmizz.sshj.transport.mac.MAC; import net.schmizz.sshj.transport.mac.MAC;
import net.schmizz.sshj.transport.verification.HostKeyVerifier; import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -68,6 +70,8 @@ final class KeyExchanger
*/ */
private final Queue<HostKeyVerifier> hostVerifiers = new LinkedList<HostKeyVerifier>(); private final Queue<HostKeyVerifier> hostVerifiers = new LinkedList<HostKeyVerifier>();
private final Queue<AlgorithmsVerifier> algorithmVerifiers = new LinkedList<AlgorithmsVerifier>();
private final AtomicBoolean kexOngoing = new AtomicBoolean(); private final AtomicBoolean kexOngoing = new AtomicBoolean();
/** What we are expecting from the next packet */ /** What we are expecting from the next packet */
@@ -108,6 +112,10 @@ final class KeyExchanger
hostVerifiers.add(hkv); hostVerifiers.add(hkv);
} }
synchronized void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
algorithmVerifiers.add(verifier);
}
/** /**
* Returns the session identifier computed during key exchange. * Returns the session identifier computed during key exchange.
* *
@@ -218,6 +226,13 @@ final class KeyExchanger
final Proposal serverProposal = new Proposal(buf); final Proposal serverProposal = new Proposal(buf);
negotiatedAlgs = clientProposal.negotiate(serverProposal); negotiatedAlgs = clientProposal.negotiate(serverProposal);
log.debug("Negotiated algorithms: {}", negotiatedAlgs); log.debug("Negotiated algorithms: {}", negotiatedAlgs);
for(AlgorithmsVerifier v: algorithmVerifiers) {
log.debug("Trying to verify algorithms with {}", v);
if(!v.verify(negotiatedAlgs)) {
throw new TransportException(DisconnectReason.KEY_EXCHANGE_FAILED,
"Failed to verify negotiated algorithms `" + negotiatedAlgs + "`");
}
}
kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(), kex = Factory.Named.Util.create(transport.getConfig().getKeyExchangeFactories(),
negotiatedAlgs.getKeyExchangeAlgorithm()); negotiatedAlgs.getKeyExchangeAlgorithm());
try { try {

View File

@@ -20,6 +20,7 @@ import net.schmizz.sshj.Service;
import net.schmizz.sshj.common.DisconnectReason; import net.schmizz.sshj.common.DisconnectReason;
import net.schmizz.sshj.common.SSHPacket; import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.common.SSHPacketHandler; import net.schmizz.sshj.common.SSHPacketHandler;
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
import net.schmizz.sshj.transport.verification.HostKeyVerifier; import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import java.io.InputStream; import java.io.InputStream;
@@ -51,6 +52,13 @@ public interface Transport
*/ */
void addHostKeyVerifier(HostKeyVerifier hkv); void addHostKeyVerifier(HostKeyVerifier hkv);
/**
* Adds the specified verifier.
*
* @param verifier The verifier to call with negotiated algorithms
*/
void addAlgorithmsVerifier(AlgorithmsVerifier verifier);
/** /**
* Do key exchange and algorithm negotiation. This can be the initial one or for algorithm renegotiation. * Do key exchange and algorithm negotiation. This can be the initial one or for algorithm renegotiation.
* *

View File

@@ -27,6 +27,7 @@ import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.Message; import net.schmizz.sshj.common.Message;
import net.schmizz.sshj.common.SSHException; import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.common.SSHPacket; import net.schmizz.sshj.common.SSHPacket;
import net.schmizz.sshj.transport.verification.AlgorithmsVerifier;
import net.schmizz.sshj.transport.verification.HostKeyVerifier; import net.schmizz.sshj.transport.verification.HostKeyVerifier;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -235,6 +236,11 @@ public final class TransportImpl
kexer.addHostKeyVerifier(hkv); kexer.addHostKeyVerifier(hkv);
} }
@Override
public void addAlgorithmsVerifier(AlgorithmsVerifier verifier) {
kexer.addAlgorithmsVerifier(verifier);
}
@Override @Override
public void doKex() public void doKex()
throws TransportException { throws TransportException {

View File

@@ -0,0 +1,27 @@
/**
* Copyright 2009 sshj contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.schmizz.sshj.transport.verification;
import net.schmizz.sshj.transport.NegotiatedAlgorithms;
public interface AlgorithmsVerifier {
/**
* Callback is invoked when algorithms have been negotiated between client and server.
* @return False to interrupt the connection
*/
boolean verify(NegotiatedAlgorithms algorithms);
}