Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,19 @@
import org.jivesoftware.openfire.session.DomainPair;
import org.jivesoftware.openfire.session.LocalOutgoingServerSession;
import org.jivesoftware.openfire.spi.ConnectionConfiguration;
import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateRevokedException;
import java.security.cert.X509Certificate;
import java.time.Duration;

/**
Expand Down Expand Up @@ -128,14 +131,30 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc
return;
}

if (!ServerDialback.isEnabled() && !ServerDialback.isEnabledForSelfSigned()) {
if (!ServerDialback.isEnabled()) {
Log.warn("As peer's certificates are not valid for its domain ('{}'), the SASL EXTERNAL authentication mechanism cannot be used. The Server Dialback authentication mechanism is disabled by configuration. Aborting session, as this leaves no available authentication mechanisms.", domainPair.getRemote());
stanzaHandler.setSession(null);
stanzaHandler.setAttemptedAllAuthenticationMethods();
ctx.channel().close();
return;
}

boolean usingSelfSigned;
final Certificate[] chain = connection.getPeerCertificates();
if (chain == null || chain.length == 0) {
usingSelfSigned = true;
} else {
usingSelfSigned = CertificateManager.isSelfSignedCertificate((X509Certificate) chain[0]);
}

if (usingSelfSigned && !ServerDialback.isEnabledForSelfSigned()) {
Log.warn("As peer's certificates are not valid for its domain ('{}'), the SASL EXTERNAL authentication mechanism cannot be used. The peer uses a selfsigned certificate and the Server Dialback authentication mechanism is not enabled for selfsigned certificate. Aborting session, as this leaves no available authentication mechanisms.", domainPair.getRemote());
stanzaHandler.setSession(null);
stanzaHandler.setAttemptedAllAuthenticationMethods();
ctx.channel().close();
return;
}

// If TLS cannot be used for authentication, it is permissible to use another authentication mechanism
// such as dialback. RFC 6120 does not explicitly allow this, as it does not take into account any other
// authentication mechanism other than TLS (it does mention dialback in an interoperability note. However,
Expand All @@ -144,7 +163,7 @@ public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exc
// keys [XEP-0220] are used." In short: if Dialback is allowed, unauthenticated TLS is better than no TLS.

Log.warn("As peer's certificates are not valid for its domain ('{}'), the SASL EXTERNAL authentication mechanism cannot be used. The Server Dialback authentication mechanism is available.", domainPair.getRemote());

sendNewStreamHeader(connection);
connection.setEncrypted(true);
ctx.fireChannelActive();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.jivesoftware.openfire.server.ServerDialbackErrorException;
import org.jivesoftware.openfire.server.ServerDialbackKeyInvalidException;
import org.jivesoftware.util.CertificateManager;
import org.jivesoftware.util.JiveGlobals;
import org.jivesoftware.util.StreamErrorException;
import org.jivesoftware.util.StringUtils;
import org.slf4j.Logger;
Expand Down Expand Up @@ -194,7 +195,7 @@ public static LocalIncomingServerSession createSession(String serverName, XmlPul

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
// after TLS has been negotiated
final Element dialback = DocumentHelper.createElement(QName.get("dialback", "urn:xmpp:features:dialback"));
dialback.addElement("errors");
features.add(dialback);
Expand Down Expand Up @@ -432,18 +433,25 @@ public List<Element> getAvailableStreamFeatures()
}

// Offer server dialback if using self-signed certificates and no authentication has been done yet
boolean usingSelfSigned;
final Certificate[] chain = conn.getLocalCertificates();
if (chain == null || chain.length == 0) {
usingSelfSigned = true;
} else {
usingSelfSigned = CertificateManager.isSelfSignedCertificate((X509Certificate) chain[0]);
}

if (usingSelfSigned && ServerDialback.isEnabledForSelfSigned() && validatedDomains.isEmpty()) {
final Element dialback = DocumentHelper.createElement(QName.get("dialback", "urn:xmpp:features:dialback"));
dialback.addElement("errors");
result.add(dialback);
// Also offer dialback if strict certificate validation is not set (fallback if SASL EXTERNAL fails), as per XEP-0178 section 3.9
if (ServerDialback.isEnabled()) {
boolean usingSelfSigned;
final Certificate[] chain = conn.getLocalCertificates();
if (chain == null || chain.length == 0) {
usingSelfSigned = true;
} else {
usingSelfSigned = CertificateManager.isSelfSignedCertificate((X509Certificate) chain[0]);
}

boolean offerDialback = !JiveGlobals.getBooleanProperty(ConnectionSettings.Server.STRICT_CERTIFICATE_VALIDATION, true);

if ((usingSelfSigned && ServerDialback.isEnabledForSelfSigned()) || offerDialback) {
if (validatedDomains.isEmpty()) {
final Element dialback = DocumentHelper.createElement(QName.get("dialback", "urn:xmpp:features:dialback"));
dialback.addElement("errors");
result.add(dialback);
}
}
}

if (!ConnectionSettings.Server.STREAM_LIMITS_ADVERTISEMENT_DISABLED.getValue()) {
Expand Down