/*
 ************************************************************************
 *
 * Copyright (c) 2003-2004, C&C Research Laboratories, NEC Europe Ltd.
 *
 * Copyright in this software belongs to C&C Research Laboratories,
 * Rathausallee 10, 53757 Sankt Augustin, Germany.
 *
 * This software may not be used, sold, licensed, transferred, copied
 * or reproduced in whole or in part in any manner or form or in or
 * on any media by any person other than in accordance with the terms
 * of the Licence Agreement supplied with the software, or otherwise
 * without the prior written consent of the copyright owners.
 *
 * This software is distributed WITHOUT ANY WARRANTY, without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 * PURPOSE, except where stated in the Licence Agreement supplied with
 * the software.
 *
 *  Created By :           G.A. Kohring
 *  Created for Project :  GEMSS (IST-2001-37153)
 *
 ************************************************************************
 */

package de.nece.ccrle.sandbox;

import java.io.BufferedInputStream;
import java.io.InputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.Policy;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.CRL;
import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;

import eu.gemss.sandbox.Sandbox;

/**
 * A sandbox for constraining the actions of pluggable components.
 *
 *
 * @author Greg Kohring
 */
final public class NECsandbox extends Sandbox {

    private static final String NAME = "NEC CCRLE";
    private static final String VERSION = "$Revision: 1.4 $";
    private SandboxPolicy sandboxPolicy = null;
    private TrustManager trustManager = null;

    private static final String SECURITY_PROVIDER = 
                "org.bouncycastle.jce.provider.BouncyCastleProvider";

    private static Logger logger =
                       Logger.getLogger( NECsandbox.class.getName() );

    /**
     * Create a new sandbox using standard directories for obtaining
     * trust information.
     *
     * @throws IOException if an I/O error occurs while reading the
     *      from the CA certificate directory.
     * @throws GeneralSecurityException if an error occurs while
     *      setting up the sandbox.
     * @throws SecurityException if a security manager is already installed
     *      and its settings prevents the creation of the sandbox.
     */
    public NECsandbox() throws IOException, GeneralSecurityException {
        super( NAME, VERSION );
    }

    /**
     * Initialze the sandbox using the specified directories for obtaining
     * trust information.
     *
     * @param caCerts a <code>String</code> containing the
     *      name of the directory in which CA certificates are stored.
     * @param crlDirName a <code>String</code> containing the name of
     *      directory in which CRLs are stored.
     * @throws IOException if an I/O error occurs while reading the
     *      from the CA certificate directory.
     * @throws GeneralSecurityException if an error occurs while
     *      setting up the sandbox.
     * @throws SecurityException if a security manager is already installed
     *      and its settings prevents the creation of the sandbox.
     */
    public void init( String caCerts, String crlDirName ) 
            throws IOException, GeneralSecurityException {

        KeyStore trustStore = null;
        Collection cas = null;
        Collection crls = null;


        if ( caCerts == null ){
            throw new FileNotFoundException( "caCerts == null!" );
        }

       // Load the CA certs from the ca cert directory

        File cacerts = new File( caCerts );

        if ( cacerts.isDirectory() ) {

            if ( !cacerts.exists() ){
                throw new FileNotFoundException( "directory not found: " + 
                                                cacerts );
            }

            try {
                final CertStoreLDR cdr = new CertStoreLDR( cacerts, "X.509" );
                cas = (Set) AccessController.doPrivileged( 
                        new PrivilegedExceptionAction() {
                            public Object run() throws CertStoreException {
                                return cdr.getTrustAnchors();
                            }
                        }
                    ) ;
            } catch ( PrivilegedActionException pae ){
                logger.severe( pae.getException().getMessage() );
            } catch ( CertificateException ce ){
                throw new GeneralSecurityException ( ce.getMessage() );
            }

            if ( (cas == null) || cas.isEmpty() ){
                throw new GeneralSecurityException( 
                        "No CA certificates found in : " + caCerts );
            }
        } else {
            trustStore = KeyStore.getInstance( "JKS" );
            trustStore.load( new FileInputStream( cacerts ), null );
                
        }

       // Load the CRLs from the crl directory.

        File crlDir = new File( crlDirName );

        if ( !crlDir.exists() ){
            logger.warning( "CRL directory not found: " + crlDirName );
        } else {
            try {
                final CertStoreLDR crlDR = new CertStoreLDR( crlDir, "X.509" );
                crls = (Set) AccessController.doPrivileged( 
                    new PrivilegedExceptionAction() {
                        public Object run() throws CertStoreException {
                            return crlDR.getCRLs();
                        }
                    }
                  ) ;
            } catch ( PrivilegedActionException pae ){
                logger.warning( pae.getException().getMessage() );
            } catch ( CertificateException ce ){
                logger.warning( ce.getMessage() );
            }
        }

        if ( (crls == null) || crls.isEmpty() ){
            logger.warning( "No CRL certificates found in : " + crlDirName );
        }

        // Create the trust manager

        if ( trustStore != null ){
            trustManager = new X509TrustManager( trustStore, crls );
        } else {
            trustManager = new X509TrustManager( cas, crls );
        }

        // Find a security provider

        try{
            Class spClass = Class.forName( SECURITY_PROVIDER );
            Provider securityProvider = (Provider) spClass.newInstance();
            try {
                Security.addProvider( securityProvider );
                trustManager.setSecurityProvider( securityProvider );
            } catch ( SecurityException se ){
                logger.warning( "Cannot add provider " + SECURITY_PROVIDER
                    + "  " + se.getMessage() );
            }
        } catch ( ClassNotFoundException cnfe ){
            logger.warning( cnfe.getMessage() );
        } catch ( InstantiationException ie ){
            logger.warning( ie.getMessage() );
        } catch (  IllegalAccessException iae ){
            logger.warning( iae.getMessage() );
        }


        // Create the sandbox policy

        sandboxPolicy = new SandboxPolicy( trustManager ); 

        // Install the sandbox policy and a security manger to enforce it.

        Policy.setPolicy( sandboxPolicy );

        System.setSecurityManager( new SecurityManager() );
    }

}
