SASL subjectAlternateName parsing fails (related to OF-1245)

I’m facing an issue trying to use SASL External with client certificates that have an otherName:1.3.6.1.5.5.7.8.5 SAN. Validation works fine against the common name, but with the SAN certificate OF 4.1.3 responds to the client with “not authorized” and then terminates the SSL session, leaving the client to time out. Fine, the certificate from my hacked-together openssl ca might be wrong in some way. There’s an exception in the debug output, but nothing that tells me why the certificate was rejected:

2017.04.04 08:39:31 org.apache.mina.core.filterchain.IoFilterEvent - Firing a MESSAGE_RECEIVED event for session 505
2017.04.04 08:39:31 org.apache.mina.filter.codec.ProtocolCodecFilter - Processing a MESSAGE_RECEIVED for session 505
2017.04.04 08:39:31 org.apache.mina.filter.ssl.SslFilter - Session Server[505]: Writing Message : WriteRequest: HeapBuffer[pos=0 lim=31 cap=33: 15 03 03 00 1A 00 00 00 00 00 00 00 03 5A B8 A8…]
2017.04.04 08:39:31 org.apache.mina.core.filterchain.IoFilterEvent - Event MESSAGE_RECEIVED has been fired for session 505
2017.04.04 08:39:31 org.apache.mina.filter.ssl.SslHandler - Unexpected exception from SSLEngine.closeInbound().
javax.net.ssl.SSLException: Inbound closed before receiving peer’s close_notify: possible truncation attack?
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1666)
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1634)
at sun.security.ssl.SSLEngineImpl.closeInbound(SSLEngineImpl.java:1561)
at org.apache.mina.filter.ssl.SslHandler.destroy(SslHandler.java:204)
at org.apache.mina.filter.ssl.SslFilter.sessionClosed(SslFilter.java:439)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextSessionClosed(Def aultIoFilterChain.java:382)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$900(DefaultIoFilte rChain.java:47)
at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.sessionClosed (DefaultIoFilterChain.java:750)
at org.apache.mina.core.filterchain.IoFilterAdapter.sessionClosed(IoFilterAdapter. java:88)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextSessionClosed(Def aultIoFilterChain.java:382)
at org.apache.mina.core.filterchain.DefaultIoFilterChain.fireSessionClosed(Default IoFilterChain.java:375)
at org.apache.mina.core.service.IoServiceListenerSupport.fireSessionDestroyed(IoSe rviceListenerSupport.java:244)
at org.apache.mina.core.polling.AbstractPollingIoProcessor.removeNow(AbstractPolli ngIoProcessor.java:600)
at org.apache.mina.core.polling.AbstractPollingIoProcessor.removeSessions(Abstract PollingIoProcessor.java:560)
at org.apache.mina.core.polling.AbstractPollingIoProcessor.access$800(AbstractPoll ingIoProcessor.java:67)
at org.apache.mina.core.polling.AbstractPollingIoProcessor$Processor.run(AbstractP ollingIoProcessor.java:1132)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:64)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
2017.04.04 08:39:31 org.apache.mina.filter.executor.OrderedThreadPoolExecutor - Adding event SESSION_CLOSED to session 505
Queue : [SESSION_CLOSED, ]

This is the client log (using swift; I’ve also tried jitsi with the same result):

<?xml version="1.0"?><stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" to="some-domain.com" version="1.0">
<!-- IN 2017-04-04T10:39:31 -->
<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="some-domain.com" id="auughtiv2k" xml:lang="en" version="1.0">
<!-- IN 2017-04-04T10:39:31 -->
<stream:features><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>EXTERNAL</mechanism></mechanisms></stream:features>
<!-- OUT 2017-04-04T10:39:31 -->
<starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
<!-- IN 2017-04-04T10:39:31 -->
<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
<!-- OUT 2017-04-04T10:39:31 -->
<?xml version="1.0"?><stream:stream xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams" to="some-domain.com" version="1.0">
<!-- IN 2017-04-04T10:39:31 -->
<?xml version='1.0' encoding='UTF-8'?><stream:stream xmlns:stream="http://etherx.jabber.org/streams" xmlns="jabber:client" from="some-domain.com" id="auughtiv2k" xml:lang="en" version="1.0"><stream:features><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><mechanism>EXTERNAL</mechanism></mechanisms><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
<!-- OUT 2017-04-04T10:39:31 -->
<auth xmlns="urn:ietf:params:xml:ns:xmpp-sasl" mechanism="EXTERNAL">=</auth>
<!-- IN 2017-04-04T10:39:31 -->
<failure xmlns="urn:ietf:params:xml:ns:xmpp-sasl"><not-authorized/></failure>
<!-- OUT 2017-04-04T10:39:31 -->
</stream:stream>

This is my test certificate:

Certificate:

Data:

Version: 3 (0x2)

Serial Number: 4096 (0x1000)

Signature Algorithm: sha256WithRSAEncryption

    Issuer: C=De, ST=Some-State, O=some-org, CN=some-domain.com/emailAddress=admin@some-domain.com

Validity

Not Before: Apr 3 15:09:47 2017 GMT

Not After : May 3 15:09:47 2017 GMT

Subject: CN=[drz]

Subject Public Key Info:

Public Key Algorithm: rsaEncryption

Public-Key: (2048 bit)

Modulus:

00:ba:dc:cb:[…]

Exponent: 65537 (0x10001)

X509v3 extensions:

X509v3 Authority Key Identifier:

keyid:5C:37:C6:32:49:14:DE:57:A9:83:89:D8:26:8A:E7:CD:67:24:86:1A

X509v3 Key Usage:

Digital Signature, Key Encipherment

X509v3 Extended Key Usage:

TLS Web Client Authentication

X509v3 Subject Alternative Name:

            othername:<unsupported> [otherName:1.3.6.1.5.5.7.8.5;UTF8:username@some-domain.com]

How can i find out what is wrong with the client certificate that causes this behavior?

Edits: formatting and added Openfire version

Edit: I realised the exception posted above also occurs when an authenticated client disconnects, so it probably has no relation to the certificate being rejected.

digging through the code, it seems to me that org.jivesoftware.util.cert.SANCertificateIdentityMapping.parseOtherNameXmppAddr is failing on my certificate, which explicitly encodes the string as UTF8 as per RFC 6120.

The error message is:

org.jivesoftware.util.cert.SANCertificateIdentityMapping - Unable to parse a byte array (of length 49) as a subjectAltName ‘otherName’. It is ignored.

java.lang.ClassCastException: org.bouncycastle.asn1.DERTaggedObject cannot be cast to org.bouncycastle.asn1.ASN1String

at org.jivesoftware.util.cert.SANCertificateIdentityMapping.parseOtherNameXmppAddr (SANCertificateIdentityMapping.java:213)

at org.jivesoftware.util.cert.SANCertificateIdentityMapping.parseOtherName(SANCert ificateIdentityMapping.java:160)

at org.jivesoftware.util.cert.SANCertificateIdentityMapping.mapIdentity(SANCertifi cateIdentityMapping.java:75)

at org.jivesoftware.util.CertificateManager.getClientIdentities(CertificateManager .java:299)

at org.jivesoftware.openfire.sasl.ExternalClientSaslServer.evaluateResponse(Extern alClientSaslServer.java:77)

at org.jivesoftware.openfire.net.SASLAuthentication.handle(SASLAuthentication.java :324)

at org.jivesoftware.openfire.net.StanzaHandler.process(StanzaHandler.java:182)

at org.jivesoftware.openfire.nio.ConnectionHandler.messageReceived(ConnectionHandl er.java:181)

at org.apache.mina.core.filterchain.DefaultIoFilterChain$TailFilter.messageReceive d(DefaultIoFilterChain.java:690)

at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(D efaultIoFilterChain.java:417)

at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilt erChain.java:47)

at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceiv ed(DefaultIoFilterChain.java:765)

at org.apache.mina.core.filterchain.IoFilterAdapter.messageReceived(IoFilterAdapte r.java:109)

at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(D efaultIoFilterChain.java:417)

at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilt erChain.java:47)

at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceiv ed(DefaultIoFilterChain.java:765)

at org.apache.mina.filter.codec.ProtocolCodecFilter$ProtocolDecoderOutputImpl.flus h(ProtocolCodecFilter.java:407)

at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecF ilter.java:236)

at org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(D efaultIoFilterChain.java:417)

at org.apache.mina.core.filterchain.DefaultIoFilterChain.access$1200(DefaultIoFilt erChain.java:47)

at org.apache.mina.core.filterchain.DefaultIoFilterChain$EntryImpl$1.messageReceiv ed(DefaultIoFilterChain.java:765)

at org.apache.mina.core.filterchain.IoFilterEvent.fire(IoFilterEvent.java:74)

at org.apache.mina.core.session.IoEvent.run(IoEvent.java:63)

at org.apache.mina.filter.executor.OrderedThreadPoolExecutor$Worker.runTask(Ordere dThreadPoolExecutor.java:769)

at org.apache.mina.filter.executor.OrderedThreadPoolExecutor$Worker.runTasks(Order edThreadPoolExecutor.java:761)

at org.apache.mina.filter.executor.OrderedThreadPoolExecutor$Worker.run(OrderedThr eadPoolExecutor.java:703)

at java.lang.Thread.run(Thread.java:745)

2017.04.04 12:41:37 DEBUG [socket_c2s-thread-2]: org.jivesoftware.util.CertificateManager - CertificateManager: Subject Alternative Name Mapping returned []

https://github.com/igniterealtime/Openfire/blob/4.1/src/java/org/jivesoftware/ut il/cert/SANCertificateIdentityMapping.java