Package org.jboss.remoting.security

Source Code of org.jboss.remoting.security.SSLSocketBuilder$UserModeSSLServerSocketFactory

/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.remoting.security;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.net.UnknownHostException;
import java.security.AccessController;
import java.security.InvalidParameterException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedAction;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;

/**
* This builds SSL server socket factories and SSL socket factories.<p/>
* The main methods are createSSLServerSocketFactory() and createSSLSocketFactory().
* By default, these methods will use SSLServerSocketFactory.getDefault() and
* SSLSocketFactory.getDefault() and will require the proper system properties to
* be set.  To use a custom configuration, will need to set either the useSSLServerSocketFactory or useSSLSocketFactory
* properties to be false.<p/>
* Some common errors seen are:<p/>
* <p/>
* 1.  javax.net.ssl.SSLException: No available certificate corresponds to the SSL cipher suites which are enabled <p/>
* <p/>
* The 'javax.net.ssl.keyStore' system property has not been set and are using the default SSLServerSocketFactory.<p/>
* <p/>
* 2.  java.net.SocketException: Default SSL context init failed: Cannot recover key <p/>
* <p/>
* The 'javax.net.ssl.keyStorePassword' system property has not been set and are using the default SSLServerSocketFactory. <p/>
* <p/>
* 3.  java.io.IOException: Can not create SSL Server Socket Factory due to the url to the key store not being set. <p/>
* <p/>
* The default SSLServerSocketFactory is NOT being used (so custom configuration for the server socket factory) and the key store url has not been set. <p/>
* <p/>
* 4.  java.lang.IllegalArgumentException: password can't be null <p/>
* <p/>
* The default SSLServerSocketFactory is NOT being used (so custom configuration for the server socket factory) and the key store password has not been set. <p/>
*
* @author <a href="mailto:tom.elrod@jboss.com">Tom Elrod</a>
*/
public class SSLSocketBuilder implements SSLSocketBuilderMBean
{
   /**
    * Value is TLS (Transport Layer Security).
    */
   public static final String DEFAULT_SECURE_SOCKET_PROTOCOL = "TLS";
   /**
    * Value is SunX509.
    */
   public static final String DEFAULT_KEY_MANAGEMENT_ALGORITHM = "SunX509";
   /**
    * Value is JKS
    */
   public static final String DEFAULT_KEY_STORE_TYPE = "JKS";

   /**
    * Defaults to DEFAULT_SECURE_SOCKET_PROTOCOL.  Some acceptable values are TLS, SSL, and SSLv3.
    */
   private String secureSocketProtocol = DEFAULT_SECURE_SOCKET_PROTOCOL;

   /**
    * Defaults to DEFAULT_KEY_MANAGEMENT_ALGORITHM.
    */
   private String keyManagementAlgorithm = DEFAULT_KEY_MANAGEMENT_ALGORITHM;

   /**
    * Defaults to DEFAULT_KEY_STORE_TYPE.  Some acceptable values are JKS (Java Keystore - Sun's keystore format),
    * JCEKS (Java Cryptography Extension keystore - More secure version of JKS), and
    * PKCS12 (Public-Key Cryptography Standards #12 keystore - RSA's Personal Information Exchange Syntax Standard).
    * These are not case sensitive.
    */
   private String keyStoreType = DEFAULT_KEY_STORE_TYPE;

   private boolean useSSLServerSocketFactory = true;
   private boolean useSSLSocketFactory = true;
   private char[] keyStorePassword = null;
   private char[] keyPassword = null;
   private URL keyStoreURL = null;
   private URL trustStoreURL = null;

   private boolean useClientMode;

   public SSLSocketBuilder()
   {
   }

   /**
    * Will indicate if should use the SSLServerSocketFactory.getDefault() for getting the ServerSocketFactory
    * to use (when calling createSSLServerSocketFactory()).
    * If true, will allow for setting key store location (via javax.net.ssl.keyStore system property) and
    * setting of the key store password (via javax.net.ssl.keyStorePassword system property) and no other
    * configuration is needed (none of the other setters will need to be called and are in fact ignored).  If set to
    * false, will allow the custom setting of secure socket protocol, key management algorithm, key store type,
    * key store url, key store password, and key password.<p/>
    * The default value is true.<p/>
    * <b>NOTE: If this is not explicitly set to false, no customizations can be made and the default implementation
    * provided by the JVM vendor being used will be executed.</b>
    *
    * @param shouldUse
    */
   public void setUseSSLServerSocketFactory(boolean shouldUse)
   {
      this.useSSLServerSocketFactory = shouldUse;
   }

   /**
    * Return whether SSLServerSocketFactory.getDefault() will be used or not.  See setUseSSLServerSocketFactory() for more
    * information on what this means.
    *
    * @return
    */
   public boolean getUseSSLServerSocketFactory()
   {
      return useSSLServerSocketFactory;
   }

   /**
    * Will indicate if should use the SSLSocketFactory.getDefault() for getting the SocketFactory
    * to use (when calling createSSLSocketFactory()).
    * If true, will allow for setting trust store location (via Djavax.net.ssl.trustStore system property) and no other
    * configuration is needed (none of the other setters will need to be called and are in fact ignored).  If set to
    * false, will allow the custom setting of secure socket protocol, key management algorithm, key store type,
    * ant trust store url.<p/>
    * The default value is true.<p/>
    * <b>NOTE: If this is not explicitly set to false, no customizations can be made and the default implementation
    * provided by the JVM vendor being used will be executed.</b>
    *
    * @param shouldUse
    */
   public void setUseSSLSocketFactory(boolean shouldUse)
   {
      this.useSSLSocketFactory = shouldUse;
   }

   /**
    * Return whether SSLSocketFactory.getDefault() will be used or not.  See setUseSSLSocketFactory() for more
    * information on what this means.
    *
    * @return
    */
   public boolean getUseSSLSocketFactory()
   {
      return useSSLSocketFactory;
   }

   /**
    * The protocol for the SSLContext.  Some acceptable values are TLS, SSL, and SSLv3.
    * Defaults to DEFAULT_SECURE_SOCKET_PROTOCOL.
    */
   public String getSecureSocketProtocol()
   {
      return secureSocketProtocol;
   }

   /**
    * The protocol for the SSLContext.  Some acceptable values are TLS, SSL, and SSLv3.
    * Defaults to DEFAULT_SECURE_SOCKET_PROTOCOL.
    */
   public void setSecureSocketProtocol(String secureSocketProtocol)
   {
      this.secureSocketProtocol = secureSocketProtocol;
   }

   /**
    * The algorithm for the key manager factory.
    * Defaults to DEFAULT_KEY_MANAGEMENT_ALGORITHM.
    */
   public String getKeyManagementAlgorithm()
   {
      return keyManagementAlgorithm;
   }

   /**
    * The algorithm for the key manager factory.
    * Defaults to DEFAULT_KEY_MANAGEMENT_ALGORITHM.
    */
   public void setKeyManagementAlgorithm(String keyManagementAlgorithm)
   {
      this.keyManagementAlgorithm = keyManagementAlgorithm;
   }

   /**
    * The type to be used for the key store.
    * Defaults to DEFAULT_KEY_STORE_TYPE.  Some acceptable values are JKS (Java Keystore - Sun's keystore format),
    * JCEKS (Java Cryptography Extension keystore - More secure version of JKS), and
    * PKCS12 (Public-Key Cryptography Standards #12 keystore - RSA's Personal Information Exchange Syntax Standard).
    * These are not case sensitive.
    */
   public String getKeyStoreType()
   {
      return keyStoreType;
   }

   /**
    * The type to be used for the key store.
    * Defaults to DEFAULT_KEY_STORE_TYPE.  Some acceptable values are JKS (Java Keystore - Sun's keystore format),
    * JCEKS (Java Cryptography Extension keystore - More secure version of JKS), and
    * PKCS12 (Public-Key Cryptography Standards #12 keystore - RSA's Personal Information Exchange Syntax Standard).
    * These are not case sensitive.
    */
   public void setKeyStoreType(String keyStoreType)
   {
      this.keyStoreType = keyStoreType;
   }

   /**
    * Sets the password to use for the key store.  This only needs to be set if setUseSSLServerSocketFactory() is set
    * to false (otherwise will be ignored).  The value passed will also be used for the key password if it is not
    * explicitly set.
    *
    * @param passphrase
    */
   public void setKeyStorePassword(String passphrase)
   {
      if(passphrase != null && passphrase.length() > 0)
      {
         keyStorePassword = passphrase.toCharArray();
      }
      else
      {
         throw new InvalidParameterException("Must enter a non null key store passphrase with at least one character.");
      }
   }

   /**
    * Sets the password to use for the keys within the key store.  This only needs to be set if setUseSSLServerSocketFactory()
    * is set to false (otherwise will be ignored).  If this value is not set, but the key store password is, it will use
    * that value for the key password.
    *
    * @param passphrase
    */
   public void setKeyPassword(String passphrase)
   {
      if(passphrase != null && passphrase.length() > 0)
      {
         keyPassword = passphrase.toCharArray();
      }
      else
      {
         throw new InvalidParameterException("Must enter a non null key passphrase with at least one character.");
      }
   }


   /**
* Determines whether factories returned by SSLSocketBuilder create Sockets/ServerSockets in client or server mode.
*
* @param useClientMode
*/
   public void setUseClientMode(boolean useClientMode)
   {
      this.useClientMode = useClientMode;
   }

   /**
    * Will create a SSLServerSocketFactory.  If the useSSLServerSocketFactory property is set to true (which is the default),
    * it will use SSLServerSocketFactory.getDefault() to get the server socket factory.  Otherwise, if property is false,
    * will use all the other custom properties that have been set to create a custom server socket factory.
    *
    * @return
    * @throws IOException
    * @throws NoSuchAlgorithmException
    * @throws KeyStoreException
    * @throws CertificateException
    * @throws UnrecoverableKeyException
    * @throws KeyManagementException
    */
   public ServerSocketFactory createSSLServerSocketFactory()
         throws IOException, NoSuchAlgorithmException, KeyStoreException,
                CertificateException, UnrecoverableKeyException, KeyManagementException
   {
      ServerSocketFactory ssf = null;

      if(useSSLServerSocketFactory)
      {
         ssf = SSLServerSocketFactory.getDefault();
      }
      else
      {
         ssf = createCustomServerSocketFactory();
      }

      return ssf;
   }

   /**
    * This is the full on custom ssl server socket configuration.  The only thing not allowed at this point
    * is the changing of providers.  Everything else, including the protocol, algorithm, and key store type
    * can be customized.
    *
    * @return
    * @throws NoSuchAlgorithmException
    * @throws KeyStoreException
    * @throws IOException
    * @throws CertificateException
    * @throws UnrecoverableKeyException
    * @throws KeyManagementException
    */
   private ServerSocketFactory createCustomServerSocketFactory()
         throws NoSuchAlgorithmException, KeyStoreException, IOException,
                CertificateException, UnrecoverableKeyException, KeyManagementException
   {
      ServerSocketFactory ssf = null;

      SSLContext sslContext = SSLContext.getInstance(secureSocketProtocol);
      KeyManagerFactory keyMgrFactory = getKeyManagerFactory();

      KeyManager[] keyManagers = keyMgrFactory.getKeyManagers();
      sslContext.init(keyManagers, null, null);
      ssf = sslContext.getServerSocketFactory();

      if (useClientMode)
         return new UserModeSSLServerSocketFactory((SSLServerSocketFactory) ssf);

      return ssf;
   }

   /**
    * Will create a SSLSocketFactory.  If the useSSLSocketFactory property is set to true (which is the default),
    * it will use SSLSocketFactory.getDefault() to get the socket factory.  Otherwise, if property is false,
    * will use all the other custom properties that have been set to create a custom server socket factory.
    *
    * @return
    * @throws IOException
    * @throws NoSuchAlgorithmException
    * @throws KeyStoreException
    * @throws CertificateException
    * @throws KeyManagementException
    */
   public SocketFactory createSSLSocketFactory()
         throws IOException, NoSuchAlgorithmException, KeyStoreException,
                CertificateException, KeyManagementException
   {
      SocketFactory sf = null;

      if(useSSLSocketFactory)
      {
         sf = SSLSocketFactory.getDefault();
      }
      else
      {
         sf = createCustomSocketFactory();
      }

      return sf;
   }


   private SocketFactory createCustomSocketFactory()
         throws NoSuchAlgorithmException, IOException, CertificateException, KeyStoreException, KeyManagementException
   {
      SocketFactory sf = null;

      SSLContext sslContext = SSLContext.getInstance(secureSocketProtocol);
      TrustManagerFactory trustMgrFactory = getTrustManagerFactory();

      TrustManager[] trustManagers = trustMgrFactory.getTrustManagers();
      sslContext.init(null, trustManagers, null);
      sf = sslContext.getSocketFactory();

      return sf;
   }

   private TrustManagerFactory getTrustManagerFactory()
         throws NoSuchAlgorithmException, IOException, CertificateException, KeyStoreException
   {
      TrustManagerFactory truestMgrFactory = null;

      truestMgrFactory = TrustManagerFactory.getInstance(keyManagementAlgorithm);
      KeyStore keyStore = getKeyStore(trustStoreURL);
      truestMgrFactory.init(keyStore);

      return truestMgrFactory;

   }

   private KeyManagerFactory getKeyManagerFactory()
         throws NoSuchAlgorithmException, KeyStoreException, IOException, CertificateException, UnrecoverableKeyException
   {
      KeyManagerFactory keyMgrFactory = null;

      keyMgrFactory = KeyManagerFactory.getInstance(keyManagementAlgorithm);
      KeyStore keyStore = getKeyStore(keyStoreURL);
      keyMgrFactory.init(keyStore, keyPassword);

      return keyMgrFactory;

   }

   private KeyStore getKeyStore(URL storeURL) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException
   {
      KeyStore keyStore = KeyStore.getInstance(keyStoreType);
      if(storeURL == null)
      {
         throw new IOException("Can not create SSL Server Socket Factory due to the url to the key store not being set.");
      }
      InputStream is = storeURL.openStream();
      keyStore.load(is, keyStorePassword);

      // if key password not set, just try the key store password
      if(keyPassword == null || keyPassword.length > 0)
      {
         keyPassword = keyStorePassword;
      }

      return keyStore;

   }

   /**
    * This is the url string to the key store to use.  If UseSSLServerSocketFactory is true, this will be ignored
    * and will use the value set by the javax.net.ssl.keyStore system property.  Otherwise, if UseSSLServerSocketFactory
    * is false, this must be set.
    *
    * @param storeURL
    * @throws IOException
    */
   public void setKeyStoreURL(String storeURL) throws IOException
   {
      this.keyStoreURL = this.validateStoreURL(storeURL);
   }

   /**
    * This is the url string to the trust store to use.  If UseSSLSocketFactory is true, this will be ignored
    * and will use the value set by the javax.net.ssl.trustStore system property.  Otherwise, if UseSSLSocketFactory
    * is false, this must be set.
    *
    * @param storeURL
    * @throws IOException
    */
   public void setTrustStoreURL(String storeURL) throws IOException
   {
      this.trustStoreURL = this.validateStoreURL(storeURL);
   }

   private URL validateStoreURL(String storeURL) throws IOException
   {
      URL url = null;
      // First see if this is a URL
      try
      {
         url = new URL(storeURL);
      }
      catch(MalformedURLException e)
      {
         // Not a URL or a protocol without a handler
      }

      // Next try to locate this as file path
      if(url == null)
      {
         File tst = new File(storeURL);
         if(tst.exists() == true)
         {
            url = tst.toURL();
         }
      }

      // Last try to locate this as a classpath resource
      if(url == null)
      {
         ClassLoader loader = getContextClassLoader();
         url = loader.getResource(storeURL);
      }

      // Fail if no valid key store was located
      if(url == null)
      {
         String msg = "Failed to find url=" + storeURL + " as a URL, file or resource";
         throw new MalformedURLException(msg);
      }
      return url;
   }

   /****************************************************************************************************************
    * The following are just needed in order to make it a service mbean.  They are just NOOPs (no implementation). *
    ****************************************************************************************************************/

   /**
    * create the service, do expensive operations etc
    */
   public void create() throws Exception
   {
      //NOOP - nothing to do here.  Just needed for mbean service api
   }

   /**
    * start the service, create is already called
    */
   public void start() throws Exception
   {
      //NOOP - nothing to do here.  Just needed for mbean service api
   }

   /**
    * stop the service
    */
   public void stop()
   {
      //NOOP - nothing to do here.  Just needed for mbean service api
   }

   /**
    * destroy the service, tear down
    */
   public void destroy()
   {
      //NOOP - nothing to do here.  Just needed for mbean service api
   }


   // TODO: -TME getContextClassLoader() and GetTCLAction were both taken from org.jboss.security.plugins package
   static ClassLoader getContextClassLoader()
   {
      ClassLoader loader = (ClassLoader) AccessController.doPrivileged(GetTCLAction.ACTION);
      return loader;
   }

   private static class GetTCLAction implements PrivilegedAction
   {
      static PrivilegedAction ACTION = new GetTCLAction();

      public Object run()
      {
         ClassLoader loader = Thread.currentThread().getContextClassLoader();
         return loader;
      }
   }


   private static class UserModeSSLServerSocketFactory extends ServerSocketFactory
   {
      SSLServerSocketFactory serverSocketFactory;

      public UserModeSSLServerSocketFactory(SSLServerSocketFactory serverSocketFactory)
      {
         this.serverSocketFactory = serverSocketFactory;
}

      public ServerSocket createServerSocket() throws IOException
      {
         SSLServerSocket ss = (SSLServerSocket) serverSocketFactory.createServerSocket();
         ss.setUseClientMode(true);
         return ss;
      }

      public ServerSocket createServerSocket(int arg0) throws IOException
      {
         SSLServerSocket ss = (SSLServerSocket) serverSocketFactory.createServerSocket(arg0);
         ss.setUseClientMode(true);
         return ss;
      }

      public ServerSocket createServerSocket(int arg0, int arg1) throws IOException
      {
         SSLServerSocket ss = (SSLServerSocket) serverSocketFactory.createServerSocket(arg0, arg1);
         ss.setUseClientMode(true);
         return ss;
      }

      public ServerSocket createServerSocket(int arg0, int arg1, InetAddress arg2) throws IOException
      {
         SSLServerSocket ss = (SSLServerSocket) serverSocketFactory.createServerSocket(arg0, arg1, arg2);
         ss.setUseClientMode(true);
         return ss;
      }

      public boolean equals(Object obj)
      {
         return serverSocketFactory.equals(obj);
      }

      public String[] getDefaultCipherSuites()
      {
         return serverSocketFactory.getDefaultCipherSuites();
      }

      public String[] getSupportedCipherSuites()
      {
         return serverSocketFactory.getSupportedCipherSuites();
      }

      public int hashCode()
      {
         return serverSocketFactory.hashCode();
      }

      public String toString()
      {
         return serverSocketFactory.toString();
      }
   }
}
TOP

Related Classes of org.jboss.remoting.security.SSLSocketBuilder$UserModeSSLServerSocketFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.