I’m trying to set up a TLS-only connection but I’m having trouble detecting the failure case.
Specifically, I’m unable to detect when a connection fails due to the presence of a self-signed certificate on the server.
Using smack 3.2.0
Here’s my test application:
package smacktest; import org.jivesoftware.smack.Connection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection; public class SmackTest {
public static void main(String[] args) throws Exception {
ConnectionConfiguration conf = new ConnectionConfiguration("myserver", 5222, "mydomain");
conf.setSecurityMode(ConnectionConfiguration.SecurityMode.required);
conf.setSelfSignedCertificateEnabled(false);
conf.setVerifyChainEnabled(true);
conf.setVerifyRootCAEnabled(true); Connection conn = new XMPPConnection(conf); System.out.println("Connecting...");
conn.connect();
if (conn.isConnected()) {
System.out.println("Connected"); System.out.println("Logging in...");
conn.login("byron", "foobar12", "smacktest");
System.out.println("Login successful"); conn.disconnect();
} else {
System.out.println("Connection failed");
}
}
}
And here’s the output:
Connecting...
javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: root certificate not trusted of [lancelot]
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1649)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:893)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1165)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1149)
at org.jivesoftware.smack.XMPPConnection.proceedTLSReceived(XMPPConnection.java:806)
at org.jivesoftware.smack.PacketReader.parsePackets(PacketReader.java:267)
at org.jivesoftware.smack.PacketReader.access$000(PacketReader.java:43)
at org.jivesoftware.smack.PacketReader$1.run(PacketReader.java:70)
Caused by: java.security.cert.CertificateException: root certificate not trusted of [lancelot]
at org.jivesoftware.smack.ServerTrustManager.checkServerTrusted(ServerTrustManager.java:144)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1198)
... 11 more
Connected
Logging in...
Exception in thread "main" No response from the server.: at org.jivesoftware.smack.NonSASLAuthentication.authenticate(NonSASLAuthentication.java:73)
at org.jivesoftware.smack.SASLAuthentication.authenticate(SASLAuthentication.java:352)
at org.jivesoftware.smack.XMPPConnection.login(XMPPConnection.java:203)
at smacktest.SmackTest.main(SmackTest.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) Process finished with exit code 1
Note that my conn.isConnected() guard is passing, despire the (correct) failure to log in connect.
For reference, “myserver” is a secondary box running Openfire 3.7.0 with a self-signed certificate.
Now I do see a work-around here in that I can catch XMPPException on the login call, but I’d really like to fail right on conn.connect()
Am I doing something wrong or have I found a defect?
Edit: I confused login and connect in my description