Package org.jwall.security.cert

Source Code of org.jwall.security.cert.CustomTrustManager

package org.jwall.security.cert;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.net.URL;
import java.security.KeyStore;
import java.security.Principal;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.logging.Logger;

import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.security.auth.x500.X500Principal;
import javax.swing.JOptionPane;

import org.jwall.security.cert.ui.CertificateValidationDialog;



/**
* <p>
* This class implements a customizable trust manager for use within jwall.org applications.
* It basically loads trusted certificates from a keystore denoted by the system properties
* <div>
* <pre>
*    org.jwall.security.cert.keystore.file
*    org.jwall.security.cert.keystore.type
* </pre>
* </div>
* Per default (if these properties are not set) it searches for a keystore of type JKS at
* <code>/org/jwall/security/cert/keystore</code>.
* </p>
*
* @author Christian Bockermann &lt;chris@jwall.org&gt;
*
*/
public class CustomTrustManager
implements X509TrustManager, TrustManager
{

    /** A unique logger for this class */
    private static Logger log = Logger.getLogger( "ZeroTrustManager" );

    /** The system property for disabling validation */
    public final static String PROPERTY_TRUST_ALL = "org.jwall.security.certs.trust-all";

    /** A system property for enabling/disabling user validation on unknown certificates */
    public final static String PROPERTY_USER_VALIDATION = "org.jwall.security.certs.user-validation";


    /** The singleton object of this class */
    private static CustomTrustManager trustManager;


    /** This is the list of accepted certs by this trust manager */
    private KeyStore keystore;
   
    /** The passphrase for the key store */
    private char[] passphrase = "secret".toCharArray();

    /** This flag can be used to disable certificate validation and trust everything */
    private boolean trustAll = false;

    /** A flag indicating whether the user is asked for approval on unknown certificates */
    private boolean userValidation = true;


    /**
     * We usually allow only for one custom jwall trust manager to be available at a time.
     * This singleton ensures no other manager of this class can be instantiated.
     *
     * @return The global trust manager.
     */
    public synchronized static CustomTrustManager getInstance(){

        if( trustManager == null )
            trustManager = new CustomTrustManager();

        return trustManager;
    }


    /**
     *
     * This constructor initializes the trust manager by loading the key store and
     * looking for additional system properties.
     *
     */
    private CustomTrustManager(){

        String keystoreFile = System.getProperty("user.home") + "/.jwall/keystore";

        File f = new File( keystoreFile );
       
        try {
            log.info("Using default keystore...");
            keystoreFile = "/org/jwall/security/cert/keystore";

            char[] passphrase = "secret".toCharArray();

            keystore = KeyStore.getInstance( "JKS" );
            keystore.load( new FileInputStream( f ), passphrase );

        } catch (Exception e){
            e.printStackTrace();
            keystore = null;
        }


        if( keystore == null ){
            log.info( "Trying to load default keystore... " );

           
            try {

                URL url = CustomTrustManager.class.getResource( keystoreFile );
                log.info( "  loading from " + url );
               
                char[] passphrase = "secret".toCharArray();
                keystore = KeyStore.getInstance("JKS");
                if( url != null )
                    keystore.load( url.openStream(), passphrase);


                // now create a new user-specific key store by copying the default store in place
                //
                if( f.getParentFile() != null && !f.getParentFile().isDirectory() )
                    f.getParentFile().mkdirs();
               
                keystore.store( new FileOutputStream( f ), passphrase );
               
            } catch (Exception e) {
                e.printStackTrace();

                log.info( "Creating an empty keystore..." );
               
                try {
                    keystore = KeyStore.getInstance( KeyStore.getDefaultType() );
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            }
        }

        // check if trust-checking is disabled, i.e. we trust all certificates, defaults to "false"
        //
        if( System.getProperty( PROPERTY_TRUST_ALL ) != null ){
            trustAll = "true".equalsIgnoreCase( System.getProperty( PROPERTY_TRUST_ALL ) );
        } else
            trustAll = false;

        // check if user-validation is wanted, defaults to "true"
        //
        if( System.getProperty( PROPERTY_USER_VALIDATION ) != null )
            userValidation = "true".equalsIgnoreCase( System.getProperty( PROPERTY_USER_VALIDATION ) );
        else
            userValidation = true;
    }



    /**
     * @see javax.net.ssl.X509TrustManager#checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String)
     */
    public void checkClientTrusted(X509Certificate[] chain, String authType)
    throws CertificateException {

        log.fine( "checkClientTrusted: \n");

        for( X509Certificate cert : chain ){
            log.fine("-------------------------------------------------------");
            log.fine( " SubjectDN = "+cert.getSubjectDN() );
            log.fine( " Issuer = " + cert.getIssuerDN() );
        }   

        checkServerTrusted( chain, authType );
    }


    /**
     * @see javax.net.ssl.X509TrustManager#checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String)
     */
    public void checkServerTrusted(X509Certificate[] chain, String authType)
    throws CertificateException {

        log.fine( "checkServerTrusted: \n");
        for( X509Certificate cert : chain ){
            log.fine("-------------------------------------------------------");
            log.fine( " SubjectDN = "+cert.getSubjectDN() );
            log.fine( " Issuer = " + cert.getIssuerDN() );
        }   


        if( trustAll )
            return;

        boolean[] verified = new boolean[chain.length];
        boolean allTrusted = true;

        // verify all certificates by checking for validity and looking up their issuer certificates within the key store
        //
        for( int i = 0; i < chain.length; i++ ){
            verified[i] = isIssuerTrusted( chain[i] );
            allTrusted = allTrusted && verified[i];
        }


        // if one certificate cannot be verified we either directly throw an error or as for user approval
        //
        if( allTrusted )
            return;

        if( userValidation ){

            if( requestUserApproval( chain, authType ) ) {
                return;
            } else
                throw new CertificateException( "Untrusted issuer, user-approval not given!" );

        } else
            throw new CertificateException( "Untrusted/unknown issuer, user-approval disabled!" );
    }


    /**
     *
     * This method opens up a validation dialog presenting the certificate chain to the user
     * and requesting manual approval.
     *
     * @param chain The certificate chain that is to be approved.
     * @param authType The authType requested for this chain.
     * @return <code>true</code>, if the user approved the certificate chain.
     */
    public boolean requestUserApproval( X509Certificate[] chain, String authType ){

        CertificateValidationDialog validator = new CertificateValidationDialog( chain );
        validator.setVisible( true );

        boolean approved = validator.isChainApproved();

        if( approved && validator.isApprovedPermanently() ){
           
            X509Certificate cert = chain[ chain.length - 1 ];
           
            try {
                StringBuffer alias = new StringBuffer();
               
                Principal subject = cert.getSubjectDN();
                log.info("Subject = " + subject);
               
                if( subject != null )
                    log.info( "  Subject.getName(): " + subject.getName() );
               
                X500Principal x500 = cert.getSubjectX500Principal();
                log.info( "x500 = " + x500 );
               
               
                if( x500 != null ){
                   
                    String[] tok = x500.toString().split(",");
                    int i = 0;
                   
                    alias.append( cert.getSerialNumber() );
                   
                    while( keystore.getCertificate( alias.toString() ) != null && i < tok.length ) {
                
                        log.info("Adding another attribute for uniqueness to current alias " + alias.toString() );
                       
                        if( alias.length() > 0 )
                            alias.append( "," );
                       
                        String[] kv = tok[i++].split( "=" );
                        alias.append( kv[1].trim() );
                       
                    }
                   
                    log.info( "Created unique alias: " + alias.toString() );
                }
               
                log.info( "Adding new certificate with alias \"" + alias + "\"" );
                keystore.setCertificateEntry( alias.toString(), cert );
               
                saveKeystore();
               
            } catch (Exception e) {
                e.printStackTrace();
                JOptionPane.showMessageDialog( validator, "Error while adding certificate to trusted cert store: " + e.getMessage(), "Error Storing Certificate", JOptionPane.ERROR_MESSAGE );
            }
           
        }

        return approved;
    }


    /**
     * This method checks if the issuer of the given certificate is valid and trusted, i.e.
     * within the list of trusted issuers.
     *
     * @param cert The certificate which's issuers is to be checked.
     * @return <code>true</code>, if the issuer is trusted to sign the certificate.
     */
    public boolean isIssuerTrusted( X509Certificate cert ) {
        try {

            for( X509Certificate caCert : getAcceptedIssuers() ){

                caCert.checkValidity();

                // we require the CA cert to be allowed for key-signing
                //
//              if( caCert.getKeyUsage()[5] ){

                if( cert.getIssuerDN() != null && cert.getIssuerDN().equals( caCert.getSubjectDN() ) )
                    return true;

                if( cert.getSubjectAlternativeNames() != null && caCert.getSubjectAlternativeNames().contains( cert.getIssuerDN() ))
                    return true;

//              }
            }
        } catch ( CertificateException e ) {
            e.printStackTrace();
        }

        return false;
    }


    public boolean isValid( X509Certificate[] chain ){
        // TODO: Implement
        return false;
    }

    public boolean isValid( X509Certificate cert ){
        // TODO: Implement
        return false;
    }


    public void saveCertificate( X509Certificate cert ){

        try {
            String alias = "";
            keystore.setCertificateEntry( alias, cert );
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Return all issuer certificates that are found in our keystore.
     *
     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
     */
    public X509Certificate[] getAcceptedIssuers() {

        try {
            ArrayList<X509Certificate> certs = new ArrayList<X509Certificate>();
            Enumeration<String> en = keystore.aliases();
            while( en.hasMoreElements() ){
                String alias = en.nextElement();
                try {
                    X509Certificate cert = (X509Certificate) keystore.getCertificate( alias );

//                  if( cert.getKeyUsage() != null && cert.getKeyUsage()[5] ){

                    cert.checkValidity();

                    certs.add( cert );

//                  } else
//                  log.info( "Skipping certificate " + cert + " as it is not suited for keyCertSigning!" );

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            X509Certificate[] issuers = new X509Certificate[ certs.size() ];
            for( int i = 0; i < issuers.length; i++ )
                issuers[i] = certs.get( i );

            return issuers;

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
   
   
    private void saveKeystore(){
       
        try {

            String keystoreFileName = System.getProperty("user.home") + "/.jwall/keystore";
            File keystoreFile = new File( keystoreFileName );

            log.info( "Writing key store to " + keystoreFile.getAbsolutePath() );
            keystore.store( new FileOutputStream( keystoreFile ), passphrase );
           
        } catch (Exception e) {
            e.printStackTrace();
        }
       
    }
   
   
   
    public static void main( String args[] ){

        try {
           
            KeyStore keystore = KeyStore.getInstance( "JKS" );
            keystore.load( CustomTrustManager.class.getResourceAsStream( "/org/jwall/security/cert/keystore" ), "secret".toCharArray() );           
           
            Enumeration<String> en = keystore.aliases();
            String alias = en.nextElement();
           
            X509Certificate[] chain = new X509Certificate[]{ (X509Certificate) keystore.getCertificate( alias ) };
           
            CustomTrustManager tm = CustomTrustManager.getInstance();
           
            tm.requestUserApproval( chain, "" );
           
        } catch (Exception e) {
           
        }
    }
}
TOP

Related Classes of org.jwall.security.cert.CustomTrustManager

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.