Projects tigase _server server-core Issues #448
SSL socket client certificate not working (#448)
Daniele Ricci opened 10 years ago
Due Date
2015-08-31

I've been trying to use direct SSL connections with Tigase, with EXTERNAL authentication, so a client certificate.

The client certificate is self-signed, so I had to make some "adjustments" to allow it to be used, namely:

https://github.com/kontalk/tigase-server/commit/da739f58495da44f86c2300ab383169fb3170839

https://github.com/kontalk/tigase-server/commit/c850a447d5663d2bcbcaf3ce69f3800866bf1e9a

https://github.com/kontalk/tigase-server/commit/a4d70f8402ba7ca2730ca99735d898cf427a10b5

The last commit is a dirty workaround, try not to look at it :) I will fix that when I will have a working situation.

On connection I have this on client side:

E / MessageCenterService ( 6080): connection error
E / MessageCenterService ( 6080): javax.net.ssl.SSLException: Connection closed by peer
E / MessageCenterService ( 6080):       at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
E / MessageCenterService ( 6080):       at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
E / MessageCenterService ( 6080):       at com.android.org.conscrypt.OpenSSLSocketImpl$SSLInputStream.<init>(OpenSSLSocketImpl.java:661)
E / MessageCenterService ( 6080):       at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:632)

As you can see I'm using Android, however, even openssl s_client utility fails with unknown error:

3073992380:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:

Server is (if you'd like to try) beta.kontalk.net listening for direct SSL on ports 443, 5223, 8443.

Connection with STARTTLS works perfectly.

Artur Hefczyc commented 10 years ago

My suggestion is not to use legacy SSL connections. I say this in relation to this and other bug reports. The legacy SSL has many disadvantages and TLS has many advantages, so I would avoid using SSL whenever possible.

Daniele Ricci commented 10 years ago

Artur Hefczyc wrote:

My suggestion is not to use legacy SSL connections. I say this in relation to this and other bug reports. The legacy SSL has many disadvantages and TLS has many advantages, so I would avoid using SSL whenever possible.

I have the need to connect via HTTPS CONNECT for corporate proxies, and this is not possible with STARTTLS.

Artur Hefczyc commented 10 years ago

Indeed, if you use HTTP than SSL is the only option right now.

Bartosz, please take a look at the problem. What would be the best way to handle this?

Daniele Ricci commented 10 years ago

Is there any way I can help with this? Maybe some SSL debug log you need or any other kind of test I could make?

Bartosz Małkowski commented 10 years ago

I don't understand your first commit.

You can use SASL EXTERNAL but first it must be configured properly

http://docs.tigase.org/tigase-server/7.0.0/Administration_Guide/webhelp/_configuration_sasl_external.html

Daniele Ricci commented 10 years ago

Bartosz Malkowski wrote:

I don't understand your first commit.

You can use SASL EXTERNAL but first it must be configured properly

http://docs.tigase.org/tigase-server/7.0.0/Administration_Guide/webhelp/_configuration_sasl_external.html

Certificates I use in Kontalk are self-signed. They are later checked during SASL auth through other processes (they use a special X.509 extension). By the way is there some cleaner method to accept self-signed certificates in Tigase without patching the code?

Daniele Ricci commented 10 years ago

Guys do you mind reassigning this to the proper person? I don't want to stop notifications because of a single ticket :)

Daniele Ricci commented 10 years ago

Ok I think I know what is happening here.

As soon as the SSL connection goes through, ClientConnectionManager.tlsHandshakeCompleted is called, which is given the task to build the CLIENT_AUTH command for the SessionManager to authenticate the connection.

However:

String id = (String) serv.getSessionData().get(IOService.SESSION_ID_KEY);

A session ID doesn't exist yet, because the stream hasn't been opened yet. If I try to make one and make the method build a correct CLIENT_AUTH command, look what happens in the SessionManager:

2015-06-23 11:02:21.857 [in_5-sess-man]    AbstractMessageReceiver$QueueListener.run()  SEVERE: [in_5-sess-man] Exception during packet processing: from=null, to=null, DATA=<iq id="ssl_85f9a118-f263-4fd2-9d78-40b830f64ffb" from="ws2s@dricci.atos.net/127.0.0.1_5290_127.0.0.1_49090" to="sess-man@dricci.atos.net" type="get"><command xmlns="http://jabber.org/protocol/commands" node="GETFEATURES"/></iq>, SIZE=228, XMLNS=null, PRIORITY=HIGH, PERMISSION=NONE, TYPE=get
java.lang.NullPointerException
        at tigase.server.xmppsession.SessionManager.processCommand(SessionManager.java:1324)
        at tigase.server.xmppsession.SessionManager.processPacket(SessionManager.java:503)
        at tigase.server.AbstractMessageReceiver$QueueListener.run(AbstractMessageReceiver.java:1424)

Because of course SessionManager.connectionsByFrom is still empty - no actual stream has been opened yet, we just completed SSL handshake.

I discovered this while I was experimenting with BOSH and WebSockets in SSL mode, same issue when using direct SSL sockets.

How can we fix this? CLIENT_AUTH command should be sent after the stream has been opened, otherwise stream features will not have SASL EXTERNAL and the client will not use client certificate authentication (forcing SASL EXTERNAL doesn't work either because the connection was not filled in with certificate information, which happens in the CLIENT_AUTH handler).

Daniele Ricci commented 10 years ago

I did a quick test for a workaround by adding a call to:

tlsHandshakeCompleted(serv);

in ClientConnectionManager.xmppStreamOpened, client certificate authentication is now working.

Also, a check against a null id in tlsHandshakeCompleted is needed to avoid triggering a NullPointerException which will cause the connection to force stop.

Now we need to know if we can call tlsHandshakeCompleted or not. Should I just check the socket type? What do you suggest? I'm eager to prepare a patch for this :)

Bartosz Małkowski commented 10 years ago

Fixed I hope :-)

Daniele Ricci commented 10 years ago

Thanks Bartosz, however I think two more pieces are missing.

https://github.com/kontalk/tigase-server/commit/c850a447d5663d2bcbcaf3ce69f3800866bf1e9a

This commit is required to create a correct SSL context with a configured trust manager. I think this commit can be used as-is.

https://github.com/kontalk/tigase-server/commit/a4d70f8402ba7ca2730ca99735d898cf427a10b5

This is a hack I had to introduce to call XMPPIOService.setX509TrustManagers() also for SSL sockets. Currently, it is only called in STARTTLS code (ClientConnectionManager.processCommand, STARTTLS case). This commit requires modifications because it's a hack that relies on the component name.

Artur Hefczyc commented 9 years ago

Bartek, what is status of this task? Please provide estimate so we know if it can be completed for 7.1.

Daniele Ricci commented 9 years ago

Thanks for merging Bartosz, but I strongly advise to not use this hack:

if ("c2s".equals(getName())) {
    ClientTrustManagerFactory factory = ((ClientConnectionManager) ConnectionManager.this).getClientTrustManagerFactory();
    TrustManager[] x = factory.getManager((XMPPIOService<Object>) serv);
    serv.setX509TrustManagers(x);
}

For a number of reasons that I think you know already :)

I advise creating something like an interface exposing a method to set the X.509 trust manager to be used by the component.

I could even work on that on the short term (like 3-4 days), if the effort is what I think it is.

Andrzej Wójcik (Tigase) commented 9 years ago

Removed dependency on component name

Daniele Ricci commented 9 years ago

Thanks!

issue 1 of 1
Type
Bug
Priority
Major
Assignee
RedmineID
2860
Version
tigase-server-7.1.0
Spent time
4h 30m
Issue Votes (0)
Watchers (0)
Reference
tigase/_server/server-core#448
Please wait...
Page is in error, reload to recover