//
// CertificateManager.java
//
// The contents of this file are subject to the SNIA Public License Version 1.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.snia.org/resources/openSource.html
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
// License for the specific language governing rights and limitations
// under the License.
//
// The Original Code is CertificateManager.java
//
// The Initial Developer of the Original Code is Bapu Patil.
//
// Contributor(s):
//
//
//
// Revision 1.1  2002/05/15 09:36:59 bpatil 
// Initial revision
//

package org.snia.wbemcmd.xml;

import java.util.Enumeration;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import java.security.SecureRandom;
import java.security.KeyStore;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.TrustManagerFactory;

/**
 * CertificateManager implements the X509TrustManager interface. CertficateManager
 * trusts known certificate chains, and queries the user to approve unknown
 * chains. 
 */

public class CertificateManager implements X509TrustManager
{

        X509TrustManager  myX509TrustManager;
        private KeyStore keyStore;

        /**
         * CertficateManager constructor 
         */
        public CertificateManager() 
        { 
            try 
            {
               TrustManagerFactory tmf =
                    TrustManagerFactory.getInstance("SunX509", "SunJSSE");
               TrustManager[] tm = tmf.getTrustManagers();
               myX509TrustManager = (X509TrustManager)tm[0];
            }
            catch ( java.security.NoSuchAlgorithmException nsa ) { }
            catch ( java.security.NoSuchProviderException nsp ) { }

           // TODO: bpatil
           // Can I just call super()..may be. I will check later
           // for now the above stuff works
           // super();  
        }

        /**
         * checkClientTrusted checks to see if the chain is in the keyStore object.
         * This is done with a call to checkChainTrusted.
         */
        public boolean isClientTrusted(X509Certificate[] chain)
        {
            return isCertificateChainTrusted(chain);
        }

        /**
         * isServerTrusted verifies to see if the chain is in the keyStore object.
         * This is done with a call to isCertificateChainTrusted. If not it queries the
         * user to see if the chain should be trusted.
         */
        public boolean isServerTrusted(X509Certificate[] chain)
        {
            boolean trusted = false;

            try
            {
		//
                // find out if the chain is in the keyStore object.
		// If it is  trusted, we can just accept if we want to
		//
                trusted = isCertificateChainTrusted(chain);

                System.out.println("Certificate chain is:");
                for (int i = 0; i < chain.length; i++)
                {
                        // display certificate chain information
                        System.out.println("Certificate chain[" + i + "]:");
                        System.out.println("Subject: "
                                         + chain[i].getSubjectDN().toString());
                        System.out.println("Issuer: "
                                         + chain[i].getIssuerDN().toString());
                }

                //
                // Ask the user if the certificate should be trusted.
                //
                System.out.print("Would you like to Trust this certificate and"
                                   + " (y or n) ");
                int readStatus = System.in.read();
                if(readStatus == 'y'|| readStatus == 'Y')
                {
                     // Trust the chain.
                     trusted = true;
                     System.out.println("I iill Accept it that case.");
                }
                else
                {  
                     trusted = false;
                     System.out.println("I will reject this one.");
                }
            }
            catch( Exception e )
            {
                System.err.println( "isServerTrusted Error: " + e.toString() );
                trusted = false;
            }
            return trusted;
        }

        /**
         * getAcceptedIssuers retrieves all of the certificates in the keyStore
         * and returns them in an X509Certificate array.
         */
        public X509Certificate[] getAcceptedIssuers()
        {
            return myX509TrustManager.getAcceptedIssuers();
        }

        /**
         isCertificateChainTrusted searches the keyStore for certificates in the
         certificate chain.
        */
        private boolean isCertificateChainTrusted(X509Certificate[] chain)
        {
            boolean trusted = false;
            try
            {
                // Start with the root and see if it is in the Keystore.
                // The root is at the end of the chain.
                for (int i = chain.length - 1; i >= 0; i-- )
                {
                    if (keyStore.getCertificateAlias(chain[i]) != null)
                    {
                        trusted = true;
                        break;
                    }
                }
            }
            catch( Exception e )
            {
                System.err.println( "checkChainTrusted Exception: "
                                 + e.toString() );
                trusted = false;
            }
            return trusted;
        }
       
       public void checkClientTrusted(X509Certificate[] chain,
                               String authType)
                        throws CertificateException  
       { 
            boolean istrusted = this.isClientTrusted(chain);
            if ( istrusted != true )
               throw new CertificateException("Invalid certificate");
       }


       public void checkServerTrusted(X509Certificate[] chain,
                               String authType)
                        throws CertificateException  
       { 
            boolean istrusted = this.isServerTrusted(chain);
            if ( istrusted != true )
               throw new CertificateException("Invalid certificate");
       }
  
}
