From 3b3fbd347a9c275a39380c0835d2d294f832ca12 Mon Sep 17 00:00:00 2001 From: Leon Schwandt <65220996+Leon-Schwandt@users.noreply.github.com> Date: Thu, 21 Mar 2024 20:29:39 +0100 Subject: [PATCH 1/2] Adds the possibility to change the USE_TLS_RESPONSE HTTP response Enables the USE_TLS_RESPONSE message to be changed at a global level. A possible use case would be a redirect to HTTPS --- .../tomcat/util/net/SecureNio2Channel.java | 2 +- .../tomcat/util/net/SecureNioChannel.java | 2 +- .../util/net/TLSClientHelloExtractor.java | 39 ++++++++++++++++++- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/java/org/apache/tomcat/util/net/SecureNio2Channel.java b/java/org/apache/tomcat/util/net/SecureNio2Channel.java index 92b5f3d5c494..0437edc30a72 100644 --- a/java/org/apache/tomcat/util/net/SecureNio2Channel.java +++ b/java/org/apache/tomcat/util/net/SecureNio2Channel.java @@ -423,7 +423,7 @@ protected int processSNI() throws IOException { break; case NON_SECURE: netOutBuffer.clear(); - netOutBuffer.put(TLSClientHelloExtractor.USE_TLS_RESPONSE); + netOutBuffer.put(extractor.getUseTlsResponse()); netOutBuffer.flip(); flush(); throw new IOException(sm.getString("channel.nio.ssl.foundHttp")); diff --git a/java/org/apache/tomcat/util/net/SecureNioChannel.java b/java/org/apache/tomcat/util/net/SecureNioChannel.java index 768ec458f175..e2c7985a920e 100644 --- a/java/org/apache/tomcat/util/net/SecureNioChannel.java +++ b/java/org/apache/tomcat/util/net/SecureNioChannel.java @@ -293,7 +293,7 @@ protected int processSNI() throws IOException { break; case NON_SECURE: netOutBuffer.clear(); - netOutBuffer.put(TLSClientHelloExtractor.USE_TLS_RESPONSE); + netOutBuffer.put(extractor.getUseTlsResponse()); netOutBuffer.flip(); flushOutbound(); throw new IOException(sm.getString("channel.nio.ssl.foundHttp")); diff --git a/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java b/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java index 28d3358510cc..8ac32c31e62f 100644 --- a/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java +++ b/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java @@ -40,6 +40,7 @@ public class TLSClientHelloExtractor { private static final Log log = LogFactory.getLog(TLSClientHelloExtractor.class); private static final StringManager sm = StringManager.getManager(TLSClientHelloExtractor.class); + private final ByteBuffer netInBuffer; private final ExtractorResult result; private final List clientRequestedCiphers; private final List clientRequestedCipherNames; @@ -60,6 +61,7 @@ public class TLSClientHelloExtractor { "Bad Request\r\n" + "This combination of host and port requires TLS.\r\n").getBytes(StandardCharsets.UTF_8); + public static ResponseCustomizer RESPONSE_CUSTOMIZER = new ResponseCustomizer() {}; /** * Creates the instance of the parser and processes the provided buffer. The @@ -71,6 +73,7 @@ public class TLSClientHelloExtractor { * @throws IOException If the client hello message is malformed */ public TLSClientHelloExtractor(ByteBuffer netInBuffer) throws IOException { + this.netInBuffer = netInBuffer; // 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(); @@ -245,6 +248,20 @@ public List getClientRequestedProtocols() { } } + public byte[] getUseTlsResponse() { + // 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(); + int limit = netInBuffer.limit(); + try { + netInBuffer.flip(); + return RESPONSE_CUSTOMIZER.customize(netInBuffer); + } finally { + // Whatever happens, return the buffer to its original state + netInBuffer.limit(limit); + netInBuffer.position(pos); + } + } private static ExtractorResult handleIncompleteRead(ByteBuffer bb) { if (bb.limit() == bb.capacity()) { @@ -433,7 +450,6 @@ private static void readSupportedVersions(ByteBuffer bb, List protocolNa } } - public enum ExtractorResult { COMPLETE, NOT_PRESENT, @@ -441,4 +457,25 @@ public enum ExtractorResult { NEED_READ, NON_SECURE } + + /** + * Allows the HTTP response to be changed. + *
+     * {@code
+     * new ResponseCustomizer() {
+     *     @Override
+     *     public byte[] customize(ByteBuffer netInBuffer) {
+     *         return ("HTTP/1.1 302 \r\n" +
+     *             "Location: https://www.example.org/index.html\r\n" +
+     *             "\r\n").getBytes(StandardCharsets.UTF_8);
+     *     }
+     * }
+     * }
+     * 
+ */ + public interface ResponseCustomizer { + default byte[] customize(ByteBuffer netInBuffer) { + return TLSClientHelloExtractor.USE_TLS_RESPONSE; + } + } } From 4fbdc5a31c745e134edda15641b1203300bc445f Mon Sep 17 00:00:00 2001 From: Leon Schwandt <65220996+Leon-Schwandt@users.noreply.github.com> Date: Fri, 22 Mar 2024 07:33:26 +0100 Subject: [PATCH 2/2] optimize example --- java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java b/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java index 8ac32c31e62f..de233124f4e9 100644 --- a/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java +++ b/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java @@ -462,14 +462,14 @@ public enum ExtractorResult { * Allows the HTTP response to be changed. *
      * {@code
-     * new ResponseCustomizer() {
+     * TLSClientHelloExtractor.RESPONSE_CUSTOMIZER = new ResponseCustomizer() {
      *     @Override
      *     public byte[] customize(ByteBuffer netInBuffer) {
      *         return ("HTTP/1.1 302 \r\n" +
      *             "Location: https://www.example.org/index.html\r\n" +
      *             "\r\n").getBytes(StandardCharsets.UTF_8);
      *     }
-     * }
+     * };
      * }
      * 
*/