Skip to content
OcspLookup.java 10.9 KiB
Newer Older
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (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.mozilla.org/MPL/
 *
 * 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 Java RASP toolkit.
 *
 * The Initial Developer of the Original Code is Lenio. Portions
 * created by Lenio are Copyright (C) 2007 Danish National IT and
 * Telecom Agency (http://www.itst.dk). All Rights Reserved.
 *
 * Contributor(s):
 *   Tommy Dejbjerg Pedersen, Lenio
 *   Hans Guldager Knudsen, Lenio
 *   Patrik Johansson, Accenture
 *   Dennis Søgaard, Accenture
 *   Martin Bentzen, Accenture
 *   Jesper Jensen, Avanade
 *   Ramzi Fadel, Avanade
 *   Christian Pedersen, Accenture
 *   Morten Hougesen, Accenture
 *   Mikkel Hippe Brun, ITST
 *   Finn Hartmann Jordal, ITST
 *   Christian Lanng, ITST
package dk.gov.oiosi.security.revocation.ocsp;

import dk.certifikat.ocsp.client.OcspCertificateResponse;
import dk.certifikat.ocsp.client.OcspCertificateResponse.OcspCertificateStatus;
import dk.certifikat.ocsp.client.OcspClient;
import dk.certifikat.ocsp.client.OcspRegistry;
import dk.certifikat.ocsp.client.OcspSystemException;
import dk.gov.oiosi.common.OutVariable;
import dk.gov.oiosi.common.cache.ICache;
import dk.gov.oiosi.configuration.CacheConfig;
hknudsen's avatar
hknudsen committed
import dk.gov.oiosi.configuration.ConfigurationException;
import dk.gov.oiosi.configuration.ConfigurationHandler;
import dk.gov.oiosi.security.CertificateHandlingException;
import dk.gov.oiosi.security.revocation.IRevocationLookup;
import dk.gov.oiosi.security.revocation.RevocationException;
import dk.gov.oiosi.security.revocation.RevocationResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.ocsp.OCSPException;

import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
/**
 * Class for checking certificate revocation status against an OCSP server.
 */
public class OcspLookup implements IRevocationLookup {
	/**
	 * local log.
	 */
	private Log log = LogFactory.getLog(OcspLookup.class);

	/**
	 * OCSP configuration.
	 */
	private OcspConfig configuration;

	/**
	 * Root certificate
	 */
	private List<X509Certificate> rootcertList = null;
    //private X509Certificate  rootcert = null;
    // Set cache time to one hour
	private static final ICache<X500Principal, RevocationResponse> ocspCache = createCache();
	/**
	 * Gets the configuration of the lookup client.
	 * 
	 * @return OCSP configuration
	 */
	public OcspConfig getConfiguration() {
		return configuration;
	}

	/**
	 * Instantiates OcspLookup and loads the OCES default root certificate.
	 * 
cpedersen's avatar
cpedersen committed
	 * @param conf Configuration parameters
cpedersen's avatar
cpedersen committed
	public OcspLookup(OcspConfig conf) {
        rootcertList = null;
cpedersen's avatar
cpedersen committed
	 * Creates a new OcspLookup class
cpedersen's avatar
cpedersen committed
	 * @param conf The configuration to use in this lookup
	 * @param defaultRootCertificate The root certificate
cpedersen's avatar
cpedersen committed
	public OcspLookup(OcspConfig conf, X509Certificate defaultRootCertificate) {
        //rootcert = defaultRootCertificate;
        rootcertList = new ArrayList<X509Certificate>();
        rootcertList.add(defaultRootCertificate);
	}

    	/**
	 * Creates a new OcspLookup class
	 *
	 * @param conf The configuration to use in this lookup
	 * @param defaultRootCertificateList The root certificate
	 */
	public OcspLookup(OcspConfig conf, ArrayList<X509Certificate> defaultRootCertificateList) {
		configuration = conf;
        rootcertList = defaultRootCertificateList;
	}

	/**
	 * Default constructor. Attempts to load configuration from configuration
	 * file.
	 * 
	 * @throws ConfigurationException
	 */
	public OcspLookup() throws ConfigurationException {
		try {
			configuration = ConfigurationHandler.getInstance().getOcspConfig();
		} catch (URISyntaxException e) {
			throw new ConfigurationException(e.getMessage());
		}
    private static ICache<X500Principal, RevocationResponse> createCache()
    {
        CacheConfig cacheConfig = ConfigurationHandler.getInstance().getCacheConfig();
	/**
	 * Checks a certificate status on a ocsp server.
	 * 
	 * @param certificate
	 *            The certificate to check
	 * @return The RevocationResponse object that contains the result
	 * @throws RevocationException
	public RevocationResponse checkCertificate(X509Certificate certificate)
			throws RevocationException
    {
		OutVariable<RevocationResponse> value = new OutVariable<RevocationResponse>();
		if (ocspCache.tryGetValue(certificate.getSubjectX500Principal(), value)) {
			return value.getVariable();
		}

        // The response was not in the cache - we must validete the certificate our self
		RevocationResponse response = new RevocationResponse();
        // default to false
        response.setIsValid(false);
        String serverUrl;

            log.debug("Setting up OCSP client:");
			if (rootcertList  == null) {
				// get the rootcert(s) from configurationsettings
				rootcertList = configuration.getDefaultOcesRootCertificateCollectionFromStore()  ;
				//		.getDefaultOcesRootCertificateFromStore();
            if(rootcertList.size() <= 0 )
            {
                // no root certificate is defined
                // we can't proceed
                throw new RevocationException("No root certificate has been defined.");
            }

			if (configuration.getServerUrl() == null) {
				// Use OCSP server specified in certificate
				serverUrl = GetServerUriFromCertificate(certificate);
			} else {
				// Use OCSP server specified in configuration
				serverUrl = configuration.getServerUrl();
        }
        catch (RevocationException e)
        {
                throw e;
        }
        catch (CertificateHandlingException e) {
			log.error("Error handling the certificate" + e.getMessage());
			throw new RevocationException(e);
		}
        catch (Exception e) {
			log.error("Error initailizing validator : " + e.getMessage(), e);
			throw new RevocationException(e);
		}

        OcspCertificateResponse ocspCertificateResponse = null;
        OcspClient client = null;
        boolean validationNotFinish = true;
        int rootCertificateIndex = 0;

        while(validationNotFinish == true && rootCertificateIndex < rootcertList.size())
        {
            try
            {
                log.debug("start validation certificate");
                client = OcspRegistry.getOcspClient();
			    client.setResponderUrl(serverUrl);
                client.setCaCert(rootcertList.get(rootCertificateIndex));

                // Try validation if this is the correct root certificate
                /*****/
                 BigInteger[] serNos = { certificate.getSerialNumber() };

                log.debug("Getting certificate status for:" + serNos[0]);
                ocspCertificateResponse = client.getCertificateStatus(serNos);

                log.trace("Validating certificate...");
                client.validateCerts(ocspCertificateResponse);

                if (ocspCertificateResponse.isOk())
                {
                    OcspCertificateStatus status = ocspCertificateResponse.getCertificateStatus(serNos[0]);

                    if ("Good".equals(status.toString()))
                    {
                        log.debug("Status of cert " + certificate.getSubjectDN() + " : [" + status + "]");
                        response.setIsValid(true);
                        response.setNextUpdate(ocspCertificateResponse.getNextUpdate());
                        // all okay, do not check other root certificate
                        validationNotFinish = false;
                    }
                    else
                    {
                        // The used root certificate is not valid, check the next one
                        // The rootCertificateIndex is increased at the buttom of this try-catch

                        log.warn("Certificate validation failed " + serNos[0] + " : [" + status + "]");
                    }
                }
                else
                {
                    // The certificateResponse is invalid
                    log.error("Response returned an error: " + ocspCertificateResponse.getError());
                    throw new RevocationException("Response returned an error: " + ocspCertificateResponse.getError());
                }

            }
            catch (RevocationException e)
            {
                throw e;
            }
            catch (OcspSystemException e)
            {
                log.debug("Error validating certificate : " + e.getMessage(), e);
                //throw new RevocationException(e);
            }
            catch (OCSPException e)
            {
                log.error("Error validating certificate : " + e.getMessage(), e);
                throw new RevocationException(e);
            }
            catch (Exception e)
            {
			    log.error("Error validator certificate : " + e.getMessage(), e);
			    throw new RevocationException(e);
		    }

            rootCertificateIndex++;

        }

        log.debug("Validating X509 certificate finished.");

        // add the result to cache
        ocspCache.set(certificate.getSubjectX500Principal(), response);

        return response;
	}

	public String GetServerUriFromCertificate(X509Certificate certificate)
			throws RevocationException {

		try {
			byte[] ext = certificate
					.getExtensionValue(X509Extensions.AuthorityInfoAccess
							.getId());
			ASN1InputStream aIn = new ASN1InputStream(ext);
			aIn = new ASN1InputStream(((ASN1OctetString) aIn.readObject())
					.getOctets());
			ASN1Encodable object = (ASN1Encodable) aIn.readObject();
			AuthorityInformationAccess auth = AuthorityInformationAccess
					.getInstance(object);
			AccessDescription[] acc = auth.getAccessDescriptions();
			return acc[0].getAccessLocation().toString().substring(3);
		} catch (IOException e) {
			throw new RevocationException(e);