Skip to content

Commit 35d8448

Browse files
committed
Revert "Direct use of the ALPN API"
This reverts commit 7763877.
1 parent 7763877 commit 35d8448

File tree

10 files changed

+131
-7
lines changed

10 files changed

+131
-7
lines changed

java/org/apache/tomcat/util/compat/JreCompat.java

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,18 @@
1919
import java.io.File;
2020
import java.io.IOException;
2121
import java.lang.reflect.AccessibleObject;
22+
import java.lang.reflect.InvocationTargetException;
23+
import java.lang.reflect.Method;
2224
import java.net.URL;
2325
import java.net.URLConnection;
2426
import java.util.Deque;
2527
import java.util.jar.JarFile;
2628

29+
import javax.net.ssl.SSLEngine;
30+
import javax.net.ssl.SSLParameters;
31+
32+
import org.apache.tomcat.util.res.StringManager;
33+
2734
/**
2835
* This is the base implementation class for JRE compatibility and provides an
2936
* implementation based on Java 8. Sub-classes may extend this class and provide
@@ -37,6 +44,10 @@ public class JreCompat {
3744
private static final boolean graalAvailable;
3845
private static final boolean jre11Available;
3946
private static final boolean jre9Available;
47+
private static final StringManager sm = StringManager.getManager(JreCompat.class);
48+
49+
protected static final Method setApplicationProtocolsMethod;
50+
protected static final Method getApplicationProtocolMethod;
4051

4152
static {
4253
// This is Tomcat 9 with a minimum Java version of Java 8.
@@ -55,6 +66,17 @@ public class JreCompat {
5566
jre9Available = false;
5667
}
5768
jre11Available = instance.jarFileRuntimeMajorVersion() >= 11;
69+
70+
Method m1 = null;
71+
Method m2 = null;
72+
try {
73+
m1 = SSLParameters.class.getMethod("setApplicationProtocols", String[].class);
74+
m2 = SSLEngine.class.getMethod("getApplicationProtocol");
75+
} catch (ReflectiveOperationException | IllegalArgumentException e) {
76+
// Only the newest Java 8 have the ALPN API, so ignore
77+
}
78+
setApplicationProtocolsMethod = m1;
79+
getApplicationProtocolMethod = m2;
5880
}
5981

6082

@@ -68,6 +90,11 @@ public static boolean isGraalAvailable() {
6890
}
6991

7092

93+
public static boolean isAlpnSupported() {
94+
return setApplicationProtocolsMethod != null && getApplicationProtocolMethod != null;
95+
}
96+
97+
7198
public static boolean isJre9Available() {
7299
return jre9Available;
73100
}
@@ -95,6 +122,48 @@ public boolean isInstanceOfInaccessibleObjectException(Throwable t) {
95122
}
96123

97124

125+
/**
126+
* Set the application protocols the server will accept for ALPN
127+
*
128+
* @param sslParameters The SSL parameters for a connection
129+
* @param protocols The application protocols to be allowed for that
130+
* connection
131+
*/
132+
public void setApplicationProtocols(SSLParameters sslParameters, String[] protocols) {
133+
if (setApplicationProtocolsMethod != null) {
134+
try {
135+
setApplicationProtocolsMethod.invoke(sslParameters, (Object) protocols);
136+
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
137+
throw new UnsupportedOperationException(e);
138+
}
139+
} else {
140+
throw new UnsupportedOperationException(sm.getString("jreCompat.noApplicationProtocols"));
141+
}
142+
}
143+
144+
145+
/**
146+
* Get the application protocol that has been negotiated for connection
147+
* associated with the given SSLEngine.
148+
*
149+
* @param sslEngine The SSLEngine for which to obtain the negotiated
150+
* protocol
151+
*
152+
* @return The name of the negotiated protocol
153+
*/
154+
public String getApplicationProtocol(SSLEngine sslEngine) {
155+
if (getApplicationProtocolMethod != null) {
156+
try {
157+
return (String) getApplicationProtocolMethod.invoke(sslEngine);
158+
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
159+
throw new UnsupportedOperationException(e);
160+
}
161+
} else {
162+
throw new UnsupportedOperationException(sm.getString("jreCompat.noApplicationProtocol"));
163+
}
164+
}
165+
166+
98167
/**
99168
* Disables caching for JAR URL connections. For Java 8 and earlier, this also disables
100169
* caching for ALL URL connections.

java/org/apache/tomcat/util/compat/LocalStrings.properties

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,6 @@
1616
jre9Compat.invalidModuleUri=The module URI provided [{0}] could not be converted to a URL for the JarScanner to process
1717
jre9Compat.javaPre9=Class not found so assuming code is running on a pre-Java 9 JVM
1818
jre9Compat.unexpected=Failed to create references to Java 9 classes and methods
19+
20+
jreCompat.noApplicationProtocol=Java Runtime does not support SSLEngine.getApplicationProtocol(). You must use Java 9 to use this feature.
21+
jreCompat.noApplicationProtocols=Java Runtime does not support SSLParameters.setApplicationProtocols(). You must use Java 9 to use this feature.

java/org/apache/tomcat/util/net/AbstractJsseEndpoint.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import javax.net.ssl.SSLEngine;
2929
import javax.net.ssl.SSLParameters;
3030

31+
import org.apache.tomcat.util.compat.JreCompat;
3132
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
3233

3334
public abstract class AbstractJsseEndpoint<S,U> extends AbstractEndpoint<S,U> {
@@ -122,7 +123,7 @@ protected SSLEngine createSSLEngine(String sniHostName, List<Cipher> clientReque
122123

123124
SSLParameters sslParameters = engine.getSSLParameters();
124125
sslParameters.setUseCipherSuitesOrder(sslHostConfig.getHonorCipherOrder());
125-
if (clientRequestedApplicationProtocols != null
126+
if (JreCompat.isAlpnSupported() && clientRequestedApplicationProtocols != null
126127
&& clientRequestedApplicationProtocols.size() > 0
127128
&& negotiableProtocols.size() > 0) {
128129
// Only try to negotiate if both client and server have at least
@@ -133,7 +134,7 @@ protected SSLEngine createSSLEngine(String sniHostName, List<Cipher> clientReque
133134
commonProtocols.retainAll(clientRequestedApplicationProtocols);
134135
if (commonProtocols.size() > 0) {
135136
String[] commonProtocolsArray = commonProtocols.toArray(new String[0]);
136-
sslParameters.setApplicationProtocols(commonProtocolsArray);
137+
JreCompat.getInstance().setApplicationProtocols(sslParameters, commonProtocolsArray);
137138
}
138139
}
139140
switch (sslHostConfig.getCertificateVerification()) {
@@ -192,7 +193,20 @@ private SSLHostConfigCertificate selectCertificate(
192193
@Override
193194
public boolean isAlpnSupported() {
194195
// ALPN requires TLS so if TLS is not enabled, ALPN cannot be supported
195-
return isSSLEnabled();
196+
if (!isSSLEnabled()) {
197+
return false;
198+
}
199+
200+
// Depends on the SSLImplementation.
201+
SSLImplementation sslImplementation;
202+
try {
203+
sslImplementation = SSLImplementation.getInstance(getSslImplementationName());
204+
} catch (ClassNotFoundException e) {
205+
// Ignore the exception. It will be logged when trying to start the
206+
// end point.
207+
return false;
208+
}
209+
return sslImplementation.isAlpnSupported();
196210
}
197211

198212

java/org/apache/tomcat/util/net/SSLImplementation.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,5 @@ public static SSLImplementation getInstance(String className)
6868

6969
public abstract SSLUtil getSSLUtil(SSLHostConfigCertificate certificate);
7070

71+
public abstract boolean isAlpnSupported();
7172
}

java/org/apache/tomcat/util/net/SSLUtil.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,16 @@ public interface SSLUtil {
6767
*/
6868
public String[] getEnabledCiphers() throws IllegalArgumentException;
6969

70+
/**
71+
* Optional interface that can be implemented by
72+
* {@link javax.net.ssl.SSLEngine}s to indicate that they support ALPN and
73+
* can provided the protocol agreed with the client.
74+
*/
75+
public interface ProtocolInfo {
76+
/**
77+
* ALPN information.
78+
* @return the protocol selected using ALPN
79+
*/
80+
public String getNegotiatedProtocol();
81+
}
7082
}

java/org/apache/tomcat/util/net/SecureNio2Channel.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.apache.juli.logging.Log;
3939
import org.apache.juli.logging.LogFactory;
4040
import org.apache.tomcat.util.buf.ByteBufferUtils;
41+
import org.apache.tomcat.util.compat.JreCompat;
4142
import org.apache.tomcat.util.net.TLSClientHelloExtractor.ExtractorResult;
4243
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
4344
import org.apache.tomcat.util.res.StringManager;
@@ -241,7 +242,13 @@ protected int handshakeInternal(boolean async) throws IOException {
241242
}
242243
case FINISHED: {
243244
if (endpoint.hasNegotiableProtocols()) {
244-
socketWrapper.setNegotiatedProtocol(sslEngine.getApplicationProtocol());
245+
if (sslEngine instanceof SSLUtil.ProtocolInfo) {
246+
socketWrapper.setNegotiatedProtocol(
247+
((SSLUtil.ProtocolInfo) sslEngine).getNegotiatedProtocol());
248+
} else if (JreCompat.isAlpnSupported()) {
249+
socketWrapper.setNegotiatedProtocol(
250+
JreCompat.getInstance().getApplicationProtocol(sslEngine));
251+
}
245252
}
246253
//we are complete if we have delivered the last package
247254
handshakeComplete = !netOutBuffer.hasRemaining();

java/org/apache/tomcat/util/net/SecureNioChannel.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.apache.juli.logging.Log;
3636
import org.apache.juli.logging.LogFactory;
3737
import org.apache.tomcat.util.buf.ByteBufferUtils;
38+
import org.apache.tomcat.util.compat.JreCompat;
3839
import org.apache.tomcat.util.net.NioEndpoint.NioSocketWrapper;
3940
import org.apache.tomcat.util.net.TLSClientHelloExtractor.ExtractorResult;
4041
import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
@@ -166,7 +167,13 @@ public int handshake(boolean read, boolean write) throws IOException {
166167
throw new IOException(sm.getString("channel.nio.ssl.notHandshaking"));
167168
case FINISHED:
168169
if (endpoint.hasNegotiableProtocols()) {
169-
socketWrapper.setNegotiatedProtocol(sslEngine.getApplicationProtocol());
170+
if (sslEngine instanceof SSLUtil.ProtocolInfo) {
171+
socketWrapper.setNegotiatedProtocol(
172+
((SSLUtil.ProtocolInfo) sslEngine).getNegotiatedProtocol());
173+
} else if (JreCompat.isAlpnSupported()) {
174+
socketWrapper.setNegotiatedProtocol(
175+
JreCompat.getInstance().getApplicationProtocol(sslEngine));
176+
}
170177
}
171178
//we are complete if we have delivered the last package
172179
handshakeComplete = !netOutBuffer.hasRemaining();

java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import javax.net.ssl.SSLSession;
2020

21+
import org.apache.tomcat.util.compat.JreCompat;
2122
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
2223
import org.apache.tomcat.util.net.SSLImplementation;
2324
import org.apache.tomcat.util.net.SSLSupport;
@@ -49,4 +50,8 @@ public SSLUtil getSSLUtil(SSLHostConfigCertificate certificate) {
4950
return new JSSEUtil(certificate);
5051
}
5152

53+
@Override
54+
public boolean isAlpnSupported() {
55+
return JreCompat.isAlpnSupported();
56+
}
5257
}

java/org/apache/tomcat/util/net/openssl/OpenSSLEngine.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import org.apache.tomcat.jni.SSLContext;
4747
import org.apache.tomcat.util.buf.ByteBufferUtils;
4848
import org.apache.tomcat.util.net.Constants;
49+
import org.apache.tomcat.util.net.SSLUtil;
4950
import org.apache.tomcat.util.net.openssl.ciphers.OpenSSLCipherConfigurationParser;
5051
import org.apache.tomcat.util.res.StringManager;
5152

@@ -54,7 +55,7 @@
5455
* <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL
5556
* BIO abstractions</a>.
5657
*/
57-
public final class OpenSSLEngine extends SSLEngine {
58+
public final class OpenSSLEngine extends SSLEngine implements SSLUtil.ProtocolInfo {
5859

5960
private static final Log logger = LogFactory.getLog(OpenSSLEngine.class);
6061
private static final StringManager sm = StringManager.getManager(OpenSSLEngine.class);
@@ -208,7 +209,7 @@ private enum Accepted { NOT, IMPLICIT, EXPLICIT }
208209
}
209210

210211
@Override
211-
public String getApplicationProtocol() {
212+
public String getNegotiatedProtocol() {
212213
return selectedProtocol;
213214
}
214215

java/org/apache/tomcat/util/net/openssl/OpenSSLImplementation.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,9 @@ public SSLUtil getSSLUtil(SSLHostConfigCertificate certificate) {
3636
return new OpenSSLUtil(certificate);
3737
}
3838

39+
@Override
40+
public boolean isAlpnSupported() {
41+
// OpenSSL supported ALPN
42+
return true;
43+
}
3944
}

0 commit comments

Comments
 (0)