Commit 6aa0314b authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gato

Added support for server dialback over TLS and server dialback a la XMPP 1.0 (XEP-220 & XEP-238)

git-svn-id: http://svn.igniterealtime.org/svn/repos/openfire/trunk@10683 b35dd754-fafc-0310-a699-88a17e54d16e
parent 9f725b9a
...@@ -2418,3 +2418,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2418,3 +2418,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2404,3 +2404,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2404,3 +2404,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -460,6 +460,7 @@ ...@@ -460,6 +460,7 @@
## Added key: 'prelogin.setup.sidebar.title.clearspace' ## Added key: 'prelogin.setup.sidebar.title.clearspace'
## Added key: 'prelogin.setup.error.clearspace.sharedsecret' ## Added key: 'prelogin.setup.error.clearspace.sharedsecret'
## Added key: 'prelogin.setup.error.clearspace.connection' ## Added key: 'prelogin.setup.error.clearspace.connection'
## Added key: 'ssl.settings.client.label_self-signed'
...@@ -2115,6 +2116,7 @@ ssl.settings.client.label_notrequired=Optional ...@@ -2115,6 +2116,7 @@ ssl.settings.client.label_notrequired=Optional
ssl.settings.client.label_notrequired_info=Clients may connect to the server using secured connections. ssl.settings.client.label_notrequired_info=Clients may connect to the server using secured connections.
ssl.settings.client.label_custom=Custom ssl.settings.client.label_custom=Custom
ssl.settings.client.label_custom_info=Advanced configuration ssl.settings.client.label_custom_info=Advanced configuration
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
ssl.settings.client.customSSL=Old SSL method: ssl.settings.client.customSSL=Old SSL method:
ssl.settings.client.customTLS=TLS method: ssl.settings.client.customTLS=TLS method:
ssl.settings.available=Available ssl.settings.available=Available
......
...@@ -2455,3 +2455,4 @@ setup.clearspace.service.certificate.verify.validity=Verificar certificado no ex ...@@ -2455,3 +2455,4 @@ setup.clearspace.service.certificate.verify.validity=Verificar certificado no ex
setup.clearspace.service.certificate.verify.validity_help=Certificado sea valido en el tiempo actual setup.clearspace.service.certificate.verify.validity_help=Certificado sea valido en el tiempo actual
reg.settings.ips_all=Restringir TODOS los ingresos de estas IPs: reg.settings.ips_all=Restringir TODOS los ingresos de estas IPs:
reg.settings.ips_anonymous=Restringir ingresos anonimos de estas IPs: reg.settings.ips_anonymous=Restringir ingresos anonimos de estas IPs:
ssl.settings.client.label_self-signed=Aceptar certificados auto-firmados. Server dialback sobre TLS esta habilitado.
\ No newline at end of file
...@@ -2024,3 +2024,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2024,3 +2024,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2551,3 +2551,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2551,3 +2551,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2409,3 +2409,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2409,3 +2409,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2384,3 +2384,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2384,3 +2384,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2418,3 +2418,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2418,3 +2418,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2533,3 +2533,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2533,3 +2533,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2196,3 +2196,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e ...@@ -2196,3 +2196,4 @@ setup.clearspace.service.certificate.verify.validity=Verify certificate is not e
setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time. setup.clearspace.service.certificate.verify.validity_help=Certificate is valid at the current time.
reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's: reg.settings.ips_all=Restrict ALL (including anonymous) logins by these IP's:
reg.settings.ips_anonymous=Restrict anonymous logins by these IP's: reg.settings.ips_anonymous=Restrict anonymous logins by these IP's:
ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -90,12 +90,39 @@ public interface Connection { ...@@ -90,12 +90,39 @@ public interface Connection {
public String getHostName() throws UnknownHostException; public String getHostName() throws UnknownHostException;
/** /**
* Returns the underlying {@link javax.security.cert.X509Certificate} for the connection. * Returns the local underlying {@link javax.security.cert.X509Certificate} for the connection.
*
* @return <tt>null</tt> if no {@link javax.security.cert.X509Certificate} is present for the connection.
*/
public Certificate[] getLocalCertificates();
/**
* Returns the underlying {@link javax.security.cert.X509Certificate} for the connection of the peer.
* *
* @return <tt>null</tt> if no {@link javax.security.cert.X509Certificate} is present for the connection. * @return <tt>null</tt> if no {@link javax.security.cert.X509Certificate} is present for the connection.
*/ */
public Certificate[] getPeerCertificates(); public Certificate[] getPeerCertificates();
/**
* Keeps track if the other peer of this session presented a self-signed certificate. When
* using self-signed certificate for server-2-server sessions then SASL EXTERNAL will not be
* used and instead server-dialback will be preferred for vcerifying the identify of the remote
* server.
*
* @param isSelfSigned true if the other peer presented a self-signed certificate.
*/
public void setUsingSelfSignedCertificate(boolean isSelfSigned);
/**
* Returns true if the other peer of this session presented a self-signed certificate. When
* using self-signed certificate for server-2-server sessions then SASL EXTERNAL will not be
* used and instead server-dialback will be preferred for vcerifying the identify of the remote
* server.
*
* @return true if the other peer of this session presented a self-signed certificate.
*/
public boolean isUsingSelfSignedCertificate();
/** /**
* Close this session including associated socket connection. The order of * Close this session including associated socket connection. The order of
* events for closing the session is: * events for closing the session is:
......
...@@ -27,7 +27,6 @@ import org.jivesoftware.util.CertificateManager; ...@@ -27,7 +27,6 @@ import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.jivesoftware.util.StringUtils; import org.jivesoftware.util.StringUtils;
import org.xmpp.packet.JID;
import javax.security.sasl.Sasl; import javax.security.sasl.Sasl;
import javax.security.sasl.SaslException; import javax.security.sasl.SaslException;
...@@ -123,7 +122,7 @@ public class SASLAuthentication { ...@@ -123,7 +122,7 @@ public class SASLAuthentication {
* *
* @return a string with the valid SASL mechanisms available for the specified session. * @return a string with the valid SASL mechanisms available for the specified session.
*/ */
public static String getSASLMechanisms(Session session) { public static String getSASLMechanisms(LocalSession session) {
if (!(session instanceof ClientSession) && !(session instanceof IncomingServerSession)) { if (!(session instanceof ClientSession) && !(session instanceof IncomingServerSession)) {
return ""; return "";
} }
...@@ -132,10 +131,25 @@ public class SASLAuthentication { ...@@ -132,10 +131,25 @@ public class SASLAuthentication {
if (session instanceof IncomingServerSession) { if (session instanceof IncomingServerSession) {
// Server connections dont follow the same rules as clients // Server connections dont follow the same rules as clients
if (session.isSecure()) { if (session.isSecure()) {
// Offer SASL EXTERNAL only if TLS has already been negotiated boolean usingSelfSigned = false;
Certificate[] certificates = session.getConnection().getLocalCertificates();
for (Certificate certificate : certificates) {
try {
if (CertificateManager
.isSelfSignedCertificate(SSLConfig.getKeyStore(), (X509Certificate) certificate)) {
usingSelfSigned = true;
}
} catch (Exception e) {
usingSelfSigned = true;
}
}
if (!usingSelfSigned) {
// Offer SASL EXTERNAL only if TLS has already been negotiated and we are not
// using a self-signed certificate
sb.append("<mechanism>EXTERNAL</mechanism>"); sb.append("<mechanism>EXTERNAL</mechanism>");
} }
} }
}
else { else {
for (String mech : getSupportedMechanisms()) { for (String mech : getSupportedMechanisms()) {
sb.append("<mechanism>"); sb.append("<mechanism>");
...@@ -604,8 +618,6 @@ public class SASLAuthentication { ...@@ -604,8 +618,6 @@ public class SASLAuthentication {
} }
else if (session instanceof IncomingServerSession) { else if (session instanceof IncomingServerSession) {
String hostname = username; String hostname = username;
// Set the first validated domain as the address of the session
session.setAddress(new JID(null, hostname, null));
// Add the validated domain as a valid domain. The remote server can // Add the validated domain as a valid domain. The remote server can
// now send packets from this address // now send packets from this address
((LocalIncomingServerSession) session).addValidatedDomain(hostname); ((LocalIncomingServerSession) session).addValidatedDomain(hostname);
......
...@@ -219,6 +219,10 @@ public class ServerSocketReader extends SocketReader { ...@@ -219,6 +219,10 @@ public class ServerSocketReader extends SocketReader {
return "jabber:server"; return "jabber:server";
} }
public String getExtraNamespaces() {
return "xmlns:db=\"jabber:server:dialback\"";
}
String getName() { String getName() {
return "Server SR - " + hashCode(); return "Server SR - " + hashCode();
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
package org.jivesoftware.openfire.net; package org.jivesoftware.openfire.net;
import org.jivesoftware.openfire.Connection;
import org.jivesoftware.util.CertificateManager; import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
...@@ -40,11 +41,16 @@ public class ServerTrustManager implements X509TrustManager { ...@@ -40,11 +41,16 @@ public class ServerTrustManager implements X509TrustManager {
* Holds the domain of the remote server we are trying to connect * Holds the domain of the remote server we are trying to connect
*/ */
private String server; private String server;
/**
* Holds the LocalIncomingServerSession that is part of the TLS negotiation.
*/
private Connection connection;
public ServerTrustManager(String server, KeyStore trustTrust) { public ServerTrustManager(String server, KeyStore trustTrust, Connection connection) {
super(); super();
this.server = server; this.server = server;
this.trustStore = trustTrust; this.trustStore = trustTrust;
this.connection = connection;
} }
public void checkClientTrusted(X509Certificate[] x509Certificates, public void checkClientTrusted(X509Certificate[] x509Certificates,
...@@ -120,6 +126,8 @@ public class ServerTrustManager implements X509TrustManager { ...@@ -120,6 +126,8 @@ public class ServerTrustManager implements X509TrustManager {
boolean trusted = false; boolean trusted = false;
try { try {
trusted = trustStore.getCertificateAlias(x509Certificates[nSize - 1]) != null; trusted = trustStore.getCertificateAlias(x509Certificates[nSize - 1]) != null;
// Keep track if the other peer presented a self-signed certificate
connection.setUsingSelfSignedCertificate(!trusted && nSize == 1);
if (!trusted && nSize == 1 && JiveGlobals if (!trusted && nSize == 1 && JiveGlobals
.getBooleanProperty("xmpp.server.certificate.accept-selfsigned", false)) .getBooleanProperty("xmpp.server.certificate.accept-selfsigned", false))
{ {
......
...@@ -102,6 +102,7 @@ public class SocketConnection implements Connection { ...@@ -102,6 +102,7 @@ public class SocketConnection implements Connection {
* TLS policy currently in use for this connection. * TLS policy currently in use for this connection.
*/ */
private TLSPolicy tlsPolicy = TLSPolicy.optional; private TLSPolicy tlsPolicy = TLSPolicy.optional;
private boolean usingSelfSignedCertificate;
/** /**
* Compression policy currently in use for this connection. * Compression policy currently in use for this connection.
...@@ -158,7 +159,8 @@ public class SocketConnection implements Connection { ...@@ -158,7 +159,8 @@ public class SocketConnection implements Connection {
if (!secure) { if (!secure) {
secure = true; secure = true;
// Prepare for TLS // Prepare for TLS
tlsStreamHandler = new TLSStreamHandler(socket, clientMode, remoteServer, session instanceof IncomingServerSession); tlsStreamHandler = new TLSStreamHandler(this, socket, clientMode, remoteServer,
session instanceof IncomingServerSession);
if (!clientMode) { if (!clientMode) {
// Indicate the client that the server is ready to negotiate TLS // Indicate the client that the server is ready to negotiate TLS
deliverRawText("<proceed xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>"); deliverRawText("<proceed xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\"/>");
...@@ -395,6 +397,13 @@ public class SocketConnection implements Connection { ...@@ -395,6 +397,13 @@ public class SocketConnection implements Connection {
this.flashClient = flashClient; this.flashClient = flashClient;
} }
public Certificate[] getLocalCertificates() {
if (tlsStreamHandler != null) {
return tlsStreamHandler.getSSLSession().getLocalCertificates();
}
return new Certificate[0];
}
public Certificate[] getPeerCertificates() { public Certificate[] getPeerCertificates() {
if (tlsStreamHandler != null) { if (tlsStreamHandler != null) {
try { try {
...@@ -407,6 +416,14 @@ public class SocketConnection implements Connection { ...@@ -407,6 +416,14 @@ public class SocketConnection implements Connection {
return new Certificate[0]; return new Certificate[0];
} }
public void setUsingSelfSignedCertificate(boolean isSelfSigned) {
this.usingSelfSignedCertificate = isSelfSigned;
}
public boolean isUsingSelfSignedCertificate() {
return usingSelfSignedCertificate;
}
public PacketDeliverer getPacketDeliverer() { public PacketDeliverer getPacketDeliverer() {
return backupDeliverer; return backupDeliverer;
} }
......
...@@ -471,4 +471,8 @@ public abstract class SocketReader implements Runnable { ...@@ -471,4 +471,8 @@ public abstract class SocketReader implements Runnable {
*/ */
abstract boolean createSession(String namespace) throws UnauthorizedException, abstract boolean createSession(String namespace) throws UnauthorizedException,
XmlPullParserException, IOException; XmlPullParserException, IOException;
public String getExtraNamespaces() {
return null;
}
} }
...@@ -248,8 +248,12 @@ abstract class SocketReadingMode { ...@@ -248,8 +248,12 @@ abstract class SocketReadingMode {
sb.append("<stream:stream "); sb.append("<stream:stream ");
} }
sb.append("xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\""); sb.append("xmlns:stream=\"http://etherx.jabber.org/streams\" xmlns=\"");
sb.append(socketReader.getNamespace()); sb.append(socketReader.getNamespace()).append("\"");
sb.append("\" from=\""); if (socketReader.getExtraNamespaces() != null) {
sb.append(" ");
sb.append(socketReader.getExtraNamespaces());
}
sb.append(" from=\"");
sb.append(socketReader.session.getServerName()); sb.append(socketReader.session.getServerName());
sb.append("\" id=\""); sb.append("\" id=\"");
sb.append(socketReader.session.getStreamID().toString()); sb.append(socketReader.session.getStreamID().toString());
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
package org.jivesoftware.openfire.net; package org.jivesoftware.openfire.net;
import org.jivesoftware.openfire.Connection;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
...@@ -83,6 +84,7 @@ public class TLSStreamHandler { ...@@ -83,6 +84,7 @@ public class TLSStreamHandler {
* <tt>remoteServer</tt> is the server name of the remote server. Otherwise <tt>clientMode</tt> * <tt>remoteServer</tt> is the server name of the remote server. Otherwise <tt>clientMode</tt>
* will be <code>false</code> and <tt>remoteServer</tt> null. * will be <code>false</code> and <tt>remoteServer</tt> null.
* *
* @param connection the connection to secure
* @param socket the plain socket connection to secure * @param socket the plain socket connection to secure
* @param clientMode boolean indicating if this entity is a client or a server. * @param clientMode boolean indicating if this entity is a client or a server.
* @param remoteServer server name of the remote server we are connecting to or <tt>null</tt> * @param remoteServer server name of the remote server we are connecting to or <tt>null</tt>
...@@ -92,9 +94,9 @@ public class TLSStreamHandler { ...@@ -92,9 +94,9 @@ public class TLSStreamHandler {
* EXTERNAL SASL is going to be used. * EXTERNAL SASL is going to be used.
* @throws java.io.IOException * @throws java.io.IOException
*/ */
public TLSStreamHandler(Socket socket, boolean clientMode, String remoteServer, public TLSStreamHandler(Connection connection, Socket socket, boolean clientMode, String remoteServer,
boolean needClientAuth) throws IOException { boolean needClientAuth) throws IOException {
wrapper = new TLSWrapper(clientMode, needClientAuth, remoteServer); wrapper = new TLSWrapper(connection, clientMode, needClientAuth, remoteServer);
tlsEngine = wrapper.getTlsEngine(); tlsEngine = wrapper.getTlsEngine();
reader = new TLSStreamReader(wrapper, socket); reader = new TLSStreamReader(wrapper, socket);
writer = new TLSStreamWriter(wrapper, socket); writer = new TLSStreamWriter(wrapper, socket);
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
package org.jivesoftware.openfire.net; package org.jivesoftware.openfire.net;
import org.jivesoftware.openfire.Connection;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import javax.net.ssl.*; import javax.net.ssl.*;
...@@ -57,7 +58,7 @@ public class TLSWrapper { ...@@ -57,7 +58,7 @@ public class TLSWrapper {
private int netBuffSize; private int netBuffSize;
private int appBuffSize; private int appBuffSize;
public TLSWrapper(boolean clientMode, boolean needClientAuth, String remoteServer) { public TLSWrapper(Connection connection, boolean clientMode, boolean needClientAuth, String remoteServer) {
boolean c2sConnection = (remoteServer == null); boolean c2sConnection = (remoteServer == null);
if (debug) { if (debug) {
...@@ -85,7 +86,7 @@ public class TLSWrapper { ...@@ -85,7 +86,7 @@ public class TLSWrapper {
} }
else { else {
// Check if we can trust certificates presented by the server // Check if we can trust certificates presented by the server
tm = new TrustManager[]{new ServerTrustManager(remoteServer, ksTrust)}; tm = new TrustManager[]{new ServerTrustManager(remoteServer, ksTrust, connection)};
} }
} }
...@@ -101,10 +102,10 @@ public class TLSWrapper { ...@@ -101,10 +102,10 @@ public class TLSWrapper {
*/ */
tlsEngine = tlsContext.createSSLEngine(); tlsEngine = tlsContext.createSSLEngine();
tlsEngine.setUseClientMode(clientMode); tlsEngine.setUseClientMode(clientMode);
SSLSession session = tlsEngine.getSession(); SSLSession sslSession = tlsEngine.getSession();
netBuffSize = session.getPacketBufferSize(); netBuffSize = sslSession.getPacketBufferSize();
appBuffSize = session.getApplicationBufferSize(); appBuffSize = sslSession.getApplicationBufferSize();
} catch (KeyManagementException e) { } catch (KeyManagementException e) {
Log.error("TLSHandler startup problem.\n" + " SSLContext initialisation failed.", e); Log.error("TLSHandler startup problem.\n" + " SSLContext initialisation failed.", e);
......
...@@ -58,11 +58,23 @@ public abstract class VirtualConnection implements Connection { ...@@ -58,11 +58,23 @@ public abstract class VirtualConnection implements Connection {
return 0; return 0;
} }
public Certificate[] getLocalCertificates() {
// Ignore
return new Certificate[0];
}
public Certificate[] getPeerCertificates() { public Certificate[] getPeerCertificates() {
// Ignore // Ignore
return new Certificate[0]; return new Certificate[0];
} }
public void setUsingSelfSignedCertificate(boolean isSelfSigned) {
}
public boolean isUsingSelfSignedCertificate() {
return false;
}
public boolean isClosed() { public boolean isClosed() {
if (session == null) { if (session == null) {
return closed; return closed;
......
...@@ -72,6 +72,7 @@ public class NIOConnection implements Connection { ...@@ -72,6 +72,7 @@ public class NIOConnection implements Connection {
* TLS policy currently in use for this connection. * TLS policy currently in use for this connection.
*/ */
private TLSPolicy tlsPolicy = TLSPolicy.optional; private TLSPolicy tlsPolicy = TLSPolicy.optional;
private boolean usingSelfSignedCertificate;
/** /**
* Compression policy currently in use for this connection. * Compression policy currently in use for this connection.
...@@ -131,6 +132,14 @@ public class NIOConnection implements Connection { ...@@ -131,6 +132,14 @@ public class NIOConnection implements Connection {
return ((InetSocketAddress) ioSession.getRemoteAddress()).getAddress().getHostName(); return ((InetSocketAddress) ioSession.getRemoteAddress()).getAddress().getHostName();
} }
public Certificate[] getLocalCertificates() {
SSLSession sslSession = (SSLSession) ioSession.getAttribute(SSLFilter.SSL_SESSION);
if (sslSession != null) {
return sslSession.getLocalCertificates();
}
return new Certificate[0];
}
public Certificate[] getPeerCertificates() { public Certificate[] getPeerCertificates() {
try { try {
SSLSession sslSession = (SSLSession) ioSession.getAttribute(SSLFilter.SSL_SESSION); SSLSession sslSession = (SSLSession) ioSession.getAttribute(SSLFilter.SSL_SESSION);
...@@ -143,6 +152,14 @@ public class NIOConnection implements Connection { ...@@ -143,6 +152,14 @@ public class NIOConnection implements Connection {
return new Certificate[0]; return new Certificate[0];
} }
public void setUsingSelfSignedCertificate(boolean isSelfSigned) {
this.usingSelfSignedCertificate = isSelfSigned;
}
public boolean isUsingSelfSignedCertificate() {
return usingSelfSignedCertificate;
}
public PacketDeliverer getPacketDeliverer() { public PacketDeliverer getPacketDeliverer() {
return backupDeliverer; return backupDeliverer;
} }
...@@ -304,7 +321,7 @@ public class NIOConnection implements Connection { ...@@ -304,7 +321,7 @@ public class NIOConnection implements Connection {
tm = new TrustManager[]{new ClientTrustManager(ksTrust)}; tm = new TrustManager[]{new ClientTrustManager(ksTrust)};
} else { } else {
// Check if we can trust certificates presented by the server // Check if we can trust certificates presented by the server
tm = new TrustManager[]{new ServerTrustManager(remoteServer, ksTrust)}; tm = new TrustManager[]{new ServerTrustManager(remoteServer, ksTrust, this)};
} }
} }
......
...@@ -99,7 +99,8 @@ public class ServerDialback { ...@@ -99,7 +99,8 @@ public class ServerDialback {
* *
* When TLS is enabled between servers and server dialback method is enabled then TLS is going * When TLS is enabled between servers and server dialback method is enabled then TLS is going
* to be tried first, when connecting to a remote server, and if TLS fails then server dialback * to be tried first, when connecting to a remote server, and if TLS fails then server dialback
* is going to be used as a last resort. * is going to be used as a last resort. If enabled and the remote server offered server-dialback
* after TLS and no SASL EXTERNAL then server dialback will be used.
* *
* @return true if server dialback is enabled. * @return true if server dialback is enabled.
*/ */
...@@ -107,6 +108,36 @@ public class ServerDialback { ...@@ -107,6 +108,36 @@ public class ServerDialback {
return JiveGlobals.getBooleanProperty("xmpp.server.dialback.enabled", true); return JiveGlobals.getBooleanProperty("xmpp.server.dialback.enabled", true);
} }
/**
* Returns true if server dialback can be used when the remote server presented a self-signed
* certificate. During TLS the remote server can present a self-signed certificate, if this
* setting is enabled then the self-signed certificate will be accepted and if SASL EXTERNAL
* is not offered then server dialback will be used for verifying the remote server.<p>
*
* If self-signed certificates are accepted then server dialback over TLS is enabled.
*
* @return true if server dialback can be used when the remote server presented a self-signed
* certificate.
*/
public static boolean isEnabledForSelfSigned() {
return JiveGlobals.getBooleanProperty("xmpp.server.certificate.accept-selfsigned", false);
}
/**
* Sets if server dialback can be used when the remote server presented a self-signed
* certificate. During TLS the remote server can present a self-signed certificate, if this
* setting is enabled then the self-signed certificate will be accepted and if SASL EXTERNAL
* is not offered then server dialback will be used for verifying the remote server.<p>
*
* If self-signed certificates are accepted then server dialback over TLS is enabled.
*
* @param enabled if server dialback can be used when the remote server presented a self-signed
* certificate.
*/
public static void setEnabledForSelfSigned(boolean enabled) {
JiveGlobals.setProperty("xmpp.server.certificate.accept-selfsigned", Boolean.toString(enabled));
}
/** /**
* Creates a new instance that will be used for creating {@link IncomingServerSession}, * Creates a new instance that will be used for creating {@link IncomingServerSession},
* validating subsequent domains or authenticatig new domains. Use * validating subsequent domains or authenticatig new domains. Use
...@@ -352,8 +383,6 @@ public class ServerDialback { ...@@ -352,8 +383,6 @@ public class ServerDialback {
// Create a server Session for the remote server // Create a server Session for the remote server
LocalIncomingServerSession session = sessionManager. LocalIncomingServerSession session = sessionManager.
createIncomingServerSession(connection, streamID); createIncomingServerSession(connection, streamID);
// Set the first validated domain as the address of the session
session.setAddress(new JID(null, hostname, null));
// Add the validated domain as a valid domain // Add the validated domain as a valid domain
session.addValidatedDomain(hostname); session.addValidatedDomain(hostname);
// Set the domain or subdomain of the local server used when // Set the domain or subdomain of the local server used when
......
...@@ -21,14 +21,17 @@ import org.jivesoftware.openfire.net.SASLAuthentication; ...@@ -21,14 +21,17 @@ import org.jivesoftware.openfire.net.SASLAuthentication;
import org.jivesoftware.openfire.net.SSLConfig; import org.jivesoftware.openfire.net.SSLConfig;
import org.jivesoftware.openfire.net.SocketConnection; import org.jivesoftware.openfire.net.SocketConnection;
import org.jivesoftware.openfire.server.ServerDialback; import org.jivesoftware.openfire.server.ServerDialback;
import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals; import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.Log; import org.jivesoftware.util.Log;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserException;
import org.xmpp.packet.JID;
import org.xmpp.packet.Packet; import org.xmpp.packet.Packet;
import org.xmpp.packet.StreamError;
import java.io.IOException; import java.io.IOException;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
...@@ -95,19 +98,10 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -95,19 +98,10 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
public static LocalIncomingServerSession createSession(String serverName, XMPPPacketReader reader, public static LocalIncomingServerSession createSession(String serverName, XMPPPacketReader reader,
SocketConnection connection) throws XmlPullParserException, IOException { SocketConnection connection) throws XmlPullParserException, IOException {
XmlPullParser xpp = reader.getXPPParser(); XmlPullParser xpp = reader.getXPPParser();
if (xpp.getNamespace("db") != null) {
// Server is trying to establish connection and authenticate using server dialback
if (ServerDialback.isEnabled()) {
ServerDialback method = new ServerDialback(connection, serverName);
return method.createIncomingSession(reader);
}
Log.debug("LocalIncomingServerSession: Server dialback is disabled. Rejecting connection: " + connection);
}
String version = xpp.getAttributeValue("", "version"); String version = xpp.getAttributeValue("", "version");
int[] serverVersion = version != null ? decodeVersion(version) : new int[] {0,0}; int[] serverVersion = version != null ? decodeVersion(version) : new int[] {0,0};
if (serverVersion[0] >= 1) { if (serverVersion[0] >= 1) {
// Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection // Remote server is XMPP 1.0 compliant so offer TLS and SASL to establish the connection (and server dialback)
if (JiveGlobals.getBooleanProperty("xmpp.server.tls.enabled", true)) {
try { try {
return createIncomingSession(connection, serverName); return createIncomingSession(connection, serverName);
} }
...@@ -115,11 +109,13 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -115,11 +109,13 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
Log.error("Error establishing connection from remote server", e); Log.error("Error establishing connection from remote server", e);
} }
} }
else { else if (xpp.getNamespace("db") != null) {
connection.deliverRawText( // Server is trying to establish connection and authenticate using server dialback (pre XMPP 1.0)
new StreamError(StreamError.Condition.invalid_namespace).toXML()); if (ServerDialback.isEnabled()) {
Log.debug("LocalIncomingServerSession: Server TLS is disabled. Rejecting connection: " + connection); ServerDialback method = new ServerDialback(connection, serverName);
return method.createIncomingSession(reader);
} }
Log.debug("LocalIncomingServerSession: Server dialback is disabled. Rejecting connection: " + connection);
} }
// Close the connection since remote server is not XMPP 1.0 compliant and is not // Close the connection since remote server is not XMPP 1.0 compliant and is not
// using server dialback to establish and authenticate the connection // using server dialback to establish and authenticate the connection
...@@ -148,6 +144,7 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -148,6 +144,7 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
// Send the stream header // Send the stream header
StringBuilder openingStream = new StringBuilder(); StringBuilder openingStream = new StringBuilder();
openingStream.append("<stream:stream"); openingStream.append("<stream:stream");
openingStream.append(" xmlns:db=\"jabber:server:dialback\"");
openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\""); openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
openingStream.append(" xmlns=\"jabber:server\""); openingStream.append(" xmlns=\"jabber:server\"");
openingStream.append(" from=\"").append(serverName).append("\""); openingStream.append(" from=\"").append(serverName).append("\"");
...@@ -182,12 +179,19 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -182,12 +179,19 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("<stream:features>"); sb.append("<stream:features>");
if (JiveGlobals.getBooleanProperty("xmpp.server.tls.enabled", true)) {
sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">"); sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
if (!ServerDialback.isEnabled()) { if (!ServerDialback.isEnabled()) {
// Server dialback is disabled so TLS is required // Server dialback is disabled so TLS is required
sb.append("<required/>"); sb.append("<required/>");
} }
sb.append("</starttls>"); sb.append("</starttls>");
}
if (ServerDialback.isEnabled()) {
// Also offer server dialback (when TLS is not required). Server dialback may be offered
// after TLS has been negotiated and a self-signed certificate is being used
sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"/>");
}
// Include available SASL Mechanisms // Include available SASL Mechanisms
sb.append(SASLAuthentication.getSASLMechanisms(session)); sb.append(SASLAuthentication.getSASLMechanisms(session));
sb.append("</stream:features>"); sb.append("</stream:features>");
...@@ -273,6 +277,10 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -273,6 +277,10 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
*/ */
public void addValidatedDomain(String domain) { public void addValidatedDomain(String domain) {
if (validatedDomains.add(domain)) { if (validatedDomains.add(domain)) {
// Set the first validated domain as the address of the session
if (validatedDomains.size() < 2) {
setAddress(new JID(null, domain, null));
}
// Register the new validated domain for this server session in SessionManager // Register the new validated domain for this server session in SessionManager
SessionManager.getInstance().registerIncomingServerSession(domain, this); SessionManager.getInstance().registerIncomingServerSession(domain, this);
} }
...@@ -329,12 +337,28 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -329,12 +337,28 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming
} }
public String getAvailableStreamFeatures() { public String getAvailableStreamFeatures() {
StringBuilder sb = new StringBuilder();
// Include Stream Compression Mechanism // Include Stream Compression Mechanism
if (conn.getCompressionPolicy() != Connection.CompressionPolicy.disabled && if (conn.getCompressionPolicy() != Connection.CompressionPolicy.disabled &&
!conn.isCompressed()) { !conn.isCompressed()) {
return "<compression xmlns=\"http://jabber.org/features/compress\"><method>zlib</method></compression>"; sb.append("<compression xmlns=\"http://jabber.org/features/compress\"><method>zlib</method></compression>");
} }
// Nothing special to add // Offer server dialback if using self-signed certificaftes and no authentication has been done yet
return null; boolean usingSelfSigned = false;
Certificate[] certificates = conn.getLocalCertificates();
for (Certificate certificate : certificates) {
try {
if (CertificateManager
.isSelfSignedCertificate(SSLConfig.getKeyStore(), (X509Certificate) certificate)) {
usingSelfSigned = true;
}
} catch (Exception e) {
// Ignore
}
}
if (usingSelfSigned && ServerDialback.isEnabledForSelfSigned() && validatedDomains.isEmpty()) {
sb.append("<dialback xmlns=\"urn:xmpp:features:dialback\"/>");
}
return sb.toString();
} }
} }
...@@ -237,8 +237,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -237,8 +237,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
//useTLS = configuration.isTLSEnabled(); //useTLS = configuration.isTLSEnabled();
} }
if (useTLS) { // Connect to remote server using XMPP 1.0 (TLS + SASL EXTERNAL or TLS + server dialback or server dialback)
// Connect to remote server using TLS + SASL
SocketConnection connection = null; SocketConnection connection = null;
String realHostname = null; String realHostname = null;
int realPort = port; int realPort = port;
...@@ -269,6 +268,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -269,6 +268,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
// Send the stream header // Send the stream header
StringBuilder openingStream = new StringBuilder(); StringBuilder openingStream = new StringBuilder();
openingStream.append("<stream:stream"); openingStream.append("<stream:stream");
openingStream.append(" xmlns:db=\"jabber:server:dialback\"");
openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\""); openingStream.append(" xmlns:stream=\"http://etherx.jabber.org/streams\"");
openingStream.append(" xmlns=\"jabber:server\""); openingStream.append(" xmlns=\"jabber:server\"");
openingStream.append(" to=\"").append(hostname).append("\""); openingStream.append(" to=\"").append(hostname).append("\"");
...@@ -289,6 +289,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -289,6 +289,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
} }
String serverVersion = xpp.getAttributeValue("", "version"); String serverVersion = xpp.getAttributeValue("", "version");
String id = xpp.getAttributeValue("", "id");
// Check if the remote server is XMPP 1.0 compliant // Check if the remote server is XMPP 1.0 compliant
if (serverVersion != null && decodeVersion(serverVersion)[0] >= 1) { if (serverVersion != null && decodeVersion(serverVersion)[0] >= 1) {
...@@ -296,8 +297,9 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -296,8 +297,9 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
socket.setSoTimeout(soTimeout); socket.setSoTimeout(soTimeout);
// Get the stream features // Get the stream features
Element features = reader.parseDocument().getRootElement(); Element features = reader.parseDocument().getRootElement();
if (features != null) {
// Check if TLS is enabled // Check if TLS is enabled
if (features != null && features.element("starttls") != null) { if (useTLS && features.element("starttls") != null) {
// Secure the connection with TLS and authenticate using SASL // Secure the connection with TLS and authenticate using SASL
LocalOutgoingServerSession answer; LocalOutgoingServerSession answer;
answer = secureAndAuthenticate(hostname, connection, reader, openingStream, answer = secureAndAuthenticate(hostname, connection, reader, openingStream,
...@@ -308,6 +310,25 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -308,6 +310,25 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
return answer; return answer;
} }
} }
// Check if we are going to try server dialback (XMPP 1.0)
else if (ServerDialback.isEnabled() && features.element("dialback") != null) {
Log.debug("LocalOutgoingServerSession: OS - About to try connecting using server dialback XMPP 1.0 with: " + hostname);
ServerDialback method = new ServerDialback(connection, domain);
OutgoingServerSocketReader newSocketReader = new OutgoingServerSocketReader(reader);
if (method.authenticateDomain(newSocketReader, domain, hostname, id)) {
Log.debug("LocalOutgoingServerSession: OS - SERVER DIALBACK XMPP 1.0 with " + hostname + " was successful");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(domain, connection, newSocketReader, streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, hostname, null));
return session;
}
else {
Log.debug("LocalOutgoingServerSession: OS - Error, SERVER DIALBACK with " + hostname + " failed");
}
}
}
else { else {
Log.debug("LocalOutgoingServerSession: OS - Error, <starttls> was not received"); Log.debug("LocalOutgoingServerSession: OS - Error, <starttls> was not received");
} }
...@@ -343,10 +364,10 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -343,10 +364,10 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
connection.close(); connection.close();
} }
} }
}
if (ServerDialback.isEnabled()) { if (ServerDialback.isEnabled()) {
Log.debug("LocalOutgoingServerSession: OS - Going to try connecting using server dialback with: " + hostname); Log.debug("LocalOutgoingServerSession: OS - Going to try connecting using server dialback with: " + hostname);
// Use server dialback over a plain connection // Use server dialback (pre XMPP 1.0) over a plain connection
return new ServerDialback().createOutgoingSession(domain, hostname, port); return new ServerDialback().createOutgoingSession(domain, hostname, port);
} }
return null; return null;
...@@ -380,9 +401,11 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -380,9 +401,11 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) { for (int eventType = xpp.getEventType(); eventType != XmlPullParser.START_TAG;) {
eventType = xpp.next(); eventType = xpp.next();
} }
// Get the stream ID
String id = xpp.getAttributeValue("", "id");
// Get new stream features // Get new stream features
features = reader.parseDocument().getRootElement(); features = reader.parseDocument().getRootElement();
if (features != null && features.element("mechanisms") != null) { if (features != null && (features.element("mechanisms") != null || features.element("dialback") != null)) {
// Check if we can use stream compression // Check if we can use stream compression
String policyName = JiveGlobals.getProperty("xmpp.server.compression.policy", String policyName = JiveGlobals.getProperty("xmpp.server.compression.policy",
Connection.CompressionPolicy.disabled.toString()); Connection.CompressionPolicy.disabled.toString());
...@@ -444,6 +467,9 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -444,6 +467,9 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
} }
} }
// Skip SASL EXTERNAL and use server dialback over TLS when using self-signed certificates
boolean dialbackOffered = features.element("dialback") != null;
if (!dialbackOffered || !connection.isUsingSelfSignedCertificate()) {
Iterator it = features.element("mechanisms").elementIterator(); Iterator it = features.element("mechanisms").elementIterator();
while (it.hasNext()) { while (it.hasNext()) {
Element mechanism = (Element) it.next(); Element mechanism = (Element) it.next();
...@@ -464,7 +490,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -464,7 +490,7 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
// SASL authentication was successful so create new // SASL authentication was successful so create new
// OutgoingServerSession // OutgoingServerSession
String id = xpp.getAttributeValue("", "id"); id = xpp.getAttributeValue("", "id");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id); StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(domain, LocalOutgoingServerSession session = new LocalOutgoingServerSession(domain,
connection, new OutgoingServerSocketReader(reader), streamID); connection, new OutgoingServerSocketReader(reader), streamID);
...@@ -482,10 +508,32 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing ...@@ -482,10 +508,32 @@ public class LocalOutgoingServerSession extends LocalSession implements Outgoing
} }
} }
} }
Log.debug("LocalOutgoingServerSession: OS - Error, EXTERNAL SASL was not offered by " + hostname); }
// Check if server dialback (over TLS) was offered
if (dialbackOffered && (ServerDialback.isEnabled() || ServerDialback.isEnabledForSelfSigned())) {
Log.debug("LocalOutgoingServerSession: OS - About to try connecting using server dialback over TLS with: " + hostname);
ServerDialback method = new ServerDialback(connection, domain);
OutgoingServerSocketReader newSocketReader = new OutgoingServerSocketReader(reader);
if (method.authenticateDomain(newSocketReader, domain, hostname, id)) {
Log.debug("LocalOutgoingServerSession: OS - SERVER DIALBACK OVER TLS with " + hostname + " was successful");
StreamID streamID = new BasicStreamIDFactory().createStreamID(id);
LocalOutgoingServerSession session = new LocalOutgoingServerSession(domain, connection, newSocketReader, streamID);
connection.init(session);
// Set the hostname as the address of the session
session.setAddress(new JID(null, hostname, null));
return session;
}
else {
Log.debug("LocalOutgoingServerSession: OS - Error, SERVER DIALBACK with " + hostname + " failed");
}
}
else {
Log.debug("LocalOutgoingServerSession: OS - Error, EXTERNAL SASL and SERVER DIALBACK were not offered by " + hostname);
}
} }
else { else {
Log.debug("LocalOutgoingServerSession: OS - Error, no SASL mechanisms were offered by " + hostname); Log.debug("LocalOutgoingServerSession: OS - Error, no SASL mechanisms or SERVER DIALBACK were offered by " + hostname);
} }
} }
else { else {
......
...@@ -335,4 +335,16 @@ public abstract class LocalSession implements Session { ...@@ -335,4 +335,16 @@ public abstract class LocalSession implements Session {
answer[1] = Integer.parseInt(versionString[1]); answer[1] = Integer.parseInt(versionString[1]);
return answer; return answer;
} }
/**
* Returns true if the other peer of this session presented a self-signed certificate. When
* using self-signed certificate for server-2-server sessions then SASL EXTERNAL will not be
* used and instead server-dialback will be preferred for vcerifying the identify of the remote
* server.
*
* @return true if the other peer of this session presented a self-signed certificate.
*/
public boolean isUsingSelfSignedCertificate() {
return conn.isUsingSelfSignedCertificate();
}
} }
...@@ -321,6 +321,23 @@ public class CertificateManager { ...@@ -321,6 +321,23 @@ public class CertificateManager {
return certificateChain == null || certificateChain.length == 1; return certificateChain == null || certificateChain.length == 1;
} }
/**
* Returns true if the specified certificate is a self-signed certificate. If the certificate
* was not found in the store then a KeyStoreException is returned.
*
* @param keyStore key store that holds the certificate to verify.
* @param certificate the certificate in the key store.
* @return true if the specified certificate is a self-signed certificate.
* @throws KeyStoreException if an error happens while usign the keystore
*/
public static boolean isSelfSignedCertificate(KeyStore keyStore, X509Certificate certificate) throws KeyStoreException {
String alias = keyStore.getCertificateAlias(certificate);
if (alias == null) {
throw new KeyStoreException("Certificate not found in store: " + certificate);
}
return isSelfSignedCertificate(keyStore, alias);
}
/** /**
* Returns true if the specified certificate is ready to be signed by a Certificate Authority. Self-signed * Returns true if the specified certificate is ready to be signed by a Certificate Authority. Self-signed
* certificates need to get their issuer information entered to be able to generate a Certificate * certificates need to get their issuer information entered to be able to generate a Certificate
......
...@@ -12,11 +12,12 @@ ...@@ -12,11 +12,12 @@
<%@ page import="org.jivesoftware.openfire.Connection, <%@ page import="org.jivesoftware.openfire.Connection,
org.jivesoftware.openfire.ConnectionManager, org.jivesoftware.openfire.ConnectionManager,
org.jivesoftware.openfire.XMPPServer, org.jivesoftware.openfire.XMPPServer,
org.jivesoftware.openfire.server.ServerDialback,
org.jivesoftware.openfire.session.LocalClientSession, org.jivesoftware.openfire.session.LocalClientSession,
org.jivesoftware.util.JiveGlobals, org.jivesoftware.util.JiveGlobals"
org.jivesoftware.util.ParamUtils"
errorPage="error.jsp" errorPage="error.jsp"
%> %>
<%@ page import="org.jivesoftware.util.ParamUtils" %>
<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %> <%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %> <%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
String serverSecurityRequired = ParamUtils.getParameter(request, "serverSecurityRequired"); String serverSecurityRequired = ParamUtils.getParameter(request, "serverSecurityRequired");
String dialback = ParamUtils.getParameter(request, "dialback"); String dialback = ParamUtils.getParameter(request, "dialback");
String server_tls = ParamUtils.getParameter(request, "server_tls"); String server_tls = ParamUtils.getParameter(request, "server_tls");
boolean selfSigned = ParamUtils.getBooleanParameter(request, "selfSigned");
if (update) { if (update) {
if ("req".equals(clientSecurityRequired)) { if ("req".equals(clientSecurityRequired)) {
...@@ -107,6 +109,7 @@ ...@@ -107,6 +109,7 @@
JiveGlobals.setProperty("xmpp.server.tls.enabled", "false"); JiveGlobals.setProperty("xmpp.server.tls.enabled", "false");
} }
} }
ServerDialback.setEnabledForSelfSigned(selfSigned);
success = true; success = true;
// Log the event // Log the event
webManager.logEvent("updated SSL configuration", "xmpp.server.dialback.enabled = "+JiveGlobals.getProperty("xmpp.server.dialback.enabled")+"\nxmpp.server.tls.enabled = "+JiveGlobals.getProperty("xmpp.server.tls.enabled")); webManager.logEvent("updated SSL configuration", "xmpp.server.dialback.enabled = "+JiveGlobals.getProperty("xmpp.server.dialback.enabled")+"\nxmpp.server.tls.enabled = "+JiveGlobals.getProperty("xmpp.server.tls.enabled"));
...@@ -152,6 +155,7 @@ ...@@ -152,6 +155,7 @@
dialback = dialbackEnabled ? "available" : "notavailable"; dialback = dialbackEnabled ? "available" : "notavailable";
server_tls = "notavailable"; server_tls = "notavailable";
} }
selfSigned = ServerDialback.isEnabledForSelfSigned();
%> %>
<html> <html>
...@@ -380,6 +384,16 @@ ...@@ -380,6 +384,16 @@
</table> </table>
</td> </td>
</tr> </tr>
<tr valign="middle">
<td width="1%" nowrap>
<input type="checkbox" name="selfSigned" id="cb02" <%= (selfSigned ? "checked" : "") %>>
</td>
<td width="99%">
<label for="rb02">
<fmt:message key="ssl.settings.client.label_self-signed" />
</label>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
......
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