-
Bug
-
Resolution: Unresolved
-
P4
-
None
-
8
-
generic
-
generic
ADDITIONAL SYSTEM INFORMATION :
All systems.
A DESCRIPTION OF THE PROBLEM :
When using LDAP with the StartTLS command and a specified SSLFactory the SSL context is not correctly cleared on hostname validation errors.
The error is in the `public SSLSession negotiate(SSLSocketFactory factory)` [1] method and the associated `close` [2] method
if the TLS handshake and negotiation passes but the hostname does not match the presented certificate then the call to verify on line 225 [3] will throw an exception.
if a custom hostname validator has been specified then this will be called and if it is ok all is good.
In both the success cases the isClosed is set to false (the default is true).
Now the issue is that if there is normal hostname validation failed, as well as a custom validator (or if there was no customer validator) you fall through as per the comment on line 239 [4]
At this point the code attempts to clear up the SSL context.
it does this by first calling close() however the first thing this does is return early if isClosed is true - and at this point it is.
it then calls sslSession.invalidate() [5]
At this point I would expect the underlying connection to not be using TLS, however it still is as the streams where replaced during the handshake. [6]
thus in case of a failure to validate the hostname the LDAP connection is still TLS encrypted, even though an exception has been thrown. It would be expected that the TLS connection would be closed and the original streams would be replaced, or the connection otherwise closed at this point
Code that catches the exception and just blunders on will be using TLS encrypted streams at this point when they are expecting not to be.
[1] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L203-L249
[2] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L258-L279
[3] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L225
[4] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L239
[5] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L241
[6] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L361-L362
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
the issue can bee seen by inspecting the code,
however to reproduce the issue setup a Samba AD server and connect to it via LDAP not using it's canonical host name (e.g. create an entry in your local /etc/hosts for "ip.addr.of.samba.server incorrectHostname")
Create an LDAP SSL contect and attempt to connect, and perform a search. simultanoeusly capture the network traffic.
Observe that the search is TLS encrytped.
Can be demonstrated with Jenkins Active-driectory plugin 2.13 https://github.com/jenkinsci/active-directory-plugin/blame/active-directory-2.13/src/main/java/hudson/plugins/active_directory/ActiveDirectorySecurityRealm.java#L657-L715
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the stream is no longer TLS encrpted if `StartTLSResoponse.negotiate()` throws an exception
ACTUAL -
the stream is still encrytped if it was just a certificate hostname mismatch that caused the error
---------- BEGIN SOURCE ----------
https://github.com/jenkinsci/active-directory-plugin/blame/active-directory-2.13/src/main/java/hudson/plugins/active_directory/ActiveDirectorySecurityRealm.java#L657-L715
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
when catching the exception, you need to completely close the context.
https://github.com/jenkinsci/active-directory-plugin/blob/88b2d311ad7eb2b003a7ffba0c19d5ef98632bf7/src/main/java/hudson/plugins/active_directory/ActiveDirectorySecurityRealm.java#L645-L647
FREQUENCY : always
All systems.
A DESCRIPTION OF THE PROBLEM :
When using LDAP with the StartTLS command and a specified SSLFactory the SSL context is not correctly cleared on hostname validation errors.
The error is in the `public SSLSession negotiate(SSLSocketFactory factory)` [1] method and the associated `close` [2] method
if the TLS handshake and negotiation passes but the hostname does not match the presented certificate then the call to verify on line 225 [3] will throw an exception.
if a custom hostname validator has been specified then this will be called and if it is ok all is good.
In both the success cases the isClosed is set to false (the default is true).
Now the issue is that if there is normal hostname validation failed, as well as a custom validator (or if there was no customer validator) you fall through as per the comment on line 239 [4]
At this point the code attempts to clear up the SSL context.
it does this by first calling close() however the first thing this does is return early if isClosed is true - and at this point it is.
it then calls sslSession.invalidate() [5]
At this point I would expect the underlying connection to not be using TLS, however it still is as the streams where replaced during the handshake. [6]
thus in case of a failure to validate the hostname the LDAP connection is still TLS encrypted, even though an exception has been thrown. It would be expected that the TLS connection would be closed and the original streams would be replaced, or the connection otherwise closed at this point
Code that catches the exception and just blunders on will be using TLS encrypted streams at this point when they are expecting not to be.
[1] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L203-L249
[2] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L258-L279
[3] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L225
[4] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L239
[5] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L241
[6] https://github.com/openjdk/jdk/blob/a37cd5a3133d7c66942919655d977912491d5b8c/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java#L361-L362
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
the issue can bee seen by inspecting the code,
however to reproduce the issue setup a Samba AD server and connect to it via LDAP not using it's canonical host name (e.g. create an entry in your local /etc/hosts for "ip.addr.of.samba.server incorrectHostname")
Create an LDAP SSL contect and attempt to connect, and perform a search. simultanoeusly capture the network traffic.
Observe that the search is TLS encrytped.
Can be demonstrated with Jenkins Active-driectory plugin 2.13 https://github.com/jenkinsci/active-directory-plugin/blame/active-directory-2.13/src/main/java/hudson/plugins/active_directory/ActiveDirectorySecurityRealm.java#L657-L715
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
the stream is no longer TLS encrpted if `StartTLSResoponse.negotiate()` throws an exception
ACTUAL -
the stream is still encrytped if it was just a certificate hostname mismatch that caused the error
---------- BEGIN SOURCE ----------
https://github.com/jenkinsci/active-directory-plugin/blame/active-directory-2.13/src/main/java/hudson/plugins/active_directory/ActiveDirectorySecurityRealm.java#L657-L715
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
when catching the exception, you need to completely close the context.
https://github.com/jenkinsci/active-directory-plugin/blob/88b2d311ad7eb2b003a7ffba0c19d5ef98632bf7/src/main/java/hudson/plugins/active_directory/ActiveDirectorySecurityRealm.java#L645-L647
FREQUENCY : always