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.
* Tommy Dejbjerg Pedersen, Lenio
* 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;
Jacob Lund Mogensen
committed
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;
Jacob Lund Mogensen
committed
import dk.gov.oiosi.configuration.CacheConfig;
import dk.gov.oiosi.configuration.CacheFactory;
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;
Jacob Lund Mogensen
committed
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;
// Set cache time to one hour
private static final ICache<X500Principal, RevocationResponse> ocspCache = CacheFactory.getInstance().getOcspLookupCache();
/**
* Gets the configuration of the lookup client.
*
* @return OCSP configuration
*/
public OcspConfig getConfiguration() {
return configuration;
}
/**
* Instantiates OcspLookup and loads the OCES default root certificate.
*
* @param conf Configuration parameters
*/
public OcspLookup(OcspConfig conf) {
configuration = conf;
}
/**
* Creates a new OcspLookup class
*
* @param conf The configuration to use in this lookup
* @param defaultRootCertificate The root certificate
*/
public OcspLookup(OcspConfig conf, X509Certificate defaultRootCertificate) {
configuration = conf;
//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;
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
}
/**
* Default constructor. Attempts to load configuration from configuration
* file.
*
* @throws ConfigurationException On error...
*/
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();
}
// The response was not in the cache - we must validete the certificate our self
// default to false
response.setIsValid(false);
String serverUrl;
log.debug("Setting up OCSP client:");
rootcertList = configuration.getDefaultOcesRootCertificateCollectionFromStore() ;
// 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 && rootCertificateIndex < rootcertList.size()) {
try {
log.debug("start validation certificate");
client = OcspRegistry.getOcspClient();
client.setCaCert(rootcertList.get(rootCertificateIndex));
// Try validation if this is the correct root certificate
log.debug("Getting certificate status for:" + serNos[0]);
ocspCertificateResponse = client.getCertificateStatus(serNos);
log.trace("Validating certificate...");
client.validateCerts(ocspCertificateResponse);
OcspCertificateStatus status = ocspCertificateResponse.getCertificateStatus(serNos[0]);
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;
// 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 + "]");
}
// The certificateResponse is invalid
log.error("Response returned an error: " + ocspCertificateResponse.getError());
throw new RevocationException("Response returned an error: " + ocspCertificateResponse.getError());
}
log.debug("Error validating certificate : " + e.getMessage(), e);
//throw new RevocationException(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);
}
}
}