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.Buffer;
|
||||||
import org.apache.tomcat.jni.SSL;
|
import org.apache.tomcat.jni.SSL;
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ReadOnlyBufferException;
|
import java.nio.ReadOnlyBufferException;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
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 ENGINE_CLOSED = new SSLException("engine closed");
|
||||||
private static final SSLException RENEGOTIATION_UNSUPPORTED = new SSLException("renegotiation unsupported");
|
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 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 {
|
static {
|
||||||
ENGINE_CLOSED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
|
ENGINE_CLOSED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
|
||||||
RENEGOTIATION_UNSUPPORTED.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");
|
destroyedUpdater = AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed");
|
||||||
}
|
}
|
||||||
DESTROYED_UPDATER = destroyedUpdater;
|
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
|
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 ClientAuth clientAuth = ClientAuth.NONE;
|
||||||
|
|
||||||
private volatile String endPointIdentificationAlgorithm;
|
private String endPointIdentificationAlgorithm;
|
||||||
// Store as object as AlgorithmConstraints only exists since java 7.
|
// Store as object as AlgorithmConstraints only exists since java 7.
|
||||||
private volatile Object algorithmConstraints;
|
private Object algorithmConstraints;
|
||||||
|
private List<?> sniHostNames;
|
||||||
|
|
||||||
// SSL Engine status variables
|
// SSL Engine status variables
|
||||||
private boolean isInboundDone;
|
private boolean isInboundDone;
|
||||||
@ -1393,23 +1433,55 @@ public final class OpenSslEngine extends SSLEngine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SSLParameters getSSLParameters() {
|
public synchronized SSLParameters getSSLParameters() {
|
||||||
SSLParameters sslParameters = super.getSSLParameters();
|
SSLParameters sslParameters = super.getSSLParameters();
|
||||||
|
|
||||||
if (PlatformDependent.javaVersion() >= 7) {
|
int version = PlatformDependent.javaVersion();
|
||||||
|
if (version >= 7) {
|
||||||
sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
|
sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
|
||||||
SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints);
|
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;
|
return sslParameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSSLParameters(SSLParameters sslParameters) {
|
public synchronized void setSSLParameters(SSLParameters sslParameters) {
|
||||||
super.setSSLParameters(sslParameters);
|
super.setSSLParameters(sslParameters);
|
||||||
|
|
||||||
if (PlatformDependent.javaVersion() >= 7) {
|
int version = PlatformDependent.javaVersion();
|
||||||
|
if (version >= 7) {
|
||||||
endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
|
endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
|
||||||
algorithmConstraints = sslParameters.getAlgorithmConstraints();
|
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