
/*
 *        Written for JacORB - a free Java ORB
 *
 *   Copyright (C) 2000 Gerald Brose
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library 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
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public
 *   License along with this library; if not, write to the Free
 *   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package jacorb.security.ssl;

/**
 * @author Andr'e Benvenuti, Gerald Brose.
 * @version $Id: SSLSocketFactory.java,v 1.10 2000/09/15 14:42:48 brose Exp $
 * 
 * We follow the design of socket factories in package javax.net 
 * and javax.net.ssl.* Because this package doesn't exist in the JDK yet we 
 * don't extend its classes, but we are fully compatible.
 *
 * The basic idea is to provide one extra constructor that sets up
 * a default SSL configuration that is implicitly used by all other 
 * constructors. The default SSL credentials can also be changed by
 * calling setDefaultSSLContext().
 * 
 * After creating a new SSL socket, this factory swaps roles for
 * the SSL handshake, i.e. any client socket created takes the
 * server role in the handshake, so the actual server need not
 * authenticate.
 */

import jacorb.security.level2.*;
import jacorb.security.util.*;
import jacorb.util.*;
import iaik.security.ssl.SSLSocket;

public class SSLSocketFactory 
    implements jacorb.orb.factory.SocketFactory 
{
    private iaik.security.ssl.SSLServerContext defaultContext;
    private iaik.security.ssl.CipherSuite[] cs;

    private CurrentImpl securityCurrent = null;

    public SSLSocketFactory( jacorb.orb.ORB orb ) 
    {
	cs = SSLSetup.getCipherSuites();

        try
        {
            securityCurrent = (CurrentImpl)
                orb.resolve_initial_references("SecurityCurrent");
        }
        catch ( org.omg.CORBA.ORBPackage.InvalidName in )
        {}
    }


    /** 
     * @returns a socket connected to a ServerSocket on the named host, 
     * at the given port. This socket is configured using the socket 
     * options established for this factory. This constructor also sets
     * the default SSL context data to be used in other socket creation
     * operations.
     * 
     * Parameters:
     * 	host - the server host
     * 	port - the server port
     *  chain - a chain of X509 certificates to be used in SSL connection setup
     *  key - the private key for the first cert in the chain.
     *
     * @throws:
     * 	java.io.IOException - if the connection can't be established
     * 	java.net.UnknownHostException - if the host is not known
     */

    public java.net.Socket createSocket( String host, 
                                         int port )
	throws java.io.IOException, java.net.UnknownHostException
    {       
        setDefaultContext();

        SSLSocket sock = new SSLSocket( host, port, defaultContext );

        sock.setUseClientMode( false );	

        return sock;
    }

    private void setDefaultContext()
    {
        defaultContext = new iaik.security.ssl.SSLServerContext();

        KeyAndCert[] kac = securityCurrent.getSSLCredentials();

        for( int i = 0; i < kac.length; i++ )
        {
            defaultContext.addServerCredentials( kac[i].chain,  kac[i].key );
        }

        if( ( (byte)Environment.requiredBySSL() & 0x20) != 0  ) 
            // 32 = Establish trust in target
        {

            defaultContext.setRequestClientCertificate(true);
            String [] trusteeFileNames = 
                Environment.getPropertyValueList("jacorb.security.trustees");
            
            for( int i = 0; i < trusteeFileNames.length; i++ )
            {
                defaultContext.addTrustedCertificate( CertUtils.readCertificate( trusteeFileNames[i] ));
            }
        }

        //defaultContext.setDebugStream( System.out );
    }
    
    /**
     * Returns the list of cipher suites which are enabled by 
     * default. Unless a different list is enabled, handshaking 
     * on an SSL connection will use one of these cipher suites. 
     * The minimum quality of service for these defaults requires 
     * confidentiality protection and server authentication.
     *
     * @returns:
     *	array of the cipher suites enabled by default
     */

    public java.lang.String[] getDefaultCipherSuites()
    {
	java.lang.String lst [] = new java.lang.String[ cs.length ];
	for ( int i = 0; i < lst.length; i++ )
	    lst [ i ] = cs[ i ].toString ();
	return lst;
    }

    /**
     * Returns the names of the cipher suites which could be enabled 
     * for use on an SSL connection.
     * Normally, only a subset of these will actually be enabled by 
     * default, since this list may include
     * cipher suites which do not meet quality of service 
     * requirements for those defaults.
     * Such cipher suites are useful in specialized applications.
     *
     * @returns:
     * 	an array of cipher suite names
     */
    public java.lang.String[] getSupportedCipherSuites()
    {
	iaik.security.ssl.CipherSuite [] suites = iaik.security.ssl.CipherSuite.getDefault ();
	java.lang.String lst [] = new java.lang.String[ suites.length ];
	for ( int i = 0; i < lst.length; i++ )
	    lst [ i ] = suites[ i ].toString ();
	return lst;
    }

    public boolean isSSL ( java.net.Socket s )
    { 
        return ( s instanceof iaik.security.ssl.SSLSocket); 
    }
}
