2017-11-03 27 views
0

내 웹 사이트에서 요청이있을 때 pdf 문서에 서명하는 wcf 웹 서비스가 있습니다. 모든 것은 개발 중에 문서를 거의 사인하지 않으려 고 현지에서 잘 작동합니다. 오류 N : 내 코드는 프로덕션 환경에 배포 된 후에는 몇 시간 동안 잘 작동했지만 갑자기 시작 수신 오류 N 48 N (224)Ncrytoki 오류 n 48 & 224

메시지 다음에

. 48 자료 : NCryptoki 스택 추적 : Cryptware.NCryptoki.Session.Sign에서 (바이트 [] 데이터) iTextSharp.text.pdf.security.MakeSignature.SignDetached (PdfSignatureAppearance 수액, IExternalSignature externalSignature 에서, 1은 ICollection 1 chain, ICollection crlList, IOcspClient ocspClient , ITSAClient tsaClient, Int32 estimatedSize, CryptoStandard sigtype)

메시지 : 오류 n. 224 자료 : NCryptoki 스택 추적 : Cryptware.NCryptoki.Session.Sign에서 (바이트 [] 데이터) iTextSharp.text.pdf.security.MakeSignature.SignDetached (PdfSignatureAppearance 수액, IExternalSignature externalSignature 에서, 1은 ICollection 1 chain, ICollection crlList, IOcspClient ocspClient , ITSAClient tsaClient, INT32 estimatedSize, CryptoStandard의 sigtype)

나는 일이있을 수 있는지 이해하는 데 어려움을 겪고 그리고 난 로컬이 문제를 복제 할 수있는 방법을 그래서 난 그것을 해결하기 위해 시도 할 수 있습니다. 나는로드 문제가 될 수 있다고 생각했지만 로그 서버에 따르면 분당 4-5 건의 요청 만 서명했다.

다음은 내 서명 코드 스 니펫입니다. 정적

1)

public void TestSignPDF() 
    { 

     string fileName = Guid.NewGuid().ToString(); 
     String src = @"C:\tmp\singlepage.pdf"; 
     String DEST = string.Format(@"C:\tmp\{0}.pdf", fileName); 

     MemoryStream ms = new MemoryStream(); 

     FileStream file = new FileStream(src, FileMode.Open, FileAccess.Read); 
     byte[] bytes = new byte[file.Length]; 
     file.Read(bytes, 0, (int)file.Length); 
     ms.Write(bytes, 0, (int)file.Length); 
     file.Close(); 
     ms.Seek(0, SeekOrigin.Begin); 

     HSMSignDocument x = new HSMSignDocument(); 
     Stream result = x.SignDocument(ms, "334", fileName); 

     if (result != null) 
     { 
      FileStream file2 = new FileStream(DEST, FileMode.Create, System.IO.FileAccess.Write); 
      byte[] bytes2 = new byte[result.Length]; 
      result.Read(bytes2, 0, (int)result.Length); 
      file2.Write(bytes2, 0, bytes2.Length); 
      file2.Close(); 
      result.Close(); 
     } 

     ms.Close(); 
    } 

2.

WCF의 SOAP 액션) HSMSignDocument 클래스()

public class HSMSignDocument : IDisposable 
{ 
    private static Cryptoki cryptoki = null; 
    private static Session session = null; 
    private static NLogger LOGGER = new NLogger(); 
    private static readonly string HSMPartitionPwd = ConfigurationManager.AppSettings["HSMPartitionPassword"]; 

    private string TIME_STAMPING_SERVER_URL = "xx"; 
    private string TIME_STAMPING_SERVER_ACCOUNT = "xx"; 
    private string TIME_STAMPING_SERVER_PASSWORD = "xx"; 


    static HSMSignDocument() 
    { 
     Cryptoki.Licensee = "xxx"; 
     Cryptoki.ProductKey = "xxx"; 

     if (cryptoki == null) 
     { 
      cryptoki = new Cryptoki(); 
      cryptoki.Attach(@"C:\Program Files\SafeNet\LunaClient\cryptoki.dll"); 
      cryptoki.Initialize(); 
     } 

     if (session == null) 
     { 
      // Reads the set of slots containing a token 
      SlotList slots = cryptoki.Slots; 
      if (slots.Count == 0) 
      { 
       LOGGER.Error("slots.Count == 0, no slots available"); 
       return; 
      } 

      // Gets the first slot available 
      Slot slot = slots[0]; 
      if (!slot.IsTokenPresent) 
      { 
       LOGGER.Error("!slot.IsTokenPresent, no tokens present"); 
       return;; 
      } 

      // Gets the first token available 
      Token token = slot.Token; 

      // Opens a read/write serial session 
      session = token.OpenSession(Session.CKF_SERIAL_SESSION | Session.CKF_RW_SESSION, null, null); 

      int nRes = session.Login(Session.CKU_USER, HSMPartitionPwd); 
      if (nRes != 0) 
      { 
       LOGGER.Error("Could not login to Session"); 
      } 
     } 
    } 

    private IList<Org.BouncyCastle.X509.X509Certificate> GetKeyChain() 
    { 
     //Private key pointers have been installed in 
     X509Store x509Store = new X509Store(StoreName.My, StoreLocation.LocalMachine); 

     x509Store.Open(OpenFlags.ReadOnly); 
     X509Certificate2Collection certificates = x509Store.Certificates; 
     IList<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>(); 
     X509Certificate2 pk = null; 

     string HSMCertSerialNumber = ConfigurationManager.AppSettings["HSMCertificateSerialNumber"]; 

     if (certificates.Count > 0) 
     { 
      foreach (X509Certificate2 mCert in x509Store.Certificates) 
      { 
       //GETS THE KEY WE ARE LOOKING - Private key for HSM 
       if (String.Compare(mCert.SerialNumber, HSMCertSerialNumber, true) == 0) 
       { 
        pk = mCert; 
        break; 
       } 
      } 

      X509Chain x509chain = new X509Chain(); 
      x509chain.Build(pk); 

      foreach (X509ChainElement x509ChainElement in x509chain.ChainElements) 
      { 
       // Build up root chain 
       chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate)); 
      } 
     } 

     x509Store.Close(); 

     return chain; 
    } 

    public bool ApplySignatureDetails(Session session, String alias, Stream inputFile, string tempWorkingFile) 
    { 
     IList<Org.BouncyCastle.X509.X509Certificate> chain = GetKeyChain(); 

     // creates a TSA client(Time Stampingserver) 
     ITSAClient timeStampingClient = new TSAClientBouncyCastle(TIME_STAMPING_SERVER_URL, TIME_STAMPING_SERVER_ACCOUNT, TIME_STAMPING_SERVER_PASSWORD); 

     IOcspClient ocspClient = new OcspClientBouncyCastle(); // Online Certificate Status Protocol - adobe requirement 
     List<ICrlClient> crlList = new List<ICrlClient>(); //revocation list - adobe requirement 
     crlList.Add(new CrlClientOnline(chain)); 

     return PKCS11Signer.Sign(inputFile, String.Format(tempWorkingFile, alias), chain, session, alias, DigestAlgorithms.SHA256, CryptoStandard.CMS, "Doc Signed", "My Company", crlList, ocspClient, timeStampingClient, 0); 
    } 


    void IDisposable.Dispose() 
    { 
     if (session != null) 
     { 
      session.Logout(); 
      session.Close(); 
      session = null; 
     } 
     if (cryptoki != null) 
     { 
      cryptoki.Finalize(IntPtr.Zero); 
      cryptoki = null; 
     } 
    } 
} 

3) PKCS11Signer 클래스

class PKCS11Signer 
{ 
    private static NLogger LOGGER = new NLogger(); 

    private static Semaphore Bouncer { get; set; } 

    public static bool Sign(Stream inputFile, String dest, ICollection<Org.BouncyCastle.X509.X509Certificate> chain, Session session, String alias, 
        String digestAlgorithm, CryptoStandard subfilter, String reason, String location, 
        ICollection<ICrlClient> crlList, IOcspClient ocspClient, ITSAClient tsaClient, int estimatedSize) 
    { 

     // Creating the reader and the stamper 
     PdfReader reader = null; 
     PdfStamper stamper = null; 
     FileStream outputStream = null; 

     try 
     { 

      if (Bouncer == null) 
      { 
       Bouncer = new Semaphore(1, 1); 
      } 

      Bouncer.WaitOne(); 
      LOGGER.Info("Start Actual Signing"); 
      reader = new PdfReader(inputFile); 

      outputStream = new FileStream(dest, FileMode.Create, FileAccess.Write); 
      stamper = PdfStamper.CreateSignature(reader, outputStream, '\0'); 
      LOGGER.Info("PDFStamper Created"); 

      // Creating the appearance 
      PdfSignatureAppearance appearance = stamper.SignatureAppearance; 

      LOGGER.Info("PdfSignatureAppearance Created"); 

      appearance.Reason = reason; 
      appearance.Location = location; 

      //Uncomment to show signiture text 
      //appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(56, 128, 164, 160), 1, "signature"); 


      appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED; 
      LOGGER.Info("PdfSignatureAppearance Created"); 

      // Creating the signature 
      IExternalSignature pks = new PrivateKeySignature(session, alias); 
      LOGGER.Info("Encryption algorithm " + pks.GetEncryptionAlgorithm()); 
      LOGGER.Info("Hash algorithm " + pks.GetHashAlgorithm()); 
      LOGGER.Info("Hash code " + pks.GetHashCode()); 
      LOGGER.Info("pks : " + pks.ToString()); 


      LOGGER.Info("IExternalSignature Created perform sign"); 
      MakeSignature.SignDetached(appearance, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter); 
      //System.Threading.Thread.Sleep(1000); //Globalsign requirement 

      LOGGER.Info("MakeSignature.SignDetached Completed"); 
     } 
     catch (Exception ex) 
     { 
      LOGGER.Error(ex); 
      throw ex; 
     } 
     finally 
     { 
      Bouncer.Release(); 
      if (stamper != null) 
       stamper.Close(); 
      if (reader != null) 
       reader.Close(); 
      if (outputStream != null) 
       outputStream.Close(); 
      if (inputFile != null) 
       inputFile.Close(); 
     } 
     return true; 
    } 
} 

}

4.) PrivateKeySignature 클래스

class PrivateKeySignature : IExternalSignature 
{ 

    private static NLogger LOGGER = new NLogger(); 
    private static ObjectCache cache = MemoryCache.Default; 

    private readonly Session session; 
    RSAPrivateKey privateKey; 

    public PrivateKeySignature(Session session, String alias) 
    { 
     string HSMPrivateKeyCertReq = ConfigurationManager.AppSettings["HSMPrivateKeyCertReq"]; 
     this.session = session; 
     LOGGER.Info("Starting to get PrivateKeySignature"); 
     CryptokiCollection pkobjects = findTarget(session, HSMPrivateKeyCertReq); 

     LOGGER.Info("Search session for private key using template"); 

     foreach(var keyObject in pkobjects) 
     { 
      LOGGER.Info("RSA/CertReq:" + HSMPrivateKeyCertReq); 
      privateKey = (RSAPrivateKey)keyObject; 
     } 

     if (privateKey == null) 
     { 
      throw new Exception("privateKey not found"); 
     } 

     LOGGER.Info("Private Key Found"); 
    } 

    public String GetHashAlgorithm() 
    { 
     return "SHA1"; 
    } 

    public String GetEncryptionAlgorithm() 
    { 
     return "RSA"; 
    } 

    public byte[] Sign(byte[] message) 
    { 
     LOGGER.Info("Start apply Private Key"); 
     session.SignInit(Mechanism.SHA1_RSA_PKCS, privateKey); 
     LOGGER.Info("End apply Private Key"); 
     return session.Sign(message); 
    } 

    public CryptokiCollection findTarget(Session session, string label) 
    { 
     if (cache.Contains(label)) 
     { 
      return (CryptokiCollection)cache.Get(label); 
     } 
     else 
     { 
      CryptokiCollection template = new CryptokiCollection(); 

      template.Add(new ObjectAttribute(ObjectAttribute.CKA_LABEL, label)); 
      template.Add(new ObjectAttribute(ObjectAttribute.CKA_CLASS, CryptokiObject.CKO_PRIVATE_KEY)); 
      template.Add(new ObjectAttribute(ObjectAttribute.CKA_KEY_TYPE, Key.CKK_RSA)); 

      var pk = session.Objects.Find(template, 1); 

      // Store data in the cache 
      CacheItemPolicy cacheItemPolicy = new CacheItemPolicy(); 
      cacheItemPolicy.SlidingExpiration = TimeSpan.FromHours(4); 
      cache.Add(label, pk, cacheItemPolicy); 

      return pk; 
     } 
    } 
} 

은}

답변

1

NCryptoki는 기본 PKCS # 11 모듈에서 오류를 다시 반환합니다.

는 PKCS # 11 오류 목록은 여기

이다 :

224 (0xE0)을 의미

동안 CKR_DEVICE_ERROR : 케이스 48 (0x30의)에서

http://wiki.ncryptoki.com/How-NCryptoki-manages-PKCS-11-errors.ashx

수단 CKR_TOKEN_NOT_PRESENT을

생산 HSM에 구성 문제가있는 것으로 보입니다.

+0

I PrivateKeySignature 클래스에있는 개인 키 캐싱 - findTarget. 이로 인해 문제가 발생했을 수 있습니까? 내가 목표물을 찾으려고 할 때 1 초 이상 걸리면 서명이 추가됩니다. 이 작업을 수행하는 더 좋은 방법이 있습니까? – user1754675

+0

캐싱은 문제와 관련이 없다고 생각합니다. 어떻게 목표물을 찾으십니까? –

+0

PrivateKeySignature 클래스에는 FindTarget 메서드가 있습니다. – user1754675