Author: markt Date: Thu May 7 14:31:16 2015 New Revision: 1678218 URL: http://svn.apache.org/r1678218 Log: Add a configurable limit to the size of client hello that Tomcat parses looking for SNI data. Fallback to the default if the limit is not enough
Modified: tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java tomcat/trunk/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java tomcat/trunk/webapps/docs/config/http.xml Modified: tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java?rev=1678218&r1=1678217&r2=1678218&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java (original) +++ tomcat/trunk/java/org/apache/coyote/http11/AbstractHttp11JsseProtocol.java Thu May 7 14:31:16 2015 @@ -35,4 +35,10 @@ public abstract class AbstractHttp11Jsse public String getSslImplementationName() { return getEndpoint().getSslImplementationName(); } public void setSslImplementationName(String s) { getEndpoint().setSslImplementationName(s); } + + + public int getSniParseLimit() { return getEndpoint().getSniParseLimit(); } + public void setSniParseLimit(int sniParseLimit) { + getEndpoint().setSniParseLimit(sniParseLimit); + } } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java?rev=1678218&r1=1678217&r2=1678218&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java Thu May 7 14:31:16 2015 @@ -30,6 +30,7 @@ import org.apache.tomcat.util.net.jsse.N public abstract class AbstractJsseEndpoint<S> extends AbstractEndpoint<S> { private String sslImplementationName = null; + private int sniParseLimit = 64 * 1024; private SSLImplementation sslImplementation = null; @@ -49,6 +50,16 @@ public abstract class AbstractJsseEndpoi } + public int getSniParseLimit() { + return sniParseLimit; + } + + + public void setSniParseLimit(int sniParseLimit) { + this.sniParseLimit = sniParseLimit; + } + + @Override protected Type getSslConfigType() { return SSLHostConfig.Type.JSSE; Modified: tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties?rev=1678218&r1=1678217&r2=1678218&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties Thu May 7 14:31:16 2015 @@ -99,6 +99,7 @@ channel.nio.ssl.closing=Channel is in cl channel.nio.ssl.invalidBuffer=You can only read using the application read buffer provided by the handler. channel.nio.ssl.expandNetInBuffer=Expanding network input buffer to [{0}] bytes channel.nio.ssl.expandNetOutBuffer=Expanding network output buffer to [{0}] bytes +channel.nio.ssl.sniDefault=Unable to buffer enough data to determine requested SNI host name. Using default channel.nio.ssl.sniHostName=The SNI host name extracted for this connection was [{0}] sniExtractor.clientHelloTooBig=The ClientHello was not presented in a single TLS record so no SNI information could be extracted Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java?rev=1678218&r1=1678217&r2=1678218&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java Thu May 7 14:31:16 2015 @@ -299,13 +299,15 @@ public class SecureNio2Channel extends N SNIExtractor extractor = new SNIExtractor(netInBuffer); - while (extractor.getResult() == SNIResult.UNDERFLOW) { + while (extractor.getResult() == SNIResult.UNDERFLOW && + netInBuffer.capacity() < endpoint.getSniParseLimit()) { // extractor needed more data to process but netInBuffer was full so - // double the size of the buffer and read some more data. + // expand the buffer and read some more data. + int newLimit = Math.min(netInBuffer.capacity() * 2, endpoint.getSniParseLimit()); log.info(sm.getString("channel.nio.ssl.expandNetInBuffer", - Integer.toString(netInBuffer.capacity() * 2))); + Integer.toString(newLimit))); - netInBuffer = ByteBufferUtils.expand(netInBuffer); + netInBuffer = ByteBufferUtils.expand(netInBuffer, newLimit); sc.read(netInBuffer); extractor = new SNIExtractor(netInBuffer); } @@ -322,7 +324,11 @@ public class SecureNio2Channel extends N sc.read(netInBuffer, socket, handshakeReadCompletionHandler); return 1; case UNDERFLOW: - // Can't happen. Buffer would have been expanded above. + // Unable to buffer enough data to read SNI extension data + if (log.isDebugEnabled()) { + log.debug(sm.getString("channel.nio.ssl.sniDefault")); + } + hostName = endpoint.getDefaultSSLHostConfigName(); break; } Modified: tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java?rev=1678218&r1=1678217&r2=1678218&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Thu May 7 14:31:16 2015 @@ -235,13 +235,15 @@ public class SecureNioChannel extends Ni sc.read(netInBuffer); SNIExtractor extractor = new SNIExtractor(netInBuffer); - while (extractor.getResult() == SNIResult.UNDERFLOW) { + while (extractor.getResult() == SNIResult.UNDERFLOW && + netInBuffer.capacity() < endpoint.getSniParseLimit()) { // extractor needed more data to process but netInBuffer was full so - // double the size of the buffer and read some more data. + // expand the buffer and read some more data. + int newLimit = Math.min(netInBuffer.capacity() * 2, endpoint.getSniParseLimit()); log.info(sm.getString("channel.nio.ssl.expandNetInBuffer", - Integer.toString(netInBuffer.capacity() * 2))); + Integer.toString(newLimit))); - netInBuffer = ByteBufferUtils.expand(netInBuffer); + netInBuffer = ByteBufferUtils.expand(netInBuffer, newLimit); sc.read(netInBuffer); extractor = new SNIExtractor(netInBuffer); } @@ -257,7 +259,11 @@ public class SecureNioChannel extends Ni case NEED_READ: return SelectionKey.OP_READ; case UNDERFLOW: - // Can't happen. Buffer would have been expanded above. + // Unable to buffer enough data to read SNI extension data + if (log.isDebugEnabled()) { + log.debug(sm.getString("channel.nio.ssl.sniDefault")); + } + hostName = endpoint.getDefaultSSLHostConfigName(); break; } Modified: tomcat/trunk/webapps/docs/config/http.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/http.xml?rev=1678218&r1=1678217&r2=1678218&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/http.xml (original) +++ tomcat/trunk/webapps/docs/config/http.xml Thu May 7 14:31:16 2015 @@ -1330,6 +1330,19 @@ <attributes> + <attribute name="sniParseLimit" required="false"> + <p>In order to implement SNI support, Tomcat has to parse the first TLS + message received on a new TLS connection (the client hello) to extract the + requested server name. The message needs to be buffered so it can then be + passed to the JSSE implementation for normal TLS processing. In theory, + this first message could be very large although in practise it is + typically a few hundered bytes. This attribute sets the maximum message + size that Tomcat will buffer. If a message exceeds this size, the + connection will be configured as if no server name was indicated by the + client. If not specified a default of <code>65536</code> (64k) will be + used.</p> + </attribute> + <attribute name="sslImplementationName" required="false"> <p>The class name of the SSL implementation to use. If not specified, the default of <code>org.apache.tomcat.util.net.jsse.JSSEImplementation</code> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org