Package org.w3c.jigsaw.https.socket

Source Code of org.w3c.jigsaw.https.socket.SSLSocketClientFactory

/**
* Copyright (c) 2000/2001 Thomas Kopp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
// $Id: SSLSocketClientFactory.java,v 1.8 2004/11/04 16:20:05 ylafon Exp $

package org.w3c.jigsaw.https.socket;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

import java.lang.reflect.Constructor;
/* import java.lang.reflect.InvocationHandler; */
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/* import java.lang.reflect.Proxy; */

import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;

import java.security.InvalidAlgorithmParameterException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableKeyException;

import java.security.cert.CertificateException;

import java.security.spec.InvalidParameterSpecException;

import javax.net.ServerSocketFactory;

import javax.net.ssl.SSLKeyException;
import javax.net.ssl.SSLProtocolException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;

import org.w3c.jigsaw.http.httpd;
import org.w3c.jigsaw.http.socket.SocketClient;
import org.w3c.jigsaw.http.socket.SocketClientFactory;
import org.w3c.jigsaw.http.socket.SocketClientState;

import org.w3c.jigsaw.https.SSLAdapter;

import org.w3c.util.ObservableProperties;

/**
* @author Thomas Kopp, Dialogika GmbH
* @version 1.1, 27 December 2000, 6 February 2004
*
* This class extends a Jigsaw SocketClientFactory designed for the
* http protocol
* in order to supply a SocketClientFactory for the https protocol
* in accordance with the JSSE API.
*
* Three legal tricks are applied for working around if required:
* Proxy classes are used for addressing multiple inheritance and
* non-official api.
* Non-static access via introspection provides for addressing static api.
* The java.lang.Object type is used for mapping non-official types.
*/
public class SSLSocketClientFactory extends SocketClientFactory {
   
    /**
     * The used api-part of javax.net.ssl.KeyManagerFactory.
     * A static interface KeyManagerFactory can be used under a
     * real proxy approach.
     */
    private static final class KeyManagerFactory extends Delegator {
       
        /**
         * Creates the specified pseudo-proxy front end.
         *
         * @param target  the target object in use
         */
        private KeyManagerFactory(Object target) {
            super(target);
        }
       
        /**
         * Supplies the default factory algorithm.
         *
         * @return the default algorithm
         */
        public /* static */ String getDefaultAlgorithm() {
            try {
    return (String)invoke("getDefaultAlgorithm", null, null);
            }
            catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }      
       
        /**
         * Generates a key manager factory.
         *
         * @param algorithm  the name of the factory algorithm
         * @return  a key manager factory instance
         * @throws NoSuchAlgorithmException if the factory algorithm is
   * unavailable
         */
        public /* static */ Object getInstance(String algorithm)
            throws NoSuchAlgorithmException {
            try {
                  return invoke("getInstance",
                                new Class[] {String.class},
                                new Object[] {algorithm});
            }
            catch (NoSuchAlgorithmException ex) {
                  throw ex;
            }
            catch (Exception ex) {
                  RuntimeException rex = new RuntimeException(ex.toString());
                  SSLAdapter.fillInStackTrace(rex, ex);
                  throw rex;
            }
        }

        /**
         * Initializes this factory.
         *
         * @param ks  the underlying keystore
         * @param password  the key access password in use
         * @throws KeyStoreException  if initialization fails
         * @throws NoSuchAlgorithmException  if the specified algorithm
   *         is unavailable
         * @throws UnrecoverableKeyException  if the key in question
   *         cannot be recovered
         */
        public void init(KeyStore ks, char[] password)
            throws KeyStoreException, NoSuchAlgorithmException,
             UnrecoverableKeyException
  {
            try {
    invoke("init",
           new Class[] {KeyStore.class, char[].class},
           new Object[] {ks, password});
            } catch (KeyStoreException ex) {
    throw ex;
            } catch (NoSuchAlgorithmException ex) {
    throw ex;
            } catch (UnrecoverableKeyException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }

        /**
         * Alternatively initializes this factory.
         *
         * @param parameters the manager factory parameters
   *                   (unavailable prior to JDK 1.4)
         * @throws InvalidAlgorithmParameterException  if initialization fails
         */
        public void init(Object parameters)
            throws InvalidAlgorithmParameterException
  {
            try {
    invoke("init",
           new Class[] {Object.class},
           new Object[] {parameters});
            } catch (InvalidAlgorithmParameterException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
       
        /**
         * Supplies the available key managers of this factory.
         *
         * @return  the available key managers
         */
        public Object getKeyManagers() {
            try {
    return invoke("getKeyManagers", null, null);
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
    }
   
   
    /**
     * The used api-part of javax.net.ssl.TrustManagerFactory.
     * A static interface TrustManagerFactory can be used under a
     * real proxy approach.
     */
    private static final class TrustManagerFactory extends Delegator {
 
        /**
         * Creates the specified pseudo-proxy front end.
         *
         * @param target  the target object in use
         */
        private TrustManagerFactory(Object target) {
            super(target);
        }
       
        /**
         * Supplies the default factory algorithm.
         *
         * @return the default algorithm
         */
        public /* static */ String getDefaultAlgorithm() {
            try {
    return (String)invoke("getDefaultAlgorithm", null, null);
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }      
       
        /**
         * Generates a trust manager factory.
         *
         * @param algorithm  the name of the factory algorithm
         * @return  a trust manager factory instance
         * @throws NoSuchAlgorithmException  if the factory algorithm
   *         is unavailable
         */
        public /* static */ Object getInstance(String algorithm)
            throws NoSuchAlgorithmException
  {
            try {
    return invoke("getInstance",
            new Class[] {String.class},
            new Object[] {algorithm});
            } catch (NoSuchAlgorithmException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
 
        /**
         * Initializes this factory.
         *
         * @param ks  the underlying keystore
         * @throws KeyStoreException  if initialization fails
         */
        public void init(KeyStore ks)
            throws KeyStoreException
  {
            try {
    invoke("init",
           new Class[] {KeyStore.class},
           new Object[] {ks});
            } catch (KeyStoreException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }

        /**
         * Alternatively initializes this factory.
         *
         * @param parameters  the manager factory parameters
   *        (unavailable prior to JDK 1.4)
         * @throws InvalidAlgorithmParameterException  if initialization fails
         */
        public void init(Object parameters)
            throws InvalidAlgorithmParameterException
  {
            try {
    invoke("init",
           new Class[] {Object.class},
           new Object[] {parameters});
            } catch (InvalidAlgorithmParameterException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
       
        /**
         * Supplies the available trust managers of this factory.
         *
         * @return  the available truat managers
         */
        public Object getTrustManagers() {
            try {
    return invoke("getTrustManagers", null, null);
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
    }

   
    /**
     * The used api-part of javxx.net.ssl.SSLContext.
     * A static interface SSLContext can be used under a real proxy approach.
     */
    private static final class SSLContext extends Delegator {
       
        /**
         * Creates the specified pseudo-proxy front end.
         *
         * @param target  the target object in use
         */
        private SSLContext(Object target) {
            super(target);
        }
       
        /**
         * Generates an ssl context, which implements the specified
   * secure socket protocol.
         *
         * @param protcol  the name of protocol implementation
         * @return  an ssl context instance
         * @throws NoSuchAlgorithmException if the specified implementation
   *                                  is not available
         */
        public /* static */ Object getInstance(String protocol)
            throws NoSuchAlgorithmException
  {
            try {
    return invoke("getInstance",
            new Class[] {String.class},
            new Object[] {protocol});
            } catch (NoSuchAlgorithmException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }

        /**
         * Initializes this context.
         *
         * @param km  the key manager array used
         * @param tm  the trust manager array used
         * @param random  the secure random used for initializing seed
         * @throws KeyManagementException  if initialization fails
         */
        public void init(Object km, Object tm, SecureRandom random)
            throws KeyManagementException
  {
            try {
    invoke("init",
           new Class[] {Object.class, Object.class,
          SecureRandom.class},
           new Object[] {km, tm, random});
            } catch (KeyManagementException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
       
        /**
         * Supplies an ssl server socket factory.
         *
         * @return  a server socket factory instance.
         */
        public SSLServerSocketFactory getServerSocketFactory() {
            try {
    return (SSLServerSocketFactory)invoke("getServerSocketFactory",
                  null, null);
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
    }
   
   
    /**
     * The generic manager factory paremeters bridge.
     * A static interface ManagerFactoryParametersFactory can be used under
     * a real proxy approach.
     */
    private static final class ManagerFactoryParametersFactory
  extends Delegator
    {
       
        /**
         * Creates the specified pseudo-proxy front end.
         *
         * @param target  the target object in use
         */
        private ManagerFactoryParametersFactory(Object target) {
            super(target);
        }
       
        /**
         * Generates a manager factory parameters instance.
         *
         * @param path  the generic path argument for a parameters instance
         * @param password  the password for a parameters instance
         * @return  a manager factory parameters instance
         * @throws InvalidAlgorithmParameterException  if the specified
   *                                         arguments are not suitable
         * @throws NoSuchMethodException  if the specified method
   *                                         is not available
         */
        public /* static */ Object getInstance(String path, String password)
            throws InvalidAlgorithmParameterException, NoSuchMethodException
  {
            try {
    return invoke("getInstance",
            new Class[] {String.class, String.class},
            new Object[] {path, password});
            } catch (InvalidAlgorithmParameterException ex) {
    throw ex;
            } catch (NoSuchMethodException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
       
        /**
         * Generates a manager factory parameters instance.
         *
         * @param path  the generic path argument for a parameters instance
         * @return  a manager factory parameters instance
         * @throws InvalidAlgorithmParameterException  if the specified
   *         arguments are not suitable
         * @throws NoSuchMethodException  if the specified method is not
   *         available
         */
        public /* static */ Object getInstance(String path)
            throws InvalidAlgorithmParameterException, NoSuchMethodException
  {
            try {
    return invoke("getInstance",
            new Class[] {String.class},
            new Object[] {path});
            } catch (InvalidAlgorithmParameterException ex) {
    throw ex;
            } catch (NoSuchMethodException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
       
        /**
         * Generates a manager factory parameters instance.
         *
         * @return a manager factory parameters instance
         * @throws InvalidAlgorithmParameterException  if the specified
   *         arguments are not suitable
         * @throws NoSuchMethodException  if the specified method is not
   *         available
         */
        public /* static */ Object getInstance()
            throws InvalidAlgorithmParameterException, NoSuchMethodException
  {
            try {
    return invoke("getInstance", null, null);
            } catch (InvalidAlgorithmParameterException ex) {
    throw ex;
            } catch (NoSuchMethodException ex) {
    throw ex;
            } catch (Exception ex) {
    RuntimeException rex = new RuntimeException(ex.toString());
    SSLAdapter.fillInStackTrace(rex, ex);
    throw rex;
            }
        }
    }
   
   
    /**
     * The standard delegation pattern used as a quasi-proxy implementation.
     * Unfortunately, a real proxy requires at least JDK 1.3.
     */
    private static class Delegator /* implements InvocationHandler */ {
       
        /**
         * The facade type in use
         */
        private final Class facade;
    
        /**
         * The delegation target type
         */
        private final Class type;
       
        /**
         * The delegation target object
         */
        private final Object peer;
       
        /**
         * Constructs a delegator instance.
         *
         * @param target  the target object in use
         * @param source  the source interface in use
         */
        public Delegator(Object target, Class source) {
            if (target instanceof Class) {
    // static delegation
    type = (Class)target;
    peer = null;
            } else {
    // object delegation
    type = target.getClass();
    peer = target;
            }
            facade = source;
        }
       
        /**
         * Constructs a delegator instance.
         *
         * @param target  the target object in use
         */
        public Delegator(Object target) {
            this(target, null);
        }
       
        /**
         * Delegates the specified method.
         *
         * @param name  the accessed method name
         * @param deftypes  the method type
         * @param args  the method arguments
         * @return  the method invocation result
         * @throws Throwable  if the invocation fails
         */
        /*
    public Object invoke(String method, Class[] types, Object[] args)
                   throws Throwable {
                String name = method.getName();
                Class[] deftypes = method.getParameterTypes();
            ...
        */
        public Object invoke(String name, Class[] deftypes, Object[] args)
      throws Exception
  {
            int count = ((args != null) ? args.length : 0);
            Class[] types = new Class[count];
            Object[] param = new Object[count];
            for (int i = 0; i < count; i++) {
                Object arg = args[i];
                // a delegator proxy being aware of its own, hence
                // supplying its target object and interface
                // type if applicable
                Class art = null;
                if (null != arg) {
        art = arg.getClass();
        /*
                   if (Proxy.isProxyClass(art)) {
                     InvocationHandler handler=Proxy.getInvocationHandler(arg);
                      if (Delegator.class == handler.getClass()) {
                         // supply the underlying peer instance
                         arg = ((Delegator)handler).peer;     
                         // supply the wrapped interface type
                         Class[] cls = art.getInterfaces();
                         if ((null != cls)&&(cls.length == 1)) {
                            art = cls[0];
                         }
                      }
                   }
        */
        if (arg instanceof Delegator) {
      Delegator ref = (Delegator)arg;
      arg = ref.peer;
      if (null != ref.facade) {
          art = ref.facade;
      }
        }
                }
   
                // runtime types overwrite interface types
                types[i] = ((null != art) ? art :
                            ((null != deftypes)&&(i < deftypes.length) ?
                             deftypes[i] : Object.class));
                param[i] = arg;
            }
            Method m = type.getMethod(name, types);
            return m.invoke(peer, param);
        }
 
        /**
         * Supplies a proxy for this delegator.
         *
         * @param source  the interface in use
         * @return  an delegation proxy instance
         */
        /*
           public Object getProxy(Class source) {
              return Proxy.newProxyInstance(source.getClassLoader(),
                                             new Class[] { source }, this);
            }
         */
    }
   
    /**
     * The client authentication support level indicator
     * (for JSSE backward compatibility),
     * which also indicates the api level in question.
     */
    private static final boolean supportsOptionalClientAuth;
   
    /**
     * The implementation nmespace depending on the api level in question.
     */
    private static final String implementationNamespace;
   
    static {
        boolean supported = false;
        try {
            Class c = javax.net.ssl.SSLServerSocket.class;
            Class cp[] = { java.lang.Boolean.TYPE };
            Method ic = null;
            supported = (null != c.getMethod("setWantClientAuth", cp));
        } catch (Exception ex) {
            supported = false;
        } finally {
            supportsOptionalClientAuth = supported;
            implementationNamespace = (supported ?
                                       "javax.net.ssl." :
                                       "com.sun.net.ssl.");
        }
    }
   

    /**
     * The property key for the system protocol package lookup
     */
    public static final String PROTOCOL_HANDLER_S="java.protocol.handler.pkgs";
   
    /**
     * static flag for enabling debug output if applicable
     */
    private static boolean debug = false;
   
    /**
     * The context used for creating a server socket factory
     */
    private SSLContext context = null;
   
    /**
     * The daemon of this factory
     */
    private httpd daemon = null;
   
    /**
     * The daemon bind address for this factory
     */
    private InetAddress bindAddr = null;

    /**
     * The daemon bind address for this factory
     */
    private int maxClients = 0;

    /**
     * factory method for creating a secure server socket
     * @return a new server socket instance
     * @throws java.io.IOException due to socket creation problems
     */
    public ServerSocket createServerSocket()
  throws IOException
    {
  int port = daemon.getPort();
  int clients = Math.max(128, maxClients);
  ServerSocket serversocket = null;
  if (bindAddr == null) {
      serversocket = getFactory().createServerSocket(port, clients);
  } else {
      serversocket = getFactory().createServerSocket(port, clients,
                 bindAddr);
  }
  // tk, 1 February 2004,
  // added optional client authentication,
  // which is forced, if a truststore is configured and
  // the org.w3c.jigsaw.ssl.authenticate is not set to false
  if (serversocket instanceof SSLServerSocket) {
      ObservableProperties props = daemon.getProperties();
       
        // decide client authentication based on trust configuration
      boolean mandatory;
      mandatory = props.getBoolean(SSLProperties.MUST_AUTHENTICATE_P,
           false);
      boolean generic;
      generic = props.getBoolean(SSLProperties.TRUSTSTORE_GENERIC_P,
               false);
      String trust;
      trust = props.getString(SSLProperties.TRUSTSTORE_PATH_P,
            null);
     
      boolean authenticate = mandatory||generic||
                       ((null != trust)&&(trust.length() > 0));
     
      if (authenticate) {
    SSLServerSocket sslsocket = (SSLServerSocket)serversocket;
    if (mandatory) {
        sslsocket.setNeedClientAuth(true);
    } else {
        if (supportsOptionalClientAuth) {
      sslsocket.setWantClientAuth(true);
        } else {
      throw new SSLProtocolException("Optional client "+
              "authentication not supported by the"+
              " current api level. Consider upgrading"+
              " your api or using obligatory client"+
              " authentication or using server "+
              "authentication only");
        }
    }
      }
  }
  return serversocket;
    }

    /**
     * Adds a security provider.
     *
     * @param provider  the provider class name in question
     * @throws java.lang.ClassNotFoundException  if the provider is unavailable
     * @throws java.lang.IllegalAccessException  if the provider has no
     *         accessible default constructor
     * @throws java.lang.InstantiationException  if the provider cannot be
     *         instantiated
     */
    private static final void addProvider(String provider)
        throws ClassNotFoundException, IllegalAccessException,
         InstantiationException
    {
        if (null != provider) {
      if (null == Security.getProvider(provider)) {
    Class support = Class.forName(provider);
    Provider supplier = (Provider)support.newInstance();
    Security.addProvider(supplier);
    if (debug) {
        System.out.println("Added new security provider: " +
               supplier.getInfo() + ".");
    }
      }
        }
    }

    /**
     * Sets the protocol handler.
     *
     * @param handler  the handler class name in question
     */
    private static final void setHandler(String handler) {
        if (null != handler) {
      System.setProperty(PROTOCOL_HANDLER_S, handler);
      if (debug) {
    System.out.println("Set new protocol handler: "+handler+".");
      }
        }
    }
   
    /**
     * Loads a key store for read access.
     *
     * @param props  the underlying property set
     * @param typekey  the store type property key
     * @param pathkey  the keystore path property key
     * @param passkey  the password property key
     * @return  the loaded keystore
     * @throws KeyStoreException  if initialization fails
     * @throws java.io.IOException  if keystore cannot be loaded
     * @throws NoSuchAlgorithmException  if the integrity check is inavailable
     * @throws CertificateException  if the a certificate is inaccessible
     */
    private static final KeyStore getStore(ObservableProperties props,
                                           String typekey, String pathkey,
             String passkey)
        throws KeyStoreException, IOException, NoSuchAlgorithmException,
         CertificateException
    {
        String storepath = props.getString(pathkey, null);
        if (null != storepath) {
            if ("".equals(storepath.trim())) storepath = null;
        }
  String storepass = props.getString(passkey, null);
        if ((null != storepath)||(null != storepass)) {
      String storetype = props.getString(typekey,
                 KeyStore.getDefaultType());
      KeyStore store = KeyStore.getInstance(storetype);
     
      store.load((null != storepath) ?
           new BufferedInputStream(new FileInputStream(storepath)):
           null,
      (null != storepass) ? storepass.toCharArray() : new char[0]);
      return store;
        } else {
      return null;
  }
    }
   
    /**
     * Instantiates a manager factory parameters object.
     *
     * @param props  the underlying property set
     * @param typekey  the store type property key
     * @param pathkey  the keystore path property key
     * @param passkey  the password property key
     * @return the specified manager factory parameters instance
     * @throws InvalidParameterSpecException  if api support is not sufficient
     * @throws InvalidAlgorithmParameterException  if generic initialization
     *         fails
     * @throws ClassNotFoundException  if the provider is unavailable
     */
    private static final Object getParams(ObservableProperties props,
                                          String typekey, String pathkey,
            String passkey)
        throws InvalidParameterSpecException,
         InvalidAlgorithmParameterException,
         ClassNotFoundException
    {
        if (supportsOptionalClientAuth) {
      String paratype = props.getString(typekey, null);
      if ((null != paratype)&&(paratype.length() > 0)) {
    Class parameterFactory = Class.forName(paratype);
    String path = props.getString(pathkey, null);
    String pass = props.getString(passkey, null);

    ManagerFactoryParametersFactory mfpboot;
    mfpboot =new ManagerFactoryParametersFactory(parameterFactory);
    Object mfpload = null;
    try {
                    mfpload = mfpboot.getInstance(path, pass);
    } catch (NoSuchMethodException ex) {
                    try {
      mfpload = mfpboot.getInstance(path);
                    } catch (NoSuchMethodException sub) {
      try {
          mfpload = mfpboot.getInstance();
      } catch (NoSuchMethodException next) {
          throw new InvalidAlgorithmParameterException(
        "Factory specified by type property has no "+
        "suitable instantiation method");
      }
                    }
    }
             
    Class managerFactoryParameters =
        Class.forName(implementationNamespace +
                           "ManagerFactoryParameters");
    if (managerFactoryParameters.isInstance(mfpload)) {
        return new Delegator(mfpload, managerFactoryParameters);
    } else {
        throw new InvalidAlgorithmParameterException(
      "Factory specified by type property does not "+
      "supply manager factory parameters");
    }
      } else {
    throw new InvalidAlgorithmParameterException("No manager "+
         "factory parameter class specified as the type property");
      }
        } else {
      throw new InvalidParameterSpecException("Generic manager "+
    "factory parameters not supported by the current api level. " +
    "Consider upgrading your api or using a classic keystore");
  }
    }

    /**
     * Creates an ssl context.
     *
     * @param props  the underlying property set
     * @return  the ssl context used for the socket factory
     * @throws ClassNotFoundException  if the provider is unavailable
     * @throws KeyStoreException  if keystore initialization fails
     * @throws IOException  if keystore cannot be loaded
     * @throws NoSuchAlgorithmException  if the integrity check is unavailable
     * @throws InvalidParameterSpecException  if api support is not sufficient
     * @throws InvalidAlgorithmParameterException  if generic initialization
     *         fails
     * @throws CertificateException  if the a certificate is inaccessible
     * @throws UnrecoverableKeyException  if the key in question cannot
     *         be recovered
     * @throws InstantiationException  if the specified factory is abstract
     * @throws IllegalAccessException  if factory constructor is unreachable
     * @throws InvocationTargetException  if factory initialization fails
     * @throws KeyManagementException  if initialization fails
     */
    private static final SSLContext createContext(ObservableProperties props)
        throws ClassNotFoundException, KeyStoreException, IOException,
               NoSuchAlgorithmException, InvalidParameterSpecException,
               InvalidAlgorithmParameterException, CertificateException,
               UnrecoverableKeyException, InstantiationException,
               IllegalAccessException, InvocationTargetException,
               KeyManagementException
    {
 
  // switch according to api-level
  Class keyManagerFactory   = Class.forName(implementationNamespace +
              "KeyManagerFactory");
  Class trustManagerFactory = Class.forName(implementationNamespace +
              "TrustManagerFactory");
  Class sslContext          = Class.forName(implementationNamespace +
              "SSLContext");
 
              // the ugly but legal key manager factory bootstrap
  KeyManagerFactory kmfboot = new KeyManagerFactory(keyManagerFactory);
  String kmftype = props.getString(SSLProperties.KEYMANAGER_TYPE_P,null);
  Object kmfload = kmfboot.getInstance((null != kmftype) ?
               kmftype :
               kmfboot.getDefaultAlgorithm());
  KeyManagerFactory kmf = new KeyManagerFactory(kmfload);
 
  boolean kgen = props.getBoolean(SSLProperties.KEYSTORE_GENERIC_P,
               SSLProperties.DEFAULT_KEYSTORE_GENERIC);
  if (kgen) {
      // generic key material instantiation (not prior to before JDK 1.4)
      Object kmfp = getParams(props,
            SSLProperties.TRUSTSTORE_TYPE_P,
            SSLProperties.TRUSTSTORE_PATH_P,
            SSLProperties.TRUSTSTORE_PASSWORD_P);
     
      kmf.init(kmfp);
  } else {
      KeyStore ks = getStore(props,
           SSLProperties.KEYSTORE_TYPE_P,
           SSLProperties.KEYSTORE_PATH_P,
           SSLProperties.KEYSTORE_PASSWORD_P);
     
      // reusing the store password for key access
      String keypass = props.getString(SSLProperties.KEYSTORE_PASSWORD_P,
               null);
     
      kmf.init(ks, (null != keypass ? keypass.toCharArray() :
                          new char[0]));
  }
 
  // the ugly but legal trust manager factory bootstrap
  TrustManagerFactory tmfboot;
  tmfboot = new TrustManagerFactory(trustManagerFactory);
  String tmftype = props.getString(SSLProperties.TRUSTMANAGER_TYPE_P,
           null);
  Object tmfload = tmfboot.getInstance((null != tmftype) ? tmftype :
                  tmfboot.getDefaultAlgorithm());
  TrustManagerFactory tmf = new TrustManagerFactory(tmfload);
 
  boolean tgen = props.getBoolean(SSLProperties.TRUSTSTORE_GENERIC_P,
             SSLProperties.DEFAULT_TRUSTSTORE_GENERIC);
  if (tgen) {
      // generic trust material instantiation (not < JDK 1.4)
      Object tmfp = getParams(props,
            SSLProperties.TRUSTSTORE_TYPE_P,
            SSLProperties.TRUSTSTORE_PATH_P,
            SSLProperties.TRUSTSTORE_PASSWORD_P);
      tmf.init(tmfp);
  } else {
      KeyStore ts = getStore(props,
           SSLProperties.TRUSTSTORE_TYPE_P,
           SSLProperties.TRUSTSTORE_PATH_P,
           SSLProperties.TRUSTSTORE_PASSWORD_P);
      tmf.init(ts);
  }
 
  // accessing the protocol type
  String protocol = props.getString(SSLProperties.PROTOCOL_NAME_P,
            SSLProperties.DEFAULT_PROTOCOL_NAME);
 
  // the ugly but legal ssl context bootstrap
  SSLContext ctxboot = new SSLContext(sslContext);
  Object ctxload = ctxboot.getInstance(protocol);
  SSLContext context = new SSLContext(ctxload);
  context.init(kmf.getKeyManagers(), tmf.getTrustManagers(),
         new SecureRandom());
  return context;
    }
   
    /**
     * method for intializing this factory
     * @param server the daemon of this factory
     */
    public void initialize(httpd server) {
        super.initialize(server);
        daemon = server;
        daemon.registerPropertySet(new SSLProperties(daemon));
        ObservableProperties props = daemon.getProperties();
 
        try {
           
      // Providers or protocols are switched by default
      // in a compatible way as postulated by the JDK 1.4 policies
      String provider;
      provider = props.getString(SSLProperties.SECURITY_PROVIDER_P,
               (supportsOptionalClientAuth ? null :
             SSLProperties.DEFAULT_SECURITY_PROVIDER));
      addProvider(provider);
     
      String handler = props.getString(SSLProperties.PROTOCOL_HANDLER_P,
            (supportsOptionalClientAuth ? null :
              SSLProperties.DEFAULT_PROTOCOL_HANDLER));
      setHandler(handler);
     
      context = createContext(props);
     
      String bindAddrName = props.getString(BINDADDR_P, null);
      if (bindAddrName != null) {
    try {
        bindAddr = InetAddress.getByName(bindAddrName);
    } catch (Exception ex) {
        bindAddr = null;
    }
      } else {
    bindAddr = null;
      }
     
      maxClients = props.getInteger(MAXCLIENTS_P, MAXCLIENTS);
     
        } catch (Exception ex) {
      String mes;
      mes = "Unable to initialize secure socket provider";
      daemon.fatal(ex, mes);
      if (debug) {
    System.err.println(mes);
    ex.printStackTrace();
      }
      RuntimeException rex;
      rex = new RuntimeException(mes);
      SSLAdapter.fillInStackTrace(rex, ex);
      throw rex;
        }
    }

    /**
     * method for handling a dynamic property modification
     * @param name the name of the property modified
     * @return true if and only if the modification has been handled
     * successfully
     */
    public boolean propertyChanged(String name) {
        if (super.propertyChanged(name)) {
      ObservableProperties props = daemon.getProperties();
     
      try {
    if (name.equals(MAXCLIENTS_P)) {
                    int newmax = props.getInteger(MAXCLIENTS_P, -1);
                    if (newmax > maxClients) {
      for (int i = maxClients-newmax; --i >= 0; ) {
          addClient(true);
      }
                    } else if (newmax > 0) {
      maxClients = newmax;
                    }
                    return true;
    } else if (name.equals(BINDADDR_P)) {
        bindAddr = InetAddress.getByName(
      props.getString(BINDADDR_P, null));
        return true;
    } else if ((name.equals(SSLProperties.KEYSTORE_GENERIC_P)) ||
         (name.equals(SSLProperties.KEYSTORE_PATH_P)) ||
         (name.equals(SSLProperties.KEYSTORE_TYPE_P)) ||
         (name.equals(SSLProperties.KEYSTORE_PASSWORD_P)) ||
         (name.equals(SSLProperties.TRUSTSTORE_GENERIC_P)) ||
         (name.equals(SSLProperties.TRUSTSTORE_PATH_P)) ||
         (name.equals(SSLProperties.TRUSTSTORE_TYPE_P)) ||
         (name.equals(SSLProperties.TRUSTSTORE_PASSWORD_P))||
         (name.equals(SSLProperties.PROTOCOL_NAME_P))) {
       
        context = createContext(props);
        return true;
    } else {
        return true;
    }
      } catch (Exception ex) {
    String mes;
    mes = "Unable to re-initialize secure socket provider";
    daemon.fatal(ex, mes);
    if (debug) {
                    System.err.println(mes);
                    ex.printStackTrace();
    }
    // RuntimeException rex;
    // rex = new RuntimeException(sub);
    // SSLAdapter.fillInStackTrace(rex, cause);
    // throw rex;
    return false;
      }
        } else {
      return false;
  }
    }
   
    /**
     * server sockt factory creation
     * @return the secure server socket factory
     * @throws java.io.IOException due to factory creation problems
     */
    private ServerSocketFactory getFactory()
  throws SSLKeyException
    {
        ServerSocketFactory factory;
        factory = ((null != context) ?
                   context.getServerSocketFactory() :
                   // make best effort to obtain a factory
                   SSLServerSocketFactory.getDefault());
 
        String[] supported =
            ((SSLServerSocketFactory)factory).getSupportedCipherSuites();
        if (debug) {
      System.out.println("Supported suites:");
      for (int i = 0; i < supported.length; i++) {
    System.out.println("          " + supported[i]);
      }
      String[] enabled =
    ((SSLServerSocketFactory)factory).getDefaultCipherSuites();
      System.out.println("Enabled suites:");
      for (int i = 0; i < enabled.length; i++) {
    System.out.println("         " + enabled[i]);
      }
        }
 
        if (supported.length < 1) {
            SSLKeyException ex = new SSLKeyException(
    "No cipher suites supported by this "
    + "SSL socket factory. "
    + "Please check your factory, key store, "
    + "store password and cerificates");
      daemon.fatal(ex, ex.getMessage());
      if (debug) {
    ex.printStackTrace();
      }
      throw ex;
        }
        return factory;
    }

    /**
     * Factory for creating a new client for this pool.
     * @param server  the target http daemon
     * @param state  the client state holder
     * @return a new socket client
     */
    protected SocketClient createClient(httpd server,
          SocketClientState state) {
        return new SSLSocketClient(server, this, state);
    }
}
TOP

Related Classes of org.w3c.jigsaw.https.socket.SSLSocketClientFactory

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.