| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.security.ssl;  | 
 | 
 | 
 | 
import java.security.AccessControlContext;  | 
 | 
import java.security.AccessController;  | 
 | 
import java.security.AlgorithmConstraints;  | 
 | 
import java.security.NoSuchAlgorithmException;  | 
 | 
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.action.GetIntegerAction;  | 
 | 
import sun.security.action.GetPropertyAction;  | 
 | 
import sun.security.ssl.SSLExtension.ClientExtensions;  | 
 | 
import sun.security.ssl.SSLExtension.ServerExtensions;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
final class SSLConfiguration implements Cloneable { | 
 | 
      | 
 | 
    AlgorithmConstraints        userSpecifiedAlgorithmConstraints;  | 
 | 
    List<ProtocolVersion>       enabledProtocols;  | 
 | 
    List<CipherSuite>           enabledCipherSuites;  | 
 | 
    ClientAuthType              clientAuthType;  | 
 | 
    String                      identificationProtocol;  | 
 | 
    List<SNIServerName>         serverNames;  | 
 | 
    Collection<SNIMatcher>      sniMatchers;  | 
 | 
    String[]                    applicationProtocols;  | 
 | 
    boolean                     preferLocalCipherSuites;  | 
 | 
    int                         maximumPacketSize = 0;  | 
 | 
 | 
 | 
    // The configured signature schemes for "signature_algorithms" and  | 
 | 
      | 
 | 
    List<SignatureScheme>       signatureSchemes;  | 
 | 
 | 
 | 
      | 
 | 
    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 final int maxHandshakeMessageSize = AccessController.doPrivileged(  | 
 | 
            new GetIntegerAction("jdk.tls.maxHandshakeMessageSize", 32768)).intValue(); | 
 | 
 | 
 | 
      | 
 | 
    static final int maxCertificateChainLength = AccessController.doPrivileged(  | 
 | 
            new GetIntegerAction("jdk.tls.maxCertificateChainLength", 10)).intValue(); | 
 | 
 | 
 | 
      | 
 | 
    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.userSpecifiedAlgorithmConstraints =  | 
 | 
                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.signatureSchemes = isClientMode ?  | 
 | 
                CustomizedClientSignatureSchemes.signatureSchemes :  | 
 | 
                CustomizedServerSignatureSchemes.signatureSchemes;  | 
 | 
        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.userSpecifiedAlgorithmConstraints);  | 
 | 
        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);  | 
 | 
 | 
 | 
        return params;  | 
 | 
    }  | 
 | 
 | 
 | 
    void setSSLParameters(SSLParameters params) { | 
 | 
        AlgorithmConstraints ac = params.getAlgorithmConstraints();  | 
 | 
        if (ac != null) { | 
 | 
            this.userSpecifiedAlgorithmConstraints = 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();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    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]);  | 
 | 
    }  | 
 | 
 | 
 | 
    void toggleClientMode() { | 
 | 
        this.isClientMode ^= true;  | 
 | 
 | 
 | 
          | 
 | 
        this.signatureSchemes = isClientMode ?  | 
 | 
                CustomizedClientSignatureSchemes.signatureSchemes :  | 
 | 
                CustomizedServerSignatureSchemes.signatureSchemes;  | 
 | 
    }  | 
 | 
 | 
 | 
    @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;      | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
    // lazy initialization holder class idiom for static default parameters  | 
 | 
    //  | 
 | 
      | 
 | 
    private static final class CustomizedClientSignatureSchemes { | 
 | 
        private static List<SignatureScheme> signatureSchemes =  | 
 | 
                getCustomizedSignatureScheme("jdk.tls.client.SignatureSchemes"); | 
 | 
    }  | 
 | 
 | 
 | 
    // lazy initialization holder class idiom for static default parameters  | 
 | 
    //  | 
 | 
      | 
 | 
    private static final class CustomizedServerSignatureSchemes { | 
 | 
        private static List<SignatureScheme> signatureSchemes =  | 
 | 
                getCustomizedSignatureScheme("jdk.tls.server.SignatureSchemes"); | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static List<SignatureScheme> getCustomizedSignatureScheme(  | 
 | 
            String propertyName) { | 
 | 
 | 
 | 
        String property = GetPropertyAction.privilegedGetProperty(propertyName);  | 
 | 
        if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { | 
 | 
            SSLLogger.fine(  | 
 | 
                    "System property " + propertyName + " is set to '" +  | 
 | 
                    property + "'");  | 
 | 
        }  | 
 | 
        if (property != null && !property.isEmpty()) { | 
 | 
              | 
 | 
            if (property.length() > 1 && property.charAt(0) == '"' &&  | 
 | 
                    property.charAt(property.length() - 1) == '"') { | 
 | 
                property = property.substring(1, property.length() - 1);  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        if (property != null && !property.isEmpty()) { | 
 | 
            String[] signatureSchemeNames = property.split(","); | 
 | 
            List<SignatureScheme> signatureSchemes =  | 
 | 
                        new ArrayList<>(signatureSchemeNames.length);  | 
 | 
            for (int i = 0; i < signatureSchemeNames.length; i++) { | 
 | 
                signatureSchemeNames[i] = signatureSchemeNames[i].trim();  | 
 | 
                if (signatureSchemeNames[i].isEmpty()) { | 
 | 
                    continue;  | 
 | 
                }  | 
 | 
 | 
 | 
                SignatureScheme scheme =  | 
 | 
                    SignatureScheme.nameOf(signatureSchemeNames[i]);  | 
 | 
                if (scheme != null && scheme.isAvailable) { | 
 | 
                    signatureSchemes.add(scheme);  | 
 | 
                } else { | 
 | 
                    if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { | 
 | 
                        SSLLogger.fine(  | 
 | 
                                "The current installed providers do not " +  | 
 | 
                                "support signature scheme: " +  | 
 | 
                                signatureSchemeNames[i]);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
 | 
 | 
            return signatureSchemes;  | 
 | 
        }  | 
 | 
 | 
 | 
        return Collections.emptyList();  | 
 | 
    }  | 
 | 
}  |