Connection issue using TLS

Hello all!

This is my first post here! :slight_smile:

I need help from you for a problem about connection between client and server. It fails most of the time. I tried to use a 30 seconds timeout to no avail.

Expected:
Connect successfully each time when TLS security mode is set to required.
*Note: No problem when security is set to ā€œdisabledā€.

Actual:
Fail like 90% of the time, and throw an exception.
*Note: I donā€™t know why it can connect sometime though!

Version:
Smack 4.4.5 (4.4.5-4.4 2022-03-02).
Openfire 4.1.6

Exception:
org.jivesoftware.smack.SmackException$NoResponseException

Stacktrace:

org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 10000ms (~10s). While waiting for establishing TLS [XMPPTCPConnection[not-authenticated] (0)]
	at org.jivesoftware.smack.SmackException$NoResponseException.newWith(SmackException.java:99) ~[smack-core-4.4.5.jar:4.4.5]
	at org.jivesoftware.smack.AbstractXMPPConnection.waitForConditionOrConnectionException(AbstractXMPPConnection.java:729) ~[smack-core-4.4.5.jar:4.4.5]
	at org.jivesoftware.smack.AbstractXMPPConnection.waitForConditionOrThrowConnectionException(AbstractXMPPConnection.java:734) ~[smack-core-4.4.5.jar:4.4.5]
	at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection.java:857) ~[smack-tcp-4.4.5.jar:4.4.5]
	at org.jivesoftware.smack.AbstractXMPPConnection.connect(AbstractXMPPConnection.java:526) ~[smack-core-4.4.5.jar:4.4.5]

XMPP trace:

15:23:08 SENT (0): 
<stream:stream xmlns='jabber:client' to='example.com' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en-US'>
15:23:08 RECV (0): ?xml version='1.0' encoding='UTF-8'?>
<stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="example.com" id="6y5wexe95i" xml:lang="en-US" version="1.0">
15:23:08 RECV (0): 
<stream:features>
  <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls">
  </starttls>
  <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
    <mechanism>
      PLAIN
    </mechanism>
    <mechanism>
      SCRAM-SHA-1
    </mechanism>
    <mechanism>
      CRAM-MD5
    </mechanism>
    <mechanism>
      DIGEST-MD5
    </mechanism>
  </mechanisms>
  <compression xmlns="http://jabber.org/features/compress">
    <method>
      zlib
    </method>
  </compression>
  <register xmlns="http://jabber.org/features/iq-register"/>
</stream:features>
15:23:08 SENT (0): 
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
15:23:08 RECV (0): 
<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
15:23:08 SENT (0): 
<stream:stream xmlns='jabber:client' to='example.com' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='6y5wexe95i' xml:lang='en-US'>

Code:

SmackConfiguration.setDefaultReplyTimeout(10000);
SmackConfiguration.DEBUG = true;

this.tcpConnection = new XMPPTCPConnection(
	XMPPTCPConnectionConfiguration.builder()
		.setHostAddress(InetAddress.getByName("example.com"))
		.setPort(15222)
		.setXmppDomain(JidCreate.domainBareFrom("example.com"))
		.setSendPresence(false)
		.setCompressionEnabled(true)
		.setSecurityMode(SecurityMode.required)
		.build());

try
{
	this.tcpConnection.connect();
}
catch (Exception ex)
{
	// org.jivesoftware.smack.SmackException$NoResponseException is caught
}
  • Is there some known issues about the communication between a recent version of Smack and an older Openfire version?
  • Can it be something about the version of some dependencies? As far as I know, everything should be okay based on the Maven repository website (https://mvnrepository.com/).
    *Note: I am not using Maven directly to manage them, I do it manually in NetBeans 13 for now.

Thank you
Jonathan

EDIT: Fixed code, there was an error. Passing ā€œexample.comā€ to getByName() now.

Hi Jonathan, welcome! Thanks for your elaborate report.

First, an obligatory side-note: Openfire 4.1.6 is old. You should consider upgrading.

I have tried to reproduce the issue with Smack 4.4.5 and Openfire 4.1.6, but I have failed to do so. Connecting to the server works every time for me, using this code (which is slightly different from yours, more on that below):

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jivesoftware.smack.util.SslContextFactory;
import org.jxmpp.jid.impl.JidCreate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.net.InetAddress;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.time.Duration;

public class TestClientA {
    public static void main(String[] args) throws Exception {

        SmackConfiguration.setDefaultReplyTimeout(10000);
        SmackConfiguration.DEBUG = true;

        XMPPTCPConnection tcpConnection = new XMPPTCPConnection(
                XMPPTCPConnectionConfiguration.builder()
                        .setHostAddress(InetAddress.getByName("example.org"))
                        .setPort(5222)
                        .setXmppDomain(JidCreate.domainBareFrom("example.org"))
                        .setSendPresence(false)
                        .setCompressionEnabled(true)
                        .setSecurityMode(ConnectionConfiguration.SecurityMode.required)
                        .setSslContextFactory(getSslContextFactory())
                        .setCustomX509TrustManager(new DummyTrustManager())
                        .build());


        tcpConnection.connect();
        Thread.sleep(Duration.ofSeconds(2).toMillis());
        tcpConnection.disconnect();
    }

    private static SslContextFactory getSslContextFactory() {
        return () -> {
            try {
                final SSLContext result = SSLContext.getInstance("SSL");
                result.init(null, new TrustManager[]{new DummyTrustManager()}, new SecureRandom());
                return result;
            } catch (Exception e) {
                throw new RuntimeException("can't init SSL Context.", e);
            }
        };
    }

    private static class DummyTrustManager implements X509TrustManager
    {
        public boolean isClientTrusted(X509Certificate[] cert) {
            return true;
        }

        public boolean isServerTrusted(X509Certificate[] cert) {
            return true;
        }

        public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
        }
    }
}

The corresponding debug output is:

11:31:59 SENT (0): 
<stream:stream xmlns='jabber:client' to='example.org' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en-US'>
11:31:59 RECV (0): ?xml version='1.0' encoding='UTF-8'?>
<stream:stream xmlns:strea
11:31:59 RECV (0): m="http://etherx.jabber.org/streams" xmlns="jabber:client" from="example.org" id="3dhbpjj8qq" xml:lang="en-US" version="1.0">
<stream:features>
  <starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls">
  </starttls>
  <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
    <mechanism>
      PLAIN
    </mechanism>
    <mechanism>
      SCRAM-SHA-1
    </mechanism>
    <mechanism>
      CRAM-MD5
    </mechanism>
    <mechanism>
      DIGEST-MD5
    </mechanism>
  </mechanisms>
  <compression xmlns="http://jabber.org/features/compress">
    <method>
      zlib
    </method>
  </compression>
  <register xmlns="http://jabber.org/features/iq-register"/>
</stream:features>
11:31:59 SENT (0): 
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
11:31:59 RECV (0): 
<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
11:31:59 SENT (0): 
<stream:stream xmlns='jabber:client' to='example.org' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' id='3dhbpjj8qq' xml:lang='en-US'>
11:31:59 RECV (0): ?xml version='1.0' encoding='UTF-8'?>
<stream:stream xmlns:strea
11:31:59 RECV (0): m="http://etherx.jabber.org/streams" xmlns="jabber:client" from="example.org" id="3dhbpjj8qq" xml:lang="en-US" version="1.0">
<stream:features>
  <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
    <mechanism>
      PLAIN
    </mechanism>
    <mechanism>
      SCRAM-SHA-1
    </mechanism>
    <mechanism>
      CRAM-MD5
    </mechanism>
    <mechanism>
      DIGEST-MD5
    </mechanism>
  </mechanisms>
  <compression xmlns="http://jabber.org/features/compress">
    <method>
      zlib
    </method>
  </compression>
  <register xmlns="http://jabber.org/features/iq-register"/>
</stream:features>
11:32:01 SENT (0): 
</stream:stream>
Mar 16, 2022 11:32:11 AM org.jivesoftware.smack.AbstractXMPPConnection waitForClosingStreamTagFromServer
INFO: Exception while waiting for closing stream element from the server XMPPTCPConnection[not-authenticated] (0)
org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 10000ms (~10s). While waiting for closing stream tag from the server [XMPPTCPConnection[not-authenticated] (0)]
	at org.jivesoftware.smack.SmackException$NoResponseException.newWith(SmackException.java:99)
	at org.jivesoftware.smack.AbstractXMPPConnection.waitForConditionOrConnectionException(AbstractXMPPConnection.java:729)
	at org.jivesoftware.smack.AbstractXMPPConnection.waitForConditionOrThrowConnectionException(AbstractXMPPConnection.java:734)
	at org.jivesoftware.smack.AbstractXMPPConnection.waitForClosingStreamTagFromServer(AbstractXMPPConnection.java:1021)
	at org.jivesoftware.smack.tcp.XMPPTCPConnection.shutdown(XMPPTCPConnection.java:513)
	at org.jivesoftware.smack.tcp.XMPPTCPConnection.shutdown(XMPPTCPConnection.java:493)
	at org.jivesoftware.smack.AbstractXMPPConnection.disconnect(AbstractXMPPConnection.java:969)
	at org.jivesoftware.smack.AbstractXMPPConnection.disconnect(AbstractXMPPConnection.java:941)
	at TestClientA.main(TestClientA.java:38)

Process finished with exit code 0

Note that the stack trace that is reported is different from the problem that you have. It is generated by the disconnect, not the connect. It is caused by a bug in Openfire that has been fixed in newer versions.

From the information that you are providing, it seems that Smack is timing out when waiting for the new stream to be opened by the server after TLS has been established. This is indicated by both the stack trace, as well as the dump of the XMPP traffic that ā€˜stopsā€™ there.

When I tried to reproduce the issue, I could not quite get your code to run, without also adding a SslContextFactory and CustomerX509TrustManager to have the self-signed certificate of the domain name to validate. You might have replaced your actual domain name with ā€œexample.comā€ in your code. Does your server use a properly-signed certificate (that is recognized by the SSL context that is used for your client)? I have no XMPP domain that uses a proper certificate that is running Openfire 4.1.6, so I canā€™t quite test that.

What is alarming to me is that you do not get consistent results. You would think that TLS either succeeds or fails all the time. You have set a time-out of 10 seconds. What happens if you boost that to something very high? Does your success rate go up?

My advice would be to analyze the logs on the server for more clues.

If the XMPP log ends here, then it really looks, like Guus already said, that the server is not sending its stream open tag as response to the client (Smack) doing so.

Hi @guus,

Thanks for your test! I will answer some of your questions below.

Yes, we will upgrade to the latest version on our development server. We completed some tests before just in caseā€¦ Iā€™ll let you know if it fixes my problems.

Yes! And I confirm this isnā€™t expired.

Before posting here, I also tried with a factory and a custom impl of X509TrustManager just like you did. The result is exactly the same.

Nope. Like I said in original post, I tried with a 30s timeout, which IMO is enough.

Yep. We are currently reviewing the logs on the server-side thouroughly.

Thank you very much! :slight_smile:

Yes exactly, and we need to find out the reason.

Hello,

I just wanted to do a quick follow-up on this issue. We have upgraded our Openfire server to version 4.7.1 and now the issue disappeared! Each connection is successful! So in our specific setup, there was something about the old Openfire, which was version 4.1.6, versus the Smack 4.4.5 client.

Thanks to all!
Jonathan

1 Like

This topic was automatically closed 62 days after the last reply. New replies are no longer allowed.