Skip to content

Commit

Permalink
Add support for re-keying with TLS 1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
markt-asf authored and jgallimore committed Sep 27, 2024
1 parent fd94264 commit 66008b5
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
2 changes: 2 additions & 0 deletions java/org/apache/tomcat/util/net/LocalStrings.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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}].
Expand Down
26 changes: 24 additions & 2 deletions java/org/apache/tomcat/util/net/SecureNio2Channel.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -763,6 +766,11 @@ private Integer unwrap(int nRead, long timeout, TimeUnit unit) throws ExecutionE
//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) {
Expand Down Expand Up @@ -893,6 +901,8 @@ protected void wrap() {
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) {
Expand Down Expand Up @@ -958,6 +968,11 @@ public void completed(Integer nBytes, A attach) {
//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) {
Expand Down Expand Up @@ -1071,6 +1086,11 @@ public void completed(Integer nBytes, A attach) {
//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) {
Expand Down Expand Up @@ -1180,6 +1200,8 @@ public <A> void write(final ByteBuffer src, final long timeout, final TimeUnit u
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) {
Expand Down
19 changes: 19 additions & 0 deletions java/org/apache/tomcat/util/net/SecureNioChannel.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -621,6 +622,14 @@ public int read(ByteBuffer dst) throws IOException {
//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) {
Expand Down Expand Up @@ -710,6 +719,14 @@ public long read(ByteBuffer[] dsts, int offset, int length)
//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) {
Expand Down Expand Up @@ -808,6 +825,8 @@ public int write(ByteBuffer src) throws IOException {
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();
Expand Down
7 changes: 7 additions & 0 deletions webapps/docs/changelog.xml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,13 @@
</fix>
</changelog>
</subsection>
<subsection name="Coyote">
<changelog>
<add>
Add support for TLS 1.3 client initiated re-keying. (markt)
</add>
</changelog>
</subsection>
<subsection name="Other">
<changelog>
<update>
Expand Down

0 comments on commit 66008b5

Please sign in to comment.