ldaps:// ignores alternative DNS names / SNA (Subject Alternative Name) certs if hostname != CN name)

Pallavi Sonal pallavi.sonal at oracle.com
Mon Feb 11 12:49:47 UTC 2019


Just for reference and as conclusion to this thread -  had a chat with OP on another mail , this actually turned out to be an environment issue.

-----Original Message-----
From: Pallavi Sonal 
Sent: February-11-19 11:02 AM
To: Heiko Jakob <heiko.jakob at gediegos.de>
Cc: security-dev at openjdk.java.net
Subject: RE: ldaps:// ignores alternative DNS names / SNA (Subject Alternative Name) certs if hostname != CN name)

Hi Heiko,
Please refer the release notes for JDK 8u181 at https://www.oracle.com/technetwork/java/javase/8u181-relnotes-4479407.html , there is a change to improve LDAP support and make it more secure. It is not possible now to establish an LDAPS connection to a server which presents a certificate whose CN or SAN  does not contain the requested host name. So, either the same host name should be used which is there in the certificate's CN or SAN or the certificate should be updated to have the matching hostname as in its CN or SAN. I have added the snippet from the release notes below for your reference  :
---------------------------------------------------------------
➜ Improve LDAP support
Endpoint identification has been enabled on LDAPS connections.

To improve the robustness of LDAPS (secure LDAP over TLS) connections, endpoint identification algorithms have been enabled by default.

Note that there may be situations where some applications that were previously able to successfully connect to an LDAPS server may no longer be able to do so. Such applications may, if they deem appropriate, disable endpoint identification using a new system property: com.sun.jndi.ldap.object.disableEndpointIdentification.

Define this system property (or set it to true) to disable endpoint identification algorithms.
---------------------------------------------------------------

Thanks,
Pallavi Sonal

Date: Sun, 10 Feb 2019 02:34:30 +0100
From: Heiko Jakob <heiko.jakob at gediegos.de>
To: security-dev at openjdk.java.net
Subject: ldaps:// ignores alternative DNS names / SNA (Subject
	Alternative Name) certs if hostname != CN name
Message-ID: <2d1a1cfe-bb0d-5f1b-cdb7-c54bfb2d4e44 at gediegos.de>
Content-Type: text/plain; charset=utf-8; format=flowed

Hi,

connecting to a secure ldap server with a SNA certificate fails with
"javax.naming.CommunicationException: simple bind failed: 
ldap.foo.bar:636 [Root exception is javax.net.ssl.SSLHandshakeException: 
No subject alternative DNS name matching ldap.foo.bar found.]"

The certificate is valid and i've tested it on https on the same machine which works flawlessly. The problem does not effect the Oracle JDK/JRE, only OpenJDK. I've testen OpenJDK 1.8.0_181, 11.0.1, 11.0.2 and all are affected.


With best regards

Heiko Jakob


How to reproduce:
Have a valid certificate for a host named CN "realhost.foo.bar" with
x509 SNA extension for DNS.1 "realhost.foo.bar" DNS.2 "ldap.foo.bar". 
Use the same certificate for https & ldap on the same host.

Examine the certificate to have CN="realhost.foo.bar" and x509 SNA extension for ldap.foo.bar $ openssl x509 -in my.crt -text -noout | less
Certificate:

...

 ?????? Validity
 ??????????? Not Before: Feb? 8 11:28:53 2019 GMT  ??????????? Not After : Feb? 7 11:28:53 2024 GMT  ??????? Subject: C = DE, ST = BW, L = Stuttgart, O = foo.bar, OU = IT Department, CN = realhost.foo.bar ...
 ??????????? X509v3 Subject Alternative Name:
 ??????????????? DNS:realhost.foo.bar, DNS:ldap.foo.bar


Run the following small test program to reproduce the problem.

package testSSL;

import java.net.URL;
import java.net.URLConnection;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;

public final class TestSSL {

 ??? public static void main(String[] args) {  ??? ??? String url_l = "ldaps://ldap.foo.bar:636";  ??? ??? String url_h = "https://ldap.foo.bar";

 ??? ??? System.out.println("TestSSL");
 ??? ??? URL url;
 ??? ??? try {
 ??? ??? ??? System.out.println("Test " + url_h);  ??? ??? ??? url = new URL(url_h);  ??? ??? ??? URLConnection conn = url.openConnection();  ??? ??? ??? conn.connect();  ??? ??? } catch (Exception e) {  ??? ??? ??? e.printStackTrace();  ??? ??? ??? System.out.println("Failed " + url_h);  ??? ??? ??? System.exit(-1);  ??? ??? }  ??? ??? System.out.println("https:// OK");


 ??? ??? System.out.println("Test " + url_l);  ??? ??? Hashtable env = new Hashtable();  ??? ??? env.put(Context.INITIAL_CONTEXT_FACTORY,
 ??? ??? ??? "com.sun.jndi.ldap.LdapCtxFactory");
 ??? ??? env.put(Context.PROVIDER_URL, url_l);  ??? ??? env.put(Context.SECURITY_PROTOCOL, "ssl");  ??? ??? env.put(Context.SECURITY_AUTHENTICATION, "simple");  ??? ??? env.put(Context.SECURITY_PRINCIPAL, "cn=admin,dc=foo,dc=bar");  ??? ??? env.put(Context.SECURITY_CREDENTIALS, "mysecret");  ??? ??? try {  ??? ??? ??? DirContext ctx = new InitialDirContext(env);  ??? ??? } catch (Exception e) {  ??? ??? ??? e.printStackTrace();  ??? ??? ??? System.out.println("Failed " + url_l);  ??? ??? ??? System.exit(-1);  ??? ??? }  ??? ??? System.out.println("ldaps:// OK");  ??? } }

Test it against various JDKs

$ (for j in $(find /opt/java/ -type f -name 'java' 2> /dev/null); do echo $j; $j -version; $j -classpath ./ testSSL.TestSSL; echo""; echo "##############################################";echo ""; sleep 30; done
) 2>&1 | tee -a testSSL.out

Reference output from oracle JDK

opt/java/jdk1.8.0_73/bin/java
java version "1.8.0_73"
Java(TM) SE Runtime Environment (build 1.8.0_73-b02) Java HotSpot(TM) 64-Bit Server VM (build 25.73-b02, mixed mode) TestSSL https://ldap.foo.bar https:// OK
ldaps://ldap.foo.bar:636
ldaps:// OK

##############################################
....
##############################################

/opt/java/jdk-11.0.2/bin/java
openjdk version "11.0.2" 2019-01-15
OpenJDK Runtime Environment 18.9 (build 11.0.2+9) OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode) TestSSL https://ldap.foo.bar https:// OK
ldaps://ldap.foo.bar:636
javax.naming.CommunicationException: simple bind failed: 
ldap.foo.bar:636 [Root exception is javax.net.ssl.SSLHandshakeException: 
No subject alternative DNS name matching ldap.foo.bar found.]  ??????? at
java.naming/com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:219)
 ??????? at java.naming/com.sun.jndi.ldap.LdapCtx.connect(LdapCtx.java:2795)
 ??????? at java.naming/com.sun.jndi.ldap.LdapCtx.<init>(LdapCtx.java:320)
 ??????? at
java.naming/com.sun.jndi.ldap.LdapCtxFactory.getUsingURL(LdapCtxFactory.java:192)
 ??????? at
java.naming/com.sun.jndi.ldap.LdapCtxFactory.getUsingURLs(LdapCtxFactory.java:210)
 ??????? at
java.naming/com.sun.jndi.ldap.LdapCtxFactory.getLdapCtxInstance(LdapCtxFactory.java:153)
 ??????? at
java.naming/com.sun.jndi.ldap.LdapCtxFactory.getInitialContext(LdapCtxFactory.java:83)
 ??????? at
java.naming/javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:730)
 ??????? at
java.naming/javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:305)
 ??????? at
java.naming/javax.naming.InitialContext.init(InitialContext.java:236)
 ??????? at
java.naming/javax.naming.InitialContext.<init>(InitialContext.java:208)
 ??????? at
java.naming/javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:101)
 ??????? at testSSL.TestSSL.main(TestSSL.java:57)
Caused by: javax.net.ssl.SSLHandshakeException: No subject alternative DNS name matching ldap.foo.bar found.
 ??????? at
java.base/sun.security.ssl.Alert.createSSLException(Alert.java:128)
 ??????? at
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:321)
 ??????? at
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:264)
 ??????? at
java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:259)
 ??????? at
java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:642)
 ??????? at
java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:461)
 ??????? at
java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:361)
 ??????? at
java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
 ??????? at
java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:444)
 ??????? at
java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:421)
 ??????? at
java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:178)
 ??????? at
java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:164)
 ??????? at
java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1152)
 ??????? at
java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1063)
 ??????? at
java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:402)
 ??????? at
java.base/sun.security.ssl.SSLSocketImpl.ensureNegotiated(SSLSocketImpl.java:716)
 ??????? at
java.base/sun.security.ssl.SSLSocketImpl$AppOutputStream.write(SSLSocketImpl.java:970)
 ??????? at
java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81)
 ??????? at
java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142)
 ??????? at
java.naming/com.sun.jndi.ldap.Connection.writeRequest(Connection.java:398)
 ??????? at
java.naming/com.sun.jndi.ldap.Connection.writeRequest(Connection.java:371)
 ??????? at
java.naming/com.sun.jndi.ldap.LdapClient.ldapBind(LdapClient.java:359)
 ??????? at
java.naming/com.sun.jndi.ldap.LdapClient.authenticate(LdapClient.java:214)
 ??????? ... 12 more




End of security-dev Digest, Vol 140, Issue 11
*********************************************


More information about the security-dev mailing list