Adding support for Conscrypt (#6271)

Motivation:

Conscrypt is a Java Security provider that wraps OpenSSL (specifically BoringSSL). It's a possible alternative to Netty-tcnative that we should explore. So this commit is just to enable us to further investigate its use.

Modifications:

Modifying the SslContext creation path to support the Conscrypt provider.

Result:

Netty will support OpenSSL with conscrypt.
This commit is contained in:
Nathan Mittler 2017-03-31 13:55:59 -07:00 committed by GitHub
parent f4c635d30b
commit 1419f5b601
24 changed files with 973 additions and 394 deletions

View File

@ -89,6 +89,11 @@
<artifactId>${tcnative.artifactId}</artifactId>
<classifier>${tcnative.classifier}</classifier>
</dependency>
<dependency>
<groupId>${conscrypt.groupId}</groupId>
<artifactId>${conscrypt.artifactId}</artifactId>
<classifier>${conscrypt.classifier}</classifier>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>

View File

@ -70,6 +70,11 @@
<artifactId>alpn-api</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>${conscrypt.groupId}</groupId>
<artifactId>${conscrypt.artifactId}</artifactId>
<classifier>${conscrypt.classifier}</classifier>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>

View File

@ -0,0 +1,174 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static java.lang.Math.min;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import org.conscrypt.Conscrypt;
import org.conscrypt.HandshakeListener;
/**
* A {@link JdkSslEngine} that uses the Conscrypt provider or SSL with ALPN.
*/
abstract class ConscryptAlpnSslEngine extends JdkSslEngine {
private static final Class<?> ENGINES_CLASS = getEnginesClass();
/**
* Indicates whether or not conscrypt is available on the current system.
*/
static boolean isAvailable() {
return ENGINES_CLASS != null;
}
static boolean isEngineSupported(SSLEngine engine) {
return isAvailable() && isConscryptEngine(engine, ENGINES_CLASS);
}
static ConscryptAlpnSslEngine newClientEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator) {
return new ClientEngine(engine, applicationNegotiator);
}
static ConscryptAlpnSslEngine newServerEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator) {
return new ServerEngine(engine, applicationNegotiator);
}
private ConscryptAlpnSslEngine(SSLEngine engine, List<String> protocols) {
super(engine);
// Set the list of supported ALPN protocols on the engine.
Conscrypt.Engines.setAlpnProtocols(engine, protocols.toArray(new String[protocols.size()]));
}
/**
* Calculates the maximum size of the encrypted output buffer required to wrap the given plaintext bytes. Assumes
* as a worst case that there is one TLS record per buffer.
*
* @param plaintextBytes the number of plaintext bytes to be wrapped.
* @param numBuffers the number of buffers that the plaintext bytes are spread across.
* @return the maximum size of the encrypted output buffer required for the wrap operation.
*/
final int calculateOutNetBufSize(int plaintextBytes, int numBuffers) {
// Assuming a max of one frame per component in a composite buffer.
long maxOverhead = (long) Conscrypt.Engines.maxSealOverhead(getWrappedEngine()) * numBuffers;
// TODO(nmittler): update this to use MAX_ENCRYPTED_PACKET_LENGTH instead of Integer.MAX_VALUE
return (int) min(Integer.MAX_VALUE, plaintextBytes + maxOverhead);
}
final SSLEngineResult unwrap(ByteBuffer[] srcs, ByteBuffer[] dests) throws SSLException {
return Conscrypt.Engines.unwrap(getWrappedEngine(), srcs, dests);
}
private static final class ClientEngine extends ConscryptAlpnSslEngine {
private final ProtocolSelectionListener protocolListener;
ClientEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator) {
super(engine, applicationNegotiator.protocols());
// Register for completion of the handshake.
Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
@Override
public void onHandshakeFinished() throws SSLException {
selectProtocol();
}
});
protocolListener = checkNotNull(applicationNegotiator
.protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
"protocolListener");
}
private void selectProtocol() throws SSLException {
String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine());
try {
protocolListener.selected(protocol);
} catch (Throwable e) {
throw toSSLHandshakeException(e);
}
}
}
private static final class ServerEngine extends ConscryptAlpnSslEngine {
private final ProtocolSelector protocolSelector;
ServerEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator) {
super(engine, applicationNegotiator.protocols());
// Register for completion of the handshake.
Conscrypt.Engines.setHandshakeListener(engine, new HandshakeListener() {
@Override
public void onHandshakeFinished() throws SSLException {
selectProtocol();
}
});
protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
.newSelector(this,
new LinkedHashSet<String>(applicationNegotiator.protocols())),
"protocolSelector");
}
private void selectProtocol() throws SSLException {
try {
String protocol = Conscrypt.Engines.getAlpnSelectedProtocol(getWrappedEngine());
protocolSelector.select(protocol != null ? Collections.singletonList(protocol)
: Collections.<String>emptyList());
} catch (Throwable e) {
throw toSSLHandshakeException(e);
}
}
}
private static Class<?> getEnginesClass() {
try {
// Always use bootstrap class loader.
Class<?> engineClass = Class.forName("org.conscrypt.Conscrypt$Engines", true,
ConscryptAlpnSslEngine.class.getClassLoader());
// Ensure that it also has the isConscrypt method.
getIsConscryptMethod(engineClass);
return engineClass;
} catch (Throwable ignore) {
// Conscrypt was not loaded.
return null;
}
}
private static boolean isConscryptEngine(SSLEngine engine, Class<?> enginesClass) {
try {
Method method = getIsConscryptMethod(enginesClass);
return (Boolean) method.invoke(null, engine);
} catch (Throwable ignore) {
return false;
}
}
private static Method getIsConscryptMethod(Class<?> enginesClass) throws NoSuchMethodException {
return enginesClass.getMethod("isConscrypt", SSLEngine.class);
}
}

View File

@ -21,20 +21,8 @@ import javax.net.ssl.SSLEngine;
* The {@link JdkApplicationProtocolNegotiator} to use if you need ALPN and are using {@link SslProvider#JDK}.
*/
public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
private static final SslEngineWrapperFactory ALPN_WRAPPER = new SslEngineWrapperFactory() {
{
if (!JdkAlpnSslEngine.isAvailable()) {
throw new RuntimeException("ALPN unsupported. Is your classpatch configured correctly?"
+ " See http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting");
}
}
@Override
public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
boolean isServer) {
return new JdkAlpnSslEngine(engine, applicationNegotiator, isServer);
}
};
private static final boolean AVAILABLE = ConscryptAlpnSslEngine.isAvailable() || JettyAlpnSslEngine.isAvailable();
private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
/**
* Create a new instance.
@ -117,4 +105,31 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
ProtocolSelectionListenerFactory listenerFactory, String... protocols) {
super(ALPN_WRAPPER, selectorFactory, listenerFactory, protocols);
}
private static final class FailureWrapper implements SslEngineWrapperFactory {
@Override
public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
boolean isServer) {
throw new RuntimeException("ALPN unsupported. Is your classpatch configured correctly?"
+ " For Conscrypt, add the appropriate Conscrypt JAR to classpath and set the security provider."
+ " For Jetty-ALPN, see "
+ "http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html#alpn-starting");
}
}
private static final class AlpnWrapper implements SslEngineWrapperFactory {
@Override
public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
boolean isServer) {
if (ConscryptAlpnSslEngine.isEngineSupported(engine)) {
return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
: ConscryptAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
}
if (JettyAlpnSslEngine.isAvailable()) {
return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
: JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
}
throw new RuntimeException("Unable to wrap SSLEngine of type " + engine.getClass().getName());
}
}
}

View File

@ -1,126 +0,0 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
import java.util.LinkedHashSet;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import io.netty.util.internal.PlatformDependent;
import org.eclipse.jetty.alpn.ALPN;
import org.eclipse.jetty.alpn.ALPN.ClientProvider;
import org.eclipse.jetty.alpn.ALPN.ServerProvider;
final class JdkAlpnSslEngine extends JdkSslEngine {
private static boolean available;
static boolean isAvailable() {
updateAvailability();
return available;
}
private static void updateAvailability() {
// TODO: Add support for ALPN when using Java9 and still be able to configure it the Netty way.
if (available || PlatformDependent.javaVersion() > 8) {
return;
}
try {
// Always use bootstrap class loader.
Class.forName("sun.security.ssl.ALPNExtension", true, null);
available = true;
} catch (Exception ignore) {
// alpn-boot was not loaded.
}
}
JdkAlpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
super(engine);
checkNotNull(applicationNegotiator, "applicationNegotiator");
if (server) {
final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
.newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
"protocolSelector");
ALPN.put(engine, new ServerProvider() {
@Override
public String select(List<String> protocols) throws SSLException {
try {
return protocolSelector.select(protocols);
} catch (SSLHandshakeException e) {
throw e;
} catch (Throwable t) {
SSLHandshakeException e = new SSLHandshakeException(t.getMessage());
e.initCause(t);
throw e;
}
}
@Override
public void unsupported() {
protocolSelector.unsupported();
}
});
} else {
final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
.protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
"protocolListener");
ALPN.put(engine, new ClientProvider() {
@Override
public List<String> protocols() {
return applicationNegotiator.protocols();
}
@Override
public void selected(String protocol) throws SSLException {
try {
protocolListener.selected(protocol);
} catch (SSLHandshakeException e) {
throw e;
} catch (Throwable t) {
SSLHandshakeException e = new SSLHandshakeException(t.getMessage());
e.initCause(t);
throw e;
}
}
@Override
public void unsupported() {
protocolListener.unsupported();
}
});
}
}
@Override
public void closeInbound() throws SSLException {
ALPN.remove(getWrappedEngine());
super.closeInbound();
}
@Override
public void closeOutbound() {
ALPN.remove(getWrappedEngine());
super.closeOutbound();
}
}

View File

@ -41,7 +41,7 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
* @param listenerFactory How the peer being notified of the selected protocol should behave.
* @param protocols The order of iteration determines the preference of support for protocols.
*/
protected JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
ProtocolSelectorFactory selectorFactory, ProtocolSelectionListenerFactory listenerFactory,
Iterable<String> protocols) {
this(wrapperFactory, selectorFactory, listenerFactory, toList(protocols));
@ -54,7 +54,7 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
* @param listenerFactory How the peer being notified of the selected protocol should behave.
* @param protocols The order of iteration determines the preference of support for protocols.
*/
protected JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
ProtocolSelectorFactory selectorFactory, ProtocolSelectionListenerFactory listenerFactory,
String... protocols) {
this(wrapperFactory, selectorFactory, listenerFactory, toList(protocols));
@ -126,25 +126,25 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
}
};
protected static class NoFailProtocolSelector implements ProtocolSelector {
private final JdkSslEngine jettyWrapper;
static class NoFailProtocolSelector implements ProtocolSelector {
private final JdkSslEngine engineWrapper;
private final Set<String> supportedProtocols;
public NoFailProtocolSelector(JdkSslEngine jettyWrapper, Set<String> supportedProtocols) {
this.jettyWrapper = jettyWrapper;
NoFailProtocolSelector(JdkSslEngine engineWrapper, Set<String> supportedProtocols) {
this.engineWrapper = engineWrapper;
this.supportedProtocols = supportedProtocols;
}
@Override
public void unsupported() {
jettyWrapper.getSession().setApplicationProtocol(null);
engineWrapper.getSession().setApplicationProtocol(null);
}
@Override
public String select(List<String> protocols) throws Exception {
for (String p : supportedProtocols) {
if (protocols.contains(p)) {
jettyWrapper.getSession().setApplicationProtocol(p);
engineWrapper.getSession().setApplicationProtocol(p);
return p;
}
}
@ -152,14 +152,14 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
}
public String noSelectMatchFound() throws Exception {
jettyWrapper.getSession().setApplicationProtocol(null);
engineWrapper.getSession().setApplicationProtocol(null);
return null;
}
}
protected static final class FailProtocolSelector extends NoFailProtocolSelector {
public FailProtocolSelector(JdkSslEngine jettyWrapper, Set<String> supportedProtocols) {
super(jettyWrapper, supportedProtocols);
private static final class FailProtocolSelector extends NoFailProtocolSelector {
FailProtocolSelector(JdkSslEngine engineWrapper, Set<String> supportedProtocols) {
super(engineWrapper, supportedProtocols);
}
@Override
@ -168,40 +168,41 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
}
}
protected static class NoFailProtocolSelectionListener implements ProtocolSelectionListener {
private final JdkSslEngine jettyWrapper;
private static class NoFailProtocolSelectionListener implements ProtocolSelectionListener {
private final JdkSslEngine engineWrapper;
private final List<String> supportedProtocols;
public NoFailProtocolSelectionListener(JdkSslEngine jettyWrapper, List<String> supportedProtocols) {
this.jettyWrapper = jettyWrapper;
NoFailProtocolSelectionListener(JdkSslEngine engineWrapper, List<String> supportedProtocols) {
this.engineWrapper = engineWrapper;
this.supportedProtocols = supportedProtocols;
}
@Override
public void unsupported() {
jettyWrapper.getSession().setApplicationProtocol(null);
engineWrapper.getSession().setApplicationProtocol(null);
}
@Override
public void selected(String protocol) throws Exception {
if (supportedProtocols.contains(protocol)) {
jettyWrapper.getSession().setApplicationProtocol(protocol);
engineWrapper.getSession().setApplicationProtocol(protocol);
} else {
noSelectedMatchFound(protocol);
}
}
public void noSelectedMatchFound(String protocol) throws Exception {
protected void noSelectedMatchFound(String protocol) throws Exception {
// Will never be called.
}
}
protected static final class FailProtocolSelectionListener extends NoFailProtocolSelectionListener {
public FailProtocolSelectionListener(JdkSslEngine jettyWrapper, List<String> supportedProtocols) {
super(jettyWrapper, supportedProtocols);
private static final class FailProtocolSelectionListener extends NoFailProtocolSelectionListener {
FailProtocolSelectionListener(JdkSslEngine engineWrapper, List<String> supportedProtocols) {
super(engineWrapper, supportedProtocols);
}
@Override
public void noSelectedMatchFound(String protocol) throws Exception {
protected void noSelectedMatchFound(String protocol) throws Exception {
throw new SSLHandshakeException("No compatible protocols found");
}
}

View File

@ -23,7 +23,7 @@ import javax.net.ssl.SSLEngine;
public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
private static final SslEngineWrapperFactory NPN_WRAPPER = new SslEngineWrapperFactory() {
{
if (!JdkNpnSslEngine.isAvailable()) {
if (!JettyNpnSslEngine.isAvailable()) {
throw new RuntimeException("NPN unsupported. Is your classpatch configured correctly?"
+ " See https://wiki.eclipse.org/Jetty/Feature/NPN");
}
@ -32,7 +32,7 @@ public final class JdkNpnApplicationProtocolNegotiator extends JdkBaseApplicatio
@Override
public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
boolean isServer) {
return new JdkNpnSslEngine(engine, applicationNegotiator, isServer);
return new JettyNpnSslEngine(engine, applicationNegotiator, isServer);
}
};

View File

@ -16,6 +16,7 @@
package io.netty.handler.ssl;
import java.security.Provider;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
@ -164,8 +165,17 @@ public final class JdkSslClientContext extends JdkSslContext {
File certChainFile, TrustManagerFactory trustManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
this(certChainFile, trustManagerFactory, null, null, null, null,
ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
this(null, certChainFile, trustManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
}
JdkSslClientContext(Provider provider,
File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
super(newSSLContext(provider, toX509CertificatesInternal(trustCertCollectionFile),
trustManagerFactory, null, null,
null, null, sessionCacheSize, sessionTimeout), true,
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
}
/**
@ -244,24 +254,26 @@ public final class JdkSslClientContext extends JdkSslContext {
File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
super(newSSLContext(toX509CertificatesInternal(
super(newSSLContext(null, toX509CertificatesInternal(
trustCertCollectionFile), trustManagerFactory,
toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout), true,
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
}
JdkSslClientContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
JdkSslClientContext(Provider sslContextProvider,
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn, String[] protocols, long sessionCacheSize, long sessionTimeout)
throws SSLException {
super(newSSLContext(trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, sessionCacheSize, sessionTimeout), true,
ciphers, cipherFilter, toNegotiator(apn, false), ClientAuth.NONE, protocols, false);
super(newSSLContext(sslContextProvider, trustCertCollection, trustManagerFactory,
keyCertChain, key, keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout),
true, ciphers, cipherFilter, toNegotiator(apn, false), ClientAuth.NONE, protocols, false);
}
private static SSLContext newSSLContext(X509Certificate[] trustCertCollection,
private static SSLContext newSSLContext(Provider sslContextProvider,
X509Certificate[] trustCertCollection,
TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain,
PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
long sessionCacheSize, long sessionTimeout) throws SSLException {
@ -272,7 +284,8 @@ public final class JdkSslClientContext extends JdkSslContext {
if (keyCertChain != null) {
keyManagerFactory = buildKeyManagerFactory(keyCertChain, key, keyPassword, keyManagerFactory);
}
SSLContext ctx = SSLContext.getInstance(PROTOCOL);
SSLContext ctx = sslContextProvider == null ? SSLContext.getInstance(PROTOCOL)
: SSLContext.getInstance(PROTOCOL, sslContextProvider);
ctx.init(keyManagerFactory == null ? null : keyManagerFactory.getKeyManagers(),
trustManagerFactory == null ? null : trustManagerFactory.getTrustManagers(),
null);

View File

@ -16,6 +16,7 @@
package io.netty.handler.ssl;
import java.security.Provider;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
@ -138,8 +139,17 @@ public final class JdkSslServerContext extends JdkSslContext {
File certChainFile, File keyFile, String keyPassword,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
this(null, null, certChainFile, keyFile, keyPassword, null,
ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
this(null, certChainFile, keyFile, keyPassword, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
}
JdkSslServerContext(Provider provider,
File certChainFile, File keyFile, String keyPassword,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
super(newSSLContext(provider, null, null,
toX509CertificatesInternal(certChainFile), toPrivateKeyInternal(keyFile, keyPassword),
keyPassword, null, sessionCacheSize, sessionTimeout), false,
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
}
/**
@ -212,23 +222,24 @@ public final class JdkSslServerContext extends JdkSslContext {
File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, JdkApplicationProtocolNegotiator apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
super(newSSLContext(toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
super(newSSLContext(null, toX509CertificatesInternal(trustCertCollectionFile), trustManagerFactory,
toX509CertificatesInternal(keyCertChainFile), toPrivateKeyInternal(keyFile, keyPassword),
keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout), false,
ciphers, cipherFilter, apn, ClientAuth.NONE, null, false);
}
JdkSslServerContext(X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
JdkSslServerContext(Provider provider,
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword,
KeyManagerFactory keyManagerFactory, Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
ApplicationProtocolConfig apn, long sessionCacheSize, long sessionTimeout,
ClientAuth clientAuth, String[] protocols, boolean startTls) throws SSLException {
super(newSSLContext(trustCertCollection, trustManagerFactory, keyCertChain, key,
super(newSSLContext(provider, trustCertCollection, trustManagerFactory, keyCertChain, key,
keyPassword, keyManagerFactory, sessionCacheSize, sessionTimeout), false,
ciphers, cipherFilter, toNegotiator(apn, true), clientAuth, protocols, startTls);
}
private static SSLContext newSSLContext(X509Certificate[] trustCertCollection,
private static SSLContext newSSLContext(Provider sslContextProvider, X509Certificate[] trustCertCollection,
TrustManagerFactory trustManagerFactory, X509Certificate[] keyCertChain,
PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
long sessionCacheSize, long sessionTimeout)
@ -246,7 +257,8 @@ public final class JdkSslServerContext extends JdkSslContext {
}
// Initialize the SSLContext to work with our key managers.
SSLContext ctx = SSLContext.getInstance(PROTOCOL);
SSLContext ctx = sslContextProvider == null ? SSLContext.getInstance(PROTOCOL)
: SSLContext.getInstance(PROTOCOL, sslContextProvider);
ctx.init(keyManagerFactory.getKeyManagers(),
trustManagerFactory == null ? null : trustManagerFactory.getTrustManagers(),
null);

View File

@ -0,0 +1,158 @@
/*
* Copyright 2014 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
import java.util.LinkedHashSet;
import java.util.List;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import io.netty.util.internal.PlatformDependent;
import org.eclipse.jetty.alpn.ALPN;
abstract class JettyAlpnSslEngine extends JdkSslEngine {
private static final boolean available = initAvailable();
static boolean isAvailable() {
return available;
}
private static boolean initAvailable() {
// TODO: Add support for ALPN when using Java9 and still be able to configure it the Netty way.
if (PlatformDependent.javaVersion() <= 8) {
try {
// Always use bootstrap class loader.
Class.forName("sun.security.ssl.ALPNExtension", true, null);
return true;
} catch (Throwable ignore) {
// alpn-boot was not loaded.
}
}
return false;
}
static JettyAlpnSslEngine newClientEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator) {
return new ClientEngine(engine, applicationNegotiator);
}
static JettyAlpnSslEngine newServerEngine(SSLEngine engine,
JdkApplicationProtocolNegotiator applicationNegotiator) {
return new ServerEngine(engine, applicationNegotiator);
}
private JettyAlpnSslEngine(SSLEngine engine) {
super(engine);
}
private static final class ClientEngine extends JettyAlpnSslEngine {
ClientEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
super(engine);
checkNotNull(applicationNegotiator, "applicationNegotiator");
final ProtocolSelectionListener protocolListener = checkNotNull(applicationNegotiator
.protocolListenerFactory().newListener(this, applicationNegotiator.protocols()),
"protocolListener");
ALPN.put(engine, new ALPN.ClientProvider() {
@Override
public List<String> protocols() {
return applicationNegotiator.protocols();
}
@Override
public void selected(String protocol) throws SSLException {
try {
protocolListener.selected(protocol);
} catch (Throwable t) {
throw toSSLHandshakeException(t);
}
}
@Override
public void unsupported() {
protocolListener.unsupported();
}
});
}
@Override
public void closeInbound() throws SSLException {
try {
ALPN.remove(getWrappedEngine());
} finally {
super.closeInbound();
}
}
@Override
public void closeOutbound() {
try {
ALPN.remove(getWrappedEngine());
} finally {
super.closeOutbound();
}
}
}
private static final class ServerEngine extends JettyAlpnSslEngine {
ServerEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator) {
super(engine);
checkNotNull(applicationNegotiator, "applicationNegotiator");
final ProtocolSelector protocolSelector = checkNotNull(applicationNegotiator.protocolSelectorFactory()
.newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())),
"protocolSelector");
ALPN.put(engine, new ALPN.ServerProvider() {
@Override
public String select(List<String> protocols) throws SSLException {
try {
return protocolSelector.select(protocols);
} catch (Throwable t) {
throw toSSLHandshakeException(t);
}
}
@Override
public void unsupported() {
protocolSelector.unsupported();
}
});
}
@Override
public void closeInbound() throws SSLException {
try {
ALPN.remove(getWrappedEngine());
} finally {
super.closeInbound();
}
}
@Override
public void closeOutbound() {
try {
ALPN.remove(getWrappedEngine());
} finally {
super.closeOutbound();
}
}
}
}

View File

@ -31,7 +31,7 @@ import org.eclipse.jetty.npn.NextProtoNego;
import org.eclipse.jetty.npn.NextProtoNego.ClientProvider;
import org.eclipse.jetty.npn.NextProtoNego.ServerProvider;
final class JdkNpnSslEngine extends JdkSslEngine {
final class JettyNpnSslEngine extends JdkSslEngine {
private static boolean available;
static boolean isAvailable() {
@ -52,7 +52,7 @@ final class JdkNpnSslEngine extends JdkSslEngine {
}
}
JdkNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
JettyNpnSslEngine(SSLEngine engine, final JdkApplicationProtocolNegotiator applicationNegotiator, boolean server) {
super(engine);
checkNotNull(applicationNegotiator, "applicationNegotiator");

View File

@ -26,6 +26,7 @@ import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBeh
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
import io.netty.util.internal.EmptyArrays;
import java.security.Provider;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.crypto.Cipher;
@ -380,8 +381,8 @@ public abstract class SslContext {
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
try {
return newServerContextInternal(provider, toX509Certificates(trustCertCollectionFile), trustManagerFactory,
toX509Certificates(keyCertChainFile),
return newServerContextInternal(provider, null, toX509Certificates(trustCertCollectionFile),
trustManagerFactory, toX509Certificates(keyCertChainFile),
toPrivateKey(keyFile, keyPassword),
keyPassword, keyManagerFactory, ciphers, cipherFilter, apn,
sessionCacheSize, sessionTimeout, ClientAuth.NONE, null, false);
@ -395,6 +396,7 @@ public abstract class SslContext {
static SslContext newServerContextInternal(
SslProvider provider,
Provider sslContextProvider,
X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
@ -407,16 +409,18 @@ public abstract class SslContext {
switch (provider) {
case JDK:
return new JdkSslServerContext(
return new JdkSslServerContext(sslContextProvider,
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls);
case OPENSSL:
verifyNullSslContextProvider(provider, sslContextProvider);
return new OpenSslServerContext(
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
clientAuth, protocols, startTls);
case OPENSSL_REFCNT:
verifyNullSslContextProvider(provider, sslContextProvider);
return new ReferenceCountedOpenSslServerContext(
trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
@ -426,6 +430,12 @@ public abstract class SslContext {
}
}
private static void verifyNullSslContextProvider(SslProvider provider, Provider sslContextProvider) {
if (sslContextProvider != null) {
throw new IllegalArgumentException("Java Security Provider unsupported for SslProvider: " + provider);
}
}
/**
* Creates a new client-side {@link SslContext}.
*
@ -719,13 +729,15 @@ public abstract class SslContext {
*/
@Deprecated
public static SslContext newClientContext(
SslProvider provider,
File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
SslProvider provider,
File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
File keyCertChainFile, File keyFile, String keyPassword,
KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
long sessionCacheSize, long sessionTimeout) throws SSLException {
try {
return newClientContextInternal(provider, toX509Certificates(trustCertCollectionFile), trustManagerFactory,
return newClientContextInternal(provider, null,
toX509Certificates(trustCertCollectionFile), trustManagerFactory,
toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword),
keyPassword, keyManagerFactory, ciphers, cipherFilter,
apn, null, sessionCacheSize, sessionTimeout);
@ -739,6 +751,7 @@ public abstract class SslContext {
static SslContext newClientContextInternal(
SslProvider provider,
Provider sslContextProvider,
X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory,
X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
@ -748,14 +761,16 @@ public abstract class SslContext {
}
switch (provider) {
case JDK:
return new JdkSslClientContext(
return new JdkSslClientContext(sslContextProvider,
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout);
case OPENSSL:
verifyNullSslContextProvider(provider, sslContextProvider);
return new OpenSslClientContext(
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout);
case OPENSSL_REFCNT:
verifyNullSslContextProvider(provider, sslContextProvider);
return new ReferenceCountedOpenSslClientContext(
trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout);

View File

@ -16,16 +16,17 @@
package io.netty.handler.ssl;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import java.security.Provider;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManagerFactory;
import java.io.File;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManagerFactory;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
/**
* Builder for configuring a new SslContext for creation.
@ -126,6 +127,7 @@ public final class SslContextBuilder {
private final boolean forServer;
private SslProvider provider;
private Provider sslContextProvider;
private X509Certificate[] trustCertCollection;
private TrustManagerFactory trustManagerFactory;
private X509Certificate[] keyCertChain;
@ -153,6 +155,15 @@ public final class SslContextBuilder {
return this;
}
/**
* The SSLContext {@link Provider} to use. {@code null} uses the default one. This is only
* used with {@link SslProvider#JDK}.
*/
public SslContextBuilder sslContextProvider(Provider sslContextProvider) {
this.sslContextProvider = sslContextProvider;
return this;
}
/**
* Trusted certificates for verifying the remote endpoint's certificate. The file should
* contain an X.509 certificate collection in PEM format. {@code null} uses the system default.
@ -411,11 +422,11 @@ public final class SslContextBuilder {
*/
public SslContext build() throws SSLException {
if (forServer) {
return SslContext.newServerContextInternal(provider, trustCertCollection,
return SslContext.newServerContextInternal(provider, sslContextProvider, trustCertCollection,
trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, clientAuth, protocols, startTls);
} else {
return SslContext.newClientContextInternal(provider, trustCertCollection,
return SslContext.newClientContextInternal(provider, sslContextProvider, trustCertCollection,
trustManagerFactory, keyCertChain, key, keyPassword, keyManagerFactory,
ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout);
}

View File

@ -188,7 +188,7 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
int writerIndex = out.writerIndex();
final SSLEngineResult result;
if (nioBufferCount > 1) {
/**
/*
* If {@link OpenSslEngine} is in use,
* we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
* that accepts multiple {@link ByteBuffer}s without additional memory copies.
@ -214,6 +214,38 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
return ReferenceCountedOpenSslEngine.calculateOutNetBufSize(pendingBytes, numComponents);
}
},
CONSCRYPT(true, COMPOSITE_CUMULATOR) {
@Override
SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
throws SSLException {
int nioBufferCount = in.nioBufferCount();
int writerIndex = out.writerIndex();
final SSLEngineResult result;
if (nioBufferCount > 1) {
/*
* Use a special unwrap method without additional memory copies.
*/
try {
handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
in.nioBuffers(readerIndex, len),
handler.singleBuffer);
} finally {
handler.singleBuffer[0] = null;
}
} else {
result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
toByteBuffer(out, writerIndex, out.writableBytes()));
}
out.writerIndex(writerIndex + result.bytesProduced());
return result;
}
@Override
int calculateOutNetBufSize(SslHandler handler, int pendingBytes, int numComponents) {
return ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents);
}
},
JDK(false, MERGE_CUMULATOR) {
@Override
SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
@ -232,7 +264,13 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
};
static SslEngineType forEngine(SSLEngine engine) {
return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE : JDK;
if (engine instanceof ReferenceCountedOpenSslEngine) {
return TCNATIVE;
}
if (engine instanceof ConscryptAlpnSslEngine) {
return CONSCRYPT;
}
return JDK;
}
SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {

View File

@ -22,6 +22,7 @@ import io.netty.handler.codec.base64.Base64;
import io.netty.handler.codec.base64.Base64Dialect;
import java.nio.ByteBuffer;
import javax.net.ssl.SSLHandshakeException;
/**
* Constants for SSL packets.
@ -68,6 +69,17 @@ final class SslUtils {
*/
static final int NOT_ENCRYPTED = -2;
/**
* Converts the given exception to a {@link SSLHandshakeException}, if it isn't already.
*/
static SSLHandshakeException toSSLHandshakeException(Throwable e) {
if (e instanceof SSLHandshakeException) {
return (SSLHandshakeException) e;
}
return (SSLHandshakeException) new SSLHandshakeException(e.getMessage()).initCause(e);
}
/**
* Return how much bytes can be read out of the encrypted data. Be aware that this method will not increase
* the readerIndex of the given {@link ByteBuf}.

View File

@ -0,0 +1,79 @@
/*
* Copyright 2016 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
import java.security.Provider;
import org.conscrypt.OpenSSLProvider;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import javax.net.ssl.SSLException;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.junit.Assume.assumeTrue;
@RunWith(Parameterized.class)
public class ConscryptJdkSslEngineInteropTest extends SSLEngineTest {
@Parameterized.Parameters(name = "{index}: bufferType = {0}")
public static Collection<Object> data() {
List<Object> params = new ArrayList<Object>();
for (BufferType type: BufferType.values()) {
params.add(type);
}
return params;
}
public ConscryptJdkSslEngineInteropTest(BufferType type) {
super(type);
}
@BeforeClass
public static void checkConscrypt() {
assumeTrue(ConscryptAlpnSslEngine.isAvailable());
}
@Override
protected SslProvider sslClientProvider() {
return SslProvider.JDK;
}
@Override
protected SslProvider sslServerProvider() {
return SslProvider.JDK;
}
@Override
protected Provider clientSslContextProvider() {
return new OpenSSLProvider();
}
@Ignore /* Does the JDK support a "max certificate chain length"? */
@Override
public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
}
@Ignore /* Does the JDK support a "max certificate chain length"? */
@Override
public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 2017 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
import java.security.Provider;
import org.conscrypt.OpenSSLProvider;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static org.junit.Assume.assumeTrue;
@RunWith(Parameterized.class)
public class JdkConscryptSslEngineInteropTest extends SSLEngineTest {
@Parameterized.Parameters(name = "{index}: bufferType = {0}")
public static Collection<Object> data() {
List<Object> params = new ArrayList<Object>();
for (BufferType type: BufferType.values()) {
params.add(type);
}
return params;
}
public JdkConscryptSslEngineInteropTest(BufferType type) {
super(type);
}
@BeforeClass
public static void checkConscrypt() {
assumeTrue(ConscryptAlpnSslEngine.isAvailable());
}
@Override
protected SslProvider sslClientProvider() {
return SslProvider.JDK;
}
@Override
protected SslProvider sslServerProvider() {
return SslProvider.JDK;
}
@Override
protected Provider serverSslContextProvider() {
return new OpenSSLProvider();
}
@Override
@Test
@Ignore("TODO: Make this work with Conscrypt")
public void testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth() throws Exception {
super.testMutualAuthValidClientCertChainTooLongFailOptionalClientAuth();
}
@Override
@Test
@Ignore("TODO: Make this work with Conscrypt")
public void testMutualAuthValidClientCertChainTooLongFailRequireClientAuth() throws Exception {
super.testMutualAuthValidClientCertChainTooLongFailRequireClientAuth();
}
@Override
protected boolean mySetupMutualAuthServerIsValidClientException(Throwable cause) {
// TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
}
}

View File

@ -17,15 +17,29 @@ package io.netty.handler.ssl;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import javax.net.ssl.SSLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
import static io.netty.internal.tcnative.SSL.SSL_CVERIFY_IGNORED;
import static org.junit.Assume.assumeTrue;
@RunWith(Parameterized.class)
public class JdkOpenSslEngineInteroptTest extends SSLEngineTest {
@Parameterized.Parameters(name = "{index}: bufferType = {0}")
public static Collection<Object> data() {
List<Object> params = new ArrayList<Object>();
for (BufferType type: BufferType.values()) {
params.add(type);
}
return params;
}
public JdkOpenSslEngineInteroptTest(BufferType type) {
super(type);
}

View File

@ -22,128 +22,132 @@ import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
import io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectorFactory;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.security.Provider;
import java.util.ArrayList;
import java.util.Collection;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeNoException;
@RunWith(Parameterized.class)
public class JdkSslEngineTest extends SSLEngineTest {
public enum ProviderType {
NPN_DEFAULT {
@Override
boolean isAvailable() {
return JettyNpnSslEngine.isAvailable();
}
@Override
Protocol protocol() {
return Protocol.NPN;
}
@Override
Provider provider() {
return null;
}
},
ALPN_DEFAULT {
@Override
boolean isAvailable() {
return JettyAlpnSslEngine.isAvailable();
}
@Override
Protocol protocol() {
return Protocol.ALPN;
}
@Override
Provider provider() {
// Use the default provider.
return null;
}
},
ALPN_CONSCRYPT {
private Provider provider;
@Override
boolean isAvailable() {
return ConscryptAlpnSslEngine.isAvailable();
}
@Override
Protocol protocol() {
return Protocol.ALPN;
}
@Override
Provider provider() {
try {
if (provider == null) {
provider = (Provider) Class.forName("org.conscrypt.OpenSSLProvider")
.getConstructor().newInstance();
}
return provider;
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
};
abstract boolean isAvailable();
abstract Protocol protocol();
abstract Provider provider();
final void activate(JdkSslEngineTest instance) {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!isAvailable()) {
throw tlsExtensionNotFound(protocol());
}
instance.provider = provider();
}
}
private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2";
private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1";
private static final String APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE = "my-protocol-FOO";
public JdkSslEngineTest(BufferType type) {
super(type);
}
@Test
public void testNpn() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkNpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.NPN);
@Parameterized.Parameters(name = "{index}: providerType = {0}, bufferType = {1}")
public static Collection<Object[]> data() {
List<Object[]> params = new ArrayList<Object[]>();
for (ProviderType providerType : ProviderType.values()) {
for (BufferType bufferType : BufferType.values()) {
params.add(new Object[]{providerType, bufferType});
}
ApplicationProtocolConfig apn = failingNegotiator(Protocol.NPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
setupHandlers(apn);
runTest();
} catch (SkipTestException e) {
// NPN availability is dependent on the java version. If NPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
assumeNoException(e);
}
return params;
}
private final ProviderType providerType;
private Provider provider;
public JdkSslEngineTest(ProviderType providerType, BufferType bufferType) {
super(bufferType);
this.providerType = providerType;
}
@Test
public void testNpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
public void testTlsExtension() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkNpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.NPN);
}
ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
setupHandlers(serverApn, clientApn);
runTest(null);
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
assumeNoException(e);
}
}
@Test
public void testNpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkNpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.NPN);
}
ApplicationProtocolConfig clientApn = failingNegotiator(Protocol.NPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.NPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
setupHandlers(serverApn, clientApn);
assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
assertTrue(clientException instanceof SSLHandshakeException);
} catch (SkipTestException e) {
// NPN availability is dependent on the java version. If NPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
assumeNoException(e);
}
}
@Test
public void testNpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkNpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.NPN);
}
ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.NPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.NPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
setupHandlers(serverApn, clientApn);
assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
assertTrue(serverException instanceof SSLHandshakeException);
} catch (SkipTestException e) {
// NPN availability is dependent on the java version. If NPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
assumeNoException(e);
}
}
@Test
public void testAlpn() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkAlpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.ALPN);
}
ApplicationProtocolConfig apn = failingNegotiator(Protocol.ALPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
providerType.activate(this);
ApplicationProtocolConfig apn = failingNegotiator(providerType.protocol(),
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
setupHandlers(apn);
runTest();
} catch (SkipTestException e) {
@ -154,18 +158,13 @@ public class JdkSslEngineTest extends SSLEngineTest {
}
@Test
public void testAlpnNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
public void testTlsExtensionNoCompatibleProtocolsNoHandshakeFailure() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkAlpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.ALPN);
}
ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = acceptingNegotiator(Protocol.ALPN,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
providerType.activate(this);
ApplicationProtocolConfig clientApn = acceptingNegotiator(providerType.protocol(),
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = acceptingNegotiator(providerType.protocol(),
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
setupHandlers(serverApn, clientApn);
runTest(null);
} catch (SkipTestException e) {
@ -176,66 +175,23 @@ public class JdkSslEngineTest extends SSLEngineTest {
}
@Test
public void testAlpnNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
public void testTlsExtensionNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkAlpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.ALPN);
}
ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
providerType.activate(this);
if (providerType == ProviderType.NPN_DEFAULT) {
ApplicationProtocolConfig clientApn = failingNegotiator(providerType.protocol(),
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
ApplicationProtocolConfig serverApn = acceptingNegotiator(providerType.protocol(),
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
setupHandlers(serverApn, clientApn);
assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
assertTrue(serverException instanceof SSLHandshakeException);
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
assumeNoException(e);
}
}
@Test
public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkAlpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.ALPN);
}
// Even the preferred application protocol appears second in the client's list, it will be picked
// because it's the first one on server's list.
ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
setupHandlers(serverApn, clientApn);
assertNull(serverException);
runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
assumeNoException(e);
}
}
@Test
public void testAlpnNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
try {
// Typical code will not have to check this, but will get a initialization error on class load.
// Check in this test just in case we have multiple tests that just the class and we already ignored the
// initialization error.
if (!JdkAlpnSslEngine.isAvailable()) {
throw tlsExtensionNotFound(Protocol.ALPN);
}
SelfSignedCertificate ssc = new SelfSignedCertificate();
JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(true, true,
setupHandlers(serverApn, clientApn);
assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
assertTrue(clientException instanceof SSLHandshakeException);
} else {
// ALPN
SelfSignedCertificate ssc = new SelfSignedCertificate();
JdkApplicationProtocolNegotiator clientApn = new JdkAlpnApplicationProtocolNegotiator(true, true,
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(
JdkApplicationProtocolNegotiator serverApn = new JdkAlpnApplicationProtocolNegotiator(
new ProtocolSelectorFactory() {
@Override
public ProtocolSelector newSelector(SSLEngine engine, Set<String> supportedProtocols) {
@ -253,14 +209,59 @@ public class JdkSslEngineTest extends SSLEngineTest {
}, JdkBaseApplicationProtocolNegotiator.FAIL_SELECTION_LISTENER_FACTORY,
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
SslContext serverSslCtx = new JdkSslServerContext(ssc.certificate(), ssc.privateKey(), null, null,
SslContext serverSslCtx = new JdkSslServerContext(providerType.provider(),
ssc.certificate(), ssc.privateKey(), null, null,
IdentityCipherSuiteFilter.INSTANCE, serverApn, 0, 0);
SslContext clientSslCtx = new JdkSslClientContext(null, InsecureTrustManagerFactory.INSTANCE, null,
SslContext clientSslCtx = new JdkSslClientContext(providerType.provider(), null,
InsecureTrustManagerFactory.INSTANCE, null,
IdentityCipherSuiteFilter.INSTANCE, clientApn, 0, 0);
setupHandlers(serverSslCtx, clientSslCtx);
assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
assertTrue(clientException instanceof SSLHandshakeException);
setupHandlers(serverSslCtx, clientSslCtx);
assertTrue(clientLatch.await(2, TimeUnit.SECONDS));
assertTrue(clientException instanceof SSLHandshakeException);
}
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
assumeNoException(e);
}
}
@Test
public void testTlsExtensionNoCompatibleProtocolsServerHandshakeFailure() throws Exception {
try {
providerType.activate(this);
ApplicationProtocolConfig clientApn = acceptingNegotiator(providerType.protocol(),
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = failingNegotiator(providerType.protocol(),
APPLICATION_LEVEL_PROTOCOL_NOT_COMPATIBLE);
setupHandlers(serverApn, clientApn);
assertTrue(serverLatch.await(2, TimeUnit.SECONDS));
assertTrue(serverException instanceof SSLHandshakeException);
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
assumeNoException(e);
}
}
@Test
public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
try {
providerType.activate(this);
if (providerType == ProviderType.NPN_DEFAULT) {
// This test only applies to ALPN.
throw tlsExtensionNotFound(providerType.protocol());
}
// Even the preferred application protocol appears second in the client's list, it will be picked
// because it's the first one on server's list.
ApplicationProtocolConfig clientApn = acceptingNegotiator(Protocol.ALPN,
FALLBACK_APPLICATION_LEVEL_PROTOCOL, PREFERRED_APPLICATION_LEVEL_PROTOCOL);
ApplicationProtocolConfig serverApn = failingNegotiator(Protocol.ALPN,
PREFERRED_APPLICATION_LEVEL_PROTOCOL, FALLBACK_APPLICATION_LEVEL_PROTOCOL);
setupHandlers(serverApn, clientApn);
assertNull(serverException);
runTest(PREFERRED_APPLICATION_LEVEL_PROTOCOL);
} catch (SkipTestException e) {
// ALPN availability is dependent on the java version. If ALPN is not available because of
// java version incompatibility don't fail the test, but instead just skip the test
@ -303,6 +304,16 @@ public class JdkSslEngineTest extends SSLEngineTest {
return SslProvider.JDK;
}
@Override
protected Provider clientSslContextProvider() {
return provider;
}
@Override
protected Provider serverSslContextProvider() {
return provider;
}
private ApplicationProtocolConfig failingNegotiator(Protocol protocol,
String... supportedProtocols) {
return new ApplicationProtocolConfig(protocol,
@ -319,12 +330,12 @@ public class JdkSslEngineTest extends SSLEngineTest {
supportedProtocols);
}
private SkipTestException tlsExtensionNotFound(Protocol protocol) {
private static SkipTestException tlsExtensionNotFound(Protocol protocol) {
throw new SkipTestException(protocol + " not on classpath");
}
private static final class SkipTestException extends RuntimeException {
public SkipTestException(String message) {
SkipTestException(String message) {
super(message);
}
}

View File

@ -25,6 +25,8 @@ import io.netty.util.internal.PlatformDependent;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.nio.ByteBuffer;
import java.security.AlgorithmConstraints;
@ -32,6 +34,7 @@ import java.security.AlgorithmParameters;
import java.security.CryptoPrimitive;
import java.security.Key;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.net.ssl.SSLEngine;
@ -52,10 +55,20 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
@RunWith(Parameterized.class)
public class OpenSslEngineTest extends SSLEngineTest {
private static final String PREFERRED_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http2";
private static final String FALLBACK_APPLICATION_LEVEL_PROTOCOL = "my-protocol-http1_1";
@Parameterized.Parameters(name = "{index}: bufferType = {0}")
public static Collection<Object> data() {
List<Object> params = new ArrayList<Object>();
for (BufferType type: BufferType.values()) {
params.add(type);
}
return params;
}
public OpenSslEngineTest(BufferType type) {
super(type);
}

View File

@ -20,12 +20,28 @@ import org.junit.Ignore;
import org.junit.Test;
import javax.net.ssl.SSLException;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static io.netty.handler.ssl.OpenSslTestUtils.checkShouldUseKeyManagerFactory;
import static org.junit.Assume.assumeTrue;
@RunWith(Parameterized.class)
public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest {
@Parameterized.Parameters(name = "{index}: bufferType = {0}")
public static Collection<Object> data() {
List<Object> params = new ArrayList<Object>();
for (BufferType type: BufferType.values()) {
params.add(type);
}
return params;
}
public OpenSslJdkSslEngineInteroptTest(BufferType type) {
super(type);
}

View File

@ -45,8 +45,6 @@ import io.netty.util.internal.PlatformDependent;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@ -61,8 +59,7 @@ import java.nio.channels.ClosedChannelException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collection;
import java.security.Provider;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@ -86,7 +83,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.verify;
@RunWith(Parameterized.class)
public abstract class SSLEngineTest {
private static final String X509_CERT_PEM =
@ -202,15 +198,6 @@ public abstract class SSLEngineTest {
Mixed
}
@Parameterized.Parameters(name = "{index}: bufferType = {0}")
public static Collection<Object> data() {
List<Object> params = new ArrayList<Object>();
for (BufferType type: BufferType.values()) {
params.add(type);
}
return params;
}
private final BufferType type;
protected SSLEngineTest(BufferType type) {
@ -624,6 +611,7 @@ public abstract class SSLEngineTest {
throws SSLException, InterruptedException {
serverSslCtx = SslContextBuilder.forServer(serverKMF)
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider())
.trustManager(serverTrustManager)
.clientAuth(clientAuth)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
@ -633,6 +621,7 @@ public abstract class SSLEngineTest {
clientSslCtx = SslContextBuilder.forClient()
.sslProvider(sslClientProvider())
.sslContextProvider(clientSslContextProvider())
.trustManager(clientTrustManager)
.keyManager(clientKMF)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
@ -765,6 +754,7 @@ public abstract class SSLEngineTest {
final String expectedHost = "localhost";
serverSslCtx = SslContextBuilder.forServer(serverCrtFile, serverKeyFile, null)
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider())
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
.sessionCacheSize(0)
@ -773,6 +763,7 @@ public abstract class SSLEngineTest {
clientSslCtx = SslContextBuilder.forClient()
.sslProvider(sslClientProvider())
.sslContextProvider(clientSslContextProvider())
.trustManager(clientTrustCrtFile)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
.sessionCacheSize(0)
@ -882,6 +873,7 @@ public abstract class SSLEngineTest {
throws InterruptedException, SSLException {
serverSslCtx = SslContextBuilder.forServer(serverCrtFile, serverKeyFile, serverKeyPassword)
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider())
.trustManager(servertTrustCrtFile)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
.sessionCacheSize(0)
@ -890,6 +882,7 @@ public abstract class SSLEngineTest {
clientSslCtx = SslContextBuilder.forClient()
.sslProvider(sslClientProvider())
.sslContextProvider(clientSslContextProvider())
.trustManager(clientTrustCrtFile)
.keyManager(clientCrtFile, clientKeyFile, clientKeyPassword)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
@ -1038,7 +1031,9 @@ public abstract class SSLEngineTest {
@Test
public void testGetCreationTime() throws Exception {
clientSslCtx = SslContextBuilder.forClient().sslProvider(sslClientProvider()).build();
clientSslCtx = SslContextBuilder.forClient()
.sslProvider(sslClientProvider())
.sslContextProvider(clientSslContextProvider()).build();
SSLEngine engine = null;
try {
engine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
@ -1053,10 +1048,12 @@ public abstract class SSLEngineTest {
clientSslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.sslProvider(sslClientProvider())
.sslContextProvider(clientSslContextProvider())
.build();
SelfSignedCertificate ssc = new SelfSignedCertificate();
serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider())
.build();
SSLEngine clientEngine = null;
SSLEngine serverEngine = null;
@ -1080,10 +1077,12 @@ public abstract class SSLEngineTest {
clientSslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.sslProvider(sslClientProvider())
.sslContextProvider(clientSslContextProvider())
.build();
SelfSignedCertificate ssc = new SelfSignedCertificate();
serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider())
.build();
SSLEngine clientEngine = null;
SSLEngine serverEngine = null;
@ -1112,7 +1111,8 @@ public abstract class SSLEngineTest {
throws CertificateException, SSLException, InterruptedException, ExecutionException {
final SelfSignedCertificate ssc = new SelfSignedCertificate();
serverSslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey())
.sslProvider(sslServerProvider()).build();
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider()).build();
sb = new ServerBootstrap()
.group(new NioEventLoopGroup(1))
.channel(NioServerSocketChannel.class)
@ -1223,6 +1223,7 @@ public abstract class SSLEngineTest {
File serverCrtFile = new File(getClass().getResource("test.crt").getFile());
serverSslCtx = SslContextBuilder.forServer(serverCrtFile, serverKeyFile)
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider())
.build();
sslEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT);
@ -1356,6 +1357,13 @@ public abstract class SSLEngineTest {
protected abstract SslProvider sslServerProvider();
protected Provider clientSslContextProvider() {
return null;
}
protected Provider serverSslContextProvider() {
return null;
}
/**
* Called from the test cleanup code and can be used to release the {@code ctx} if it must be done manually.
*/
@ -1391,6 +1399,7 @@ public abstract class SSLEngineTest {
setupHandlers(SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey(), null)
.sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider())
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
.applicationProtocolConfig(serverApn)
.sessionCacheSize(0)
@ -1399,6 +1408,7 @@ public abstract class SSLEngineTest {
SslContextBuilder.forClient()
.sslProvider(sslClientProvider())
.sslContextProvider(clientSslContextProvider())
.applicationProtocolConfig(clientApn)
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.ciphers(null, IdentityCipherSuiteFilter.INSTANCE)
@ -1479,7 +1489,8 @@ public abstract class SSLEngineTest {
new ByteArrayInputStream(X509_CERT_PEM.getBytes(CharsetUtil.UTF_8)),
new ByteArrayInputStream(PRIVATE_KEY_PEM.getBytes(CharsetUtil.UTF_8)))
.trustManager(new ByteArrayInputStream(X509_CERT_PEM.getBytes(CharsetUtil.UTF_8)))
.clientAuth(ClientAuth.REQUIRE).sslProvider(sslServerProvider()).build();
.clientAuth(ClientAuth.REQUIRE).sslProvider(sslServerProvider())
.sslContextProvider(serverSslContextProvider()).build();
sb = new ServerBootstrap();
sb.group(new NioEventLoopGroup(), new NioEventLoopGroup());
@ -1535,7 +1546,8 @@ public abstract class SSLEngineTest {
new ByteArrayInputStream(CLIENT_X509_CERT_CHAIN_PEM.getBytes(CharsetUtil.UTF_8)),
new ByteArrayInputStream(CLIENT_PRIVATE_KEY_PEM.getBytes(CharsetUtil.UTF_8)))
.trustManager(new ByteArrayInputStream(X509_CERT_PEM.getBytes(CharsetUtil.UTF_8)))
.sslProvider(sslClientProvider()).build();
.sslProvider(sslClientProvider())
.sslContextProvider(clientSslContextProvider()).build();
cb = new Bootstrap();
cb.group(new NioEventLoopGroup());
cb.channel(NioSocketChannel.class);

View File

@ -87,7 +87,7 @@ public class SniHandlerTest {
assumeTrue(OpenSsl.isAlpnSupported());
break;
case JDK:
assumeTrue(JdkAlpnSslEngine.isAvailable());
assumeTrue(JettyAlpnSslEngine.isAvailable());
break;
default:
throw new Error();

14
pom.xml
View File

@ -244,6 +244,10 @@
<tcnative.artifactId>netty-tcnative</tcnative.artifactId>
<tcnative.version>2.0.0.Final</tcnative.version>
<tcnative.classifier>${os.detected.classifier}</tcnative.classifier>
<conscrypt.groupId>org.conscrypt</conscrypt.groupId>
<conscrypt.artifactId>conscrypt-openjdk-uber</conscrypt.artifactId>
<conscrypt.version>1.0.0.RC7</conscrypt.version>
<conscrypt.classifier></conscrypt.classifier>
<epoll.classifier>${os.detected.name}-${os.detected.arch}</epoll.classifier>
<logging.config>${project.basedir}/../common/src/test/resources/logback-test.xml</logging.config>
<logging.logLevel>debug</logging.logLevel>
@ -343,6 +347,16 @@
<optional>true</optional>
</dependency>
<!-- Conscrypt - needed for running tests, used for acclerating SSL with OpenSSL. -->
<dependency>
<groupId>${conscrypt.groupId}</groupId>
<artifactId>${conscrypt.artifactId}</artifactId>
<classifier>${conscrypt.classifier}</classifier>
<version>${conscrypt.version}</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!--
Bouncy Castle - completely optional, only needed when:
- you generate a temporary self-signed certificate using SelfSignedCertificate, and