File tomcat-9.0.36-CVE-2024-38286.patch of Package tomcat.36510

From 76c5cce6f0bcef14b0c21c38910371ca7d322d13 Mon Sep 17 00:00:00 2001
From: Mark Thomas <markt@apache.org>
Date: Wed, 12 Jun 2024 19:43:39 +0100
Subject: [PATCH] Add support for re-keying with TLS 1.3

---
Index: apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/net/LocalStrings.properties
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -23,6 +23,8 @@ channel.nio.ssl.expandNetInBuffer=Expand
 channel.nio.ssl.expandNetOutBuffer=Expanding network output buffer to [{0}] bytes
 channel.nio.ssl.foundHttp=Found an plain text HTTP request on what should be an encrypted TLS connection
 channel.nio.ssl.handshakeError=Handshake error
+channel.nio.ssl.handshakeWrapPending=There is already handshake data waiting to be wrapped
+channel.nio.ssl.handshakeWrapQueueTooLong=The queue of handshake data to be wrapped has grown too long
 channel.nio.ssl.incompleteHandshake=Handshake incomplete, you must complete handshake before reading data.
 channel.nio.ssl.invalidCloseState=Invalid close state, will not send network data.
 channel.nio.ssl.invalidStatus=Unexpected status [{0}].
Index: apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/net/SecureNio2Channel.java
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/tomcat/util/net/SecureNio2Channel.java
+++ apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/net/SecureNio2Channel.java
@@ -51,10 +51,12 @@ public class SecureNio2Channel extends N
     private static final Log log = LogFactory.getLog(SecureNio2Channel.class);
     private static final StringManager sm = StringManager.getManager(SecureNio2Channel.class);
 
-    // Value determined by observation of what the SSL Engine requested in
-    // various scenarios
+    // Value determined by observation of what the SSL Engine requested in various scenarios
     private static final int DEFAULT_NET_BUFFER_SIZE = 16921;
 
+    // Much longer than it should ever need to be but short enough to trigger connection closure if something goes wrong
+    private static final int HANDSHAKE_WRAP_QUEUE_LENGTH_LIMIT = 100;
+
     protected final Nio2Endpoint endpoint;
 
     protected ByteBuffer netInBuffer;
@@ -65,6 +67,7 @@ public class SecureNio2Channel extends N
     protected boolean sniComplete = false;
 
     private volatile boolean handshakeComplete = false;
+    private volatile int handshakeWrapQueueLength = 0;
     private volatile HandshakeStatus handshakeStatus; //gets set by handshake
 
     protected boolean closed;
@@ -726,6 +729,11 @@ public class SecureNio2Channel extends N
                     //perform any tasks if needed
                     if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                         tasks();
+                    } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
+                        if (++handshakeWrapQueueLength > HANDSHAKE_WRAP_QUEUE_LENGTH_LIMIT) {
+                            throw new ExecutionException(
+                                    new IOException(sm.getString("channel.nio.ssl.handshakeWrapQueueTooLong")));
+                        }
                     }
                     //if we need more network data, then bail out for now.
                     if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
@@ -856,6 +864,8 @@ public class SecureNio2Channel extends N
                 if (!netOutBuffer.hasRemaining()) {
                     netOutBuffer.clear();
                     SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
+                    // Call to wrap() will have included any required handshake data
+                    handshakeWrapQueueLength = 0;
                     written = result.bytesConsumed();
                     netOutBuffer.flip();
                     if (result.getStatus() == Status.OK) {
@@ -918,8 +928,14 @@ public class SecureNio2Channel extends N
                                 //we did receive some data, add it to our total
                                 read += unwrap.bytesProduced();
                                 //perform any tasks if needed
-                                if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
+                                if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                                     tasks();
+                                } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
+                                    if (++handshakeWrapQueueLength > HANDSHAKE_WRAP_QUEUE_LENGTH_LIMIT) {
+                                        throw new ExecutionException(new IOException(
+                                                sm.getString("channel.nio.ssl.handshakeWrapQueueTooLong")));
+                                    }
+                                }
                                 //if we need more network data, then bail out for now.
                                 if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
                                     if (read == 0) {
@@ -1030,8 +1046,14 @@ public class SecureNio2Channel extends N
                                     read -= getBufHandler().getReadBuffer().position();
                                 }
                                 //perform any tasks if needed
-                                if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
+                                if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                                     tasks();
+                                } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
+                                    if (++handshakeWrapQueueLength > HANDSHAKE_WRAP_QUEUE_LENGTH_LIMIT) {
+                                        throw new ExecutionException(new IOException(
+                                                sm.getString("channel.nio.ssl.handshakeWrapQueueTooLong")));
+                                    }
+                                }
                                 //if we need more network data, then bail out for now.
                                 if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
                                     if (read == 0) {
@@ -1140,6 +1162,8 @@ public class SecureNio2Channel extends N
             netOutBuffer.clear();
             // Wrap the source data into the internal buffer
             SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
+            // Call to wrap() will have included any required handshake data
+            handshakeWrapQueueLength = 0;
             final int written = result.bytesConsumed();
             netOutBuffer.flip();
             if (result.getStatus() == Status.OK) {
@@ -1254,4 +1278,4 @@ public class SecureNio2Channel extends N
         PROCESSING,
         DONE;
     }
-}
\ No newline at end of file
+}
Index: apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/net/SecureNioChannel.java
===================================================================
--- apache-tomcat-9.0.36-src.orig/java/org/apache/tomcat/util/net/SecureNioChannel.java
+++ apache-tomcat-9.0.36-src/java/org/apache/tomcat/util/net/SecureNioChannel.java
@@ -63,6 +63,7 @@ public class SecureNioChannel extends Ni
     protected boolean sniComplete = false;
 
     protected boolean handshakeComplete = false;
+    protected boolean needHandshakeWrap = false;
     protected HandshakeStatus handshakeStatus; //gets set by handshake
 
     protected boolean closed = false;
@@ -624,6 +625,14 @@ public class SecureNioChannel extends Ni
                 //perform any tasks if needed
                 if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                     tasks();
+                } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
+                    if (getOutboundRemaining() == 0) {
+                        handshakeWrap(true);
+                    } else if (needHandshakeWrap) {
+                        throw new IOException(sm.getString("channel.nio.ssl.handshakeWrapPending"));
+                    } else {
+                        needHandshakeWrap = true;
+                    }
                 }
                 //if we need more network data, then bail out for now.
                 if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
@@ -705,6 +714,14 @@ public class SecureNioChannel extends Ni
                 //perform any tasks if needed
                 if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
                     tasks();
+                } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
+                    if (getOutboundRemaining() == 0) {
+                        handshakeWrap(true);
+                    } else if (needHandshakeWrap) {
+                        throw new IOException(sm.getString("channel.nio.ssl.handshakeWrapPending"));
+                    } else {
+                        needHandshakeWrap = true;
+                    }
                 }
                 //if we need more network data, then bail out for now.
                 if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
@@ -800,6 +817,8 @@ public class SecureNioChannel extends Ni
             netOutBuffer.clear();
 
             SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
+            // Call to wrap() will have included any required handshake data
+            needHandshakeWrap = false;
             // The number of bytes written
             int written = result.bytesConsumed();
             netOutBuffer.flip();
Index: apache-tomcat-9.0.36-src/webapps/docs/changelog.xml
===================================================================
--- apache-tomcat-9.0.36-src.orig/webapps/docs/changelog.xml
+++ apache-tomcat-9.0.36-src/webapps/docs/changelog.xml
@@ -191,15 +191,14 @@
         <code>ERR_HTTP2_SERVER_REFUSED_STREAM</code> for some connections.
         (markt)
       </fix>
-    </changelog>
-  </subsection>
-  <subsection name="Coyote">
-    <changelog>
       <scode>
         Refactor synchronization blocks locking on <code>SocketWrapper</code> to
         use <code>ReentrantLock</code> to support users wishing to experiment
         with project Loom. (markt)
       </scode>
+      <add>
+        Add support for TLS 1.3 client initiated re-keying. (markt)
+      </add>
     </changelog>
   </subsection>
   <subsection name="Jasper">
openSUSE Build Service is sponsored by