2016-11-23 46 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リクエストをしたくないので、それらを「キャッシュ」しなければなりません。

私は(それがC#MemoryCacheに依存している)この種のコードでCRLをキャッシュするために管理:

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に署名する場合は、 'CrlClientOffline'と同様の' OcspClientOffline'を実装したいかもしれません。コードを見てください、それは自明です。 – mkl

+0

ありがとうございます。あなたの解決策はOKです。しかし、OCSPの回答は必ずしも短命ではありません。数分から数日です。私の場合、それは10日間です!だから私はiTextがこの問題のための標準的な解決策を与えるべきだと思う... – AEC

+0

10日間のOCSPの応答?うわー!さて、その場合、私はあなたがキャッシュしたいと理解しています。私は数分以下の生涯しか慣れていない。 – mkl

答えて

1

mlkコメントのおかげで、私はそれを行いました。私はOcspClientBouncyCastleコードに触発された自分のクラスを実装しました。実際、このコードはほんのわずかです。私のクラスはキャッシングを管理します:それはただ1つの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; 
    } 
関連する問題