This is an automated email from the ASF dual-hosted git repository. remm pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 35d84487fd10bfd6f2a00494078a5e3eef1b1830 Author: remm <r...@apache.org> AuthorDate: Fri Jul 3 11:16:24 2020 +0200 Revert "Direct use of the ALPN API" This reverts commit 7763877a98e5c74bb579b64f31e938fea17290a5. --- java/org/apache/tomcat/util/compat/JreCompat.java | 69 ++++++++++++++++++++++ .../tomcat/util/compat/LocalStrings.properties | 3 + .../tomcat/util/net/AbstractJsseEndpoint.java | 20 ++++++- .../apache/tomcat/util/net/SSLImplementation.java | 1 + java/org/apache/tomcat/util/net/SSLUtil.java | 12 ++++ .../apache/tomcat/util/net/SecureNio2Channel.java | 9 ++- .../apache/tomcat/util/net/SecureNioChannel.java | 9 ++- .../tomcat/util/net/jsse/JSSEImplementation.java | 5 ++ .../tomcat/util/net/openssl/OpenSSLEngine.java | 5 +- .../util/net/openssl/OpenSSLImplementation.java | 5 ++ 10 files changed, 131 insertions(+), 7 deletions(-) diff --git a/java/org/apache/tomcat/util/compat/JreCompat.java b/java/org/apache/tomcat/util/compat/JreCompat.java index 2f0268f..8275e60 100644 --- a/java/org/apache/tomcat/util/compat/JreCompat.java +++ b/java/org/apache/tomcat/util/compat/JreCompat.java @@ -19,11 +19,18 @@ package org.apache.tomcat.util.compat; import java.io.File; import java.io.IOException; import java.lang.reflect.AccessibleObject; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.URL; import java.net.URLConnection; import java.util.Deque; import java.util.jar.JarFile; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLParameters; + +import org.apache.tomcat.util.res.StringManager; + /** * This is the base implementation class for JRE compatibility and provides an * implementation based on Java 8. Sub-classes may extend this class and provide @@ -37,6 +44,10 @@ public class JreCompat { private static final boolean graalAvailable; private static final boolean jre11Available; private static final boolean jre9Available; + private static final StringManager sm = StringManager.getManager(JreCompat.class); + + protected static final Method setApplicationProtocolsMethod; + protected static final Method getApplicationProtocolMethod; static { // This is Tomcat 9 with a minimum Java version of Java 8. @@ -55,6 +66,17 @@ public class JreCompat { jre9Available = false; } jre11Available = instance.jarFileRuntimeMajorVersion() >= 11; + + Method m1 = null; + Method m2 = null; + try { + m1 = SSLParameters.class.getMethod("setApplicationProtocols", String[].class); + m2 = SSLEngine.class.getMethod("getApplicationProtocol"); + } catch (ReflectiveOperationException | IllegalArgumentException e) { + // Only the newest Java 8 have the ALPN API, so ignore + } + setApplicationProtocolsMethod = m1; + getApplicationProtocolMethod = m2; } @@ -68,6 +90,11 @@ public class JreCompat { } + public static boolean isAlpnSupported() { + return setApplicationProtocolsMethod != null && getApplicationProtocolMethod != null; + } + + public static boolean isJre9Available() { return jre9Available; } @@ -96,6 +123,48 @@ public class JreCompat { /** + * Set the application protocols the server will accept for ALPN + * + * @param sslParameters The SSL parameters for a connection + * @param protocols The application protocols to be allowed for that + * connection + */ + public void setApplicationProtocols(SSLParameters sslParameters, String[] protocols) { + if (setApplicationProtocolsMethod != null) { + try { + setApplicationProtocolsMethod.invoke(sslParameters, (Object) protocols); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new UnsupportedOperationException(e); + } + } else { + throw new UnsupportedOperationException(sm.getString("jreCompat.noApplicationProtocols")); + } + } + + + /** + * Get the application protocol that has been negotiated for connection + * associated with the given SSLEngine. + * + * @param sslEngine The SSLEngine for which to obtain the negotiated + * protocol + * + * @return The name of the negotiated protocol + */ + public String getApplicationProtocol(SSLEngine sslEngine) { + if (getApplicationProtocolMethod != null) { + try { + return (String) getApplicationProtocolMethod.invoke(sslEngine); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + throw new UnsupportedOperationException(e); + } + } else { + throw new UnsupportedOperationException(sm.getString("jreCompat.noApplicationProtocol")); + } + } + + + /** * Disables caching for JAR URL connections. For Java 8 and earlier, this also disables * caching for ALL URL connections. * diff --git a/java/org/apache/tomcat/util/compat/LocalStrings.properties b/java/org/apache/tomcat/util/compat/LocalStrings.properties index 34ffd70..891782c 100644 --- a/java/org/apache/tomcat/util/compat/LocalStrings.properties +++ b/java/org/apache/tomcat/util/compat/LocalStrings.properties @@ -16,3 +16,6 @@ jre9Compat.invalidModuleUri=The module URI provided [{0}] could not be converted to a URL for the JarScanner to process jre9Compat.javaPre9=Class not found so assuming code is running on a pre-Java 9 JVM jre9Compat.unexpected=Failed to create references to Java 9 classes and methods + +jreCompat.noApplicationProtocol=Java Runtime does not support SSLEngine.getApplicationProtocol(). You must use Java 9 to use this feature. +jreCompat.noApplicationProtocols=Java Runtime does not support SSLParameters.setApplicationProtocols(). You must use Java 9 to use this feature. diff --git a/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java b/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java index 1488393..925e91d 100644 --- a/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java +++ b/java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java @@ -28,6 +28,7 @@ import java.util.Set; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLParameters; +import org.apache.tomcat.util.compat.JreCompat; import org.apache.tomcat.util.net.openssl.ciphers.Cipher; public abstract class AbstractJsseEndpoint<S,U> extends AbstractEndpoint<S,U> { @@ -122,7 +123,7 @@ public abstract class AbstractJsseEndpoint<S,U> extends AbstractEndpoint<S,U> { SSLParameters sslParameters = engine.getSSLParameters(); sslParameters.setUseCipherSuitesOrder(sslHostConfig.getHonorCipherOrder()); - if (clientRequestedApplicationProtocols != null + if (JreCompat.isAlpnSupported() && clientRequestedApplicationProtocols != null && clientRequestedApplicationProtocols.size() > 0 && negotiableProtocols.size() > 0) { // Only try to negotiate if both client and server have at least @@ -133,7 +134,7 @@ public abstract class AbstractJsseEndpoint<S,U> extends AbstractEndpoint<S,U> { commonProtocols.retainAll(clientRequestedApplicationProtocols); if (commonProtocols.size() > 0) { String[] commonProtocolsArray = commonProtocols.toArray(new String[0]); - sslParameters.setApplicationProtocols(commonProtocolsArray); + JreCompat.getInstance().setApplicationProtocols(sslParameters, commonProtocolsArray); } } switch (sslHostConfig.getCertificateVerification()) { @@ -192,7 +193,20 @@ public abstract class AbstractJsseEndpoint<S,U> extends AbstractEndpoint<S,U> { @Override public boolean isAlpnSupported() { // ALPN requires TLS so if TLS is not enabled, ALPN cannot be supported - return isSSLEnabled(); + if (!isSSLEnabled()) { + return false; + } + + // Depends on the SSLImplementation. + SSLImplementation sslImplementation; + try { + sslImplementation = SSLImplementation.getInstance(getSslImplementationName()); + } catch (ClassNotFoundException e) { + // Ignore the exception. It will be logged when trying to start the + // end point. + return false; + } + return sslImplementation.isAlpnSupported(); } diff --git a/java/org/apache/tomcat/util/net/SSLImplementation.java b/java/org/apache/tomcat/util/net/SSLImplementation.java index fb11b82..43ccbe5 100644 --- a/java/org/apache/tomcat/util/net/SSLImplementation.java +++ b/java/org/apache/tomcat/util/net/SSLImplementation.java @@ -68,4 +68,5 @@ public abstract class SSLImplementation { public abstract SSLUtil getSSLUtil(SSLHostConfigCertificate certificate); + public abstract boolean isAlpnSupported(); } diff --git a/java/org/apache/tomcat/util/net/SSLUtil.java b/java/org/apache/tomcat/util/net/SSLUtil.java index 4ba3504..c65f7a2 100644 --- a/java/org/apache/tomcat/util/net/SSLUtil.java +++ b/java/org/apache/tomcat/util/net/SSLUtil.java @@ -67,4 +67,16 @@ public interface SSLUtil { */ public String[] getEnabledCiphers() throws IllegalArgumentException; + /** + * Optional interface that can be implemented by + * {@link javax.net.ssl.SSLEngine}s to indicate that they support ALPN and + * can provided the protocol agreed with the client. + */ + public interface ProtocolInfo { + /** + * ALPN information. + * @return the protocol selected using ALPN + */ + public String getNegotiatedProtocol(); + } } diff --git a/java/org/apache/tomcat/util/net/SecureNio2Channel.java b/java/org/apache/tomcat/util/net/SecureNio2Channel.java index 3db1038..394837c 100644 --- a/java/org/apache/tomcat/util/net/SecureNio2Channel.java +++ b/java/org/apache/tomcat/util/net/SecureNio2Channel.java @@ -38,6 +38,7 @@ import javax.net.ssl.SSLException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.ByteBufferUtils; +import org.apache.tomcat.util.compat.JreCompat; import org.apache.tomcat.util.net.TLSClientHelloExtractor.ExtractorResult; import org.apache.tomcat.util.net.openssl.ciphers.Cipher; import org.apache.tomcat.util.res.StringManager; @@ -241,7 +242,13 @@ public class SecureNio2Channel extends Nio2Channel { } case FINISHED: { if (endpoint.hasNegotiableProtocols()) { - socketWrapper.setNegotiatedProtocol(sslEngine.getApplicationProtocol()); + if (sslEngine instanceof SSLUtil.ProtocolInfo) { + socketWrapper.setNegotiatedProtocol( + ((SSLUtil.ProtocolInfo) sslEngine).getNegotiatedProtocol()); + } else if (JreCompat.isAlpnSupported()) { + socketWrapper.setNegotiatedProtocol( + JreCompat.getInstance().getApplicationProtocol(sslEngine)); + } } //we are complete if we have delivered the last package handshakeComplete = !netOutBuffer.hasRemaining(); diff --git a/java/org/apache/tomcat/util/net/SecureNioChannel.java b/java/org/apache/tomcat/util/net/SecureNioChannel.java index ef0a33e..a176675 100644 --- a/java/org/apache/tomcat/util/net/SecureNioChannel.java +++ b/java/org/apache/tomcat/util/net/SecureNioChannel.java @@ -35,6 +35,7 @@ import javax.net.ssl.SSLException; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.buf.ByteBufferUtils; +import org.apache.tomcat.util.compat.JreCompat; import org.apache.tomcat.util.net.NioEndpoint.NioSocketWrapper; import org.apache.tomcat.util.net.TLSClientHelloExtractor.ExtractorResult; import org.apache.tomcat.util.net.openssl.ciphers.Cipher; @@ -166,7 +167,13 @@ public class SecureNioChannel extends NioChannel { throw new IOException(sm.getString("channel.nio.ssl.notHandshaking")); case FINISHED: if (endpoint.hasNegotiableProtocols()) { - socketWrapper.setNegotiatedProtocol(sslEngine.getApplicationProtocol()); + if (sslEngine instanceof SSLUtil.ProtocolInfo) { + socketWrapper.setNegotiatedProtocol( + ((SSLUtil.ProtocolInfo) sslEngine).getNegotiatedProtocol()); + } else if (JreCompat.isAlpnSupported()) { + socketWrapper.setNegotiatedProtocol( + JreCompat.getInstance().getApplicationProtocol(sslEngine)); + } } //we are complete if we have delivered the last package handshakeComplete = !netOutBuffer.hasRemaining(); diff --git a/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java b/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java index 4fa54be..1c1eae8 100644 --- a/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java +++ b/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java @@ -18,6 +18,7 @@ package org.apache.tomcat.util.net.jsse; import javax.net.ssl.SSLSession; +import org.apache.tomcat.util.compat.JreCompat; import org.apache.tomcat.util.net.SSLHostConfigCertificate; import org.apache.tomcat.util.net.SSLImplementation; import org.apache.tomcat.util.net.SSLSupport; @@ -49,4 +50,8 @@ public class JSSEImplementation extends SSLImplementation { return new JSSEUtil(certificate); } + @Override + public boolean isAlpnSupported() { + return JreCompat.isAlpnSupported(); + } } diff --git a/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java b/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java index 16f1451..058ee71 100644 --- a/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java +++ b/java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java @@ -46,6 +46,7 @@ import org.apache.tomcat.jni.SSL; import org.apache.tomcat.jni.SSLContext; import org.apache.tomcat.util.buf.ByteBufferUtils; import org.apache.tomcat.util.net.Constants; +import org.apache.tomcat.util.net.SSLUtil; import org.apache.tomcat.util.net.openssl.ciphers.OpenSSLCipherConfigurationParser; import org.apache.tomcat.util.res.StringManager; @@ -54,7 +55,7 @@ import org.apache.tomcat.util.res.StringManager; * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL * BIO abstractions</a>. */ -public final class OpenSSLEngine extends SSLEngine { +public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolInfo { private static final Log logger = LogFactory.getLog(OpenSSLEngine.class); private static final StringManager sm = StringManager.getManager(OpenSSLEngine.class); @@ -208,7 +209,7 @@ public final class OpenSSLEngine extends SSLEngine { } @Override - public String getApplicationProtocol() { + public String getNegotiatedProtocol() { return selectedProtocol; } diff --git a/java/org/apache/tomcat/util/net/openssl/OpenSSLImplementation.java b/java/org/apache/tomcat/util/net/openssl/OpenSSLImplementation.java index 6f2c3bf..94b4bf2 100644 --- a/java/org/apache/tomcat/util/net/openssl/OpenSSLImplementation.java +++ b/java/org/apache/tomcat/util/net/openssl/OpenSSLImplementation.java @@ -36,4 +36,9 @@ public class OpenSSLImplementation extends SSLImplementation { return new OpenSSLUtil(certificate); } + @Override + public boolean isAlpnSupported() { + // OpenSSL supported ALPN + return true; + } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org