Smack 4.1.0 X.509 Mutual Authentication

**Context: **Using smack 4.1.0 in client to connect to openfire 3.9.3 server configured with xmpp.client.cert.policy=needed, sasl.mechs=EXTERNAL. Client and server trust set up and appear to authenticate.

Problem: *With a smartcard, the TLS Handshake does not complete on server side. Client performs its CertificateVerify (signed secret and prior messages), ciphersuite and finished messages but server never responds with its own ciphersuite and *finished *messages. Instead I NoResponse Timeouts in SmackException. *

Psuedo-summary*: I will post my code if requested but first I thought I would describe what it’s doing and just post the part of interest.*

  1. Using a test class with main() method.

  2. Create a KeyStore based on softoken (scenario 1) and MSCAPI “Windows-MY” (scenario 2) and initialize with KeyManagerFactory

  3. Use a jssecacerts in %JAVA_HOME%/lib/security truststore (for now)

  4. Use an X509ExtendedKeyManager to select alias (chooseClientAlias() in scenario 2 KeyManager and authenticate with smartcard.

  5. Create a custom SSLContext to initialize my custom KeyManager (array of 1).

  6. Use the XMPPTCPConnectionConfiguration.builder() to construct details of connection including my custom SSLContext and SecurityMode.required

  7. Instantiate an AbstractXMPPTCPConnection using the configuration I build in #6

  8. connect().

  9. disconnect().

Scenario 1*: Softoken (filesystem KeyStore) authentication output*

01:27:46 PM SENT (0): <stream:stream xmlns=‘jabber:client’ to=‘example.com’ xmlns:stream=‘http://etherx.jabber.org/streams’ version=‘1.0’ xml:lang=‘en’>

01:27:46 PM 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=“67bad334” xml:lang=“en” version=“1.0”>stream:featuresEXTERNAL</mecha nisms></stream:features>

01:27:46 PM SENT (0):

01:27:46 PM RECV (0):

01:27:46 PM SENT (0): <stream:stream xmlns=‘jabber:client’ to=‘example.com’ xmlns:stream=‘http://etherx.jabber.org/streams’ version=‘1.0’ xml:lang=‘en’>

01:27:46 PM 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=“67bad334” xml:lang=“en” version=“1.0”>stream:featuresEXTERNAL</mecha nisms>zlib</stream:features>

01:27:46 PM SENT (0):

01:27:46 PM SENT (0): </stream:stream>

Scenario 2*: Smartcard (through Windows-MY) authentication output*

01:34:55 PM SENT (0): <stream:stream xmlns=‘jabber:client’ to=‘example.com’ xmlns:stream=‘http://etherx.jabber.org/streams’ version=‘1.0’ xml:lang=‘en’>

01:34:55 PM 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=“c5d2996e” xml:lang=“en” version=“1.0”>

01:34:55 PM RECV (0): stream:featuresEXTERNAL</mecha nisms></stream:features>

01:34:55 PM SENT (0):

01:34:55 PM RECV (0):

org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s). Used filter: No filter used or filter was ‘null’.

at org.jivesoftware.smack.SmackException$NoResponseException.newWith(SmackExceptio n.java:106)

at org.jivesoftware.smack.SmackException$NoResponseException.newWith(SmackExceptio n.java:85)

at org.jivesoftware.smack.SynchronizationPoint.checkForResponse(SynchronizationPoi nt.java:192)

at org.jivesoftware.smack.SynchronizationPoint.checkIfSuccessOrWait(Synchronizatio nPoint.java:114)

at org.jivesoftware.smack.SynchronizationPoint.checkIfSuccessOrWaitOrThrow(Synchro nizationPoint.java:97)

at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection. java:837)

at org.jivesoftware.smack.AbstractXMPPConnection.connect(AbstractXMPPConnection.ja va:360)

at pke4chat.TestProtoType.main(TestProtoType.java:84)

01:35:00 PM SENT (0):

May 28, 2015 1:35:05 PM org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketWriter shutdown

WARNING: shutdownDone was not marked as successful by the writer thread

org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 5000ms (~5s). Used filter: No filter used or filter was ‘null’.

at org.jivesoftware.smack.SmackException$NoResponseException.newWith(SmackExceptio n.java:106)

at org.jivesoftware.smack.SmackException$NoResponseException.newWith(SmackExceptio n.java:85)

at org.jivesoftware.smack.SynchronizationPoint.checkForResponse(SynchronizationPoi nt.java:192)

at org.jivesoftware.smack.SynchronizationPoint.checkIfSuccessOrWait(Synchronizatio nPoint.java:114)

at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketWriter.shutdown(XMPPTCPConne ction.java:1265)

at org.jivesoftware.smack.tcp.XMPPTCPConnection.shutdown(XMPPTCPConnection.java:49 4)

at org.jivesoftware.smack.tcp.XMPPTCPConnection.shutdown(XMPPTCPConnection.java:47 6)

at org.jivesoftware.smack.AbstractXMPPConnection.disconnect(AbstractXMPPConnection .java:666)

at org.jivesoftware.smack.AbstractXMPPConnection.disconnect(AbstractXMPPConnection .java:646)

at pke4chat.TestProtoType.main(TestProtoType.java:108)

The Big Question: What can be causing the SmackException$NoResponseException?

Stabbing in the dark…

  1. increasing packetReply timeout made no difference

  2. while I wait for any replies (Flow?), I will move my alias selection to a callback handler implementation. Right now it is all coded within the custom KeyManager.

Thanks in advance.

regards,

tt

What can be causing the SmackException$NoResponseException?

That’s easy: The SynchronizationPoint not getting reported as success or failure.

Now the not-so-easy question is: Why isn’t it marked as success or failure? It’s hard to give a definitive answer with the information you provided. But if we assume that you run into the and , then it appears as if SSLSocket.startHandshake() does not complete nor throws an exception.

Thanks for the reply. I was reading through the XMPPTCPConnection class and saw that very thing. The SynchronizationPoint appears to be saslFeaturesReceived. I am thinking that I need to encapsulate the TLS custom context inside a SASLExternalMechanism authenticateInternal() method. Sound like a possible solution?

Sound like a possible solution?
No it does not.

The understanding lack I have about this is the SASL dependence. Since the spec says that features are negotiated after TLS is established and my handshake debug shows completion on the client side, it looks like my server side is simply not completing its part (last cipher suite and “finished” msg).

So do I need to customize my server AuthProvider first? I thought the server may have been waiting for my client to answer the feature negotiation (e.g. EXTERNAL and no compression). I also thought I would just get a failed authentication after a completed handshake.

I thought the server may have been waiting for my client to answer the feature negotiation (e.g. EXTERNAL and no compression).
Waiting until it completes the TLS handshake? No, RFC 6120 states that both sides have to negotiate TLS after the sequence.

I also thought I would just get a failed authentication after a completed handshake.
But you said the TLS handshake does not complete.

It appears you need to debug why the server does not complete the handshake. While I can’t rule out an bug in Smack, it appears to be, at least partly, an server issue. I also have reports of people using SASL EXTERNAL successfully with Smack 4.1.

Is it possible that more than one thread could be using my socket? I would think the handshake should block to allow user to select a certificate (alias) and certainly for them to enter pin. I can actually “race” to make the server complete the handshake by selecting a softtoken credential in the Windows-MY store which does not need to prompt me.

…(trimmed)

*** CertificateVerify

Signature Algorithm SHA512withRSA

Smack Packet Reader (0), WRITE: TLSv1.2 Handshake, length = 264

Smack Packet Reader (0), WRITE: TLSv1.2 Change Cipher Spec, length = 1

*** Finished

verify_data: { 95, 166, 191, 75, 192, 246, 247, 229, 74, 47, 57, 16 }


Smack Packet Reader (0), WRITE: TLSv1.2 Handshake, length = 80

Smack Packet Reader (0), READ: TLSv1.2 Change Cipher Spec, length = 1

Smack Packet Reader (0), READ: TLSv1.2 Handshake, length = 80

*** Finished

verify_data: { 37, 44, 63, 126, 226, 184, 128, 28, 245, 94, 81, 50 }


%% Cached client session: [Session-1, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256]

11:38:00 AM SENT (0): <stream:stream xmlns=‘jabber:client’ to=‘steerage.adnet.smil.mil’ xmlns:stream=‘http://etherx.jabber.org/streams’ version=‘1.0’ xml:lang=‘en’>

Smack Packet Writer (0), WRITE: TLSv1.2 Application Data, length = 192

Smack Packet Reader (0), READ: TLSv1.2 Application Data, length = 592

11:38:00 AM RECV (0): <?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream=“http://etherx.jabber.org/streams” xmlns=“jabber:client” from=“steerage.adnet.smil.mil” id=“ec3e2d2f” xml:lang=“en” version=“1.0”>stream:featuresEXTERNAL</mecha nisms>zlib</stream:features>

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

@@@@@@@ PROTOTYPE: Noted as secured. @@@@@@@

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

11:38:00 AM SENT (0):

Smack Packet Writer (0), WRITE: TLSv1.2 Application Data, length = 256

11:38:00 AM SENT (0): </stream:stream>

Smack Packet Writer (0), WRITE: TLSv1.2 Application Data, length = 80

Smack Packet Writer (0), called close()

Smack Packet Writer (0), called closeInternal(true)

Smack Packet Writer (0), SEND TLSv1.2 ALERT: warning, description = close_notify

Smack Packet Writer (0), WRITE: TLSv1.2 Alert, length = 64

Smack Packet Writer (0), called closeSocket(true)

Smack Packet Reader (0), handling exception: java.net.SocketException: Socket closed

%% Invalidated: [Session-1, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256]

Smack Packet Reader (0), called closeSocket()

main, called close()

main, called closeInternal(true)

Seems to get to my disconnect() just fine (because I hurry and get the certificate authentication done)! The SynchronizationPoint, saslFeatureReceived, is met by the bold, right? This seems like a race condition; select cert and enter pin to complete handshake; saslFeatureReceived can’t get set to true until after handshake is complete; handshake must complete by timeout. Timeout does not seem to include user interaction (select cert and pin entry). The problem does not seem to be the server but that the handshake does not block for input from user.

What am I missing? What can I provide to clarify?