Add support for SNIHostName when using Java8+
Motivation: Java8 added support for using SNIHostName with SSLParameters. We currently ignore it in OpenSslEngine. Modifications: Use reflection to support SNIHostName. Result: People using Java8 can use SNIHostName even when OpenSslEngine is used.
This commit is contained in:
parent
ee0897a1d9
commit
e14a385a88
@ -27,11 +27,14 @@ import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import org.apache.tomcat.jni.Buffer;
|
||||
import org.apache.tomcat.jni.SSL;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@ -78,6 +81,11 @@ public final class OpenSslEngine extends SSLEngine {
|
||||
private static final SSLException ENGINE_CLOSED = new SSLException("engine closed");
|
||||
private static final SSLException RENEGOTIATION_UNSUPPORTED = new SSLException("renegotiation unsupported");
|
||||
private static final SSLException ENCRYPTED_PACKET_OVERSIZED = new SSLException("encrypted packet oversized");
|
||||
private static final Class<?> SNI_HOSTNAME_CLASS;
|
||||
private static final Method GET_SERVER_NAMES_METHOD;
|
||||
private static final Method SET_SERVER_NAMES_METHOD;
|
||||
private static final Method GET_ASCII_NAME_METHOD;
|
||||
|
||||
static {
|
||||
ENGINE_CLOSED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
|
||||
RENEGOTIATION_UNSUPPORTED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
|
||||
@ -89,6 +97,37 @@ public final class OpenSslEngine extends SSLEngine {
|
||||
destroyedUpdater = AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed");
|
||||
}
|
||||
DESTROYED_UPDATER = destroyedUpdater;
|
||||
|
||||
Class<?> sniHostNameClass = null;
|
||||
Method getAsciiNameMethod = null;
|
||||
Method getServerNamesMethod = null;
|
||||
Method setServerNamesMethod = null;
|
||||
if (PlatformDependent.javaVersion() >= 8) {
|
||||
try {
|
||||
sniHostNameClass = Class.forName("javax.net.ssl.SNIHostName", false,
|
||||
PlatformDependent.getClassLoader(OpenSslEngine.class));
|
||||
Object sniHostName = sniHostNameClass.getConstructor(String.class).newInstance("netty.io");
|
||||
getAsciiNameMethod = sniHostNameClass.getDeclaredMethod("getAsciiName");
|
||||
@SuppressWarnings("unused")
|
||||
String name = (String) getAsciiNameMethod.invoke(sniHostName);
|
||||
|
||||
getServerNamesMethod = SSLParameters.class.getDeclaredMethod("getServerNames");
|
||||
setServerNamesMethod = SSLParameters.class.getDeclaredMethod("setServerNames", List.class);
|
||||
SSLParameters parameters = new SSLParameters();
|
||||
@SuppressWarnings({ "rawtypes", "unused" })
|
||||
List serverNames = (List) getServerNamesMethod.invoke(parameters);
|
||||
setServerNamesMethod.invoke(parameters, Collections.emptyList());
|
||||
} catch (Throwable ingore) {
|
||||
sniHostNameClass = null;
|
||||
getAsciiNameMethod = null;
|
||||
getServerNamesMethod = null;
|
||||
setServerNamesMethod = null;
|
||||
}
|
||||
}
|
||||
SNI_HOSTNAME_CLASS = sniHostNameClass;
|
||||
GET_ASCII_NAME_METHOD = getAsciiNameMethod;
|
||||
GET_SERVER_NAMES_METHOD = getServerNamesMethod;
|
||||
SET_SERVER_NAMES_METHOD = setServerNamesMethod;
|
||||
}
|
||||
|
||||
private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
|
||||
@ -160,9 +199,10 @@ public final class OpenSslEngine extends SSLEngine {
|
||||
|
||||
private volatile ClientAuth clientAuth = ClientAuth.NONE;
|
||||
|
||||
private volatile String endPointIdentificationAlgorithm;
|
||||
private String endPointIdentificationAlgorithm;
|
||||
// Store as object as AlgorithmConstraints only exists since java 7.
|
||||
private volatile Object algorithmConstraints;
|
||||
private Object algorithmConstraints;
|
||||
private List<?> sniHostNames;
|
||||
|
||||
// SSL Engine status variables
|
||||
private boolean isInboundDone;
|
||||
@ -1393,23 +1433,55 @@ public final class OpenSslEngine extends SSLEngine {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SSLParameters getSSLParameters() {
|
||||
public synchronized SSLParameters getSSLParameters() {
|
||||
SSLParameters sslParameters = super.getSSLParameters();
|
||||
|
||||
if (PlatformDependent.javaVersion() >= 7) {
|
||||
int version = PlatformDependent.javaVersion();
|
||||
if (version >= 7) {
|
||||
sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
|
||||
SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints);
|
||||
if (version >= 8 && SET_SERVER_NAMES_METHOD != null && sniHostNames != null) {
|
||||
try {
|
||||
SET_SERVER_NAMES_METHOD.invoke(sslParameters, sniHostNames);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new Error(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sslParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSSLParameters(SSLParameters sslParameters) {
|
||||
public synchronized void setSSLParameters(SSLParameters sslParameters) {
|
||||
super.setSSLParameters(sslParameters);
|
||||
|
||||
if (PlatformDependent.javaVersion() >= 7) {
|
||||
int version = PlatformDependent.javaVersion();
|
||||
if (version >= 7) {
|
||||
endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
|
||||
algorithmConstraints = sslParameters.getAlgorithmConstraints();
|
||||
|
||||
if (version >= 8 && SNI_HOSTNAME_CLASS != null && clientMode && !isDestroyed()) {
|
||||
assert GET_SERVER_NAMES_METHOD != null;
|
||||
assert GET_ASCII_NAME_METHOD != null;
|
||||
try {
|
||||
List<?> servernames = (List<?>) GET_SERVER_NAMES_METHOD.invoke(sslParameters);
|
||||
for (Object serverName : servernames) {
|
||||
if (SNI_HOSTNAME_CLASS.isInstance(serverName)) {
|
||||
SSL.setTlsExtHostName(ssl, (String) GET_ASCII_NAME_METHOD.invoke(serverName));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Only " + SNI_HOSTNAME_CLASS.getName()
|
||||
+ " instances are supported, but found: " + serverName);
|
||||
}
|
||||
}
|
||||
sniHostNames = servernames;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new Error(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user