|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.ssl; |
|
|
|
import java.security.AccessControlContext; |
|
import java.security.AccessController; |
|
import java.security.AlgorithmConstraints; |
|
import java.security.NoSuchAlgorithmException; |
|
import java.security.PrivilegedActionException; |
|
import java.security.PrivilegedExceptionAction; |
|
import java.util.ArrayList; |
|
import java.util.Arrays; |
|
import java.util.Collection; |
|
import java.util.Collections; |
|
import java.util.HashMap; |
|
import java.util.List; |
|
import java.util.function.BiFunction; |
|
import javax.net.ssl.HandshakeCompletedListener; |
|
import javax.net.ssl.SNIMatcher; |
|
import javax.net.ssl.SNIServerName; |
|
import javax.net.ssl.SSLEngine; |
|
import javax.net.ssl.SSLParameters; |
|
import javax.net.ssl.SSLSocket; |
|
import sun.security.ssl.SSLExtension.ClientExtensions; |
|
import sun.security.ssl.SSLExtension.ServerExtensions; |
|
|
|
|
|
|
|
*/ |
|
final class SSLConfiguration implements Cloneable { |
|
|
|
AlgorithmConstraints algorithmConstraints; |
|
List<ProtocolVersion> enabledProtocols; |
|
List<CipherSuite> enabledCipherSuites; |
|
ClientAuthType clientAuthType; |
|
String identificationProtocol; |
|
List<SNIServerName> serverNames; |
|
Collection<SNIMatcher> sniMatchers; |
|
String[] applicationProtocols; |
|
boolean preferLocalCipherSuites; |
|
boolean enableRetransmissions; |
|
int maximumPacketSize; |
|
|
|
|
|
ProtocolVersion maximumProtocolVersion; |
|
|
|
|
|
boolean isClientMode; |
|
boolean enableSessionCreation; |
|
|
|
|
|
BiFunction<SSLSocket, List<String>, String> socketAPSelector; |
|
BiFunction<SSLEngine, List<String>, String> engineAPSelector; |
|
|
|
HashMap<HandshakeCompletedListener, AccessControlContext> |
|
handshakeListeners; |
|
|
|
boolean noSniExtension; |
|
boolean noSniMatcher; |
|
|
|
|
|
static final boolean useExtendedMasterSecret; |
|
|
|
|
|
static final boolean allowLegacyResumption = |
|
Utilities.getBooleanProperty("jdk.tls.allowLegacyResumption", true); |
|
|
|
|
|
static final boolean allowLegacyMasterSecret = |
|
Utilities.getBooleanProperty("jdk.tls.allowLegacyMasterSecret", true); |
|
|
|
|
|
static final boolean useCompatibilityMode = Utilities.getBooleanProperty( |
|
"jdk.tls.client.useCompatibilityMode", true); |
|
|
|
|
|
static final boolean acknowledgeCloseNotify = Utilities.getBooleanProperty( |
|
"jdk.tls.acknowledgeCloseNotify", false); |
|
|
|
|
|
static { |
|
boolean supportExtendedMasterSecret = Utilities.getBooleanProperty( |
|
"jdk.tls.useExtendedMasterSecret", true); |
|
if (supportExtendedMasterSecret) { |
|
try { |
|
JsseJce.getKeyGenerator("SunTlsExtendedMasterSecret"); |
|
} catch (NoSuchAlgorithmException nae) { |
|
supportExtendedMasterSecret = false; |
|
} |
|
} |
|
useExtendedMasterSecret = supportExtendedMasterSecret; |
|
} |
|
|
|
SSLConfiguration(SSLContextImpl sslContext, boolean isClientMode) { |
|
|
|
|
|
this.algorithmConstraints = SSLAlgorithmConstraints.DEFAULT; |
|
this.enabledProtocols = |
|
sslContext.getDefaultProtocolVersions(!isClientMode); |
|
this.enabledCipherSuites = |
|
sslContext.getDefaultCipherSuites(!isClientMode); |
|
this.clientAuthType = ClientAuthType.CLIENT_AUTH_NONE; |
|
|
|
this.identificationProtocol = null; |
|
this.serverNames = Collections.<SNIServerName>emptyList(); |
|
this.sniMatchers = Collections.<SNIMatcher>emptyList(); |
|
this.preferLocalCipherSuites = false; |
|
|
|
this.applicationProtocols = new String[0]; |
|
this.enableRetransmissions = sslContext.isDTLS(); |
|
this.maximumPacketSize = 0; |
|
|
|
this.maximumProtocolVersion = ProtocolVersion.NONE; |
|
for (ProtocolVersion pv : enabledProtocols) { |
|
if (pv.compareTo(maximumProtocolVersion) > 0) { |
|
this.maximumProtocolVersion = pv; |
|
} |
|
} |
|
|
|
|
|
this.isClientMode = isClientMode; |
|
this.enableSessionCreation = true; |
|
this.socketAPSelector = null; |
|
this.engineAPSelector = null; |
|
|
|
this.handshakeListeners = null; |
|
this.noSniExtension = false; |
|
this.noSniMatcher = false; |
|
} |
|
|
|
SSLParameters getSSLParameters() { |
|
SSLParameters params = new SSLParameters(); |
|
|
|
params.setAlgorithmConstraints(this.algorithmConstraints); |
|
params.setProtocols(ProtocolVersion.toStringArray(enabledProtocols)); |
|
params.setCipherSuites(CipherSuite.namesOf(enabledCipherSuites)); |
|
switch (this.clientAuthType) { |
|
case CLIENT_AUTH_REQUIRED: |
|
params.setNeedClientAuth(true); |
|
break; |
|
case CLIENT_AUTH_REQUESTED: |
|
params.setWantClientAuth(true); |
|
break; |
|
default: |
|
params.setWantClientAuth(false); |
|
} |
|
params.setEndpointIdentificationAlgorithm(this.identificationProtocol); |
|
|
|
if (serverNames.isEmpty() && !noSniExtension) { |
|
|
|
params.setServerNames(null); |
|
} else { |
|
params.setServerNames(this.serverNames); |
|
} |
|
|
|
if (sniMatchers.isEmpty() && !noSniMatcher) { |
|
|
|
params.setSNIMatchers(null); |
|
} else { |
|
params.setSNIMatchers(this.sniMatchers); |
|
} |
|
|
|
params.setApplicationProtocols(this.applicationProtocols); |
|
params.setUseCipherSuitesOrder(this.preferLocalCipherSuites); |
|
params.setEnableRetransmissions(this.enableRetransmissions); |
|
params.setMaximumPacketSize(this.maximumPacketSize); |
|
|
|
return params; |
|
} |
|
|
|
void setSSLParameters(SSLParameters params) { |
|
AlgorithmConstraints ac = params.getAlgorithmConstraints(); |
|
if (ac != null) { |
|
this.algorithmConstraints = ac; |
|
} // otherwise, use the default value |
|
|
|
String[] sa = params.getCipherSuites(); |
|
if (sa != null) { |
|
this.enabledCipherSuites = CipherSuite.validValuesOf(sa); |
|
} // otherwise, use the default values |
|
|
|
sa = params.getProtocols(); |
|
if (sa != null) { |
|
this.enabledProtocols = ProtocolVersion.namesOf(sa); |
|
|
|
this.maximumProtocolVersion = ProtocolVersion.NONE; |
|
for (ProtocolVersion pv : enabledProtocols) { |
|
if (pv.compareTo(maximumProtocolVersion) > 0) { |
|
this.maximumProtocolVersion = pv; |
|
} |
|
} |
|
} // otherwise, use the default values |
|
|
|
if (params.getNeedClientAuth()) { |
|
this.clientAuthType = ClientAuthType.CLIENT_AUTH_REQUIRED; |
|
} else if (params.getWantClientAuth()) { |
|
this.clientAuthType = ClientAuthType.CLIENT_AUTH_REQUESTED; |
|
} else { |
|
this.clientAuthType = ClientAuthType.CLIENT_AUTH_NONE; |
|
} |
|
|
|
String s = params.getEndpointIdentificationAlgorithm(); |
|
if (s != null) { |
|
this.identificationProtocol = s; |
|
} // otherwise, use the default value |
|
|
|
List<SNIServerName> sniNames = params.getServerNames(); |
|
if (sniNames != null) { |
|
this.noSniExtension = sniNames.isEmpty(); |
|
this.serverNames = sniNames; |
|
} // null if none has been set |
|
|
|
Collection<SNIMatcher> matchers = params.getSNIMatchers(); |
|
if (matchers != null) { |
|
this.noSniMatcher = matchers.isEmpty(); |
|
this.sniMatchers = matchers; |
|
} // null if none has been set |
|
|
|
sa = params.getApplicationProtocols(); |
|
if (sa != null) { |
|
this.applicationProtocols = sa; |
|
} // otherwise, use the default values |
|
|
|
this.preferLocalCipherSuites = params.getUseCipherSuitesOrder(); |
|
this.enableRetransmissions = params.getEnableRetransmissions(); |
|
this.maximumPacketSize = params.getMaximumPacketSize(); |
|
} |
|
|
|
|
|
void addHandshakeCompletedListener( |
|
HandshakeCompletedListener listener) { |
|
|
|
if (handshakeListeners == null) { |
|
handshakeListeners = new HashMap<>(4); |
|
} |
|
|
|
handshakeListeners.put(listener, AccessController.getContext()); |
|
} |
|
|
|
|
|
void removeHandshakeCompletedListener( |
|
HandshakeCompletedListener listener) { |
|
|
|
if (handshakeListeners == null) { |
|
throw new IllegalArgumentException("no listeners"); |
|
} |
|
|
|
if (handshakeListeners.remove(listener) == null) { |
|
throw new IllegalArgumentException("listener not registered"); |
|
} |
|
|
|
if (handshakeListeners.isEmpty()) { |
|
handshakeListeners = null; |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
boolean isAvailable(SSLExtension extension) { |
|
for (ProtocolVersion protocolVersion : enabledProtocols) { |
|
if (extension.isAvailable(protocolVersion)) { |
|
if (isClientMode ? |
|
ClientExtensions.defaults.contains(extension) : |
|
ServerExtensions.defaults.contains(extension)) { |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
*/ |
|
boolean isAvailable(SSLExtension extension, |
|
ProtocolVersion protocolVersion) { |
|
return extension.isAvailable(protocolVersion) && |
|
(isClientMode ? ClientExtensions.defaults.contains(extension) : |
|
ServerExtensions.defaults.contains(extension)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
SSLExtension[] getEnabledExtensions(SSLHandshake handshakeType) { |
|
List<SSLExtension> extensions = new ArrayList<>(); |
|
for (SSLExtension extension : SSLExtension.values()) { |
|
if (extension.handshakeType == handshakeType) { |
|
if (isAvailable(extension)) { |
|
extensions.add(extension); |
|
} |
|
} |
|
} |
|
|
|
return extensions.toArray(new SSLExtension[0]); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
SSLExtension[] getExclusiveExtensions(SSLHandshake handshakeType, |
|
List<SSLExtension> excluded) { |
|
List<SSLExtension> extensions = new ArrayList<>(); |
|
for (SSLExtension extension : SSLExtension.values()) { |
|
if (extension.handshakeType == handshakeType) { |
|
if (isAvailable(extension) && !excluded.contains(extension)) { |
|
extensions.add(extension); |
|
} |
|
} |
|
} |
|
|
|
return extensions.toArray(new SSLExtension[0]); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
SSLExtension[] getEnabledExtensions( |
|
SSLHandshake handshakeType, ProtocolVersion protocolVersion) { |
|
return getEnabledExtensions( |
|
handshakeType, Arrays.asList(protocolVersion)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
SSLExtension[] getEnabledExtensions( |
|
SSLHandshake handshakeType, List<ProtocolVersion> activeProtocols) { |
|
List<SSLExtension> extensions = new ArrayList<>(); |
|
for (SSLExtension extension : SSLExtension.values()) { |
|
if (extension.handshakeType == handshakeType) { |
|
if (!isAvailable(extension)) { |
|
continue; |
|
} |
|
|
|
for (ProtocolVersion protocolVersion : activeProtocols) { |
|
if (extension.isAvailable(protocolVersion)) { |
|
extensions.add(extension); |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
return extensions.toArray(new SSLExtension[0]); |
|
} |
|
|
|
@Override |
|
@SuppressWarnings({"unchecked", "CloneDeclaresCloneNotSupported"}) |
|
public Object clone() { |
|
|
|
try { |
|
SSLConfiguration config = (SSLConfiguration)super.clone(); |
|
if (handshakeListeners != null) { |
|
config.handshakeListeners = |
|
(HashMap<HandshakeCompletedListener, AccessControlContext>) |
|
handshakeListeners.clone(); |
|
} |
|
|
|
return config; |
|
} catch (CloneNotSupportedException cnse) { |
|
// unlikely |
|
} |
|
|
|
return null; |
|
} |
|
} |