Upgrading to Conscrypt 1.0.0.RC9. (#7044)

Motivation:

Starting with 1.0.0.RC9, conscrypt supports a buffer allocator.

Modifications:

- Updated the creation process for the engine to pass through the
ByteBufAllocator.
- Wrap a ByteBufAllocator with an adapter for conscrypt.
- Added a property to optionally control whether conscrypt uses
Netty's buffer allocator.

Result:

Netty+conscrypt will support using Netty's ByteBufAllocator.
This commit is contained in:
Nathan Mittler 2017-08-03 14:21:32 -07:00 committed by GitHub
parent 52f384b37f
commit 4448b8f42f
8 changed files with 98 additions and 26 deletions

View File

@ -19,6 +19,8 @@ import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
import static io.netty.util.internal.ObjectUtil.checkNotNull; import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static java.lang.Math.min; import static java.lang.Math.min;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener; import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector; import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -31,6 +33,9 @@ import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import io.netty.util.internal.PlatformDependent; import io.netty.util.internal.PlatformDependent;
import io.netty.util.internal.SystemPropertyUtil;
import org.conscrypt.AllocatedBuffer;
import org.conscrypt.BufferAllocator;
import org.conscrypt.Conscrypt; import org.conscrypt.Conscrypt;
import org.conscrypt.HandshakeListener; import org.conscrypt.HandshakeListener;
@ -38,6 +43,8 @@ import org.conscrypt.HandshakeListener;
* A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN. * A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN.
*/ */
abstract class ConscryptAlpnSslEngine extends JdkSslEngine { abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
private static final boolean USE_BUFFER_ALLOCATOR = SystemPropertyUtil.getBoolean(
"io.netty.handler.ssl.conscrypt.useBufferAllocator", true);
private static final Class<?> ENGINES_CLASS = getEnginesClass(); private static final Class<?> ENGINES_CLASS = getEnginesClass();
/** /**
@ -51,19 +58,32 @@ abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS); return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS);
} }
static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine, ByteBufAllocator alloc,
JdkApplicationProtocolNegotiator applicationNegotiator) { JdkApplicationProtocolNegotiator applicationNegotiator) {
return new ClientEngine(engine, applicationNegotiator); return new ClientEngine(engine, alloc, applicationNegotiator);
} }
static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine, ByteBufAllocator alloc,
JdkApplicationProtocolNegotiator applicationNegotiator) { JdkApplicationProtocolNegotiator applicationNegotiator) {
return new ServerEngine(engine, applicationNegotiator); return new ServerEngine(engine, alloc, applicationNegotiator);
} }
private ConscryptAlpnSslEngine(SSLEngine engine, List<String> protocols) { private ConscryptAlpnSslEngine(SSLEngine engine, ByteBufAllocator alloc, List<String> protocols) {
super(engine); super(engine);
// Configure the Conscrypt engine to use Netty's buffer allocator. This is a trade-off of memory vs
// performance.
//
// If no allocator is provided, the engine will internally allocate a direct buffer of max packet size in
// order to optimize JNI calls (this happens the first time it is provided a non-direct buffer from the
// application).
//
// Alternatively, if an allocator is provided, no internal buffer will be created and direct buffers will be
// retrieved from the allocator on-demand.
if (USE_BUFFER_ALLOCATOR) {
Conscrypt.Engines.setBufferAllocator(engine, new BufferAllocatorAdapter(alloc));
}
// Set the list of supported ALPN protocols on the engine. // Set the list of supported ALPN protocols on the engine.
Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new String[protocols.size()])); Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new String[protocols.size()]));
} }
@ -90,9 +110,9 @@ abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
private static final class ClientEngine extends ConscryptAlpnSslEngine { private static final class ClientEngine extends ConscryptAlpnSslEngine {
private final ProtocolSelectionListener protocolListener; private final ProtocolSelectionListener protocolListener;
ClientEngine(SSLEngine engine, ClientEngine(SSLEngine engine, ByteBufAllocator alloc,
JdkApplicationProtocolNegotiator applicationNegotiator) { JdkApplicationProtocolNegotiator applicationNegotiator) {
super(engine, applicationNegotiator.protocols()); super(engine, alloc, applicationNegotiator.protocols());
// Register for completion of the handshake. // Register for completion of the handshake.
Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() { Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
@Override @Override
@ -119,8 +139,9 @@ abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
private static final class ServerEngine extends ConscryptAlpnSslEngine { private static final class ServerEngine extends ConscryptAlpnSslEngine {
private final ProtocolSelector protocolSelector; private final ProtocolSelector protocolSelector;
ServerEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator) { ServerEngine(SSLEngine engine, ByteBufAllocator alloc,
super(engine, applicationNegotiator.protocols()); JdkApplicationProtocolNegotiator applicationNegotiator) {
super(engine, alloc, applicationNegotiator.protocols());
// Register for completion of the handshake. // Register for completion of the handshake.
Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() { Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
@ -173,4 +194,44 @@ abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
private static Method getIsConscryptMethod(Class<?> enginesClass) throws NoSuchMethodException { private static Method getIsConscryptMethod(Class<?> enginesClass) throws NoSuchMethodException {
return enginesClass.getMethod("isConscrypt", SSLEngine.class); return enginesClass.getMethod("isConscrypt", SSLEngine.class);
} }
private static final class BufferAllocatorAdapter extends BufferAllocator {
private final ByteBufAllocator alloc;
BufferAllocatorAdapter(ByteBufAllocator alloc) {
this.alloc = alloc;
}
@Override
public AllocatedBuffer allocateDirectBuffer(int capacity) {
return new BufferAdapter(alloc.directBuffer(capacity));
}
}
private static final class BufferAdapter extends AllocatedBuffer {
private final ByteBuf nettyBuffer;
private final ByteBuffer buffer;
BufferAdapter(ByteBuf nettyBuffer) {
this.nettyBuffer = nettyBuffer;
this.buffer = nettyBuffer.nioBuffer(0, nettyBuffer.capacity());
}
@Override
public ByteBuffer nioBuffer() {
return buffer;
}
@Override
public AllocatedBuffer retain() {
nettyBuffer.retain();
return this;
}
@Override
public AllocatedBuffer release() {
nettyBuffer.release();
return this;
}
}
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.ssl; package io.netty.handler.ssl;
import io.netty.buffer.ByteBufAllocator;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
/** /**
@ -108,8 +109,8 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
private static final class FailureWrapper implements SslEngineWrapperFactory { private static final class FailureWrapper implements SslEngineWrapperFactory {
@Override @Override
public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
boolean isServer) { JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
throw new RuntimeException("ALPN unsupported. Is your classpath configured correctly?" throw new RuntimeException("ALPN unsupported. Is your classpath configured correctly?"
+ " For Conscrypt, add the appropriate Conscrypt JAR to classpath and set the security provider." + " For Conscrypt, add the appropriate Conscrypt JAR to classpath and set the security provider."
+ " For Jetty-ALPN, see " + " For Jetty-ALPN, see "
@ -119,11 +120,11 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
private static final class AlpnWrapper implements SslEngineWrapperFactory { private static final class AlpnWrapper implements SslEngineWrapperFactory {
@Override @Override
public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
boolean isServer) { JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
if (ConscryptAlpnSslEngine.isEngineSupported(engine)) { if (ConscryptAlpnSslEngine.isEngineSupported(engine)) {
return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, applicationNegotiator) return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
: ConscryptAlpnSslEngine.newClientEngine(engine, applicationNegotiator); : ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
} }
if (JettyAlpnSslEngine.isAvailable()) { if (JettyAlpnSslEngine.isAvailable()) {
return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator) return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.ssl; package io.netty.handler.ssl;
import io.netty.buffer.ByteBufAllocator;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -31,6 +32,7 @@ public interface JdkApplicationProtocolNegotiator extends ApplicationProtocolNeg
* Abstract factory pattern for wrapping an {@link SSLEngine} object. This is useful for NPN/APLN support. * Abstract factory pattern for wrapping an {@link SSLEngine} object. This is useful for NPN/APLN support.
* *
* @param engine The engine to wrap. * @param engine The engine to wrap.
* @param alloc the buffer allocator.
* @param applicationNegotiator The application level protocol negotiator * @param applicationNegotiator The application level protocol negotiator
* @param isServer <ul> * @param isServer <ul>
* <li>{@code true} if the engine is for server side of connections</li> * <li>{@code true} if the engine is for server side of connections</li>
@ -38,8 +40,8 @@ public interface JdkApplicationProtocolNegotiator extends ApplicationProtocolNeg
* </ul> * </ul>
* @return The resulting wrapped engine. This may just be {@code engine}. * @return The resulting wrapped engine. This may just be {@code engine}.
*/ */
SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
boolean isServer); JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer);
} }
/** /**

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.ssl; package io.netty.handler.ssl;
import io.netty.buffer.ByteBufAllocator;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -29,8 +30,8 @@ final class JdkDefaultApplicationProtocolNegotiator implements JdkApplicationPro
new JdkDefaultApplicationProtocolNegotiator(); new JdkDefaultApplicationProtocolNegotiator();
private static final SslEngineWrapperFactory DEFAULT_SSL_ENGINE_WRAPPER_FACTORY = new SslEngineWrapperFactory() { private static final SslEngineWrapperFactory DEFAULT_SSL_ENGINE_WRAPPER_FACTORY = new SslEngineWrapperFactory() {
@Override @Override
public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
boolean isServer) { JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
return engine; return engine;
} }
}; };

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.handler.ssl; package io.netty.handler.ssl;
import io.netty.buffer.ByteBufAllocator;
import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngine;
/** /**
@ -30,8 +31,8 @@ public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicatio
} }
@Override @Override
public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, public SSLEngine wrapSslEngine(SSLEngine engine, ByteBufAllocator alloc,
boolean isServer) { JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
return new JettyNpnSslEngine(engine, applicationNegotiator, isServer); return new JettyNpnSslEngine(engine, applicationNegotiator, isServer);
} }
}; };

View File

@ -210,15 +210,15 @@ public class JdkSslContext extends SslContext {
@Override @Override
public final SSLEngine newEngine(ByteBufAllocator alloc) { public final SSLEngine newEngine(ByteBufAllocator alloc) {
return configureAndWrapEngine(context().createSSLEngine()); return configureAndWrapEngine(context().createSSLEngine(), alloc);
} }
@Override @Override
public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) { public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
return configureAndWrapEngine(context().createSSLEngine(peerHost, peerPort)); return configureAndWrapEngine(context().createSSLEngine(peerHost, peerPort), alloc);
} }
private SSLEngine configureAndWrapEngine(SSLEngine engine) { private SSLEngine configureAndWrapEngine(SSLEngine engine, ByteBufAllocator alloc) {
engine.setEnabledCipherSuites(cipherSuites); engine.setEnabledCipherSuites(cipherSuites);
engine.setEnabledProtocols(protocols); engine.setEnabledProtocols(protocols);
engine.setUseClientMode(isClient()); engine.setUseClientMode(isClient());
@ -236,7 +236,7 @@ public class JdkSslContext extends SslContext {
throw new Error("Unknown auth " + clientAuth); throw new Error("Unknown auth " + clientAuth);
} }
} }
return apn.wrapperFactory().wrapSslEngine(engine, apn, isServer()); return apn.wrapperFactory().wrapSslEngine(engine, alloc, apn, isServer());
} }
@Override @Override

View File

@ -73,4 +73,10 @@ public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest {
@Override @Override
public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception { public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
} }
@Override
protected boolean mySetupMutualAuthServerIsValidServerException(Throwable cause) {
// TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause);
}
} }

View File

@ -192,7 +192,7 @@
<tcnative.classifier>${os.detected.classifier}</tcnative.classifier> <tcnative.classifier>${os.detected.classifier}</tcnative.classifier>
<conscrypt.groupId>org.conscrypt</conscrypt.groupId> <conscrypt.groupId>org.conscrypt</conscrypt.groupId>
<conscrypt.artifactId>conscrypt-openjdk-uber</conscrypt.artifactId> <conscrypt.artifactId>conscrypt-openjdk-uber</conscrypt.artifactId>
<conscrypt.version>1.0.0.RC7</conscrypt.version> <conscrypt.version>1.0.0.RC9</conscrypt.version>
<conscrypt.classifier /> <conscrypt.classifier />
<jni.classifier>${os.detected.name}-${os.detected.arch}</jni.classifier> <jni.classifier>${os.detected.name}-${os.detected.arch}</jni.classifier>
<logging.config>${project.basedir}/../common/src/test/resources/logback-test.xml</logging.config> <logging.config>${project.basedir}/../common/src/test/resources/logback-test.xml</logging.config>