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;
|
package io.netty.handler.ssl;
|
||||||
|
|
||||||
import io.netty.buffer.ByteBufAllocator;
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,7 +27,10 @@ import javax.net.ssl.SSLEngine;
|
|||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public final class JdkAlpnApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
|
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();
|
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)
|
return isServer ? ConscryptAlpnSslEngine.newServerEngine(engine, alloc, applicationNegotiator)
|
||||||
: ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
|
: ConscryptAlpnSslEngine.newClientEngine(engine, alloc, applicationNegotiator);
|
||||||
}
|
}
|
||||||
|
if (jdkAlpnSupported()) {
|
||||||
|
return new Java9SslEngine(engine, applicationNegotiator, isServer);
|
||||||
|
}
|
||||||
if (JettyAlpnSslEngine.isAvailable()) {
|
if (JettyAlpnSslEngine.isAvailable()) {
|
||||||
return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
|
return isServer ? JettyAlpnSslEngine.newServerEngine(engine, applicationNegotiator)
|
||||||
: JettyAlpnSslEngine.newClientEngine(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());
|
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
|
@Override
|
||||||
public void unsupported() {
|
public void unsupported() {
|
||||||
engineWrapper.getSession().setApplicationProtocol(null);
|
engineWrapper.setApplicationProtocol(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String select(List<String> protocols) throws Exception {
|
public String select(List<String> protocols) throws Exception {
|
||||||
for (String p : supportedProtocols) {
|
for (String p : supportedProtocols) {
|
||||||
if (protocols.contains(p)) {
|
if (protocols.contains(p)) {
|
||||||
engineWrapper.getSession().setApplicationProtocol(p);
|
engineWrapper.setApplicationProtocol(p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +152,7 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String noSelectMatchFound() throws Exception {
|
public String noSelectMatchFound() throws Exception {
|
||||||
engineWrapper.getSession().setApplicationProtocol(null);
|
engineWrapper.setApplicationProtocol(null);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,13 +179,13 @@ class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNego
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unsupported() {
|
public void unsupported() {
|
||||||
engineWrapper.getSession().setApplicationProtocol(null);
|
engineWrapper.setApplicationProtocol(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void selected(String protocol) throws Exception {
|
public void selected(String protocol) throws Exception {
|
||||||
if (supportedProtocols.contains(protocol)) {
|
if (supportedProtocols.contains(protocol)) {
|
||||||
engineWrapper.getSession().setApplicationProtocol(protocol);
|
engineWrapper.setApplicationProtocol(protocol);
|
||||||
} else {
|
} else {
|
||||||
noSelectedMatchFound(protocol);
|
noSelectedMatchFound(protocol);
|
||||||
}
|
}
|
||||||
|
@ -24,18 +24,26 @@ import javax.net.ssl.SSLException;
|
|||||||
import javax.net.ssl.SSLParameters;
|
import javax.net.ssl.SSLParameters;
|
||||||
import javax.net.ssl.SSLSession;
|
import javax.net.ssl.SSLSession;
|
||||||
|
|
||||||
class JdkSslEngine extends SSLEngine {
|
class JdkSslEngine extends SSLEngine implements ApplicationProtocolAccessor {
|
||||||
private final SSLEngine engine;
|
private final SSLEngine engine;
|
||||||
private final JdkSslSession session;
|
private volatile String applicationProtocol;
|
||||||
|
|
||||||
JdkSslEngine(SSLEngine engine) {
|
JdkSslEngine(SSLEngine engine) {
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
session = new JdkSslSession(engine);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JdkSslSession getSession() {
|
public String getApplicationProtocol() {
|
||||||
return session;
|
return applicationProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setApplicationProtocol(String applicationProtocol) {
|
||||||
|
this.applicationProtocol = applicationProtocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SSLSession getSession() {
|
||||||
|
return engine.getSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SSLEngine getWrappedEngine() {
|
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() {
|
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) {
|
if (PlatformDependent.javaVersion() <= 8) {
|
||||||
try {
|
try {
|
||||||
// Always use bootstrap class loader.
|
// 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 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.
|
* 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);
|
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 renegotiationPending;
|
||||||
private boolean receivedShutdown;
|
private boolean receivedShutdown;
|
||||||
private volatile int destroyed;
|
private volatile int destroyed;
|
||||||
|
private volatile String applicationProtocol;
|
||||||
|
|
||||||
// Reference Counting
|
// Reference Counting
|
||||||
private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
|
private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
|
||||||
@ -1827,7 +1828,12 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
|||||||
return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
|
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;
|
private final OpenSslSessionContext sessionContext;
|
||||||
|
|
||||||
// These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
|
// 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 X509Certificate[] x509PeerCerts;
|
||||||
private Certificate[] peerCerts;
|
private Certificate[] peerCerts;
|
||||||
private String protocol;
|
private String protocol;
|
||||||
private String applicationProtocol;
|
|
||||||
private String cipher;
|
private String cipher;
|
||||||
private byte[] id;
|
private byte[] id;
|
||||||
private long creationTime;
|
private long creationTime;
|
||||||
@ -2043,14 +2048,14 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
|||||||
case ALPN:
|
case ALPN:
|
||||||
applicationProtocol = SSL.getAlpnSelected(ssl);
|
applicationProtocol = SSL.getAlpnSelected(ssl);
|
||||||
if (applicationProtocol != null) {
|
if (applicationProtocol != null) {
|
||||||
this.applicationProtocol = selectApplicationProtocol(
|
ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
|
||||||
protocols, behavior, applicationProtocol);
|
protocols, behavior, applicationProtocol);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NPN:
|
case NPN:
|
||||||
applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
||||||
if (applicationProtocol != null) {
|
if (applicationProtocol != null) {
|
||||||
this.applicationProtocol = selectApplicationProtocol(
|
ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
|
||||||
protocols, behavior, applicationProtocol);
|
protocols, behavior, applicationProtocol);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2060,7 +2065,7 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
|||||||
applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
applicationProtocol = SSL.getNextProtoNegotiated(ssl);
|
||||||
}
|
}
|
||||||
if (applicationProtocol != null) {
|
if (applicationProtocol != null) {
|
||||||
this.applicationProtocol = selectApplicationProtocol(
|
ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
|
||||||
protocols, behavior, applicationProtocol);
|
protocols, behavior, applicationProtocol);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2159,13 +2164,6 @@ public class ReferenceCountedOpenSslEngine extends SSLEngine implements Referenc
|
|||||||
return protocol;
|
return protocol;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getApplicationProtocol() {
|
|
||||||
synchronized (ReferenceCountedOpenSslEngine.this) {
|
|
||||||
return applicationProtocol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getPeerHost() {
|
public String getPeerHost() {
|
||||||
return ReferenceCountedOpenSslEngine.this.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
|
* @return the protocol name or {@code null} if application-level protocol has not been negotiated
|
||||||
*/
|
*/
|
||||||
public String applicationProtocol() {
|
public String applicationProtocol() {
|
||||||
SSLSession sess = engine().getSession();
|
SSLEngine engine = engine();
|
||||||
if (!(sess instanceof ApplicationProtocolAccessor)) {
|
if (!(engine instanceof ApplicationProtocolAccessor)) {
|
||||||
return null;
|
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.security.Provider;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@ -43,7 +45,7 @@ import static org.junit.Assume.assumeNoException;
|
|||||||
@RunWith(Parameterized.class)
|
@RunWith(Parameterized.class)
|
||||||
public class JdkSslEngineTest extends SSLEngineTest {
|
public class JdkSslEngineTest extends SSLEngineTest {
|
||||||
public enum ProviderType {
|
public enum ProviderType {
|
||||||
NPN_DEFAULT {
|
NPN_JETTY {
|
||||||
@Override
|
@Override
|
||||||
boolean isAvailable() {
|
boolean isAvailable() {
|
||||||
return JettyNpnSslEngine.isAvailable();
|
return JettyNpnSslEngine.isAvailable();
|
||||||
@ -59,7 +61,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ALPN_DEFAULT {
|
ALPN_JETTY {
|
||||||
@Override
|
@Override
|
||||||
boolean isAvailable() {
|
boolean isAvailable() {
|
||||||
return JettyAlpnSslEngine.isAvailable();
|
return JettyAlpnSslEngine.isAvailable();
|
||||||
@ -76,6 +78,23 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
|||||||
return null;
|
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 {
|
ALPN_CONSCRYPT {
|
||||||
private Provider provider;
|
private Provider provider;
|
||||||
|
|
||||||
@ -178,7 +197,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
|||||||
public void testTlsExtensionNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
|
public void testTlsExtensionNoCompatibleProtocolsClientHandshakeFailure() throws Exception {
|
||||||
try {
|
try {
|
||||||
providerType.activate(this);
|
providerType.activate(this);
|
||||||
if (providerType == ProviderType.NPN_DEFAULT) {
|
if (providerType == ProviderType.NPN_JETTY) {
|
||||||
ApplicationProtocolConfig clientApn = failingNegotiator(providerType.protocol(),
|
ApplicationProtocolConfig clientApn = failingNegotiator(providerType.protocol(),
|
||||||
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
|
PREFERRED_APPLICATION_LEVEL_PROTOCOL);
|
||||||
ApplicationProtocolConfig serverApn = acceptingNegotiator(providerType.protocol(),
|
ApplicationProtocolConfig serverApn = acceptingNegotiator(providerType.protocol(),
|
||||||
@ -249,7 +268,7 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
|||||||
public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
|
public void testAlpnCompatibleProtocolsDifferentClientOrder() throws Exception {
|
||||||
try {
|
try {
|
||||||
providerType.activate(this);
|
providerType.activate(this);
|
||||||
if (providerType == ProviderType.NPN_DEFAULT) {
|
if (providerType == ProviderType.NPN_JETTY) {
|
||||||
// This test only applies to ALPN.
|
// This test only applies to ALPN.
|
||||||
throw tlsExtensionNotFound(providerType.protocol());
|
throw tlsExtensionNotFound(providerType.protocol());
|
||||||
}
|
}
|
||||||
@ -314,16 +333,14 @@ public class JdkSslEngineTest extends SSLEngineTest {
|
|||||||
return provider;
|
return provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApplicationProtocolConfig failingNegotiator(Protocol protocol,
|
private static ApplicationProtocolConfig failingNegotiator(Protocol protocol, String... supportedProtocols) {
|
||||||
String... supportedProtocols) {
|
|
||||||
return new ApplicationProtocolConfig(protocol,
|
return new ApplicationProtocolConfig(protocol,
|
||||||
SelectorFailureBehavior.FATAL_ALERT,
|
SelectorFailureBehavior.FATAL_ALERT,
|
||||||
SelectedListenerFailureBehavior.FATAL_ALERT,
|
SelectedListenerFailureBehavior.FATAL_ALERT,
|
||||||
supportedProtocols);
|
supportedProtocols);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ApplicationProtocolConfig acceptingNegotiator(Protocol protocol,
|
private static ApplicationProtocolConfig acceptingNegotiator(Protocol protocol, String... supportedProtocols) {
|
||||||
String... supportedProtocols) {
|
|
||||||
return new ApplicationProtocolConfig(protocol,
|
return new ApplicationProtocolConfig(protocol,
|
||||||
SelectorFailureBehavior.NO_ADVERTISE,
|
SelectorFailureBehavior.NO_ADVERTISE,
|
||||||
SelectedListenerFailureBehavior.ACCEPT,
|
SelectedListenerFailureBehavior.ACCEPT,
|
||||||
|
1
pom.xml
1
pom.xml
@ -710,6 +710,7 @@
|
|||||||
|
|
||||||
<!-- JDK 8 -->
|
<!-- JDK 8 -->
|
||||||
<ignore>java.util.concurrent.atomic.LongAdder</ignore>
|
<ignore>java.util.concurrent.atomic.LongAdder</ignore>
|
||||||
|
<ignore>java.util.function.BiFunction</ignore>
|
||||||
|
|
||||||
<!-- Resolver -->
|
<!-- Resolver -->
|
||||||
<ignore>java.net.InetAddress</ignore>
|
<ignore>java.net.InetAddress</ignore>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user