Support JDK9-native ALPN
Motivation: Netty is unable to use Java9s ALPN support atm. Modifications: When running on Java9+ we invoke the correct methods that are exposed on the Java9+ implementation of SSLEngine and so be able to support ALPN. This patch is based on the work of @rschmitt and so https://github.com/netty/netty/pull/6992. Result: Fixes #6933.
This commit is contained in:
parent
c93e58c453
commit
1065e0f26e
175
handler/src/main/java/io/netty/handler/ssl/Java9SslEngine.java
Normal file
175
handler/src/main/java/io/netty/handler/ssl/Java9SslEngine.java
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 io.netty.util.internal.StringUtil;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import static io.netty.handler.ssl.SslUtils.toSSLHandshakeException;
|
||||
import static io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelectionListener;
|
||||
import static io.netty.handler.ssl.JdkApplicationProtocolNegotiator.ProtocolSelector;
|
||||
|
||||
final class Java9SslEngine extends JdkSslEngine {
|
||||
private final ProtocolSelectionListener selectionListener;
|
||||
private final AlpnSelector alpnSelector;
|
||||
|
||||
private final class AlpnSelector implements BiFunction<SSLEngine, List<String>, String> {
|
||||
private final ProtocolSelector selector;
|
||||
private boolean called;
|
||||
|
||||
AlpnSelector(ProtocolSelector selector) {
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String apply(SSLEngine sslEngine, List<String> strings) {
|
||||
assert !called;
|
||||
called = true;
|
||||
|
||||
try {
|
||||
String selected = selector.select(strings);
|
||||
return selected == null ? StringUtil.EMPTY_STRING : selected;
|
||||
} catch (Exception cause) {
|
||||
// Returning null means we want to fail the handshake.
|
||||
//
|
||||
// See http://download.java.net/java/jdk9/docs/api/javax/net/ssl/
|
||||
// SSLEngine.html#setHandshakeApplicationProtocolSelector-java.util.function.BiFunction-
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
void checkUnsupported() {
|
||||
if (called) {
|
||||
// ALPN message was received by peer and so apply(...) was called.
|
||||
// See:
|
||||
// http://hg.openjdk.java.net/jdk9/dev/jdk/file/65464a307408/src/
|
||||
// java.base/share/classes/sun/security/ssl/ServerHandshaker.java#l933
|
||||
return;
|
||||
}
|
||||
String protocol = getApplicationProtocol();
|
||||
assert protocol != null;
|
||||
|
||||
if (protocol.isEmpty()) {
|
||||
// ALPN is not supported
|
||||
selector.unsupported();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Java9SslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator, boolean isServer) {
|
||||
super(engine);
|
||||
if (isServer) {
|
||||
selectionListener = null;
|
||||
alpnSelector = new AlpnSelector(applicationNegotiator.protocolSelectorFactory().
|
||||
newSelector(this, new LinkedHashSet<String>(applicationNegotiator.protocols())));
|
||||
Java9SslUtils.setHandshakeApplicationProtocolSelector(engine, alpnSelector);
|
||||
} else {
|
||||
selectionListener = applicationNegotiator.protocolListenerFactory()
|
||||
.newListener(this, applicationNegotiator.protocols());
|
||||
alpnSelector = null;
|
||||
Java9SslUtils.setApplicationProtocols(engine, applicationNegotiator.protocols());
|
||||
}
|
||||
}
|
||||
|
||||
private SSLEngineResult verifyProtocolSelection(SSLEngineResult result) throws SSLException {
|
||||
if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.FINISHED) {
|
||||
if (alpnSelector == null) {
|
||||
// This means we are using client-side and
|
||||
try {
|
||||
String protocol = getApplicationProtocol();
|
||||
assert protocol != null;
|
||||
if (protocol.isEmpty()) {
|
||||
// If empty the server did not announce ALPN:
|
||||
// See:
|
||||
// http://hg.openjdk.java.net/jdk9/dev/jdk/file/65464a307408/src/java.base/
|
||||
// share/classes/sun/security/ssl/ClientHandshaker.java#l741
|
||||
selectionListener.unsupported();
|
||||
} else {
|
||||
selectionListener.selected(protocol);
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw toSSLHandshakeException(e);
|
||||
}
|
||||
} else {
|
||||
assert selectionListener == null;
|
||||
alpnSelector.checkUnsupported();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
|
||||
return verifyProtocolSelection(super.wrap(src, dst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngineResult wrap(ByteBuffer[] srcs, ByteBuffer dst) throws SSLException {
|
||||
return verifyProtocolSelection(super.wrap(srcs, dst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngineResult wrap(ByteBuffer[] srcs, int offset, int len, ByteBuffer dst) throws SSLException {
|
||||
return verifyProtocolSelection(super.wrap(srcs, offset, len, dst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
|
||||
return verifyProtocolSelection(super.unwrap(src, dst));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
|
||||
return verifyProtocolSelection(super.unwrap(src, dsts));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dst, int offset, int len) throws SSLException {
|
||||
return verifyProtocolSelection(super.unwrap(src, dst, offset, len));
|
||||
}
|
||||
|
||||
@Override
|
||||
void setApplicationProtocol(String applicationProtocol) {
|
||||
// Do nothing as this is handled internally by the Java9 implementation of SSLEngine.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApplicationProtocol() {
|
||||
return Java9SslUtils.getApplicationProtocol(getWrappedEngine());
|
||||
}
|
||||
|
||||
// These methods will override the methods defined by Java 9. As we compile with Java8 we can not add
|
||||
// @Override annotations here.
|
||||
public String getHandshakeApplicationProtocol() {
|
||||
return Java9SslUtils.getHandshakeApplicationProtocol(getWrappedEngine());
|
||||
}
|
||||
|
||||
public void setHandshakeApplicationProtocolSelector(BiFunction<SSLEngine, List<String>, String> selector) {
|
||||
Java9SslUtils.setHandshakeApplicationProtocolSelector(getWrappedEngine(), selector);
|
||||
}
|
||||
|
||||
public BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector() {
|
||||
return Java9SslUtils.getHandshakeApplicationProtocolSelector(getWrappedEngine());
|
||||
}
|
||||
}
|
175
handler/src/main/java/io/netty/handler/ssl/Java9SslUtils.java
Normal file
175
handler/src/main/java/io/netty/handler/ssl/Java9SslUtils.java
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* 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 javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
final class Java9SslUtils {
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Java9SslUtils.class);
|
||||
private static final Method SET_APPLICATION_PROTOCOLS;
|
||||
private static final Method GET_APPLICATION_PROTOCOL;
|
||||
private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL;
|
||||
private static final Method SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
|
||||
private static final Method GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR;
|
||||
|
||||
static {
|
||||
Method getHandshakeApplicationProtocol = null;
|
||||
Method getApplicationProtocol = null;
|
||||
Method setApplicationProtocols = null;
|
||||
Method setHandshakeApplicationProtocolSelector = null;
|
||||
Method getHandshakeApplicationProtocolSelector = null;
|
||||
|
||||
try {
|
||||
SSLContext context = SSLContext.getInstance(JdkSslContext.PROTOCOL);
|
||||
context.init(null, null, null);
|
||||
SSLEngine engine = context.createSSLEngine();
|
||||
getHandshakeApplicationProtocol = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
|
||||
@Override
|
||||
public Method run() throws Exception {
|
||||
return SSLEngine.class.getMethod("getHandshakeApplicationProtocol");
|
||||
}
|
||||
});
|
||||
getHandshakeApplicationProtocol.invoke(engine);
|
||||
getApplicationProtocol = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
|
||||
@Override
|
||||
public Method run() throws Exception {
|
||||
return SSLEngine.class.getMethod("getApplicationProtocol");
|
||||
}
|
||||
});
|
||||
getApplicationProtocol.invoke(engine);
|
||||
|
||||
setApplicationProtocols = AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
|
||||
@Override
|
||||
public Method run() throws Exception {
|
||||
return SSLParameters.class.getMethod("setApplicationProtocols", String[].class);
|
||||
}
|
||||
});
|
||||
setApplicationProtocols.invoke(engine.getSSLParameters(), new Object[]{EmptyArrays.EMPTY_STRINGS});
|
||||
|
||||
setHandshakeApplicationProtocolSelector =
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
|
||||
@Override
|
||||
public Method run() throws Exception {
|
||||
return SSLEngine.class.getMethod("setHandshakeApplicationProtocolSelector", BiFunction.class);
|
||||
}
|
||||
});
|
||||
setHandshakeApplicationProtocolSelector.invoke(engine, new BiFunction<SSLEngine, List<String>, String>() {
|
||||
@Override
|
||||
public String apply(SSLEngine sslEngine, List<String> strings) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
getHandshakeApplicationProtocolSelector =
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() {
|
||||
@Override
|
||||
public Method run() throws Exception {
|
||||
return SSLEngine.class.getMethod("getHandshakeApplicationProtocolSelector");
|
||||
}
|
||||
});
|
||||
getHandshakeApplicationProtocolSelector.invoke(engine);
|
||||
} catch (Throwable t) {
|
||||
logger.error("Unable to initialize Java9SslUtils, but the detected javaVersion was: {}",
|
||||
PlatformDependent.javaVersion(), t);
|
||||
getHandshakeApplicationProtocol = null;
|
||||
getApplicationProtocol = null;
|
||||
setApplicationProtocols = null;
|
||||
setHandshakeApplicationProtocolSelector = null;
|
||||
getHandshakeApplicationProtocolSelector = null;
|
||||
}
|
||||
GET_HANDSHAKE_APPLICATION_PROTOCOL = getHandshakeApplicationProtocol;
|
||||
GET_APPLICATION_PROTOCOL = getApplicationProtocol;
|
||||
SET_APPLICATION_PROTOCOLS = setApplicationProtocols;
|
||||
SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = setHandshakeApplicationProtocolSelector;
|
||||
GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR = getHandshakeApplicationProtocolSelector;
|
||||
}
|
||||
|
||||
private Java9SslUtils() {
|
||||
}
|
||||
|
||||
static boolean supportsAlpn() {
|
||||
return GET_APPLICATION_PROTOCOL != null;
|
||||
}
|
||||
|
||||
static String getApplicationProtocol(SSLEngine sslEngine) {
|
||||
try {
|
||||
return (String) GET_APPLICATION_PROTOCOL.invoke(sslEngine);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static String getHandshakeApplicationProtocol(SSLEngine sslEngine) {
|
||||
try {
|
||||
return (String) GET_HANDSHAKE_APPLICATION_PROTOCOL.invoke(sslEngine);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static void setApplicationProtocols(SSLEngine engine, List<String> supportedProtocols) {
|
||||
SSLParameters parameters = engine.getSSLParameters();
|
||||
|
||||
String[] protocolArray = supportedProtocols.toArray(EmptyArrays.EMPTY_STRINGS);
|
||||
try {
|
||||
SET_APPLICATION_PROTOCOLS.invoke(parameters, new Object[]{protocolArray});
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
engine.setSSLParameters(parameters);
|
||||
}
|
||||
|
||||
static void setHandshakeApplicationProtocolSelector(
|
||||
SSLEngine engine, BiFunction<SSLEngine, List<String>, String> selector) {
|
||||
try {
|
||||
SET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invoke(engine, selector);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector(SSLEngine engine) {
|
||||
try {
|
||||
return (BiFunction<SSLEngine, List<String>, String>)
|
||||
GET_HANDSHAKE_APPLICATION_PROTOCOL_SELECTOR.invoke(engine);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@
|
||||
package io.netty.handler.ssl;
|
||||
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
|
||||
/**
|
||||
@ -25,7 +27,10 @@ import javax.net.ssl.SSLEngine;
|
||||
*/
|
||||
@Deprecated
|
||||
public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
|
||||
private static final boolean AVAILABLE = Conscrypt.isAvailable() || JettyAlpnSslEngine.isAvailable();
|
||||
private static final boolean AVAILABLE = Conscrypt.isAvailable() ||
|
||||
jdkAlpnSupported() ||
|
||||
JettyAlpnSslEngine.isAvailable();
|
||||
|
||||
private static final SslEngineWrapperFactory ALPN_WRAPPER = AVAILABLE ? new AlpnWrapper() : new FailureWrapper();
|
||||
|
||||
/**
|
||||
@ -129,6 +134,9 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
|
||||
return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
|
||||
: ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
|
||||
}
|
||||
if (jdkAlpnSupported()) {
|
||||
return new Java9SslEngine(engine, applicationNegotiator, isServer);
|
||||
}
|
||||
if (JettyAlpnSslEngine.isAvailable()) {
|
||||
return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
|
||||
: JettyAlpnSslEngine.newClientEngine(engine, applicationNegotiator);
|
||||
@ -136,4 +144,8 @@ public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicati
|
||||
throw new RuntimeException("Unable to wrap SSLEngine of type " + engine.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
static boolean jdkAlpnSupported() {
|
||||
return PlatformDependent.javaVersion() >= 9 && Java9SslUtils.supportsAlpn();
|
||||
}
|
||||
}
|
||||
|
@ -137,14 +137,14 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
|
||||
|
||||
@Override
|
||||
public void unsupported() {
|
||||
engineWrapper.getSession().setApplicationProtocol(null);
|
||||
engineWrapper.setApplicationProtocol(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String select(List<String> protocols) throws Exception {
|
||||
for (String p : supportedProtocols) {
|
||||
if (protocols.contains(p)) {
|
||||
engineWrapper.getSession().setApplicationProtocol(p);
|
||||
engineWrapper.setApplicationProtocol(p);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@ -152,7 +152,7 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
|
||||
}
|
||||
|
||||
public String noSelectMatchFound() throws Exception {
|
||||
engineWrapper.getSession().setApplicationProtocol(null);
|
||||
engineWrapper.setApplicationProtocol(null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -179,13 +179,13 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
|
||||
|
||||
@Override
|
||||
public void unsupported() {
|
||||
engineWrapper.getSession().setApplicationProtocol(null);
|
||||
engineWrapper.setApplicationProtocol(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selected(String protocol) throws Exception {
|
||||
if (supportedProtocols.contains(protocol)) {
|
||||
engineWrapper.getSession().setApplicationProtocol(protocol);
|
||||
engineWrapper.setApplicationProtocol(protocol);
|
||||
} else {
|
||||
noSelectedMatchFound(protocol);
|
||||
}
|
||||
|
@ -24,18 +24,26 @@ import javax.net.ssl.SSLException;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.SSLSession;
|
||||
|
||||
class JdkSslEngine extends SSLEngine {
|
||||
class JdkSslEngine extends SSLEngine implements ApplicationProtocolAccessor {
|
||||
private final SSLEngine engine;
|
||||
private final JdkSslSession session;
|
||||
private volatile String applicationProtocol;
|
||||
|
||||
JdkSslEngine(SSLEngine engine) {
|
||||
this.engine = engine;
|
||||
session = new JdkSslSession(engine);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdkSslSession getSession() {
|
||||
return session;
|
||||
public String getApplicationProtocol() {
|
||||
return applicationProtocol;
|
||||
}
|
||||
|
||||
void setApplicationProtocol(String applicationProtocol) {
|
||||
this.applicationProtocol = applicationProtocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLSession getSession() {
|
||||
return engine.getSession();
|
||||
}
|
||||
|
||||
public SSLEngine getWrappedEngine() {
|
||||
|
@ -1,152 +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 javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.security.cert.X509Certificate;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.Certificate;
|
||||
|
||||
final class JdkSslSession implements SSLSession, ApplicationProtocolAccessor {
|
||||
private final SSLEngine engine;
|
||||
private volatile String applicationProtocol;
|
||||
|
||||
JdkSslSession(SSLEngine engine) {
|
||||
this.engine = engine;
|
||||
}
|
||||
|
||||
private SSLSession unwrap() {
|
||||
return engine.getSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return unwrap().getProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApplicationProtocol() {
|
||||
return applicationProtocol;
|
||||
}
|
||||
|
||||
void setApplicationProtocol(String applicationProtocol) {
|
||||
this.applicationProtocol = applicationProtocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getId() {
|
||||
return unwrap().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLSessionContext getSessionContext() {
|
||||
return unwrap().getSessionContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getCreationTime() {
|
||||
return unwrap().getCreationTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastAccessedTime() {
|
||||
return unwrap().getLastAccessedTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
unwrap().invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
return unwrap().isValid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putValue(String s, Object o) {
|
||||
unwrap().putValue(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(String s) {
|
||||
return unwrap().getValue(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeValue(String s) {
|
||||
unwrap().removeValue(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getValueNames() {
|
||||
return unwrap().getValueNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
|
||||
return unwrap().getPeerCertificates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Certificate[] getLocalCertificates() {
|
||||
return unwrap().getLocalCertificates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
|
||||
return unwrap().getPeerCertificateChain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
|
||||
return unwrap().getPeerPrincipal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Principal getLocalPrincipal() {
|
||||
return unwrap().getLocalPrincipal();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCipherSuite() {
|
||||
return unwrap().getCipherSuite();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPeerHost() {
|
||||
return unwrap().getPeerHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPeerPort() {
|
||||
return unwrap().getPeerPort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPacketBufferSize() {
|
||||
return unwrap().getPacketBufferSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getApplicationBufferSize() {
|
||||
return unwrap().getApplicationBufferSize();
|
||||
}
|
||||
}
|
@ -38,7 +38,6 @@ abstract class JettyAlpnSslEngine extends JdkSslEngine {
|
||||
}
|
||||
|
||||
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.
|
||||
|
@ -87,7 +87,7 @@ import static javax.net.ssl.SSLEngineResult.Status.OK;
|
||||
* the instance depends upon are released. Otherwise if any method of this class is called which uses the
|
||||
* the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
|
||||
*/
|
||||
public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted {
|
||||
public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted, ApplicationProtocolAccessor {
|
||||
|
||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
|
||||
|
||||
@ -159,6 +159,7 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
private boolean renegotiationPending;
|
||||
private boolean receivedShutdown;
|
||||
private volatile int destroyed;
|
||||
private volatile String applicationProtocol;
|
||||
|
||||
// Reference Counting
|
||||
private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
|
||||
@ -1827,7 +1828,12 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
|
||||
}
|
||||
|
||||
private final class OpenSslSession implements SSLSession, ApplicationProtocolAccessor {
|
||||
@Override
|
||||
public String getApplicationProtocol() {
|
||||
return applicationProtocol;
|
||||
}
|
||||
|
||||
private final class OpenSslSession implements SSLSession {
|
||||
private final OpenSslSessionContext sessionContext;
|
||||
|
||||
// These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
|
||||
@ -1835,7 +1841,6 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
private X509Certificate[] x509PeerCerts;
|
||||
private Certificate[] peerCerts;
|
||||
private String protocol;
|
||||
private String applicationProtocol;
|
||||
private String cipher;
|
||||
private byte[] id;
|
||||
private long creationTime;
|
||||
@ -2043,14 +2048,14 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
case ALPN:
|
||||
applicationProtocol = SSL.getAlpnSelected(ssl);
|
||||
if (applicationProtocol != null) {
|
||||
this.applicationProtocol = selectApplicationProtocol(
|
||||
ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
|
||||
protocols, behavior, applicationProtocol);
|
||||
}
|
||||
break;
|
||||
case NPN:
|
||||
applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
||||
if (applicationProtocol != null) {
|
||||
this.applicationProtocol = selectApplicationProtocol(
|
||||
ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
|
||||
protocols, behavior, applicationProtocol);
|
||||
}
|
||||
break;
|
||||
@ -2060,7 +2065,7 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
||||
}
|
||||
if (applicationProtocol != null) {
|
||||
this.applicationProtocol = selectApplicationProtocol(
|
||||
ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
|
||||
protocols, behavior, applicationProtocol);
|
||||
}
|
||||
break;
|
||||
@ -2159,13 +2164,6 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
||||
return protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getApplicationProtocol() {
|
||||
synchronized (ReferenceCountedOpenSslEngine.this) {
|
||||
return applicationProtocol;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPeerHost() {
|
||||
return ReferenceCountedOpenSslEngine.this.getPeerHost();
|
||||
|
@ -573,12 +573,12 @@ public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundH
|
||||
* @return the protocol name or {@code null} if application-level protocol has not been negotiated
|
||||
*/
|
||||
public String applicationProtocol() {
|
||||
SSLSession sess = engine().getSession();
|
||||
if (!(sess instanceof ApplicationProtocolAccessor)) {
|
||||
SSLEngine engine = engine();
|
||||
if (!(engine instanceof ApplicationProtocolAccessor)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ((ApplicationProtocolAccessor) sess).getApplicationProtocol();
|
||||
return ((ApplicationProtocolAccessor) engine).getApplicationProtocol();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,6 +25,8 @@ import io.netty.handler.ssl.util.SelfSignedCertificate;
|
||||
import java.security.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -43,7 +45,7 @@ import static org.junit.Assume.assumeNoException;
|
||||
@RunWith(Parameterized.class)
|
||||
public class JdkSslEngineTest extends SSLEngineTest {
|
||||
public enum ProviderType {
|
||||
NPN_DEFAULT {
|
||||
NPN_JETTY {
|
||||
@Override
|
||||
boolean isAvailable() {
|
||||
return JettyNpnSslEngine.isAvailable();
|
||||
@ -59,7 +61,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
ALPN_DEFAULT {
|
||||
ALPN_JETTY {
|
||||
@Override
|
||||
boolean isAvailable() {
|
||||
return JettyAlpnSslEngine.isAvailable();
|
||||
@ -76,6 +78,23 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
ALPN_JAVA9 {
|
||||
@Override
|
||||
boolean isAvailable() {
|
||||
return PlatformDependent.javaVersion() >= 9 && Java9SslUtils.supportsAlpn();
|
||||
}
|
||||
|
||||
@Override
|
||||
Protocol protocol() {
|
||||
return Protocol.ALPN;
|
||||
}
|
||||
|
||||
@Override
|
||||
Provider provider() {
|
||||
// Use the default provider.
|
||||
return null;
|
||||
}
|
||||
},
|
||||
ALPN_CONSCRYPT {
|
||||
private Provider provider;
|
||||
|
||||
@ -178,7 +197,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
||||
public void testTlsExtensionNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
|
||||
try {
|
||||
providerType.activate(this);
|
||||
if (providerType == ProviderType.NPN_DEFAULT) {
|
||||
if (providerType == ProviderType.NPN_JETTY) {
|
||||
ApplicationProtocolConfig clientApn = failingNegotiator(providerType.protocol(),
|
||||
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
|
||||
ApplicationProtocolConfig serverApn = acceptingNegotiator(providerType.protocol(),
|
||||
@ -249,7 +268,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
||||
public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
|
||||
try {
|
||||
providerType.activate(this);
|
||||
if (providerType == ProviderType.NPN_DEFAULT) {
|
||||
if (providerType == ProviderType.NPN_JETTY) {
|
||||
// This test only applies to ALPN.
|
||||
throw tlsExtensionNotFound(providerType.protocol());
|
||||
}
|
||||
@ -314,16 +333,14 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
||||
return provider;
|
||||
}
|
||||
|
||||
private ApplicationProtocolConfig failingNegotiator(Protocol protocol,
|
||||
String... supportedProtocols) {
|
||||
private static ApplicationProtocolConfig failingNegotiator(Protocol protocol, String... supportedProtocols) {
|
||||
return new ApplicationProtocolConfig(protocol,
|
||||
SelectorFailureBehavior.FATAL_ALERT,
|
||||
SelectedListenerFailureBehavior.FATAL_ALERT,
|
||||
supportedProtocols);
|
||||
}
|
||||
|
||||
private ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
|
||||
String... supportedProtocols) {
|
||||
private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol, String... supportedProtocols) {
|
||||
return new ApplicationProtocolConfig(protocol,
|
||||
SelectorFailureBehavior.NO_ADVERTISE,
|
||||
SelectedListenerFailureBehavior.ACCEPT,
|
||||
|
Loading…
x
Reference in New Issue
Block a user