/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2005 Sun Microsystems Inc. All Rights Reserved
 *
 * The contents of this file are subject to the terms
 * of the Common Development and Distribution License
 * (the License). You may not use this file except in
 * compliance with the License.
 *
 * You can obtain a copy of the License at
 * https://opensso.dev.java.net/public/CDDLv1.0.html or
 * opensso/legal/CDDLv1.0.txt
 * See the License for the specific language governing
 * permission and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL
 * Header Notice in each file and include the License file
 * at opensso/legal/CDDLv1.0.txt.
 * If applicable, add the following below the CDDL Header,
 * with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * $Id: CRLValidator.java,v 1.3 2008/06/25 05:52:58 qcheng Exp $
 *
 * Portions Copyrighted 2014-2015 ForgeRock AS.
 */
package com.sun.identity.security.cert;

import java.io.IOException;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.util.Vector;

import com.sun.identity.shared.configuration.SystemPropertiesManager;
import com.sun.identity.shared.Constants;
import com.sun.identity.shared.debug.Debug;
import com.iplanet.am.util.AMPasswordUtil;
import com.iplanet.security.x509.CertUtils;
import com.sun.identity.security.SecurityDebug;

/**
 * This interface is for <code>CRLValidator</code> that is representing
 * configued <code>X509CRLValidator</code> 
 */
public class CRLValidator {
    private static Debug debug = SecurityDebug.debug;
    private static AMLDAPCertStoreParameters ldapParams = null;
    // Dir server info for CRL entry
    private static boolean crlCheckEnabled = false;
    private static String dirServerHost = null;
    private static String dirServerPort = null;
    private static String dirUseSSL = null;
    private static String dirPrincipleUser = null;
    private static String dirPrinciplePasswd = null;
    private static String dirStartSearchLoc = null;
    private static String crlSearchAttr = null;

    static {
       /*
         * Setup the LDAP certificate directory service context for
         * use in verification of signing certificates.
         */
        dirServerHost = SystemPropertiesManager.get(
                        Constants.CRL_CACHE_DIR_HOST, null);
        crlCheckEnabled = dirServerHost != null;
        if (debug.messageEnabled()) {
            debug.message("CRLValidator : " + 
                "CRL Check configured : " + crlCheckEnabled);
        }

        if (crlCheckEnabled == true) {
            dirServerHost = SystemPropertiesManager.get(
                        Constants.CRL_CACHE_DIR_HOST, null);
            dirServerPort = SystemPropertiesManager.get(
                        Constants.CRL_CACHE_DIR_PORT, "389");
            dirUseSSL = SystemPropertiesManager.get(
                        Constants.CRL_CACHE_DIR_SSL_ENABLED, "false");
            dirPrincipleUser = SystemPropertiesManager.get(
                        Constants.CRL_CACHE_DIR_USER, null);
            dirPrinciplePasswd = AMPasswordUtil.decrypt(
                        SystemPropertiesManager.get(
                            Constants.CRL_CACHE_DIR_PASSWD, null));
            dirStartSearchLoc = SystemPropertiesManager.get(
                        Constants.CRL_CACHE_DIR_SEARCH_LOC, null);
            crlSearchAttr = SystemPropertiesManager.get(
                        Constants.CRL_CACHE_DIR_SEARCH_ATTR, "CN");

            try {
                ldapParams = AMCertStore.setLdapStoreParam(dirServerHost,
                       Integer.valueOf(dirServerPort).intValue(),
                       dirPrincipleUser,
                       dirPrinciplePasswd,
                       dirStartSearchLoc,
                       null,
                       dirUseSSL.equalsIgnoreCase("true"));
            } catch (Exception e) {
                debug.error("Unable to configure ldap CRL cache " + e);
            }

            if (debug.messageEnabled()) {
                debug.message("CRLValidator : Directory Server Host : " 
                    + dirServerHost);
                debug.message("CRLValidator : Directory Server Port# : " 
                    + dirServerPort);
                debug.message("CRLValidator : SSL Enabled : " + dirUseSSL);
                debug.message("CRLValidator : Principal User : " 
                    + dirPrincipleUser);
                if (dirPrinciplePasswd != null) {
                    debug.message("CRLValidator : User Password : xxxxxx");
                } else {
                    debug.message("CRLValidator : User Password : null");
                }
                debug.message("CRLValidator : Start Search Loc : " 
                    + dirStartSearchLoc);
                debug.message("CRLValidator : CRL Search Attr : " 
                    + crlSearchAttr);
            }
        }
    }
    
    /**
     * Validate certificate against configured crl
     * @param cert cert to be validated 
     * @return true if certificate is not in crl
     */
    static public boolean validateCertificate(X509Certificate cert, 
                                       boolean checkCAStatus) {
        String method = "validateCertificate : ";
        boolean certgood = true;

    	try {
            Vector crls = new Vector();
            X509CRL crl = 
               AMCRLStore.getCRL(ldapParams, cert, crlSearchAttr);

            if (crl != null) {
                crls.add(crl);
            }

            if (debug.messageEnabled()) {
                debug.message(method + " crls size = " + crls.size());
                if (crls.size() > 0) {
                    debug.message(method + "CRL = " + crls.toString());
                } else {
                    debug.message(method + "NO CRL found.");
                }
            }

            AMCertPath certpath = new AMCertPath(crls);
            X509Certificate certs[] = { cert }; 
            if (!certpath.verify(certs, true, false)) {
                debug.error(method + "CertPath:verify failed.");
                return certgood = false;
            }
    	} catch (Exception e) {
            debug.error(method + "verify failed.", e);
            return certgood = false;
    	}

        if ((checkCAStatus == true) && (AMCertStore.isRootCA(cert) == false)) {
            X509Certificate caCert = 
                AMCertStore.getIssuerCertificate(
                    ldapParams, cert, crlSearchAttr);
            certgood = validateCertificate(caCert, checkCAStatus);
        }

        return certgood;
    }
    
    /**
     * Get certificate revocation list from cofigured ldap store
     * @param cert cert to be validated 
     * @return crl if ldap store configured with crl
     */
    static public X509CRL getCRL(X509Certificate cert) {
        X509CRL crl = null;
        //Get the CN of the input certificate
        String attrValue = CertUtils.getAttributeValue(cert.getIssuerX500Principal(), crlSearchAttr);

        if (attrValue == null || ldapParams == null) {
            return null;
        }

        if (debug.messageEnabled()) {
            debug.message("CRLValidator - attrValue to search crl : " + attrValue);
        }

        //Lookup the certificate in the LDAP certificate directory and compare the values.
        String searchFilter = AMCRLStore.setSearchFilter(crlSearchAttr, attrValue);
        ldapParams.setSearchFilter(searchFilter);
        try {
            AMCRLStore store = new AMCRLStore(ldapParams);
            crl = store.getCRL(cert);
        } catch (IOException e) {
            debug.error("X509Certificate: verifyCertificate." + e.toString());
        }

        return crl;
    }

    static public boolean isCRLCheckEnabled() {
        return crlCheckEnabled;
    }
}
