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
...@@ -2417,4 +2417,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2417,4 +2417,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2403,4 +2403,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2403,4 +2403,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file 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
......
...@@ -2454,4 +2454,5 @@ setup.clearspace.service.certificate.verify.root_help=Ultimo certificado en la c ...@@ -2454,4 +2454,5 @@ setup.clearspace.service.certificate.verify.root_help=Ultimo certificado en la c
setup.clearspace.service.certificate.verify.validity=Verificar certificado no expirado setup.clearspace.service.certificate.verify.validity=Verificar certificado no expirado
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:
\ No newline at end of file ssl.settings.client.label_self-signed=Aceptar certificados auto-firmados. Server dialback sobre TLS esta habilitado.
\ No newline at end of file
...@@ -2023,4 +2023,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2023,4 +2023,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2550,4 +2550,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2550,4 +2550,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2408,4 +2408,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2408,4 +2408,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2383,4 +2383,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2383,4 +2383,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2417,4 +2417,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2417,4 +2417,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2532,4 +2532,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2532,4 +2532,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file ssl.settings.client.label_self-signed=Accept self-signed certificates. Server dialback over TLS is now available.
\ No newline at end of file
...@@ -2195,4 +2195,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch ...@@ -2195,4 +2195,5 @@ setup.clearspace.service.certificate.verify.root_help=Last certificate in the ch
setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired setup.clearspace.service.certificate.verify.validity=Verify certificate is not expired
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:
\ No newline at end of file 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,8 +131,23 @@ public class SASLAuthentication { ...@@ -132,8 +131,23 @@ 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;
sb.append("<mechanism>EXTERNAL</mechanism>"); 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>");
}
} }
} }
else { else {
...@@ -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,32 +98,25 @@ public class LocalIncomingServerSession extends LocalSession implements Incoming ...@@ -95,32 +98,25 @@ 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);
}
catch (Exception e) {
Log.error("Error establishing connection from remote server", e);
}
} }
else { catch (Exception e) {
connection.deliverRawText( Log.error("Error establishing connection from remote server", e);
new StreamError(StreamError.Condition.invalid_namespace).toXML());
Log.debug("LocalIncomingServerSession: Server TLS is disabled. Rejecting connection: " + connection);
} }
} }
else if (xpp.getNamespace("db") != null) {
// Server is trying to establish connection and authenticate using server dialback (pre XMPP 1.0)
if (ServerDialback.isEnabled()) {
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
connection.close(); connection.close();
...@@ -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>");
sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">"); if (JiveGlobals.getBooleanProperty("xmpp.server.tls.enabled", true)) {
if (!ServerDialback.isEnabled()) { sb.append("<starttls xmlns=\"urn:ietf:params:xml:ns:xmpp-tls\">");
// Server dialback is disabled so TLS is required if (!ServerDialback.isEnabled()) {
sb.append("<required/>"); // Server dialback is disabled so TLS is required
sb.append("<required/>");
}
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\"/>");
} }
sb.append("</starttls>");
// 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();
} }
} }
...@@ -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