You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2020/07/03 09:18:03 UTC

[tomcat] 01/02: Revert "Direct use of the ALPN API"

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 <re...@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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org