com.mindbright.ssh2
Class SSH2Transport

java.lang.Object
  extended bycom.mindbright.ssh2.SSH2Transport

public class SSH2Transport
extends java.lang.Object

This class implements the transport layer of the secure shell version 2 (ssh2) protocol stack. It handles the initial negotiation of algorithms for key exchange, host key type, encryption, message authentication and compression. It also handles server authentication (through the provided SSH2TransportEventHandler).

To create a SSH2Transport instance a TCP connection to the ssh2 server must first be established using a java.net.Socket. This socket is passed to the constructor. The constructor is passive in that it doesn't start any communication. To start the protocol engine and begin communcation with the server the method boot must be called. In this method the version information echange is done and two threads are started which handles the protocol engine and all communication with the server.

The operation of the transport layer can be controlled and monitored with instances of the classes SSH2Preferences and SSH2TransportEventHandler which are provided to the constructor.

After initial negotiation the chosen key exchange algorithm is handled by a subclass of the abstract class SSH2KeyExchanger. When the key exchange is complete, keys for encryption and message authentication can be derived. The communciation at this point is secured with the selected cipher/mac algorithms. The actual encryption, message authentication and compression is handled in the class SSH2TransportPDU which is the data container implementing the specific formatting defined in the protocol.

Before the upper layers (i.e. the user authentication and connection layers) of the protocol can be started the key exchange stage must be completed. This must be checked by calling the blocking method waitForKEXComplete. When the key exchange is complete a secure connection to an authenticated server has been established. The function of the transport layer at this point is the multiplexing of protocol data units (referred to as PDU or packet) between the server and the upper layers which are implemented in the classes SSH2UserAuth and SSH2Connection.

See Also:
SSH2TransportEventHandler, SSH2Preferences, SSH2UserAuth, SSH2Connection

Nested Class Summary
static class SSH2Transport.TranceiverContext
          Context for transport tranceiver/receiver.
 
Field Summary
protected  boolean activity
           
protected  SSH2TransportEventHandler eventHandler
           
 boolean incompatibleBuggyChannelClose
           
 boolean incompatibleCantReKey
           
 boolean incompatibleChannelOpenFail
           
 boolean incompatibleHMACKeyLength
           
 boolean incompatibleMayReceiveDataAfterClose
           
 boolean incompatibleOldDHGex
           
 boolean incompatiblePublicKeyAuth
           
 boolean incompatiblePublicKeyUserId
           
 boolean incompatibleRijndael
           
 boolean incompatibleSignature
           
protected  SSH2Preferences ourPrefs
           
protected  SSH2Preferences peerPrefs
           
protected  java.io.InputStream tpIn
           
protected  Log tpLog
           
protected  java.io.OutputStream tpOut
           
protected  SecureRandomAndPad tpRand
           
protected  java.net.Socket tpSocket
           
 
Constructor Summary
SSH2Transport(java.net.Socket tpSocket, SecureRandomAndPad rand)
          This is the basic constructor used when default preferences is ok and no logging or event handling is needed.
SSH2Transport(java.net.Socket tpSocket, SSH2Preferences prefs, SecureRandomAndPad rand)
          This is the basic constructor used when no logging or event handling is needed.
SSH2Transport(java.net.Socket tpSocket, SSH2Preferences prefs, SSH2TransportEventHandler eventHandler, SecureRandomAndPad rand)
          This is the constructor used when an event handler is needed but no logging.
SSH2Transport(java.net.Socket tpSocket, SSH2Preferences prefs, SSH2TransportEventHandler eventHandler, SecureRandomAndPad rand, Log log)
          This is the constructor used when both an event handler and logging is needed.
 
Method Summary
 void authenticateHost(byte[] serverHostKey, byte[] serverSigH, byte[] exchangeHash_H)
          Authenticates the server through its host key.
 void boot()
          Starts the protocol engine and begins communication with the server.
 void boot(int timeout)
          Starts the protocol engine and begins communication with the server.
 void disableKeepAlive()
          Disables keep-alive function.
protected  void disconnectInternal(int reason, java.lang.String description, java.lang.String languageTag, boolean fromPeer)
           
 void enableKeepAlive(int intervalSeconds)
          Enables keep-alive function which sends IGNORE packets on the given time interval.
static int extractMajor(java.lang.String versionStr)
          Extracts the major version from a version string (as defined in the protocol spec.)
static int extractMinor(java.lang.String versionStr)
          Extracts the minor version from a version string (as defined in the protocol spec.)
static java.lang.String extractPackageVersion(java.lang.String versionStr)
          Extracts the package version (defined as softwareversion and comments in the protocol spec.) from a version string.
 void fatalDisconnect(int reason, java.lang.String description)
          Disconnects from peer using the DISCONNECT packet type with the given reason and description.
 SSH2TransportPDU getClientKEXINITPDU()
          Gets the PDU containing the key exchange initialization (KEXINIT) sent by the client.
 java.lang.String getClientVersion()
          Gets the client's version string
 java.lang.String getDisconnectMessage()
          Gets the message describing why transport was disconnected.
 SSH2TransportEventHandler getEventHandler()
          Gets the event handler currently in use.
 int getKeepAliveInterval()
          Gets the keep-alive interval.
 java.lang.String getLocalHostName()
           
 Log getLog()
          Gets the log handler currently in use.
 SSH2Preferences getOurPreferences()
          Gets our preferences.
 SSH2Preferences getPeerPreferences()
          Gets the preferences peer want.
 SSH2Compressor getRxCompressor()
          Gets the SSH2Compressor currently in use for the receiver.
 SecureRandom getSecureRandom()
          Gets the SecureRandom currently in use.
 SSH2TransportPDU getServerKEXINITPDU()
          Gets the PDU containing the key exchange initialization (KEXINIT) sent by the server.
 java.lang.String getServerVersion()
          Gets the server's version string.
 byte[] getSessionId()
          Gets the session identifier calculated at key exchange as defined in the protool spec.
 SSH2Compressor getTxCompressor()
          Gets the SSH2Compressor currently in use for the transmitter.
protected  boolean handleExtensionRxPacket(SSH2TransportPDU pdu)
          Function which can be overridden in subclasses to handle extensions to the SSH2 protocol.
 boolean isConnected()
          Checks if currently connected to a server.
 boolean isServer()
          Checks whether we are a server or a client.
 boolean keyExchangeInProgress()
          Checks if key exchange is currently in progress.
 void normalDisconnect(java.lang.String description)
          Disconnects from peer using the DISCONNECT packet type with the reason code DISCONNECT_BY_APPLICATION and the given description.
 SSH2TransportPDU receiveInternal()
          Receives a PDU directly from the InputStream from the peer without checking if we are connected.
protected  void reportInactivity(int duration)
          Called by the KeepAliveThread thread (if launched) to report when the connection has been inactive for a time.
 void requestService(java.lang.String service)
          Requests the given service (currently the only service defined is the "ssh-userauth" service which starts the user authentication).
 void sendDebug(boolean alwaysDisp, java.lang.String message, java.lang.String language)
          Sends a DEBUG packet (as defined in the protocol spec.) with the given message.
 void sendIgnore(byte[] data)
          Sends an IGNORE packet (as defined in the protocol spec.) with the given data as payload.
 void sendIgnore(byte[] data, int off, int len)
          Sends an IGNORE packet (as defined in the protocol spec.) with the given data as payload.
 void sendNewKeys()
          Sends the NEWKEYS paket type and changes the transmitter keys according to the current prefs (as negotiated before).
 void setConnection(SSH2Connection connection)
          Sets the SSH2Connection to use for the connection layer.
 void setEventHandler(SSH2TransportEventHandler eventHandler)
          Sets the event handler to use.
 void setLog(Log log)
          Sets the log handler to use.
 void setSocketOptions(java.lang.String desc, java.net.Socket sock)
           
 void setUserAuth(SSH2UserAuth userAuth)
          Sets the SSH2UserAuth to use for the user authenticaton stage.
 void startKeyExchange()
          Starts a key exchange with the preferences set in the constructor.
 void startKeyExchange(SSH2Preferences newPrefs)
          Starts a key exchange with the given preferences.
 void transmit(SSH2TransportPDU pdu)
          Transmits the given PDU if we are connected.
 void transmitInternal(SSH2TransportPDU pdu)
          Transmits the given PDU without checking if we are connected.
 boolean waitForKEXComplete()
          Waits (blocks) for key exchange to complete (if not in progress returns immediately).
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

ourPrefs

protected SSH2Preferences ourPrefs

peerPrefs

protected SSH2Preferences peerPrefs

eventHandler

protected SSH2TransportEventHandler eventHandler

tpLog

protected Log tpLog

tpSocket

protected java.net.Socket tpSocket

tpIn

protected java.io.InputStream tpIn

tpOut

protected java.io.OutputStream tpOut

tpRand

protected SecureRandomAndPad tpRand

activity

protected boolean activity

incompatibleSignature

public boolean incompatibleSignature

incompatiblePublicKeyAuth

public boolean incompatiblePublicKeyAuth

incompatibleHMACKeyLength

public boolean incompatibleHMACKeyLength

incompatiblePublicKeyUserId

public boolean incompatiblePublicKeyUserId

incompatibleChannelOpenFail

public boolean incompatibleChannelOpenFail

incompatibleRijndael

public boolean incompatibleRijndael

incompatibleCantReKey

public boolean incompatibleCantReKey

incompatibleBuggyChannelClose

public boolean incompatibleBuggyChannelClose

incompatibleMayReceiveDataAfterClose

public boolean incompatibleMayReceiveDataAfterClose

incompatibleOldDHGex

public boolean incompatibleOldDHGex
Constructor Detail

SSH2Transport

public SSH2Transport(java.net.Socket tpSocket,
                     SecureRandomAndPad rand)
This is the basic constructor used when default preferences is ok and no logging or event handling is needed.

Parameters:
tpSocket - the connection to the ssh2 server
rand - the source of randomness for keys and padding

SSH2Transport

public SSH2Transport(java.net.Socket tpSocket,
                     SSH2Preferences prefs,
                     SecureRandomAndPad rand)
This is the basic constructor used when no logging or event handling is needed.

Parameters:
tpSocket - the connection to the ssh2 server
prefs - the protocol preferences
rand - the source of randomness for keys and padding

SSH2Transport

public SSH2Transport(java.net.Socket tpSocket,
                     SSH2Preferences prefs,
                     SSH2TransportEventHandler eventHandler,
                     SecureRandomAndPad rand)
This is the constructor used when an event handler is needed but no logging.

Parameters:
tpSocket - the connection to the ssh2 server
prefs - the protocol preferences
eventHandler - the event handler which receives callbacks
rand - the source of randomness for keys and padding

SSH2Transport

public SSH2Transport(java.net.Socket tpSocket,
                     SSH2Preferences prefs,
                     SSH2TransportEventHandler eventHandler,
                     SecureRandomAndPad rand,
                     Log log)
This is the constructor used when both an event handler and logging is needed.

Parameters:
tpSocket - the connection to the ssh2 server
prefs - the protocol preferences
eventHandler - the event handler which receives callbacks
rand - the source of randomness for keys and padding
log - the log handler which receives all logs
Method Detail

boot

public void boot()
          throws SSH2Exception
Starts the protocol engine and begins communication with the server. It completes the version negotiation and starts two threads which handles the protocol engine and all communication with the server. The key exchange is started here.

Throws:
SSH2Exception - if a fatal error occurs such as an I/O error or a protocol mismatch.

boot

public void boot(int timeout)
          throws SSH2Exception
Starts the protocol engine and begins communication with the server. It completes the version negotiation and starts two threads which handles the protocol engine and all communication with the server. The key exchange is started here.

Parameters:
timeout - handshake timeout in ms
Throws:
SSH2Exception - if a fatal error occurs such as an I/O error or a protocol mismatch.

setSocketOptions

public void setSocketOptions(java.lang.String desc,
                             java.net.Socket sock)
                      throws java.io.IOException
Throws:
java.io.IOException

getLocalHostName

public java.lang.String getLocalHostName()

getSessionId

public byte[] getSessionId()
Gets the session identifier calculated at key exchange as defined in the protool spec.

Returns:
the session identifier as a byte array.

getClientKEXINITPDU

public SSH2TransportPDU getClientKEXINITPDU()
Gets the PDU containing the key exchange initialization (KEXINIT) sent by the client.

Returns:
the PDU containing the KEXINIT packet

getServerKEXINITPDU

public SSH2TransportPDU getServerKEXINITPDU()
Gets the PDU containing the key exchange initialization (KEXINIT) sent by the server.

Returns:
the PDU containing the KEXINIT packet.

getClientVersion

public java.lang.String getClientVersion()
Gets the client's version string

Returns:
the client's version string

getServerVersion

public java.lang.String getServerVersion()
Gets the server's version string.

Returns:
the server's version string.

getOurPreferences

public SSH2Preferences getOurPreferences()
Gets our preferences.

Returns:
our preferences.

getPeerPreferences

public SSH2Preferences getPeerPreferences()
Gets the preferences peer want.

Returns:
peer's preferences.

setEventHandler

public void setEventHandler(SSH2TransportEventHandler eventHandler)
Sets the event handler to use.

Parameters:
eventHandler - the event handler to use.

getEventHandler

public SSH2TransportEventHandler getEventHandler()
Gets the event handler currently in use.

Returns:
the event handler currently in use.

getLog

public Log getLog()
Gets the log handler currently in use.

Returns:
the log handler currently in use.

setLog

public void setLog(Log log)
Sets the log handler to use.

Parameters:
log - the log handler to use

isServer

public boolean isServer()
Checks whether we are a server or a client.

Returns:
a boolean indicating if we are a server or not.

getSecureRandom

public SecureRandom getSecureRandom()
Gets the SecureRandom currently in use.

Returns:
the SecureRandom in use.

getRxCompressor

public SSH2Compressor getRxCompressor()
Gets the SSH2Compressor currently in use for the receiver.

Returns:
the SSH2Compressor in use, null if none.

getTxCompressor

public SSH2Compressor getTxCompressor()
Gets the SSH2Compressor currently in use for the transmitter.

Returns:
the SSH2Compressor in use, null if none.

setUserAuth

public void setUserAuth(SSH2UserAuth userAuth)
Sets the SSH2UserAuth to use for the user authenticaton stage. The user authentication service is started from the class SSH2UserAuth through the method requestService.

Parameters:
userAuth - the userAuth layer

requestService

public void requestService(java.lang.String service)
Requests the given service (currently the only service defined is the "ssh-userauth" service which starts the user authentication).

Parameters:
service - the name of the service to request

setConnection

public void setConnection(SSH2Connection connection)
Sets the SSH2Connection to use for the connection layer. All actions after this stage are made through the connection layer.

Parameters:
connection - the connection layer

startKeyExchange

public void startKeyExchange()
                      throws SSH2Exception
Starts a key exchange with the preferences set in the constructor. If a key exchange is allready in progress this call have no effect.

Throws:
SSH2Exception - if a fatal error occurs.

startKeyExchange

public void startKeyExchange(SSH2Preferences newPrefs)
                      throws SSH2Exception
Starts a key exchange with the given preferences. That is change to new preferences and negotiate these with the peer. If a key exchange is allready in progress this call have no effect.

Parameters:
newPrefs - the new preferences to use
Throws:
SSH2Exception - if a fatal error occurs

waitForKEXComplete

public boolean waitForKEXComplete()
Waits (blocks) for key exchange to complete (if not in progress returns immediately).

Returns:
a boolean indicating if key exchange was successful or not.

keyExchangeInProgress

public boolean keyExchangeInProgress()
Checks if key exchange is currently in progress.

Returns:
a boolean indicating if key exchange is in progress or not.

isConnected

public boolean isConnected()
Checks if currently connected to a server.

Returns:
a boolean indicating if we are connected or not.

getDisconnectMessage

public java.lang.String getDisconnectMessage()
Gets the message describing why transport was disconnected. Useful when an error occurs and we are not hooked up with an eventhandler to see it (e.g. when an error occurs in the key exchange it's only reported as a disconnect reason).

Returns:
the disconnect message or null if still connected

sendIgnore

public void sendIgnore(byte[] data)
Sends an IGNORE packet (as defined in the protocol spec.) with the given data as payload.

Parameters:
data - a byte array containing the payload

sendIgnore

public void sendIgnore(byte[] data,
                       int off,
                       int len)
Sends an IGNORE packet (as defined in the protocol spec.) with the given data as payload.

Parameters:
data - a byte array containing the payload
off - offset in data where payload starts
len - length of payload

sendDebug

public void sendDebug(boolean alwaysDisp,
                      java.lang.String message,
                      java.lang.String language)
Sends a DEBUG packet (as defined in the protocol spec.) with the given message.

Parameters:
alwaysDisp - boolean indicating whether this message must always be displayed or not.
message - the debug message to send
language - the language tag to use

enableKeepAlive

public void enableKeepAlive(int intervalSeconds)
Enables keep-alive function which sends IGNORE packets on the given time interval. This is to prevent the connection from beeing timed out because of TCP connection subject to idle-timeouts in a firewall.

Parameters:
intervalSeconds - interval time in seconds

getKeepAliveInterval

public int getKeepAliveInterval()
Gets the keep-alive interval.

Returns:
the keep-alive interval, 0 means keep-alive is disabled

disableKeepAlive

public void disableKeepAlive()
Disables keep-alive function.


transmit

public void transmit(SSH2TransportPDU pdu)
Transmits the given PDU if we are connected. The PDU is put in a queue which is processed by the internal threads hence this call is can only block in extreme cases since all internal queues are subject to flow control to prevent memory from beeing exhausted.

Parameters:
pdu - PDU to send

transmitInternal

public void transmitInternal(SSH2TransportPDU pdu)
                      throws SSH2Exception
Transmits the given PDU without checking if we are connected. This version of transmit writes the PDU directly to the OutputStream to the peer, hence it can only be used when the transmitter is not running.

Parameters:
pdu - PDU to send
Throws:
SSH2Exception - if an I/O exception or other fatal error occurs

fatalDisconnect

public void fatalDisconnect(int reason,
                            java.lang.String description)
Disconnects from peer using the DISCONNECT packet type with the given reason and description. See the class SSH2 for reason codes.

Parameters:
reason - the reason code
description - the textual description for the cause of disconnect
See Also:
SSH2

normalDisconnect

public void normalDisconnect(java.lang.String description)
Disconnects from peer using the DISCONNECT packet type with the reason code DISCONNECT_BY_APPLICATION and the given description.

Parameters:
description - the textual description for the cause of disconnect

disconnectInternal

protected void disconnectInternal(int reason,
                                  java.lang.String description,
                                  java.lang.String languageTag,
                                  boolean fromPeer)

extractMajor

public static int extractMajor(java.lang.String versionStr)
                        throws SSH2Exception
Extracts the major version from a version string (as defined in the protocol spec.)

Parameters:
versionStr - the full version string
Returns:
the major version number
Throws:
SSH2Exception - if there is a format error

extractMinor

public static int extractMinor(java.lang.String versionStr)
                        throws SSH2Exception
Extracts the minor version from a version string (as defined in the protocol spec.)

Parameters:
versionStr - the full version string
Returns:
the minor version number
Throws:
SSH2Exception - if there is a format error

extractPackageVersion

public static java.lang.String extractPackageVersion(java.lang.String versionStr)
                                              throws SSH2Exception
Extracts the package version (defined as softwareversion and comments in the protocol spec.) from a version string.

Parameters:
versionStr - the full version string
Returns:
the package version (i.e. software version and comments)
Throws:
SSH2Exception - if there is a format error

sendNewKeys

public void sendNewKeys()
                 throws SSH2Exception
Sends the NEWKEYS paket type and changes the transmitter keys according to the current prefs (as negotiated before). Typically used from a subclass to SSH2KeyExchanger.

Throws:
SSH2Exception - if an error occurs while sending the packet.

authenticateHost

public void authenticateHost(byte[] serverHostKey,
                             byte[] serverSigH,
                             byte[] exchangeHash_H)
                      throws SSH2Exception
Authenticates the server through its host key. Typically used from a subclass to SSH2KeyExchanger.

Parameters:
serverHostKey - byte array containing server's host key (e.g. a public key blob or a certificate).
serverSigH - byte array containing server's signature of the exchange hash which should be verified.
exchangeHash_H - the exchange hash
Throws:
SSH2Exception - if an error occurs

handleExtensionRxPacket

protected boolean handleExtensionRxPacket(SSH2TransportPDU pdu)
                                   throws ShortBufferException,
                                          java.io.IOException,
                                          SSH2Exception
Function which can be overridden in subclasses to handle extensions to the SSH2 protocol.

Returns:
true if the packet was handled
Throws:
ShortBufferException
java.io.IOException
SSH2Exception

receiveInternal

public SSH2TransportPDU receiveInternal()
                                 throws SSH2Exception,
                                        ShortBufferException,
                                        java.io.IOException
Receives a PDU directly from the InputStream from the peer without checking if we are connected. This method can only be used when the receiver is not running.

Returns:
the PDU which was read
Throws:
SSH2Exception
ShortBufferException
java.io.IOException

reportInactivity

protected void reportInactivity(int duration)
Called by the KeepAliveThread thread (if launched) to report when the connection has been inactive for a time.

Parameters:
duration - How long (in seconds) the connection has been inactive