2016-11-23 4 views
0

Я использую iTextSharp 5.5.10 для создания подписанного PDF. В частности, мне нужна подпись LTV. LTV может выполняться с запросами CRL и OCSP.Как я могу кэшировать ответ OCSP с помощью iTextSharp (подпись LTV)?

Я сделал это с таким кодом:

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); 

Проблема заключается в том: я буду подписывать много, много PDF (всегда с тем же сертификатом). Поэтому я не хочу каждый раз запрашивать CRL и OCSP, я должен «кэшировать» их.

мне удалось кэшировать CRL с таким кодом (он опирается на C# MemoryCache):

private List<ICrlClient> GetCachedListCrlClient() 
{ 
    var key = "LstCrlClient"; 

    List<ICrlClient> lstCrlClients = MyGlobalCachingProvider.GetItem<List<ICrlClient>>(key); 
    if (lstCrlClients == null) 
    {   
     lstCrlClients = new List<ICrlClient>(); 
     for (int i = 0; i < myCert.Chain.Length; i++) 
     { 
      String crlUrl = CertificateUtil.GetCRLURL(myCert.Chain[i]); 
      if (crlUrl != null) 
      { 
       byte[] crlDownloaded = new System.Net.WebClient().DownloadData(crlUrl); 
       ICrlClient crlClient = new CrlClientOffline(crlDownloaded); 
       lstCrlClients.Add(crlClient); 
      } 
     } 
     MyGlobalCachingProvider.AddItem(key, lstCrlClients, DateTime.Now.AddHours(2)); 
    } 

    return lstCrlClients; 
} 

я не могу найти какое-либо решение, однако для кэширования ответов OCSP. Кто-нибудь знает?

+0

OCSP ответы, как правило, имеют лишь очень короткое время, чтобы жить. Таким образом, обычно кэширование их не стоит. Если вы подписываете очень много PDF-файлов за короткое время, вы можете захотеть реализовать «OcspClientOffline», аналогичный «CrlClientOffline». Взгляните на код, это тривиально. – mkl

+0

Спасибо. Ваше решение в порядке. Однако ответы OCSP не всегда недолговечны: от нескольких минут до нескольких дней. В моем случае это 10 дней! Поэтому я думаю, что iText должен дать нам стандартное решение для этой проблемы ... – AEC

+0

10 дней ответов OCSP? Вау! Хорошо, в этом случае я понимаю, что вы хотите кэшировать. Я использую только время жизни не более нескольких минут. – mkl

ответ

1

Благодаря комментарию 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; 
    } 

 Смежные вопросы

  • Нет связанных вопросов^_^