Commit 37588e0f authored by Guus der Kinderen's avatar Guus der Kinderen

OF-1009: Allow non-TLS dialback

When a TLS failure occurs during dialback, allow for a non-TLS
based fallback.
parent 056012e1
...@@ -27,6 +27,7 @@ import java.io.OutputStreamWriter; ...@@ -27,6 +27,7 @@ import java.io.OutputStreamWriter;
import java.io.Writer; import java.io.Writer;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
...@@ -65,6 +66,8 @@ import org.xmpp.packet.JID; ...@@ -65,6 +66,8 @@ import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError; import org.xmpp.packet.PacketError;
import org.xmpp.packet.StreamError; import org.xmpp.packet.StreamError;
import javax.net.ssl.SSLHandshakeException;
/** /**
* Implementation of the Server Dialback method as defined by the RFC3920. * Implementation of the Server Dialback method as defined by the RFC3920.
* *
...@@ -530,7 +533,7 @@ public class ServerDialback { ...@@ -530,7 +533,7 @@ public class ServerDialback {
String key = doc.getTextTrim(); String key = doc.getTextTrim();
final Socket socket = SocketUtil.createSocketToXmppDomain( remoteDomain, RemoteServerManager.getPortForServer(remoteDomain) ); Socket socket = SocketUtil.createSocketToXmppDomain( remoteDomain, RemoteServerManager.getPortForServer(remoteDomain) );
if ( socket == null ) if ( socket == null )
{ {
...@@ -539,9 +542,30 @@ public class ServerDialback { ...@@ -539,9 +542,30 @@ public class ServerDialback {
return false; return false;
} }
VerifyResult result;
try { try {
log.debug( "Verifying dialback key..." ); log.debug( "Verifying dialback key..." );
VerifyResult result = verifyKey(key, streamID.toString(), recipient, remoteDomain, socket); try
{
result = verifyKey( key, streamID.toString(), recipient, remoteDomain, socket, false );
}
catch (SSLHandshakeException e)
{
log.debug( "Verification of dialback key failed due to TLS failure. Retry without TLS...", e );
// The receiving entity is expected to close the socket *without* sending any more data (<failure/> nor </stream>).
// It is probably (see OF-794) best if we, as the initiating entity, therefor don't send any data either.
final SocketAddress oldAddress = socket.getRemoteSocketAddress();
socket.close();
log.debug( "Re-opening socket (with the same remote peer)..." );
// Retry, without TLS.
socket = new Socket();
socket.connect( oldAddress, RemoteServerManager.getSocketTimeout() );
log.debug( "Successfully re-opened socket! Try to validate dialback key again (without TLS this time)..." );
result = verifyKey( key, streamID.toString(), recipient, remoteDomain, socket, true );
}
switch(result) { switch(result) {
case valid: case valid:
...@@ -593,7 +617,7 @@ public class ServerDialback { ...@@ -593,7 +617,7 @@ public class ServerDialback {
return host_unknown; return host_unknown;
} }
private VerifyResult sendVerifyKey(String key, String streamID, String recipient, String remoteDomain, Writer writer, XMPPPacketReader reader, Socket socket) throws IOException, XmlPullParserException, RemoteConnectionFailedException { private VerifyResult sendVerifyKey(String key, String streamID, String recipient, String remoteDomain, Writer writer, XMPPPacketReader reader, Socket socket, boolean skipTLS) throws IOException, XmlPullParserException, RemoteConnectionFailedException {
final Logger log = LoggerFactory.getLogger( Log.getName() + "[Acting as Receiving Server: Verify key with AS: " + remoteDomain + " for OS: " + recipient + " (id " + streamID + ")]" ); final Logger log = LoggerFactory.getLogger( Log.getName() + "[Acting as Receiving Server: Verify key with AS: " + remoteDomain + " for OS: " + recipient + " (id " + streamID + ")]" );
VerifyResult result = VerifyResult.error; VerifyResult result = VerifyResult.error;
...@@ -621,7 +645,7 @@ public class ServerDialback { ...@@ -621,7 +645,7 @@ public class ServerDialback {
eventType = xpp.next(); eventType = xpp.next();
} }
log.debug( "Got a response. Check if the remote server is XMPP 1.0 compliant..." ); // TODO there's code duplication here with LocalOutgoingServerSession. log.debug( "Got a response." ); // TODO there's code duplication here with LocalOutgoingServerSession.
if ((xpp.getAttributeValue("", "version") != null) && (xpp.getAttributeValue("", "version").equals("1.0"))) { if ((xpp.getAttributeValue("", "version") != null) && (xpp.getAttributeValue("", "version").equals("1.0"))) {
log.debug( "The remote server is XMPP 1.0 compliant (or at least reports to be)."); log.debug( "The remote server is XMPP 1.0 compliant (or at least reports to be).");
Document doc; Document doc;
...@@ -633,7 +657,7 @@ public class ServerDialback { ...@@ -633,7 +657,7 @@ public class ServerDialback {
} }
Element features = doc.getRootElement(); Element features = doc.getRootElement();
Element starttls = features.element("starttls"); Element starttls = features.element("starttls");
if (starttls != null) { if (!skipTLS && starttls != null) {
writer.write("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); writer.write("<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>");
writer.flush(); writer.flush();
try { try {
...@@ -650,16 +674,16 @@ public class ServerDialback { ...@@ -650,16 +674,16 @@ public class ServerDialback {
log.debug( "Negotiating TLS with AS... " ); log.debug( "Negotiating TLS with AS... " );
// Ugly hacks, apparently, copied from SocketConnection. // Ugly hacks, apparently, copied from SocketConnection.
final ConnectionManagerImpl connectionManager = ((ConnectionManagerImpl) XMPPServer.getInstance().getConnectionManager()); final ConnectionManagerImpl connectionManager = ( (ConnectionManagerImpl) XMPPServer.getInstance().getConnectionManager() );
tlsStreamHandler = new TLSStreamHandler(socket, connectionManager.getListener( ConnectionType.SOCKET_S2S, false ).generateConnectionConfiguration(), true); tlsStreamHandler = new TLSStreamHandler( socket, connectionManager.getListener( ConnectionType.SOCKET_S2S, false ).generateConnectionConfiguration(), true );
// Start handshake // Start handshake
tlsStreamHandler.start(); tlsStreamHandler.start();
// Use new wrapped writers // Use new wrapped writers
writer = new BufferedWriter(new OutputStreamWriter(tlsStreamHandler.getOutputStream(), StandardCharsets.UTF_8)); writer = new BufferedWriter( new OutputStreamWriter( tlsStreamHandler.getOutputStream(), StandardCharsets.UTF_8 ) );
reader.getXPPParser().setInput(new InputStreamReader(tlsStreamHandler.getInputStream(),StandardCharsets.UTF_8)); reader.getXPPParser().setInput( new InputStreamReader( tlsStreamHandler.getInputStream(), StandardCharsets.UTF_8 ) );
log.debug( "Successfully negotiated TLS with AS... " ); log.debug( "Successfully negotiated TLS with AS... " );
/// Recurses! /// Recurses!
return sendVerifyKey(key, streamID, recipient, remoteDomain, writer, reader, socket); return sendVerifyKey( key, streamID, recipient, remoteDomain, writer, reader, socket, skipTLS );
} }
} }
if ("jabber:server:dialback".equals(xpp.getNamespace("db"))) { if ("jabber:server:dialback".equals(xpp.getNamespace("db"))) {
...@@ -742,7 +766,7 @@ public class ServerDialback { ...@@ -742,7 +766,7 @@ public class ServerDialback {
/** /**
* Verifies the key with the Authoritative Server. * Verifies the key with the Authoritative Server.
*/ */
private VerifyResult verifyKey(String key, String streamID, String recipient, String remoteDomain, Socket socket) throws IOException, XmlPullParserException, RemoteConnectionFailedException { private VerifyResult verifyKey(String key, String streamID, String recipient, String remoteDomain, Socket socket, boolean skipTLS ) throws IOException, XmlPullParserException, RemoteConnectionFailedException {
final Logger log = LoggerFactory.getLogger( Log.getName() + "[Acting as Receiving Server: Verify key with AS: " + remoteDomain + " for OS: " + recipient + " (id " + streamID + ")]" ); final Logger log = LoggerFactory.getLogger( Log.getName() + "[Acting as Receiving Server: Verify key with AS: " + remoteDomain + " for OS: " + recipient + " (id " + streamID + ")]" );
...@@ -759,7 +783,7 @@ public class ServerDialback { ...@@ -759,7 +783,7 @@ public class ServerDialback {
reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(), CHARSET)); reader.getXPPParser().setInput(new InputStreamReader(socket.getInputStream(), CHARSET));
// Get a writer for sending the open stream tag // Get a writer for sending the open stream tag
writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), CHARSET)); writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), CHARSET));
result = sendVerifyKey(key, streamID, recipient, remoteDomain, writer, reader, socket); result = sendVerifyKey(key, streamID, recipient, remoteDomain, writer, reader, socket, skipTLS );
} }
finally { finally {
try { try {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment