| // ======================================================================== |
| // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| |
| package org.eclipse.jetty.exssl; |
| |
| import java.io.IOException; |
| import java.nio.channels.SelectionKey; |
| import java.nio.channels.SocketChannel; |
| |
| import javax.net.ssl.SSLContext; |
| import javax.net.ssl.SSLEngine; |
| import javax.net.ssl.SSLSession; |
| import javax.net.ssl.SSLSocket; |
| |
| import org.eclipse.jetty.http.HttpParser; |
| import org.eclipse.jetty.http.HttpSchemes; |
| import org.eclipse.jetty.io.Buffer; |
| import org.eclipse.jetty.io.Buffers; |
| import org.eclipse.jetty.io.Connection; |
| import org.eclipse.jetty.io.EndPoint; |
| import org.eclipse.jetty.io.SslContextFactory; |
| import org.eclipse.jetty.io.ThreadLocalBuffers; |
| import org.eclipse.jetty.io.bio.SocketEndPoint; |
| import org.eclipse.jetty.io.nio.DirectNIOBuffer; |
| import org.eclipse.jetty.io.nio.IndirectNIOBuffer; |
| import org.eclipse.jetty.io.nio.SelectChannelEndPoint; |
| import org.eclipse.jetty.io.nio.SelectorManager.SelectSet; |
| import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint; |
| import org.eclipse.jetty.server.HttpConnection; |
| import org.eclipse.jetty.server.Request; |
| import org.eclipse.jetty.server.nio.SelectChannelConnector; |
| import org.eclipse.jetty.server.ssl.SslCertificates; |
| import org.eclipse.jetty.server.ssl.SslConnector; |
| import org.eclipse.jetty.util.log.Log; |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * SslSelectChannelConnector. |
| * |
| * @org.apache.xbean.XBean element="sslConnector" description="Creates an NIO ssl connector" |
| * |
| * |
| * |
| */ |
| public class SslSelectChannelConnector extends SelectChannelConnector implements SslConnector |
| { |
| private final SslContextFactory _sslContextFactory; |
| private Buffers _sslBuffers; |
| |
| /* ------------------------------------------------------------ */ |
| public SslSelectChannelConnector() |
| { |
| this(new SslContextFactory(SslContextFactory.DEFAULT_KEYSTORE_PATH)); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public SslSelectChannelConnector(SslContextFactory sslContextFactory) |
| { |
| _sslContextFactory = sslContextFactory; |
| setUseDirectBuffers(false); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Allow the Listener a chance to customise the request. before the server |
| * does its stuff. <br> |
| * This allows the required attributes to be set for SSL requests. <br> |
| * The requirements of the Servlet specs are: |
| * <ul> |
| * <li> an attribute named "javax.servlet.request.ssl_session_id" of type |
| * String (since Servlet Spec 3.0).</li> |
| * <li> an attribute named "javax.servlet.request.cipher_suite" of type |
| * String.</li> |
| * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li> |
| * <li> an attribute named "javax.servlet.request.X509Certificate" of type |
| * java.security.cert.X509Certificate[]. This is an array of objects of type |
| * X509Certificate, the order of this array is defined as being in ascending |
| * order of trust. The first certificate in the chain is the one set by the |
| * client, the next is the one used to authenticate the first, and so on. |
| * </li> |
| * </ul> |
| * |
| * @param endpoint |
| * The Socket the request arrived on. This should be a |
| * {@link SocketEndPoint} wrapping a {@link SSLSocket}. |
| * @param request |
| * HttpRequest to be customised. |
| */ |
| @Override |
| public void customize(EndPoint endpoint, Request request) throws IOException |
| { |
| request.setScheme(HttpSchemes.HTTPS); |
| super.customize(endpoint,request); |
| |
| SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint; |
| SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine(); |
| SSLSession sslSession=sslEngine.getSession(); |
| |
| SslCertificates.customize(sslSession,endpoint,request); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @return True if SSL re-negotiation is allowed (default false) |
| * @deprecated |
| */ |
| @Deprecated |
| public boolean isAllowRenegotiate() |
| { |
| return _sslContextFactory.isAllowRenegotiate(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered |
| * a vulnerability in SSL/TLS with re-negotiation. If your JVM |
| * does not have CVE-2009-3555 fixed, then re-negotiation should |
| * not be allowed. |
| * @param allowRenegotiate true if re-negotiation is allowed (default false) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setAllowRenegotiate(boolean allowRenegotiate) |
| { |
| _sslContextFactory.setAllowRenegotiate(allowRenegotiate); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites() |
| * @deprecated |
| */ |
| @Deprecated |
| public String[] getExcludeCipherSuites() |
| { |
| return _sslContextFactory.getExcludeCipherSuites(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[]) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setExcludeCipherSuites(String[] cipherSuites) |
| { |
| _sslContextFactory.setExcludeCipherSuites(cipherSuites); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites() |
| * @deprecated |
| */ |
| @Deprecated |
| public String[] getIncludeCipherSuites() |
| { |
| return _sslContextFactory.getIncludeCipherSuites(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[]) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setIncludeCipherSuites(String[] cipherSuites) |
| { |
| _sslContextFactory.setIncludeCipherSuites(cipherSuites); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setPassword(String password) |
| { |
| _sslContextFactory.setKeystorePassword(password); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setTrustPassword(String password) |
| { |
| _sslContextFactory.setTruststorePassword(password); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setKeyPassword(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setKeyPassword(String password) |
| { |
| _sslContextFactory.setKeyManagerPassword(password); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Unsupported. |
| * |
| * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) |
| * @deprecated |
| */ |
| @Deprecated |
| public String getAlgorithm() |
| { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * Unsupported. |
| * |
| * TODO: we should remove this as it is no longer an overridden method from SslConnector (like it was in the past) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setAlgorithm(String algorithm) |
| { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getProtocol() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getProtocol() |
| { |
| return _sslContextFactory.getProtocol(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setProtocol(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setProtocol(String protocol) |
| { |
| _sslContextFactory.setProtocol(protocol); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystore(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setKeystore(String keystore) |
| { |
| _sslContextFactory.setKeystore(keystore); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystore() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getKeystore() |
| { |
| return _sslContextFactory.getKeystore(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystoreType() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getKeystoreType() |
| { |
| return _sslContextFactory.getKeystoreType(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getNeedClientAuth() |
| * @deprecated |
| */ |
| @Deprecated |
| public boolean getNeedClientAuth() |
| { |
| return _sslContextFactory.getNeedClientAuth(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getWantClientAuth() |
| * @deprecated |
| */ |
| @Deprecated |
| public boolean getWantClientAuth() |
| { |
| return _sslContextFactory.getWantClientAuth(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setNeedClientAuth(boolean) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setNeedClientAuth(boolean needClientAuth) |
| { |
| _sslContextFactory.setNeedClientAuth(needClientAuth); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setWantClientAuth(boolean) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setWantClientAuth(boolean wantClientAuth) |
| { |
| _sslContextFactory.setWantClientAuth(wantClientAuth); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystoreType(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setKeystoreType(String keystoreType) |
| { |
| _sslContextFactory.setKeystoreType(keystoreType); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getProvider() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getProvider() |
| { |
| return _sslContextFactory.getProvider(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getSecureRandomAlgorithm() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getSecureRandomAlgorithm() |
| { |
| return _sslContextFactory.getSecureRandomAlgorithm(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getSslKeyManagerFactoryAlgorithm() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getSslKeyManagerFactoryAlgorithm() |
| { |
| return _sslContextFactory.getSslKeyManagerFactoryAlgorithm(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getSslTrustManagerFactoryAlgorithm() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getSslTrustManagerFactoryAlgorithm() |
| { |
| return _sslContextFactory.getTrustManagerFactoryAlgorithm(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststore() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getTruststore() |
| { |
| return _sslContextFactory.getTruststore(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststoreType() |
| * @deprecated |
| */ |
| @Deprecated |
| public String getTruststoreType() |
| { |
| return _sslContextFactory.getTruststoreType(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setProvider(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setProvider(String provider) |
| { |
| _sslContextFactory.setProvider(provider); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setSecureRandomAlgorithm(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setSecureRandomAlgorithm(String algorithm) |
| { |
| _sslContextFactory.setSecureRandomAlgorithm(algorithm); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setSslKeyManagerFactoryAlgorithm(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setSslKeyManagerFactoryAlgorithm(String algorithm) |
| { |
| _sslContextFactory.setSslKeyManagerFactoryAlgorithm(algorithm); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setSslTrustManagerFactoryAlgorithm(String algorithm) |
| { |
| _sslContextFactory.setTrustManagerFactoryAlgorithm(algorithm); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststore(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setTruststore(String truststore) |
| { |
| _sslContextFactory.setTruststore(truststore); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setTruststoreType(String truststoreType) |
| { |
| _sslContextFactory.setTruststoreType(truststoreType); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext) |
| * @deprecated |
| */ |
| @Deprecated |
| public void setSslContext(SSLContext sslContext) |
| { |
| _sslContextFactory.setSslContext(sslContext); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext) |
| * @deprecated |
| */ |
| @Deprecated |
| public SSLContext getSslContext() |
| { |
| return _sslContextFactory.getSslContext(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * By default, we're confidential, given we speak SSL. But, if we've been |
| * told about an confidential port, and said port is not our port, then |
| * we're not. This allows separation of listeners providing INTEGRAL versus |
| * CONFIDENTIAL constraints, such as one SSL listener configured to require |
| * client certs providing CONFIDENTIAL, whereas another SSL listener not |
| * requiring client certs providing mere INTEGRAL constraints. |
| */ |
| @Override |
| public boolean isConfidential(Request request) |
| { |
| final int confidentialPort=getConfidentialPort(); |
| return confidentialPort==0||confidentialPort==request.getServerPort(); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * By default, we're integral, given we speak SSL. But, if we've been told |
| * about an integral port, and said port is not our port, then we're not. |
| * This allows separation of listeners providing INTEGRAL versus |
| * CONFIDENTIAL constraints, such as one SSL listener configured to require |
| * client certs providing CONFIDENTIAL, whereas another SSL listener not |
| * requiring client certs providing mere INTEGRAL constraints. |
| */ |
| @Override |
| public boolean isIntegral(Request request) |
| { |
| final int integralPort=getIntegralPort(); |
| return integralPort==0||integralPort==request.getServerPort(); |
| } |
| |
| /* ------------------------------------------------------------------------------- */ |
| @Override |
| protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException |
| { |
| SslSelectChannelEndPoint endp = new SslSelectChannelEndPoint(_sslBuffers,channel,selectSet,key,createSSLEngine(), SslSelectChannelConnector.this._maxIdleTime); |
| endp.setAllowRenegotiate(_sslContextFactory.isAllowRenegotiate()); |
| return endp; |
| } |
| |
| /* ------------------------------------------------------------------------------- */ |
| @Override |
| protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint) |
| { |
| HttpConnection connection=(HttpConnection)super.newConnection(channel,endpoint); |
| ((HttpParser)connection.getParser()).setForceContentBuffer(true); |
| return connection; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| protected SSLEngine createSSLEngine() throws IOException |
| { |
| SSLEngine engine = null; |
| try |
| { |
| engine = _sslContextFactory.getSslContext().createSSLEngine(); |
| engine.setUseClientMode(false); |
| |
| if (_sslContextFactory.getWantClientAuth()) |
| engine.setWantClientAuth(_sslContextFactory.getWantClientAuth()); |
| if (_sslContextFactory.getNeedClientAuth()) |
| engine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth()); |
| |
| engine.setEnabledCipherSuites( |
| _sslContextFactory.selectCipherSuites(engine.getEnabledCipherSuites(), |
| engine.getSupportedCipherSuites())); |
| } |
| catch (Exception e) |
| { |
| Log.warn("Error creating sslEngine -- closing this connector",e); |
| close(); |
| throw new IllegalStateException(e); |
| } |
| return engine; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @see org.eclipse.jetty.server.nio.SelectChannelConnector#doStart() |
| */ |
| @Override |
| protected void doStart() throws Exception |
| { |
| _sslContextFactory.createSSLContext(); // called here to prevent exception wrapping |
| |
| SSLEngine sslEngine = _sslContextFactory.getSslContext().createSSLEngine(); |
| |
| sslEngine.setUseClientMode(false); |
| sslEngine.setWantClientAuth(_sslContextFactory.getWantClientAuth()); |
| sslEngine.setNeedClientAuth(_sslContextFactory.getNeedClientAuth()); |
| |
| sslEngine.setEnabledCipherSuites(_sslContextFactory.selectCipherSuites( |
| sslEngine.getEnabledCipherSuites(), |
| sslEngine.getSupportedCipherSuites())); |
| |
| SSLSession sslSession = sslEngine.getSession(); |
| |
| ThreadLocalBuffers buffers = new ThreadLocalBuffers() |
| { |
| @Override |
| protected Buffer newBuffer(int size) |
| { |
| if (getUseDirectBuffers()) |
| return new DirectNIOBuffer(size); |
| return new IndirectNIOBuffer(size); |
| } |
| @Override |
| protected Buffer newHeader(int size) |
| { |
| if (getUseDirectBuffers()) |
| return new DirectNIOBuffer(size); |
| return new IndirectNIOBuffer(size); |
| } |
| @Override |
| protected boolean isHeader(Buffer buffer) |
| { |
| return true; |
| } |
| }; |
| buffers.setBufferSize(sslSession.getApplicationBufferSize()); |
| buffers.setHeaderSize(sslSession.getApplicationBufferSize()); |
| _sslBuffers=buffers; |
| |
| if (getRequestHeaderSize()<sslSession.getApplicationBufferSize()) |
| setRequestHeaderSize(sslSession.getApplicationBufferSize()); |
| if (getRequestBufferSize()<sslSession.getApplicationBufferSize()) |
| setRequestBufferSize(sslSession.getApplicationBufferSize()); |
| |
| super.doStart(); |
| } |
| |
| public Buffers getSslBuffers() |
| { |
| return _sslBuffers; |
| } |
| } |