Skip to content

Commit eb1d9da

Browse files
committed
Enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER when using OpenSslContext
Motivation: We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER when using OpenSslContext as the memory address of the buffer that is passed to OpenSslEngine.wrap(...) may change during calls and retries. This is the case as if the buffer is a heap-buffer we will need to copy it to a direct buffer to hand it over to the JNI layer. When not enable this mode we may see errors like: 'error:1409F07F:SSL routines:SSL3_WRITE_PENDING: bad write retry'. Related to netty/netty-tcnative#100. Modifications: Explitict set mode to SSL.SSL_MODE_RELEASE_BUFFERS | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER . (SSL.SSL_MODE_RELEASE_BUFFERS was used before implicitly). Result: No more 'error:1409F07F:SSL routines:SSL3_WRITE_PENDING: bad write retry' possible when writing heap buffers.
1 parent e220c56 commit eb1d9da

3 files changed

Lines changed: 41 additions & 1 deletion

File tree

handler/src/main/java/io/netty/handler/ssl/OpenSslContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ public SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
196196
SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_DH_USE);
197197
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
198198

199+
// We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between
200+
// calling OpenSSLEngine.wrap(...).
201+
// See https://github.com/netty/netty-tcnative/issues/100
202+
SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
203+
199204
/* List the ciphers that are permitted to negotiate. */
200205
try {
201206
SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers));

handler/src/test/java/io/netty/handler/ssl/OpenSslEngineTest.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,22 @@
1515
*/
1616
package io.netty.handler.ssl;
1717

18+
import io.netty.buffer.UnpooledByteBufAllocator;
19+
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
20+
import io.netty.handler.ssl.util.SelfSignedCertificate;
21+
import io.netty.util.internal.ThreadLocalRandom;
1822
import org.junit.Test;
1923

2024
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
2125
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
2226
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
2327

28+
import javax.net.ssl.SSLEngine;
29+
import javax.net.ssl.SSLEngineResult;
30+
import java.nio.ByteBuffer;
31+
2432
import static org.junit.Assert.assertNull;
33+
import static org.junit.Assert.assertSame;
2534
import static org.junit.Assume.assumeTrue;
2635

2736
public class OpenSslEngineTest extends SSLEngineTest {
@@ -103,6 +112,32 @@ public void testSessionInvalidate() throws Exception {
103112
super.testSessionInvalidate();
104113
}
105114

115+
@Test
116+
public void testWrapHeapBuffersNoWritePendingError() throws Exception {
117+
assumeTrue(OpenSsl.isAvailable());
118+
final SslContext clientContext = SslContextBuilder.forClient()
119+
.trustManager(InsecureTrustManagerFactory.INSTANCE)
120+
.sslProvider(sslProvider())
121+
.build();
122+
SelfSignedCertificate ssc = new SelfSignedCertificate();
123+
SslContext serverContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
124+
.sslProvider(sslProvider())
125+
.build();
126+
SSLEngine clientEngine = clientContext.newEngine(UnpooledByteBufAllocator.DEFAULT);
127+
SSLEngine serverEngine = serverContext.newEngine(UnpooledByteBufAllocator.DEFAULT);
128+
handshake(clientEngine, serverEngine);
129+
130+
ByteBuffer src = ByteBuffer.allocate(1024 * 10);
131+
ThreadLocalRandom.current().nextBytes(src.array());
132+
ByteBuffer dst = ByteBuffer.allocate(1);
133+
// Try to wrap multiple times so we are more likely to hit the issue.
134+
for (int i = 0; i < 100; i++) {
135+
src.position(0);
136+
dst.position(0);
137+
assertSame(SSLEngineResult.Status.BUFFER_OVERFLOW, clientEngine.wrap(src, dst).getStatus());
138+
}
139+
}
140+
106141
@Override
107142
protected SslProvider sslProvider() {
108143
return SslProvider.OPENSSL;

handler/src/test/java/io/netty/handler/ssl/SSLEngineTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ protected void testEnablingAnAlreadyDisabledSslProtocol(String[] protocols1, Str
366366
}
367367
}
368368

369-
private static void handshake(SSLEngine clientEngine, SSLEngine serverEngine) throws SSLException {
369+
protected static void handshake(SSLEngine clientEngine, SSLEngine serverEngine) throws SSLException {
370370
int netBufferSize = 17 * 1024;
371371
ByteBuffer cTOs = ByteBuffer.allocateDirect(netBufferSize);
372372
ByteBuffer sTOc = ByteBuffer.allocateDirect(netBufferSize);

0 commit comments

Comments
 (0)