< prev index next >

src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java

Print this page




  35 
  36 import javax.net.ssl.SSLSession;
  37 import javax.net.ssl.SSLSocket;
  38 import javax.net.ssl.SSLSocketFactory;
  39 import javax.net.ssl.SSLPeerUnverifiedException;
  40 import javax.net.ssl.HostnameVerifier;
  41 import sun.security.util.HostnameChecker;
  42 
  43 import javax.naming.ldap.*;
  44 import com.sun.jndi.ldap.Connection;
  45 
  46 /**
  47  * This class implements the LDAPv3 Extended Response for StartTLS as
  48  * defined in
  49  * <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory
  50  * Access Protocol (v3): Extension for Transport Layer Security</a>
  51  *
  52  * The object identifier for StartTLS is 1.3.6.1.4.1.1466.20037
  53  * and no extended response value is defined.
  54  *
  55  *<p>
  56  * The Start TLS extended request and response are used to establish
  57  * a TLS connection over the existing LDAP connection associated with
  58  * the JNDI context on which <tt>extendedOperation()</tt> is invoked.
  59  *
  60  * @see StartTlsRequest
  61  * @author Vincent Ryan
  62  */
  63 final public class StartTlsResponseImpl extends StartTlsResponse {
  64 
  65     private static final boolean debug = false;
  66 
  67     /*
  68      * The dNSName type in a subjectAltName extension of an X.509 certificate
  69      */
  70     private static final int DNSNAME_TYPE = 2;
  71 
  72     /*
  73      * The server's hostname.
  74      */
  75     private transient String hostname = null;
  76 
  77     /*
  78      * The LDAP socket.


 107 
 108     /*
 109      * The hostname verifier callback.
 110      */
 111     private transient HostnameVerifier verifier = null;
 112 
 113     /*
 114      * The flag to indicate that the TLS connection is closed.
 115      */
 116     private transient boolean isClosed = true;
 117 
 118     private static final long serialVersionUID = -1126624615143411328L;
 119 
 120     // public no-arg constructor required by JDK's Service Provider API.
 121 
 122     public StartTlsResponseImpl() {}
 123 
 124     /**
 125      * Overrides the default list of cipher suites enabled for use on the
 126      * TLS connection. The cipher suites must have already been listed by
 127      * <tt>SSLSocketFactory.getSupportedCipherSuites()</tt> as being supported.
 128      * Even if a suite has been enabled, it still might not be used because
 129      * the peer does not support it, or because the requisite certificates
 130      * (and private keys) are not available.
 131      *
 132      * @param suites The non-null list of names of all the cipher suites to
 133      * enable.
 134      * @see #negotiate
 135      */
 136     public void setEnabledCipherSuites(String[] suites) {
 137         // The impl does accept null suites, although the spec requires
 138         // a non-null list.
 139         this.suites = suites == null ? null : suites.clone();
 140     }
 141 
 142     /**
 143      * Overrides the default hostname verifier used by <tt>negotiate()</tt>
 144      * after the TLS handshake has completed. If
 145      * <tt>setHostnameVerifier()</tt> has not been called before
 146      * <tt>negotiate()</tt> is invoked, <tt>negotiate()</tt>
 147      * will perform a simple case ignore match. If called after
 148      * <tt>negotiate()</tt>, this method does not do anything.
 149      *
 150      * @param verifier The non-null hostname verifier callback.
 151      * @see #negotiate
 152      */
 153     public void setHostnameVerifier(HostnameVerifier verifier) {
 154         this.verifier = verifier;
 155     }
 156 
 157     /**
 158      * Negotiates a TLS session using the default SSL socket factory.
 159      * <p>
 160      * This method is equivalent to <tt>negotiate(null)</tt>.
 161      *
 162      * @return The negotiated SSL session
 163      * @throw IOException If an IO error was encountered while establishing
 164      * the TLS session.
 165      * @see #setEnabledCipherSuites
 166      * @see #setHostnameVerifier
 167      */
 168     public SSLSession negotiate() throws IOException {
 169 
 170         return negotiate(null);
 171     }
 172 
 173     /**
 174      * Negotiates a TLS session using an SSL socket factory.
 175      * <p>
 176      * Creates an SSL socket using the supplied SSL socket factory and
 177      * attaches it to the existing connection. Performs the TLS handshake
 178      * and returns the negotiated session information.
 179      * <p>
 180      * If cipher suites have been set via <tt>setEnabledCipherSuites</tt>
 181      * then they are enabled before the TLS handshake begins.
 182      * <p>
 183      * Hostname verification is performed after the TLS handshake completes.
 184      * The default check performs a case insensitive match of the server's
 185      * hostname against that in the server's certificate. The server's
 186      * hostname is extracted from the subjectAltName in the server's
 187      * certificate (if present). Otherwise the value of the common name
 188      * attribute of the subject name is used. If a callback has
 189      * been set via <tt>setHostnameVerifier</tt> then that verifier is used if
 190      * the default check fails.
 191      * <p>
 192      * If an error occurs then the SSL socket is closed and an IOException
 193      * is thrown. The underlying connection remains intact.
 194      *
 195      * @param factory The possibly null SSL socket factory to use.
 196      * If null, the default SSL socket factory is used.
 197      * @return The negotiated SSL session
 198      * @throw IOException If an IO error was encountered while establishing
 199      * the TLS session.
 200      * @see #setEnabledCipherSuites
 201      * @see #setHostnameVerifier
 202      */
 203     public SSLSession negotiate(SSLSocketFactory factory) throws IOException {
 204 
 205         if (isClosed && sslSocket != null) {
 206             throw new IOException("TLS connection is closed.");
 207         }
 208 
 209         if (factory == null) {
 210             factory = getDefaultFactory();
 211         }
 212 
 213         if (debug) {
 214             System.out.println("StartTLS: About to start handshake");
 215         }
 216 
 217         SSLSession sslSession = startHandshake(factory).getSession();
 218 


 235             isClosed = false;
 236             return sslSession;
 237         }
 238 
 239         // Verification failed
 240         close();
 241         sslSession.invalidate();
 242         if (verifExcep == null) {
 243             verifExcep = new SSLPeerUnverifiedException(
 244                         "hostname of the server '" + hostname +
 245                         "' does not match the hostname in the " +
 246                         "server's certificate.");
 247         }
 248         throw verifExcep;
 249     }
 250 
 251     /**
 252      * Closes the TLS connection gracefully and reverts back to the underlying
 253      * connection.
 254      *
 255      * @throw IOException If an IO error was encountered while closing the
 256      * TLS connection
 257      */
 258     public void close() throws IOException {
 259 
 260         if (isClosed) {
 261             return;
 262         }
 263 
 264         if (debug) {
 265             System.out.println("StartTLS: replacing SSL " +
 266                                 "streams with originals");
 267         }
 268 
 269         // Replace SSL streams with the original streams
 270         ldapConnection.replaceStreams(
 271                         originalInputStream, originalOutputStream);
 272 
 273         if (debug) {
 274             System.out.println("StartTLS: closing SSL Socket");
 275         }




  35 
  36 import javax.net.ssl.SSLSession;
  37 import javax.net.ssl.SSLSocket;
  38 import javax.net.ssl.SSLSocketFactory;
  39 import javax.net.ssl.SSLPeerUnverifiedException;
  40 import javax.net.ssl.HostnameVerifier;
  41 import sun.security.util.HostnameChecker;
  42 
  43 import javax.naming.ldap.*;
  44 import com.sun.jndi.ldap.Connection;
  45 
  46 /**
  47  * This class implements the LDAPv3 Extended Response for StartTLS as
  48  * defined in
  49  * <a href="http://www.ietf.org/rfc/rfc2830.txt">Lightweight Directory
  50  * Access Protocol (v3): Extension for Transport Layer Security</a>
  51  *
  52  * The object identifier for StartTLS is 1.3.6.1.4.1.1466.20037
  53  * and no extended response value is defined.
  54  *
  55  * <p>
  56  * The Start TLS extended request and response are used to establish
  57  * a TLS connection over the existing LDAP connection associated with
  58  * the JNDI context on which {@code extendedOperation()} is invoked.
  59  *
  60  * @see StartTlsRequest
  61  * @author Vincent Ryan
  62  */
  63 final public class StartTlsResponseImpl extends StartTlsResponse {
  64 
  65     private static final boolean debug = false;
  66 
  67     /*
  68      * The dNSName type in a subjectAltName extension of an X.509 certificate
  69      */
  70     private static final int DNSNAME_TYPE = 2;
  71 
  72     /*
  73      * The server's hostname.
  74      */
  75     private transient String hostname = null;
  76 
  77     /*
  78      * The LDAP socket.


 107 
 108     /*
 109      * The hostname verifier callback.
 110      */
 111     private transient HostnameVerifier verifier = null;
 112 
 113     /*
 114      * The flag to indicate that the TLS connection is closed.
 115      */
 116     private transient boolean isClosed = true;
 117 
 118     private static final long serialVersionUID = -1126624615143411328L;
 119 
 120     // public no-arg constructor required by JDK's Service Provider API.
 121 
 122     public StartTlsResponseImpl() {}
 123 
 124     /**
 125      * Overrides the default list of cipher suites enabled for use on the
 126      * TLS connection. The cipher suites must have already been listed by
 127      * {@code SSLSocketFactory.getSupportedCipherSuites()} as being supported.
 128      * Even if a suite has been enabled, it still might not be used because
 129      * the peer does not support it, or because the requisite certificates
 130      * (and private keys) are not available.
 131      *
 132      * @param suites The non-null list of names of all the cipher suites to
 133      * enable.
 134      * @see #negotiate
 135      */
 136     public void setEnabledCipherSuites(String[] suites) {
 137         // The impl does accept null suites, although the spec requires
 138         // a non-null list.
 139         this.suites = suites == null ? null : suites.clone();
 140     }
 141 
 142     /**
 143      * Overrides the default hostname verifier used by {@code negotiate()}
 144      * after the TLS handshake has completed. If
 145      * {@code setHostnameVerifier()} has not been called before
 146      * {@code negotiate()} is invoked, {@code negotiate()}
 147      * will perform a simple case ignore match. If called after
 148      * {@code negotiate()}, this method does not do anything.
 149      *
 150      * @param verifier The non-null hostname verifier callback.
 151      * @see #negotiate
 152      */
 153     public void setHostnameVerifier(HostnameVerifier verifier) {
 154         this.verifier = verifier;
 155     }
 156 
 157     /**
 158      * Negotiates a TLS session using the default SSL socket factory.
 159      * <p>
 160      * This method is equivalent to {@code negotiate(null)}.
 161      *
 162      * @return The negotiated SSL session
 163      * @throws IOException If an IO error was encountered while establishing
 164      * the TLS session.
 165      * @see #setEnabledCipherSuites
 166      * @see #setHostnameVerifier
 167      */
 168     public SSLSession negotiate() throws IOException {
 169 
 170         return negotiate(null);
 171     }
 172 
 173     /**
 174      * Negotiates a TLS session using an SSL socket factory.
 175      * <p>
 176      * Creates an SSL socket using the supplied SSL socket factory and
 177      * attaches it to the existing connection. Performs the TLS handshake
 178      * and returns the negotiated session information.
 179      * <p>
 180      * If cipher suites have been set via {@code setEnabledCipherSuites}
 181      * then they are enabled before the TLS handshake begins.
 182      * <p>
 183      * Hostname verification is performed after the TLS handshake completes.
 184      * The default check performs a case insensitive match of the server's
 185      * hostname against that in the server's certificate. The server's
 186      * hostname is extracted from the subjectAltName in the server's
 187      * certificate (if present). Otherwise the value of the common name
 188      * attribute of the subject name is used. If a callback has
 189      * been set via {@code setHostnameVerifier} then that verifier is used if
 190      * the default check fails.
 191      * <p>
 192      * If an error occurs then the SSL socket is closed and an IOException
 193      * is thrown. The underlying connection remains intact.
 194      *
 195      * @param factory The possibly null SSL socket factory to use.
 196      * If null, the default SSL socket factory is used.
 197      * @return The negotiated SSL session
 198      * @throws IOException If an IO error was encountered while establishing
 199      * the TLS session.
 200      * @see #setEnabledCipherSuites
 201      * @see #setHostnameVerifier
 202      */
 203     public SSLSession negotiate(SSLSocketFactory factory) throws IOException {
 204 
 205         if (isClosed && sslSocket != null) {
 206             throw new IOException("TLS connection is closed.");
 207         }
 208 
 209         if (factory == null) {
 210             factory = getDefaultFactory();
 211         }
 212 
 213         if (debug) {
 214             System.out.println("StartTLS: About to start handshake");
 215         }
 216 
 217         SSLSession sslSession = startHandshake(factory).getSession();
 218 


 235             isClosed = false;
 236             return sslSession;
 237         }
 238 
 239         // Verification failed
 240         close();
 241         sslSession.invalidate();
 242         if (verifExcep == null) {
 243             verifExcep = new SSLPeerUnverifiedException(
 244                         "hostname of the server '" + hostname +
 245                         "' does not match the hostname in the " +
 246                         "server's certificate.");
 247         }
 248         throw verifExcep;
 249     }
 250 
 251     /**
 252      * Closes the TLS connection gracefully and reverts back to the underlying
 253      * connection.
 254      *
 255      * @throws IOException If an IO error was encountered while closing the
 256      * TLS connection
 257      */
 258     public void close() throws IOException {
 259 
 260         if (isClosed) {
 261             return;
 262         }
 263 
 264         if (debug) {
 265             System.out.println("StartTLS: replacing SSL " +
 266                                 "streams with originals");
 267         }
 268 
 269         // Replace SSL streams with the original streams
 270         ldapConnection.replaceStreams(
 271                         originalInputStream, originalOutputStream);
 272 
 273         if (debug) {
 274             System.out.println("StartTLS: closing SSL Socket");
 275         }


< prev index next >