Caching 如何使用iTextSharp(LTV签名)缓存OCSP响应?

Caching 如何使用iTextSharp(LTV签名)缓存OCSP响应?,caching,itext,ocsp,Caching,Itext,Ocsp,我使用iTextSharp 5.5.10来生成签名PDF。特别是,我需要LTV签名。LTV可以通过CRL和OCSP请求完成 我是用这样的代码来做的: IOcspClient ocspClient = new OcspClientBouncyCastle(); ICrlClient crlClient = new CrlClientOnline(myCert.Chain); List<ICrlClient> lstCrlClients = new List<ICrlClient&

我使用iTextSharp 5.5.10来生成签名PDF。特别是,我需要LTV签名。LTV可以通过CRL和OCSP请求完成

我是用这样的代码来做的:

IOcspClient ocspClient = new OcspClientBouncyCastle();
ICrlClient crlClient = new CrlClientOnline(myCert.Chain);
List<ICrlClient> lstCrlClients = new List<ICrlClient> { crlClient };

MakeSignature.SignDetached(sap, signature, this.myCert.Chain, lstCrlClients, ocspClient, null, 0, CryptoStandard.CMS);
IOcspClient-ocspClient=new-OcspClientBouncyCastle();
ICrlClient crlClient=新的CrlClientOnline(myCert.Chain);
List lstCrlClients=新列表{crlClient};
MakeSignature.signDistached(sap,signature,this.myCert.Chain,lstCrlClients,ocspClient,null,0,CryptoStandard.CMS);
问题是:我签署了很多很多PDF文件(总是使用相同的证书)。所以,我不想每次都发出CRL和OCSP请求,我必须“缓存”它们

我设法用这种代码缓存CRL(它依赖于C#MemoryCache):

私有列表GetCachedListCrlClient()
{
var key=“LstCrlClient”;
List lstCrlClients=MyGlobalCachingProvider.GetItem(键);
if(lstCrlClients==null)
{           
lstCrlClients=新列表();
for(int i=0;i

但是,我找不到任何缓存OCSP响应的解决方案。有人有线索吗?

多亏了mlk的评论,我做到了:我实现了自己的类,灵感来自OcspClientBouncyCastle代码。事实上,代码是微不足道的。我的类管理缓存:它只发送一个OCSP请求。这是做这些事情的好方法

示例代码:

// Once instanciated, this class fires one and only one OCSP request : it keeps the first result in memory.
// You may want to cache this object ; ie with MemoryCache.
public class MyOcspClientBouncyCastleSingleRequest : IOcspClient
{
    private static readonly ILogger LOGGER = LoggerFactory.GetLogger(typeof(OcspClientBouncyCastle));

    private readonly OcspVerifier verifier;

    // The request-result
    private Dictionary<String, BasicOcspResp> _cachedOcspResponse = new Dictionary<string, BasicOcspResp>();

    /**
     * Create default implemention of {@code OcspClient}.
     * Note, if you use this constructor, OCSP response will not be verified.
     */
    [Obsolete]
    public MyOcspClientBouncyCastleSingleRequest()
    {
        verifier = null;
    }

    /**
     * Create {@code OcspClient}
     * @param verifier will be used for response verification. {@see OCSPVerifier}.
     */
    public MyOcspClientBouncyCastleSingleRequest(OcspVerifier verifier)
    {
        this.verifier = verifier;
    }

    /**
     * Gets OCSP response. If {@see OCSPVerifier} was set, the response will be checked.
     */
    public virtual BasicOcspResp GetBasicOCSPResp(X509Certificate checkCert, X509Certificate rootCert, String url)
    {
        String dicKey = checkCert.SubjectDN.ToString() + "-" + rootCert.SubjectDN.ToString() + "-" + url;
        if (_cachedOcspResponse != null && _cachedOcspResponse.Count > 0 && _cachedOcspResponse.ContainsKey(dicKey))
        {
            BasicOcspResp cachedResult = _cachedOcspResponse[dicKey];
            return cachedResult;
        }
        else
        {
            try
            {
                OcspResp ocspResponse = GetOcspResponse(checkCert, rootCert, url);
                if (ocspResponse == null)
                {
                    _cachedOcspResponse.Add(dicKey, null);
                    return null;
                }
                if (ocspResponse.Status != OcspRespStatus.Successful)
                {
                    _cachedOcspResponse.Add(dicKey, null);
                    return null;
                }
                BasicOcspResp basicResponse = (BasicOcspResp)ocspResponse.GetResponseObject();
                if (verifier != null)
                {
                    verifier.IsValidResponse(basicResponse, rootCert);
                }
                _cachedOcspResponse.Add(dicKey, basicResponse);
                return basicResponse;
            }
            catch (Exception ex)
            {
                if (LOGGER.IsLogging(Level.ERROR))
                    LOGGER.Error(ex.Message);
            }
            return null;
        }
    }

    /**
     * Gets an encoded byte array with OCSP validation. The method should not throw an exception.
     *
     * @param checkCert to certificate to check
     * @param rootCert  the parent certificate
     * @param url       to get the verification. It it's null it will be taken
     *                  from the check cert or from other implementation specific source
     * @return a byte array with the validation or null if the validation could not be obtained
     */
    public byte[] GetEncoded(X509Certificate checkCert, X509Certificate rootCert, String url)
    {
        try
        {
            BasicOcspResp basicResponse = GetBasicOCSPResp(checkCert, rootCert, url);
            if (basicResponse != null)
            {
                SingleResp[] responses = basicResponse.Responses;
                if (responses.Length == 1)
                {
                    SingleResp resp = responses[0];
                    Object status = resp.GetCertStatus();
                    if (status == CertificateStatus.Good)
                    {
                        return basicResponse.GetEncoded();
                    }
                    else if (status is RevokedStatus)
                    {
                        throw new IOException(MessageLocalization.GetComposedMessage("ocsp.status.is.revoked"));
                    }
                    else
                    {
                        throw new IOException(MessageLocalization.GetComposedMessage("ocsp.status.is.unknown"));
                    }
                }
            }
        }
        catch (Exception ex)
        {
            if (LOGGER.IsLogging(Level.ERROR))
                LOGGER.Error(ex.Message);
        }
        return null;
    }

    /**
    * Generates an OCSP request using BouncyCastle.
    * @param issuerCert certificate of the issues
    * @param serialNumber   serial number
    * @return   an OCSP request
    * @throws OCSPException
    * @throws IOException
    */
    private static OcspReq GenerateOCSPRequest(X509Certificate issuerCert, BigInteger serialNumber)
    {
        // Generate the id for the certificate we are looking for
        CertificateID id = new CertificateID(CertificateID.HashSha1, issuerCert, serialNumber);

        // basic request generation with nonce
        OcspReqGenerator gen = new OcspReqGenerator();
        gen.AddRequest(id);

        // create details for nonce extension
        IDictionary extensions = new Hashtable();

        extensions[OcspObjectIdentifiers.PkixOcspNonce] = new X509Extension(false, new DerOctetString(new DerOctetString(PdfEncryption.CreateDocumentId()).GetEncoded()));

        gen.SetRequestExtensions(new X509Extensions(extensions));
        return gen.Generate();
    }

    private OcspResp GetOcspResponse(X509Certificate checkCert, X509Certificate rootCert, String url)
    {
        if (checkCert == null || rootCert == null)
            return null;
        if (url == null)
        {
            url = CertificateUtil.GetOCSPURL(checkCert);
        }
        if (url == null)
            return null;
        LOGGER.Info("Getting OCSP from " + url);
        OcspReq request = GenerateOCSPRequest(rootCert, checkCert.SerialNumber);
        byte[] array = request.GetEncoded();

        HttpWebRequest con = (HttpWebRequest)WebRequest.Create(url);
        con.ContentLength = array.Length;
        con.ContentType = "application/ocsp-request";
        con.Accept = "application/ocsp-response";
        con.Method = "POST";
        Stream outp = con.GetRequestStream();
        outp.Write(array, 0, array.Length);
        outp.Close();
        HttpWebResponse response = (HttpWebResponse)con.GetResponse();
        if (response.StatusCode != HttpStatusCode.OK)
            throw new IOException(MessageLocalization.GetComposedMessage("invalid.http.response.1", (int)response.StatusCode));
        Stream inp = response.GetResponseStream();
        OcspResp ocspResponse = new OcspResp(inp);
        inp.Close();
        response.Close();
        return ocspResponse;
    }
//实例化后,此类将触发一个且仅触发一个OCSP请求:它将第一个结果保留在内存中。
//您可能希望缓存此对象;我带着记忆的疼痛。
公共类MyOcspClientBouncyCastleSingleRequest:IOcspClient
{
私有静态只读ILogger LOGGER=LoggerFactory.GetLogger(类型为(OcspClientBouncyCastle));
专用只读OcspVerifier验证器;
//请求结果
专用词典_cachedOcspResponse=新词典();
/**
*创建{@code OcspClient}的默认实现。
*注意,如果使用此构造函数,则不会验证OCSP响应。
*/
[过时]
公共服务客户BouncyCastleSingleRequest()
{
验证器=空;
}
/**
*创建{@code OcspClient}
*@param验证程序将用于响应验证。{@see OCSPVerifier}。
*/
公共事务客户端BouncyCastleSingleRequest(OcspVerifier-verifier)
{
this.verifier=验证器;
}
/**
*获取OCSP响应。如果设置了{@see OCSPVerifier},将检查响应。
*/
公共虚拟basicospresp getbasicospresp(X509证书检查证书,X509证书根证书,字符串url)
{
字符串dicKey=checkCert.SubjectDN.ToString()+“-”+根证书.SubjectDN.ToString()+“-”+url;
如果(_cachedOcspResponse!=null&&u cachedOcspResponse.Count>0&&u cachedOcspResponse.ContainsKey(dicKey))
{
basicospresp cachedResult=_cachedOcspResponse[dicKey];
返回cachedResult;
}
其他的
{
尝试
{
OcspResp ocspResponse=GetOcspResponse(checkCert、rootCert、url);
if(ocsResponse==null)
{
_cachedOcspResponse.Add(dicKey,null);
返回null;
}
if(ocspResponse.Status!=ocspResponse.Successful)
{
_cachedOcspResponse.Add(dicKey,null);
返回null;
}
basicospresp basicResponse=(basicospresp)ocsResponse.GetResponseObject();
if(验证器!=null)
{
验证人IsValidResponse(基本应答、根证书);
}
_cachedOcspResponse.Add(dicKey,basicResponse);
返回基本应答;
}
捕获(例外情况除外)
{
if(记录器IsLogging(级别错误))
记录器错误(例如消息);
}
返回null;
}
}
/**
*获取带有OCSP验证的编码字节数组。该方法不应引发异常。
*
*@param checkCert to certificate to check
*@param rootCert父证书
*@param url获取验证。它为空,将接受验证
*来自检查证书或其他特定于实现的源
*@返回带有验证的字节数组,如果无法获得验证,则返回null
*/
公共字节[]GetEncoded(X509Certificate checkCert,X509Certificate rootCert,字符串url)
{
尝试
{
basicospresp basicResponse=getbasicospresp(checkCert、rootCert、url);
if(基本应答!=null)
{
SingleResp[]响应=基本响应响应;
if(responses.Length==1)
{
SingleResp resp=响应[0];
对象状态=resp.GetCertStatus();
如果(状态==CertificateStatus.Good)
{
返回basicResponse.GetEncoded();
}
else if(状态为RevokedStatus)
{
抛出新的IOException(MessageLocalization.GetComposedMessage(“ocsp.status.is.reversed”);
}
其他的
{
抛出新IOException(MessageLocalization.GetC
// Once instanciated, this class fires one and only one OCSP request : it keeps the first result in memory.
// You may want to cache this object ; ie with MemoryCache.
public class MyOcspClientBouncyCastleSingleRequest : IOcspClient
{
    private static readonly ILogger LOGGER = LoggerFactory.GetLogger(typeof(OcspClientBouncyCastle));

    private readonly OcspVerifier verifier;

    // The request-result
    private Dictionary<String, BasicOcspResp> _cachedOcspResponse = new Dictionary<string, BasicOcspResp>();

    /**
     * Create default implemention of {@code OcspClient}.
     * Note, if you use this constructor, OCSP response will not be verified.
     */
    [Obsolete]
    public MyOcspClientBouncyCastleSingleRequest()
    {
        verifier = null;
    }

    /**
     * Create {@code OcspClient}
     * @param verifier will be used for response verification. {@see OCSPVerifier}.
     */
    public MyOcspClientBouncyCastleSingleRequest(OcspVerifier verifier)
    {
        this.verifier = verifier;
    }

    /**
     * Gets OCSP response. If {@see OCSPVerifier} was set, the response will be checked.
     */
    public virtual BasicOcspResp GetBasicOCSPResp(X509Certificate checkCert, X509Certificate rootCert, String url)
    {
        String dicKey = checkCert.SubjectDN.ToString() + "-" + rootCert.SubjectDN.ToString() + "-" + url;
        if (_cachedOcspResponse != null && _cachedOcspResponse.Count > 0 && _cachedOcspResponse.ContainsKey(dicKey))
        {
            BasicOcspResp cachedResult = _cachedOcspResponse[dicKey];
            return cachedResult;
        }
        else
        {
            try
            {
                OcspResp ocspResponse = GetOcspResponse(checkCert, rootCert, url);
                if (ocspResponse == null)
                {
                    _cachedOcspResponse.Add(dicKey, null);
                    return null;
                }
                if (ocspResponse.Status != OcspRespStatus.Successful)
                {
                    _cachedOcspResponse.Add(dicKey, null);
                    return null;
                }
                BasicOcspResp basicResponse = (BasicOcspResp)ocspResponse.GetResponseObject();
                if (verifier != null)
                {
                    verifier.IsValidResponse(basicResponse, rootCert);
                }
                _cachedOcspResponse.Add(dicKey, basicResponse);
                return basicResponse;
            }
            catch (Exception ex)
            {
                if (LOGGER.IsLogging(Level.ERROR))
                    LOGGER.Error(ex.Message);
            }
            return null;
        }
    }

    /**
     * Gets an encoded byte array with OCSP validation. The method should not throw an exception.
     *
     * @param checkCert to certificate to check
     * @param rootCert  the parent certificate
     * @param url       to get the verification. It it's null it will be taken
     *                  from the check cert or from other implementation specific source
     * @return a byte array with the validation or null if the validation could not be obtained
     */
    public byte[] GetEncoded(X509Certificate checkCert, X509Certificate rootCert, String url)
    {
        try
        {
            BasicOcspResp basicResponse = GetBasicOCSPResp(checkCert, rootCert, url);
            if (basicResponse != null)
            {
                SingleResp[] responses = basicResponse.Responses;
                if (responses.Length == 1)
                {
                    SingleResp resp = responses[0];
                    Object status = resp.GetCertStatus();
                    if (status == CertificateStatus.Good)
                    {
                        return basicResponse.GetEncoded();
                    }
                    else if (status is RevokedStatus)
                    {
                        throw new IOException(MessageLocalization.GetComposedMessage("ocsp.status.is.revoked"));
                    }
                    else
                    {
                        throw new IOException(MessageLocalization.GetComposedMessage("ocsp.status.is.unknown"));
                    }
                }
            }
        }
        catch (Exception ex)
        {
            if (LOGGER.IsLogging(Level.ERROR))
                LOGGER.Error(ex.Message);
        }
        return null;
    }

    /**
    * Generates an OCSP request using BouncyCastle.
    * @param issuerCert certificate of the issues
    * @param serialNumber   serial number
    * @return   an OCSP request
    * @throws OCSPException
    * @throws IOException
    */
    private static OcspReq GenerateOCSPRequest(X509Certificate issuerCert, BigInteger serialNumber)
    {
        // Generate the id for the certificate we are looking for
        CertificateID id = new CertificateID(CertificateID.HashSha1, issuerCert, serialNumber);

        // basic request generation with nonce
        OcspReqGenerator gen = new OcspReqGenerator();
        gen.AddRequest(id);

        // create details for nonce extension
        IDictionary extensions = new Hashtable();

        extensions[OcspObjectIdentifiers.PkixOcspNonce] = new X509Extension(false, new DerOctetString(new DerOctetString(PdfEncryption.CreateDocumentId()).GetEncoded()));

        gen.SetRequestExtensions(new X509Extensions(extensions));
        return gen.Generate();
    }

    private OcspResp GetOcspResponse(X509Certificate checkCert, X509Certificate rootCert, String url)
    {
        if (checkCert == null || rootCert == null)
            return null;
        if (url == null)
        {
            url = CertificateUtil.GetOCSPURL(checkCert);
        }
        if (url == null)
            return null;
        LOGGER.Info("Getting OCSP from " + url);
        OcspReq request = GenerateOCSPRequest(rootCert, checkCert.SerialNumber);
        byte[] array = request.GetEncoded();

        HttpWebRequest con = (HttpWebRequest)WebRequest.Create(url);
        con.ContentLength = array.Length;
        con.ContentType = "application/ocsp-request";
        con.Accept = "application/ocsp-response";
        con.Method = "POST";
        Stream outp = con.GetRequestStream();
        outp.Write(array, 0, array.Length);
        outp.Close();
        HttpWebResponse response = (HttpWebResponse)con.GetResponse();
        if (response.StatusCode != HttpStatusCode.OK)
            throw new IOException(MessageLocalization.GetComposedMessage("invalid.http.response.1", (int)response.StatusCode));
        Stream inp = response.GetResponseStream();
        OcspResp ocspResponse = new OcspResp(inp);
        inp.Close();
        response.Close();
        return ocspResponse;
    }