Author: markt
Date: Fri Jan 5 10:40:57 2018
New Revision: 1820276
URL: http://svn.apache.org/viewvc?rev=1820276&view=rev
Log:
Return a simple, plain text error message if a client attempts to make a plain
text HTTP connection to a TLS enabled NIO or NIO2 Connector.
Modified:
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/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
tomcat/trunk/webapps/docs/changelog.xml
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=1820276&r1=1820275&r2=1820276&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/LocalStrings.properties Fri
Jan 5 10:40:57 2018
@@ -121,6 +121,7 @@ channel.nio.ssl.expandNetInBuffer=Expand
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}]
+channel.nio.ssl.foundHttp=Found an plain text HTTP request on what should be
an encrypted TLS connection
jsse.invalid_truststore_password=The provided trust store password could not
be used to unlock and/or validate the trust store. Retrying to access the trust
store with a null password which will skip validation.
jsse.keystore_load_failed=Failed to load keystore type [{0}] with path [{1}]
due to [{2}]
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=1820276&r1=1820275&r2=1820276&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNio2Channel.java Fri Jan
5 10:40:57 2018
@@ -388,6 +388,12 @@ public class SecureNio2Channel extends N
hostName = endpoint.getDefaultSSLHostConfigName();
clientRequestedCiphers = Collections.emptyList();
break;
+ case NON_SECURE:
+ netOutBuffer.clear();
+ netOutBuffer.put(TLSClientHelloExtractor.USE_TLS_RESPONSE);
+ netOutBuffer.flip();
+ flush();
+ throw new IOException(sm.getString("channel.nio.ssl.foundHttp"));
}
if (log.isDebugEnabled()) {
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=1820276&r1=1820275&r2=1820276&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/SecureNioChannel.java Fri Jan
5 10:40:57 2018
@@ -316,6 +316,12 @@ public class SecureNioChannel extends Ni
hostName = endpoint.getDefaultSSLHostConfigName();
clientRequestedCiphers = Collections.emptyList();
break;
+ case NON_SECURE:
+ netOutBuffer.clear();
+ netOutBuffer.put(TLSClientHelloExtractor.USE_TLS_RESPONSE);
+ netOutBuffer.flip();
+ flushOutbound();
+ throw new IOException(sm.getString("channel.nio.ssl.foundHttp"));
}
if (log.isDebugEnabled()) {
Modified:
tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java?rev=1820276&r1=1820275&r2=1820276&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
(original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
Fri Jan 5 10:40:57 2018
@@ -25,6 +25,7 @@ import java.util.List;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.http.parser.HttpParser;
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
import org.apache.tomcat.util.res.StringManager;
@@ -47,6 +48,14 @@ public class TLSClientHelloExtractor {
private static final int TLS_EXTENSION_SERVER_NAME = 0;
private static final int TLS_EXTENSION_ALPN = 16;
+ public static byte[] USE_TLS_RESPONSE = ("HTTP/1.1 400 \r\n" +
+ "Content-Type: text/plain;charset=ISO-8859-1\r\n" +
+ "Connection: close\r\n" +
+ "\r\n" +
+ "Bad Request\r\n" +
+ "This combination of host and port requires
TLS.\r\n").getBytes(StandardCharsets.ISO_8859_1);
+
+
/**
* Creates the instance of the parser and processes the provided buffer.
The
* buffer position and limit will be modified during the execution of this
@@ -57,9 +66,6 @@ public class TLSClientHelloExtractor {
* @throws IOException If the client hello message is malformed
*/
public TLSClientHelloExtractor(ByteBuffer netInBuffer) throws IOException {
- // TODO: Detect use of http on a secure connection and provide a simple
- // error page.
-
// Buffer is in write mode at this point. Record the current position
so
// the buffer state can be restored at the end of this method.
int pos = netInBuffer.position();
@@ -80,6 +86,10 @@ public class TLSClientHelloExtractor {
}
if (!isTLSHandshake(netInBuffer)) {
+ // Is the client trying to use clear text HTTP?
+ if (isHttp(netInBuffer)) {
+ result = ExtractorResult.NON_SECURE;
+ }
return;
}
@@ -191,6 +201,7 @@ public class TLSClientHelloExtractor {
}
}
+
private static ExtractorResult handleIncompleteRead(ByteBuffer bb) {
if (bb.limit() == bb.capacity()) {
// Buffer not big enough
@@ -226,6 +237,67 @@ public class TLSClientHelloExtractor {
}
+ private static boolean isHttp(ByteBuffer bb) {
+ // Based on code in Http11InputBuffer
+ // Note: The actual request is not important. This code only checks
that
+ // the buffer contains a correctly formatted HTTP request line.
+ // The method, target and protocol are not validated.
+ byte chr = 0;
+ bb.position(0);
+
+ // Skip blank lines
+ do {
+ if (!bb.hasRemaining()) {
+ return false;
+ }
+ chr = bb.get();
+ } while (chr == '\r' || chr == '\n');
+
+ // Read the method
+ do {
+ if (!HttpParser.isToken(chr) || !bb.hasRemaining()) {
+ return false;
+ }
+ chr = bb.get();
+ } while (chr != ' ' && chr != '\t');
+
+ // Whitespace between method and target
+ while (chr == ' ' || chr == '\t') {
+ if (!bb.hasRemaining()) {
+ return false;
+ }
+ chr = bb.get();
+ }
+
+ // Read the target
+ while (chr != ' ' && chr != '\t') {
+ if (HttpParser.isNotRequestTarget(chr) || !bb.hasRemaining()) {
+ return false;
+ }
+ chr = bb.get();
+ }
+
+ // Whitespace between target and protocol
+ while (chr == ' ' || chr == '\t') {
+ if (!bb.hasRemaining()) {
+ return false;
+ }
+ chr = bb.get();
+ }
+
+ // Read protocol
+ do {
+ if (!HttpParser.isHttpProtocol(chr) || !bb.hasRemaining()) {
+ return false;
+ }
+ chr = bb.get();
+
+ } while (chr != '\r' && chr != '\n');
+
+ return true;
+ }
+
+
private static boolean isAllRecordAvailable(ByteBuffer bb) {
// Next two bytes (unsigned) are the size of the record. We need all of
// it.
@@ -288,6 +360,7 @@ public class TLSClientHelloExtractor {
COMPLETE,
NOT_PRESENT,
UNDERFLOW,
- NEED_READ
+ NEED_READ,
+ NON_SECURE
}
}
Modified: tomcat/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1820276&r1=1820275&r2=1820276&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Fri Jan 5 10:40:57 2018
@@ -107,6 +107,11 @@
<fix>
Fix NIO2 handshaking with a full input buffer. (remm)
</fix>
+ <add>
+ Return a simple, plain text error message if a client attempts to make
a
+ plain text HTTP connection to a TLS enabled NIO or NIO2 Connector.
+ (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]