Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You under the Apache License, Version 2.0
   *  (the "License"); you may not use this file except in compliance with
   *  the License.  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
  *
  *  Unless required by applicable law or agreed to in writing, software
  *  distributed under the License is distributed on an "AS IS" BASIS,
  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *  See the License for the specific language governing permissions and
  *  limitations under the License.
  */
 
 package org.apache.tomcat.util.net.jsse;
 
 import static org.jboss.web.CoyoteMessages.MESSAGES;
 
 import java.io.File;
 import java.util.List;
 import java.util.Set;
 
 
 
 /*
   1. Make the JSSE's jars available, either as an installed
      extension (copy them into jre/lib/ext) or by adding
      them to the Tomcat classpath.
   2. keytool -genkey -alias tomcat -keyalg RSA
      Use "changeit" as password ( this is the default we use )
  */

SSL server socket factory. It _requires_ a valid RSA key and JSSE.

Author(s):
Harish Prabandham
Costin Manolache
Stefan Freyr Stefansson
EKR -- renamed to JSSESocketFactory
Jan Luehe
Bill Barker
 
 public class JSSESocketFactory
 
     private static final boolean RFC_5746_SUPPORTED;
     public static final String[] DEFAULT_SERVER_PROTOCOLS;
 
     // defaults
     static String defaultProtocol = "TLS";
     static boolean defaultClientAuth = false;
     static String defaultKeystoreType = "JKS";
     private static final String defaultKeystoreFile
         = System.getProperty("user.home") + "/.keystore";
     private static final String defaultKeyPass = "changeit";
    private static final int defaultSessionCacheSize = 0;
    private static final int defaultSessionTimeout = 86400;
    static {
        boolean result = false;
        SSLContext context;
        String[] protocols = null;
        try {
            context = SSLContext.getInstance("TLS");
            context.init(nullnullnew SecureRandom());
            SSLServerSocketFactory ssf = context.getServerSocketFactory();
            String ciphers[] = ssf.getSupportedCipherSuites();
            for (String cipher : ciphers) {
                if ("TLS_EMPTY_RENEGOTIATION_INFO_SCSV".equals(cipher)) {
                    result = true;
                    break;
                }
            }
            // There is no API to obtain the default server protocols and cipher
            // suites. Having inspected the OpenJDK code there the same results
            // can be achieved via the standard API but there is no guarantee
            // that every JVM implementation determines the defaults the same
            // way. Therefore the defaults are determined by creating a server
            // socket and requested the configured values.
            SSLServerSocket socket = (SSLServerSocketssf.createServerSocket();
            // Filter out all the insecure protocols
            protocols = filterInsecureProcotols(socket.getEnabledProtocols());
        } catch (NoSuchAlgorithmException e) {
            // Assume no RFC 5746 support
        } catch (KeyManagementException e) {
            // Assume no RFC 5746 support
        } catch (IOException e) {
            // Unable to determine default ciphers/protocols so use none
        }
         = result;
         = protocols;
    }
    protected boolean initialized;
    protected String clientAuth = "false";
    protected SSLServerSocketFactory sslProxy = null;
    protected String[] enabledCiphers;
    protected boolean allowUnsafeLegacyRenegotiation = false;

    
Flag to state that we require client authentication.
    protected boolean requireClientAuth = false;

    
Flag to state that we would like client authentication.
    protected boolean wantClientAuth    = false;
    public JSSESocketFactory () {
    }
    public ServerSocket createSocket (int port)
        throws IOException
    {
        if (!init();
        ServerSocket socket = .createServerSocket(port);
        initServerSocket(socket);
        return socket;
    }
    
    public ServerSocket createSocket (int portint backlog)
        throws IOException
    {
        if (!init();
        ServerSocket socket = .createServerSocket(portbacklog);
        initServerSocket(socket);
        return socket;
    }
    
    public ServerSocket createSocket (int portint backlog,
                                      InetAddress ifAddress)
        throws IOException
    {   
        if (!init();
        ServerSocket socket = .createServerSocket(portbacklog,
                                                          ifAddress);
        initServerSocket(socket);
        return socket;
    }
    
    public Socket acceptSocket(ServerSocket socket)
        throws IOException
    {
        SSLSocket asock = null;
        try {
             asock = (SSLSocket)socket.accept();
        } catch (SSLException e){
          throw new IOException(.sslHandshakeError(), e);
        }
        return asock;
    }
    
    public void handshake(Socket sockthrows IOException {
        // We do getSession instead of startHandshake() so we can call this multiple times
        SSLSession session = ((SSLSocket)sock).getSession();
        if (session.getCipherSuite().equals("SSL_NULL_WITH_NULL_NULL"))
            throw new IOException(.invalidSslCipherSuite());
            // Prevent further handshakes by removing all cipher suites
            ((SSLSocketsock).setEnabledCipherSuites(new String[0]);
        }
    }
    /*
     * Determines the SSL cipher suites to be enabled.
     *
     * @param requestedCiphers Comma-separated list of requested ciphers
     * @param supportedCiphers Array of supported ciphers
     *
     * @return Array of SSL cipher suites to be enabled, or null if none of the
     * requested ciphers are supported
     */
    protected String[] getEnabledCiphers(String requestedCiphers,
                                         String[] supportedCiphersthrows IOException {
        String[] enabledCiphers = null;
        if (requestedCiphers != null) {
            String[] ciphers = requestedCiphers.split(",");
	    enabledCiphers = JSSEUtils.getEnabledCiphers(cipherssupportedCiphers);
	    if(enabledCiphers == null || enabledCiphers.length == 0) {
                throw new IOException(.noCipherMatch()); // Like openssl.
            }
        } else {
            enabledCiphers = .getDefaultCipherSuites();
        }
        return enabledCiphers;
    }
     
    /*
     * Gets the SSL server's keystore password.
     */
    protected String getKeystorePassword() {
        String keyPass = (String).get("keypass");
        if (keyPass == null) {
            keyPass = ;
        }
        String keystorePass = (String).get("keystorePass");
        if (keystorePass == null) {
            keystorePass = keyPass;
        }
        return keystorePass;
    }
    /*
     * Gets the SSL server's keystore.
     */
    protected KeyStore getKeystore(String typeString providerString pass)
            throws IOException {
        String keystoreFile = (String).get("keystore");
        if ("Windows-MY".equalsIgnoreCase(type))
            keystoreFile = "";
        else if (keystoreFile == null)
            keystoreFile = ;
        return getStore(typeproviderkeystoreFilepass);
    }
    /*
     * Gets the SSL server's truststore.
     */
    protected KeyStore getTrustStore(String keystoreType,
            String keystoreProviderthrows IOException {
        KeyStore trustStore = null;
        String truststoreFile = (String).get("truststoreFile");
        if(truststoreFile == null) {
            truststoreFile = System.getProperty("javax.net.ssl.trustStore");
        }
        if(..isDebugEnabled()) {
            ..debug("Truststore = " + truststoreFile);
        }
        String truststorePassword = (String).get("truststorePass");
        iftruststorePassword == null) {
            truststorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
        }
        if(..isDebugEnabled()) {
            ..debug("TrustPass = " + truststorePassword);
        }
        String truststoreType = (String).get("truststoreType");
        iftruststoreType == null) {
            truststoreType = System.getProperty("javax.net.ssl.trustStoreType");
        }
        if(truststoreType == null) {
            truststoreType = keystoreType;
        }
        if ("Windows-ROOT".equalsIgnoreCase(truststoreType))
            truststoreFile = "";
        if(..isDebugEnabled()) {
            ..debug("trustType = " + truststoreType);
        }
        String truststoreProvider =
            (String).get("truststoreProvider");
        iftruststoreProvider == null) {
            truststoreProvider =
                System.getProperty("javax.net.ssl.trustStoreProvider");
        }
        if (truststoreProvider == null) {
            truststoreProvider = keystoreProvider;
        }
        if(..isDebugEnabled()) {
            ..debug("trustProvider = " + truststoreProvider);
        }
        if (truststoreFile != null){
            trustStore = getStore(truststoreTypetruststoreProvider,
                    truststoreFiletruststorePassword);
        }
        return trustStore;
    }
    /*
     * Gets the key- or truststore with the specified type, path, and password.
     */
    private KeyStore getStore(String typeString providerString path,
            String passthrows IOException {
        KeyStore ks = null;
        InputStream istream = null;
        try {
            if (provider == null) {
                ks = KeyStore.getInstance(type);
            } else {
                ks = KeyStore.getInstance(typeprovider);
            }
            if(!("PKCS11".equalsIgnoreCase(type) || "".equalsIgnoreCase(path))) {
                File keyStoreFile = new File(path);
                if (!keyStoreFile.isAbsolute()) {
                    keyStoreFile = new File(System.getProperty("catalina.base"),
                                            path);
                }
                istream = new FileInputStream(keyStoreFile);
            }
            char[] storePass = null;
            if (pass != null) {
                storePass = pass.toCharArray(); 
            }
            ks.load(istreamstorePass);
        } catch (FileNotFoundException fnfe) {
            ..errorLoadingKeystore(typepathfnfe.getMessage());
            throw fnfe;
        } catch (IOException ioe) {
            ..errorLoadingKeystoreWithException(typepathioe.getMessage(), ioe);
            throw ioe;      
        } catch(Exception ex) {
            ..errorLoadingKeystoreWithException(typepathex.getMessage(), ex);
            throw new IOException(ex);
        } finally {
            if (istream != null) {
                try {
                    istream.close();
                } catch (IOException ioe) {
                    // Do nothing
                }
            }
        }
        return ks;
    }

    
Reads the keystore and initializes the SSL socket factory.
    void init() throws IOException {
        try {
            String clientAuthStr = (String.get("clientauth");
            if("true".equalsIgnoreCase(clientAuthStr) ||
               "yes".equalsIgnoreCase(clientAuthStr)) {
                 = true;
            } else if("want".equalsIgnoreCase(clientAuthStr)) {
                 = true;
            }
            // SSL protocol variant (e.g., TLS, SSL v3, etc.)
            String protocol = (String.get("protocol");
            if (protocol == null) {
                protocol = ;
            }
            // Certificate encoding algorithm (e.g., SunX509)
            String algorithm = (String.get("algorithm");
            if (algorithm == null) {
                algorithm = KeyManagerFactory.getDefaultAlgorithm();;
            }
            String keystoreType = (String.get("keystoreType");
            if (keystoreType == null) {
                keystoreType = ;
            }
            String keystoreProvider =
                (String.get("keystoreProvider");
            String trustAlgorithm =
                (String).get("truststoreAlgorithm");
            iftrustAlgorithm == null ) {
                trustAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            }
            // Create and init SSLContext
            SSLContext context = (SSLContext.get("SSLContext");
            if (context == null) {
                context = SSLContext.getInstance(protocol); 
                context.init(
                        getKeyManagers(keystoreTypekeystoreProvider,
                                algorithm, (String.get("keyAlias")),
                        getTrustManagers(keystoreTypekeystoreProvider,
                                trustAlgorithm), new SecureRandom());
            }
            // Configure SSL session cache
            int sessionCacheSize;
            if (.get("sessionCacheSize") != null) {
                sessionCacheSize = Integer.parseInt(
                        (String).get("sessionCacheSize"));
            } else {
                sessionCacheSize = ;
            }
            int sessionCacheTimeout;
            if (.get("sessionCacheTimeout") != null) {
                sessionCacheTimeout = Integer.parseInt(
                        (String).get("sessionCacheTimeout"));
            } else {
                sessionCacheTimeout = ;
            }
            SSLSessionContext sessionContext =
                context.getServerSessionContext();
            if (sessionContext != null) {
                sessionContext.setSessionCacheSize(sessionCacheSize);
                sessionContext.setSessionTimeout(sessionCacheTimeout);
            }
            // create proxy
             = context.getServerSocketFactory();
            // Determine which cipher suites to enable
            String requestedCiphers = (String).get("ciphers");
             = getEnabledCiphers(requestedCiphers,
                                               .getSupportedCipherSuites());
             =
                "true".equals(.get("allowUnsafeLegacyRenegotiation"));
            
            // Check the SSL config is OK
            checkConfig();
        } catch(Exception e) {
            ife instanceof IOException )
                throw (IOException)e;
            throw new IOException(e.getMessage());
        }
    }

    
Gets the initialized key managers.
    protected KeyManager[] getKeyManagers(String keystoreType,
                                          String keystoreProvider,
                                          String algorithm,
                                          String keyAlias)
                throws Exception {
        KeyManager[] kms = null;
        String keystorePass = getKeystorePassword();
        KeyStore ks = getKeystore(keystoreTypekeystoreProviderkeystorePass);
        if (keyAlias != null && !ks.isKeyEntry(keyAlias)) {
            throw new IOException(.noKeyAlias(keyAlias));
        }
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
        kmf.init(kskeystorePass.toCharArray());
        kms = kmf.getKeyManagers();
        if (keyAlias != null) {
            if (..equals(keystoreType)) {
                keyAlias = keyAlias.toLowerCase(.);
            }
            for(int i=0; i<kms.lengthi++) {
                kms[i] = new JSSEKeyManager((X509KeyManager)kms[i], keyAlias);
            }
        }
        return kms;
    }

    
Gets the intialized trust managers.
    protected TrustManager[] getTrustManagers(String keystoreType,
            String keystoreProviderString algorithm)
        throws Exception {
        String crlf = (String.get("crlFile");
        
        TrustManager[] tms = null;
        
        KeyStore trustStore = getTrustStore(keystoreTypekeystoreProvider);
        if (trustStore != null) {
            if (crlf == null) {
                TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
                tmf.init(trustStore);
                tms = tmf.getTrustManagers();
            } else {
                TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
                CertPathParameters params = getParameters(algorithmcrlftrustStore);
                ManagerFactoryParameters mfp = new CertPathTrustManagerParameters(params);
                tmf.init(mfp);
                tms = tmf.getTrustManagers();
            }
        }
        
        return tms;
    }
    
    
Return the initialization parameters for the TrustManager. Currently, only the default PKIX is supported.

Parameters:
algorithm The algorithm to get parameters for.
crlf The path to the CRL file.
trustStore The configured TrustStore.
Returns:
The parameters including the CRLs and TrustStore.
    protected CertPathParameters getParameters(String algorithm
                                                String crlf
                                                KeyStore trustStore)
        throws Exception {
        CertPathParameters params = null;
        if("PKIX".equalsIgnoreCase(algorithm)) {
            PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore
                                                                     new X509CertSelector());
            Collection crls = getCRLs(crlf);
            CertStoreParameters csp = new CollectionCertStoreParameters(crls);
            CertStore store = CertStore.getInstance("Collection"csp);
            xparams.addCertStore(store);
            xparams.setRevocationEnabled(true);
            String trustLength = (String).get("trustMaxCertLength");
            if(trustLength != null) {
                try {
                    xparams.setMaxPathLength(Integer.parseInt(trustLength));
                } catch(Exception ex) {
                    ..invalidMaxCertLength(trustLength);
                }
            }
            params = xparams;
        } else {
            throw new CRLException(.unsupportedCrl(algorithm));
        }
        return params;
    }


    
Load the collection of CRLs.
    protected Collection<? extends CRLgetCRLs(String crlf
        throws IOExceptionCRLExceptionCertificateException {
        File crlFile = new File(crlf);
        if( !crlFile.isAbsolute() ) {
            crlFile = new File(System.getProperty("catalina.base"), crlf);
        }
        Collection<? extends CRLcrls = null;
        InputStream is = null;
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            is = new FileInputStream(crlFile);
            crls = cf.generateCRLs(is);
        } catch(IOException iex) {
            throw iex;
        } catch(CRLException crle) {
            throw crle;
        } catch(CertificateException ce) {
            throw ce;
        } finally { 
            if(is != null) {
                try{
                    is.close();
                } catch(Exception ex) {
                }
            }
        }
        return crls;
    }

    
Set the SSL protocol variants to be enabled.

Parameters:
socket the SSLServerSocket.
protocols the protocols to use.
    protected void setEnabledProtocols(SSLServerSocket socketString []protocols){
        if (protocols == null) {
            socket.setEnabledProtocols();
        } else {
            socket.setEnabledProtocols(protocols);
        }
    }

    
Determines the SSL protocol variants to be enabled.

Parameters:
socket The socket to get supported list from.
requestedProtocols Comma-separated list of requested SSL protocol variants
Returns:
Array of SSL protocol variants to be enabled, or null if none of the requested protocol variants are supported
    protected String[] getEnabledProtocols(SSLServerSocket socket,
            String requestedProtocols){
        Set<StringsupportedProtocols = new HashSet<String>();
        for (String supportedProtocol : socket.getSupportedProtocols()) {
            supportedProtocols.add(supportedProtocol);
        }
        if (requestedProtocols == null) {
            return ;
        }
        String[] requestedProtocolsArr = requestedProtocols.split(",");
        List<StringenabledProtocols = new ArrayList<String>(requestedProtocolsArr.length);
        for (String requestedProtocol : requestedProtocolsArr) {
            String requestedProtocolTrim = requestedProtocol.trim();
            if (supportedProtocols.contains(requestedProtocolTrim)) {
                enabledProtocols.add(requestedProtocolTrim);
            } else {
                ..unsupportedProtocol(requestedProtocolTrim);
            }
        }
        return enabledProtocols.toArray(new String[enabledProtocols.size()]);
    }

    
Configure Client authentication for this version of JSSE. The JSSE included in Java 1.4 supports the 'want' value. Prior versions of JSSE will treat 'want' as 'false'.

Parameters:
socket the SSLServerSocket
    protected void configureClientAuth(SSLServerSocket socket){
        if (){
            socket.setWantClientAuth();
        } else {
            socket.setNeedClientAuth();
        }
    }

    
Configure Client authentication for this version of JSSE. The JSSE included in Java 1.4 supports the 'want' value. Prior versions of JSSE will treat 'want' as 'false'.

Parameters:
socket the SSLSocket
    protected void configureClientAuth(SSLSocket socket){
        // Per JavaDocs: SSLSockets returned from 
        // SSLServerSocket.accept() inherit this setting.
    }
    
    
Configures the given SSL server socket with the requested cipher suites, protocol versions, and need for client authentication
    private void initServerSocket(ServerSocket ssocket) {
        SSLServerSocket socket = (SSLServerSocketssocket;
        if ( != null) {
            socket.setEnabledCipherSuites();
        }
        String requestedProtocols = (String.get("protocols");
        socket.setEnabledProtocols(getEnabledProtocols(socketrequestedProtocols));
        // we don't know if client auth is needed -
        // after parsing the request we may re-handshake
        configureClientAuth(socket);
    }

    
Checks that the certificate is compatible with the enabled cipher suites. If we don't check now, the JIoEndpoint can enter a nasty logging loop. See bug 45528.
    private void checkConfig() throws IOException {
        // Create an unbound server socket
        ServerSocket socket = .createServerSocket();
        initServerSocket(socket);
        try {
            // Set the timeout to 1ms as all we care about is if it throws an
            // SSLException on accept. 
            socket.setSoTimeout(1);
            socket.accept();
            // Will never get here - no client can connect to an unbound port
        } catch (SSLException ssle) {
            // SSL configuration is invalid. Possibly cert doesn't match ciphers
            IOException ioe = new IOException(.invalidSSLConfiguration(ssle.getMessage()));
            ioe.initCause(ssle);
            throw ioe;
        } catch (Exception e) {
            /*
             * Possible ways of getting here
             * socket.accept() throws a SecurityException
             * socket.setSoTimeout() throws a SocketException
             * socket.accept() throws some other exception (after a JDK change)
             *      In these cases the test won't work so carry on - essentially
             *      the behaviour before this patch
             * socket.accept() throws a SocketTimeoutException
             *      In this case all is well so carry on
             */
        } finally {
            // Should be open here but just in case
            if (!socket.isClosed()) {
                socket.close();
            }
        }
        
    }
    public static String[] filterInsecureProcotols(String[] protocols) {
        if (protocols == null) {
            return null;
        }
        List<Stringresult = new ArrayList<String>(protocols.length);
        for (String protocol : protocols) {
            if (protocol == null || protocol.toUpperCase(.).contains("SSL")) {
                if (..isDebugEnabled()) {
                    ..debug("Exclude protocol: " + protocol);
                }
                if (protocol != null && protocol.equalsIgnoreCase("SSLv2Hello")) {
                    result.add(protocol);
                }
            } else {
                result.add(protocol);
            }
        }
        return result.toArray(new String[result.size()]);
    }
New to GrepCode? Check out our FAQ X