Skip to content
OcspLookup.java 7.73 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 java.io.IOException;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.security.cert.X509Certificate;

import javax.security.auth.x500.X500Principal;

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 dk.certifikat.ocsp.client.OcspCertificateResponse;
import dk.certifikat.ocsp.client.OcspClient;
import dk.certifikat.ocsp.client.OcspRegistry;
import dk.certifikat.ocsp.client.OcspSystemException;
import dk.certifikat.ocsp.client.OcspCertificateResponse.OcspCertificateStatus;
import dk.gov.oiosi.common.OutVariable;
import dk.gov.oiosi.common.cache.ICache;
import dk.gov.oiosi.common.cache.TimedCache;
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.RevocationResponse;
import dk.gov.oiosi.security.revocation.RevocationException;
/**
 * 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 X509Certificate rootcert = null;

	private static final ICache<X500Principal, RevocationResponse> ocspCache = new TimedCache<X500Principal, RevocationResponse>(60 * 60 * 1000);

	
	/**
	 * 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) {
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) {
		configuration = conf;
		rootcert = defaultRootCertificate;
	}

	/**
	 * 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());
		}
	}

	/**
	 * 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();
		}
		RevocationResponse response = new RevocationResponse();
		OcspCertificateResponse r = null;
		OcspClient client = null;
		try {

			if (rootcert == null) {
				// get the rootcert from configurationsettings
				rootcert = configuration
						.getDefaultOcesRootCertificateFromStore();
			log.debug("Setting up OCSP client:");
			client = OcspRegistry.getOcspClient();

			String serverUrl;
			if (configuration.getServerUrl() == null) {
				// Use OCSP server specified in certificate
				serverUrl = GetServerUriFromCertificate(certificate);
			} else {
				// Use OCSP server specified in configuration
				serverUrl = configuration.getServerUrl();

			client.setResponderUrl(serverUrl);
			client.setCaCert(rootcert);
		} 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);
		}
		BigInteger[] serNos = { certificate.getSerialNumber() };
		try {
pjohansson's avatar
pjohansson committed
			log.debug("Getting certificate status for:" + serNos[0]);
			r = client.getCertificateStatus(serNos);
pjohansson's avatar
pjohansson committed
			log.trace("Validating certificate...");
			client.validateCerts(r);
		} catch (OcspSystemException e) {
			log
					.error("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);
		}
		if (r.isOk()) {
			OcspCertificateStatus status = r
					.getCertificateStatus(serNos[0]);
			if ("Good".equals(status.toString())) {
				log.debug("Status of cert " + certificate.getSubjectDN()
						+ " : [" + status + "]");
				response.setIsValid(true);
				response.setNextUpdate(r.getNextUpdate());
				log.warn("Certificate validation failed " + serNos[0]
						+ " : [" + status + "]");
		} else {
			log.error("Response returned an error: " + r.getError());
			throw new RevocationException("Response returned an error: "
					+ r.getError());
		log.debug("Validating X509 certificate finished.");
		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);