2016-11-23 23 views
0

Ich benutze iTextSharp 5.5.10, um signierte PDF zu generieren. Insbesondere brauche ich die LTV-Signatur. LTV kann mit CRL- und OCSP-Anfragen durchgeführt werden.Wie könnte ich OCSP-Antwort mit iTextSharp (LTV-Signatur) zwischenspeichern?

Ich habe es mit einem solchen Code:

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

Das Problem ist: Ich bin der Unterzeichnung viele, viele PDF (immer mit dem gleichen Zertifikat). Also, ich möchte nicht jedes Mal CRL und OCSP Anfrage machen, ich muss sie "cachen".

ich es geschafft, die CRL mit dieser Art von Code cachen (es basiert auf C# Memory):

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

ich aber nicht jede Lösung cachen Antworten OCSP finden. Hat jemand eine Ahnung?

+0

OCSP-Antworten haben in der Regel nur eine sehr kurze Zeit zu leben. Daher ist es normalerweise nicht sinnvoll, sie zwischenzuspeichern. Wenn Sie sehr viele PDFs in kurzer Zeit signieren, sollten Sie eine "OcspClientOffline" ähnlich der "CrlClientOffline" implementieren. Schau dir den Code an, es ist trivial. – mkl

+0

Danke. Deine Lösung ist in Ordnung. OCSP-Antworten sind jedoch nicht immer von kurzer Dauer: ein paar Minuten bis zu einigen Tagen. In meinem Fall sind es 10 Tage! Also ich denke, iText sollte uns eine Standardlösung für dieses Problem geben ... – AEC

+0

10 Tage OCSP Antworten? Beeindruckend! Ok, in diesem Fall verstehe ich, dass du cachen willst. Ich bin nur an Lebenszeiten von nicht mehr als ein paar Minuten gewöhnt. – mkl

Antwort

1

Dank mlk Kommentar, ich habe es geschafft: Ich habe meine eigene Klasse, inspiriert von OcspClientBouncyCastle Code implementiert. Der Code ist tatsächlich trivial. Meine Klasse verwaltet das Caching: Es sendet nur eine OCSP-Anfrage. Das ist der gute Weg, um das Zeug zu machen.

Beispielcode:

// 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; 
    } 
Verwandte Themen