blob: 42deeae8136d6a3f572847984aa17c15ac76fc84 [file] [log] [blame]
// ========================================================================
// 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;
}
}