Commit 4c528c9d authored by Dave Cridland's avatar Dave Cridland

Support Dialback Without Dialback

When processing a <db:result/>, this checks for the certificate first. If
this matches, then we don't bother actually dialling back, speeding up the
session setup.

This factors out the certificate verification function.
parent 026c3f2f
......@@ -528,29 +528,14 @@ public class SASLAuthentication {
if (!verify) {
authenticationSuccessful(session, hostname, null);
return Status.authenticated;
}
// Check that hostname matches the one provided in a certificate
Connection connection = session.getConnection();
try {
X509Certificate trusted = CertificateManager.getEndEntityCertificate(connection.getPeerCertificates(), SSLConfig.getKeyStore(), SSLConfig.gets2sTrustStore());
if (trusted != null) {
for (String identity : CertificateManager.getPeerIdentities(trusted)) {
// Verify that either the identity is the same as the hostname, or for wildcarded
// identities that the hostname ends with .domainspecified or -is- domainspecified.
if ((identity.startsWith("*.")
&& (hostname.endsWith(identity.replace("*.", "."))
|| hostname.equals(identity.replace("*.", ""))))
|| hostname.equals(identity)) {
authenticationSuccessful(session, hostname, null);
return Status.authenticated;
}
}
} else if(verifyCertificates(session.getConnection().getPeerCertificates(), hostname)) {
authenticationSuccessful(session, hostname, null);
LocalIncomingServerSession s = (LocalIncomingServerSession)session;
if (s != null) {
s.tlsAuth();
}
} catch(IOException e) {
/// Keystore problem.
return Status.authenticated;
}
}
else if (session instanceof LocalClientSession) {
// Client EXTERNALL login
......@@ -618,6 +603,28 @@ public class SASLAuthentication {
return Status.failed;
}
public static boolean verifyCertificates(Certificate[] chain, String hostname) {
try {
X509Certificate trusted = CertificateManager.getEndEntityCertificate(chain, SSLConfig.getKeyStore(), SSLConfig.gets2sTrustStore());
if (trusted != null) {
for (String identity : CertificateManager.getPeerIdentities(trusted)) {
// Verify that either the identity is the same as the hostname, or for wildcarded
// identities that the hostname ends with .domainspecified or -is- domainspecified.
if ((identity.startsWith("*.")
&& (hostname.endsWith(identity.replace("*.", "."))
|| hostname.equals(identity.replace("*.", ""))))
|| hostname.equals(identity)) {
return true;
}
}
}
} catch(IOException e) {
Log.warn("Keystore issue while verifying certificate chain: {}", e.getMessage());
}
return false;
}
private static Status doSharedSecretAuthentication(LocalSession session, Element doc)
throws UnsupportedEncodingException
{
......@@ -686,6 +693,7 @@ public class SASLAuthentication {
// Add the validated domain as a valid domain. The remote server can
// now send packets from this address
((LocalIncomingServerSession) session).addValidatedDomain(hostname);
Log.info("Inbound Server {} authenticated (via TLS)", username);
}
}
......
......@@ -44,6 +44,7 @@ import org.jivesoftware.openfire.XMPPServer;
import org.jivesoftware.openfire.auth.AuthFactory;
import org.jivesoftware.openfire.net.DNSUtil;
import org.jivesoftware.openfire.net.MXParser;
import org.jivesoftware.openfire.net.SASLAuthentication;
import org.jivesoftware.openfire.net.ServerTrafficCounter;
import org.jivesoftware.openfire.net.SocketConnection;
import org.jivesoftware.openfire.session.ConnectionSettings;
......@@ -534,15 +535,23 @@ public class ServerDialback {
}
}
if (alreadyExists && !sessionManager.isMultipleServerConnectionsAllowed()) {
// Remote server already has a IncomingServerSession created
connection.deliverRawText(
new StreamError(StreamError.Condition.not_authorized).toXML());
// Close the underlying connection
connection.close();
dialbackError(recipient, hostname, new PacketError(PacketError.Condition.resource_constraint, PacketError.Type.cancel, "Incoming session already exists"));
Log.debug("ServerDialback: RS - Error, incoming connection already exists from: " + hostname);
return false;
}
else {
if (SASLAuthentication.verifyCertificates(connection.getPeerCertificates(), hostname)) {
// If the remote host passes strong auth, just skip the dialback.
Log.debug("ServerDialback: RS - Sending key verification result to OS: " + hostname);
sb = new StringBuilder();
sb.append("<db:result");
sb.append(" from=\"").append(recipient).append("\"");
sb.append(" to=\"").append(hostname).append("\"");
sb.append(" type=\"valid\"");
sb.append("/>");
connection.deliverRawText(sb.toString());
return true;
}
String key = doc.getTextTrim();
// Get a list of real hostnames and try to connect using DNS lookup of the specified domain
......
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