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 https://github.com/netty/netty-tcnative/issues/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.
This commit is contained in:
parent
0b9ff2af3a
commit
4f42079627
@ -196,6 +196,11 @@ public abstract class OpenSslContext extends SslContext {
|
|||||||
SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_DH_USE);
|
SSLContext.setOptions(ctx, SSL.SSL_OP_SINGLE_DH_USE);
|
||||||
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
SSLContext.setOptions(ctx, SSL.SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||||
|
|
||||||
|
// We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between
|
||||||
|
// calling OpenSSLEngine.wrap(...).
|
||||||
|
// See https://github.com/netty/netty-tcnative/issues/100
|
||||||
|
SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
|
||||||
|
|
||||||
/* List the ciphers that are permitted to negotiate. */
|
/* List the ciphers that are permitted to negotiate. */
|
||||||
try {
|
try {
|
||||||
SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers));
|
SSLContext.setCipherSuite(ctx, CipherSuiteConverter.toOpenSsl(unmodifiableCiphers));
|
||||||
|
@ -15,13 +15,22 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.handler.ssl;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
|
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||||
|
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
|
||||||
|
import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||||
|
import io.netty.util.internal.ThreadLocalRandom;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
|
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
|
||||||
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
|
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
|
||||||
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
|
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLEngine;
|
||||||
|
import javax.net.ssl.SSLEngineResult;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
public class OpenSslEngineTest extends SSLEngineTest {
|
public class OpenSslEngineTest extends SSLEngineTest {
|
||||||
@ -103,6 +112,32 @@ public class OpenSslEngineTest extends SSLEngineTest {
|
|||||||
super.testSessionInvalidate();
|
super.testSessionInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWrapHeapBuffersNoWritePendingError() throws Exception {
|
||||||
|
assumeTrue(OpenSsl.isAvailable());
|
||||||
|
final SslContext clientContext = SslContextBuilder.forClient()
|
||||||
|
.trustManager(InsecureTrustManagerFactory.INSTANCE)
|
||||||
|
.sslProvider(sslProvider())
|
||||||
|
.build();
|
||||||
|
SelfSignedCertificate ssc = new SelfSignedCertificate();
|
||||||
|
SslContext serverContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
|
||||||
|
.sslProvider(sslProvider())
|
||||||
|
.build();
|
||||||
|
SSLEngine clientEngine = clientContext.newEngine(UnpooledByteBufAllocator.DEFAULT);
|
||||||
|
SSLEngine serverEngine = serverContext.newEngine(UnpooledByteBufAllocator.DEFAULT);
|
||||||
|
handshake(clientEngine, serverEngine);
|
||||||
|
|
||||||
|
ByteBuffer src = ByteBuffer.allocate(1024 * 10);
|
||||||
|
ThreadLocalRandom.current().nextBytes(src.array());
|
||||||
|
ByteBuffer dst = ByteBuffer.allocate(1);
|
||||||
|
// Try to wrap multiple times so we are more likely to hit the issue.
|
||||||
|
for (int i = 0; i < 100; i++) {
|
||||||
|
src.position(0);
|
||||||
|
dst.position(0);
|
||||||
|
assertSame(SSLEngineResult.Status.BUFFER_OVERFLOW, clientEngine.wrap(src, dst).getStatus());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected SslProvider sslProvider() {
|
protected SslProvider sslProvider() {
|
||||||
return SslProvider.OPENSSL;
|
return SslProvider.OPENSSL;
|
||||||
|
@ -366,7 +366,7 @@ public abstract class SSLEngineTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void handshake(SSLEngine clientEngine, SSLEngine serverEngine) throws SSLException {
|
protected static void handshake(SSLEngine clientEngine, SSLEngine serverEngine) throws SSLException {
|
||||||
int netBufferSize = 17 * 1024;
|
int netBufferSize = 17 * 1024;
|
||||||
ByteBuffer cTOs = ByteBuffer.allocateDirect(netBufferSize);
|
ByteBuffer cTOs = ByteBuffer.allocateDirect(netBufferSize);
|
||||||
ByteBuffer sTOc = ByteBuffer.allocateDirect(netBufferSize);
|
ByteBuffer sTOc = ByteBuffer.allocateDirect(netBufferSize);
|
||||||
|
Loading…
Reference in New Issue
Block a user