2016-11-23 9 views
0

서명 된 PDF를 생성하기 위해 iTextSharp 5.5.10을 사용하고 있습니다. 특히 LTV 서명이 필요합니다. LTV는 CRL 및 OCSP 요청으로 수행 할 수 있습니다.어떻게 iTextSharp (LTV 서명)로 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); 

문제는 : 난 (동일한 인증서와 함께 항상) 많은, 많은 PDF에 서명하고있다. 그래서, 나는 CRL과 OCSP 요청을 매번 만들고 싶지 않다. 나는 그들을 "캐쉬 (cache)"해야한다.

나는 이러한 종류의 코드 (이 C# MemoryCache에 의존)으로 CRL을 캐시 관리 : 나는 그러나 OCSP 응답을 캐시 할 수있는 솔루션을 찾을 수 없습니다

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

. 아무도 단서가 있습니까?

+0

OCSP 응답은 일반적으로 살 수있는 단지 아주 짧은 시간이있다. 따라서 일반적으로 캐싱은 가치가 없습니다. 짧은 시간 내에 매우 많은 PDF에 서명하는 경우,'CrlClientOffline'와 비슷한'OcspClientOffline'을 구현하는 것이 좋습니다. 코드를 보아라, 그것은 사소하다. – 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; 
    }