This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push:
new 76c5cce6f0 Add support for re-keying with TLS 1.3
76c5cce6f0 is described below
commit 76c5cce6f0bcef14b0c21c38910371ca7d322d13
Author: Mark Thomas <[email protected]>
AuthorDate: Wed Jun 12 19:43:39 2024 +0100
Add support for re-keying with TLS 1.3
---
.../apache/tomcat/util/net/LocalStrings.properties | 2 ++
.../apache/tomcat/util/net/SecureNio2Channel.java | 26 ++++++++++++++++++++--
.../apache/tomcat/util/net/SecureNioChannel.java | 19 ++++++++++++++++
webapps/docs/changelog.xml | 3 +++
4 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/java/org/apache/tomcat/util/net/LocalStrings.properties
b/java/org/apache/tomcat/util/net/LocalStrings.properties
index 10b4fc1f47..9c7c601e59 100644
--- a/java/org/apache/tomcat/util/net/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/net/LocalStrings.properties
@@ -26,6 +26,8 @@ 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.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}].
diff --git a/java/org/apache/tomcat/util/net/SecureNio2Channel.java
b/java/org/apache/tomcat/util/net/SecureNio2Channel.java
index 4ec1b3c1c7..0a3624bc26 100644
--- a/java/org/apache/tomcat/util/net/SecureNio2Channel.java
+++ b/java/org/apache/tomcat/util/net/SecureNio2Channel.java
@@ -54,10 +54,12 @@ public class SecureNio2Channel extends Nio2Channel {
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;
@@ -68,6 +70,7 @@ public class SecureNio2Channel extends Nio2Channel {
protected volatile boolean sniComplete = false;
private volatile boolean handshakeComplete = false;
+ private volatile int handshakeWrapQueueLength = 0;
private volatile HandshakeStatus handshakeStatus; //gets set by handshake
protected boolean closed;
@@ -764,6 +767,11 @@ public class SecureNio2Channel extends Nio2Channel {
//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) {
@@ -894,6 +902,8 @@ public class SecureNio2Channel extends Nio2Channel {
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) {
@@ -959,6 +969,11 @@ public class SecureNio2Channel extends Nio2Channel {
//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) {
@@ -1072,6 +1087,11 @@ public class SecureNio2Channel extends Nio2Channel {
//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) {
@@ -1181,6 +1201,8 @@ public class SecureNio2Channel extends Nio2Channel {
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) {
diff --git a/java/org/apache/tomcat/util/net/SecureNioChannel.java
b/java/org/apache/tomcat/util/net/SecureNioChannel.java
index 24762506d7..8dfba3fae1 100644
--- a/java/org/apache/tomcat/util/net/SecureNioChannel.java
+++ b/java/org/apache/tomcat/util/net/SecureNioChannel.java
@@ -66,6 +66,7 @@ public class SecureNioChannel extends NioChannel {
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 NioChannel {
//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) {
@@ -713,6 +722,14 @@ public class SecureNioChannel extends NioChannel {
//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) {
@@ -811,6 +828,8 @@ public class SecureNioChannel extends NioChannel {
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();
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 76b0fb554b..0d012e7bf8 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -169,6 +169,9 @@
Make counting of active HTTP/2 streams per connection more robust.
(markt)
</fix>
+ <add>
+ Add support for TLS 1.3 client initiated re-keying. (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]