/*
* Copyright (c) 2012 ICM Uniwersytet Warszawski All rights reserved.
* See LICENCE.txt file for licensing information.
*/
package eu.emi.security.authn.x509.helpers.ocsp;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.cert.X509Certificate;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.cert.ocsp.OCSPReq;
import org.bouncycastle.cert.ocsp.OCSPResp;
import org.bouncycastle.cert.ocsp.SingleResp;
import eu.emi.security.authn.x509.X509Credential;
/**
* OCSP client which adds a cache layer on top of {@link OCSPClientImpl}.
* There are two caches (all of them are configurable) consulted in the given order:
* unresponsive responders cache (per responder); OCSP responses cache (per responder and checked certificate tuple).
* <p>
* This class is thread safe.
* @author K. Benedyczak
*/
public class OCSPCachingClient
{
private final long maxTtl;
private OCSPRespondersCache respondersCache;
private OCSPResponsesCache responsesCache;
/**
*
* @param maxTtl maximum time after each cached response expires. Negative for no cache at all, 0 for no limit
* (i.e. caching time will be only controlled by the OCSP response validity period). In ms.
* @param diskPath if not null, cached responses will be stored on disk.
* @param prefix used if disk cache is enabled, as a common prefix for all files created in the cache directory.
*/
public OCSPCachingClient(long maxTtl, File diskPath, String prefix)
{
this.maxTtl = maxTtl;
responsesCache = new OCSPResponsesCache(maxTtl, diskPath, prefix);
respondersCache = new OCSPRespondersCache(maxTtl, diskPath, prefix);
}
/**
* Returns the checked certificate status.
* @param responder mandatory - URL of the responder. HTTP or HTTPs, however in https mode the
* @param toCheckCert mandatory certificate to be checked
* @param issuerCert mandatory certificate of the toCheckCert issuer
* @param requester if not null, then it is assumed that request must be signed by the requester.
* @param addNonce if true nonce will be added to the request and required in response
* @param timeout timeout
* @return raw result of the query
* @throws IOException IO exception
* @throws OCSPException OCSP exception
*/
public OCSPResult queryForCertificate(URL responder, X509Certificate toCheckCert,
X509Certificate issuerCert, X509Credential requester, boolean addNonce,
int timeout) throws IOException, OCSPException
{
return queryForCertificate(responder, toCheckCert, issuerCert, requester, addNonce, timeout,
new OCSPClientImpl());
}
/**
* Returns the checked certificate status, using a custom client.
* @param responder mandatory - URL of the responder. HTTP or HTTPs, however in https mode the
* @param toCheckCert mandatory certificate to be checked
* @param issuerCert mandatory certificate of the toCheckCert issuer
* @param requester if not null, then it is assumed that request must be signed by the requester.
* @param addNonce if true nonce will be added to the request and required in response
* @param timeout timeout
* @param client client to be used for network calls
* @return raw result of the query
* @throws IOException IO exception
* @throws OCSPException OCSP exception
*/
public OCSPResult queryForCertificate(URL responder, X509Certificate toCheckCert,
X509Certificate issuerCert, X509Credential requester, boolean addNonce,
int timeout, OCSPClientImpl client) throws IOException, OCSPException
{
if (maxTtl < 0)
{
return client.queryForCertificate(responder, toCheckCert, issuerCert,
requester, addNonce, timeout);
}
String responderKey = respondersCache.createResponderKey(issuerCert);
respondersCache.checkCachedError(responderKey);
String responseKey = responsesCache.createResponseKey(toCheckCert, issuerCert);
SingleResp cachedResp = responsesCache.getCachedResp(responseKey, client,
toCheckCert, issuerCert);
if (cachedResp != null)
return new OCSPResult(cachedResp);
OCSPReq request = client.createRequest(toCheckCert, issuerCert, requester, addNonce);
OCSPResponseStructure responseWithMeta;
try
{
responseWithMeta = client.send(responder, request, timeout);
} catch (IOException e)
{
respondersCache.addToCache(responderKey, e);
throw e;
}
OCSPResp fullResponse = responseWithMeta.getResponse();
byte[] nonce = OCSPClientImpl.extractNonce(request);
SingleResp singleResp = client.verifyResponse(fullResponse, toCheckCert, issuerCert, nonce);
responsesCache.addToCache(responseKey, responseWithMeta, singleResp);
return new OCSPResult(singleResp);
}
public void clearMemoryCache()
{
responsesCache.clearMemoryCache();
respondersCache.clearMemoryCache();
}
}