2017-09-27 5 views
2

HSM에 저장된 인증서를 사용하여 XML 서명의 일부 데모를 구현하려고합니다.HSM에 저장된 개인 키를 SignedXml.SigningKey C로 변환 할 수 있습니다.

이 링크에서 흥미로운 예제를 발견했습니다 : Sign XML Document with X509Certificate2 그리고 PKCS11Interop wrapper가있는 HSM 내부의 인증서와 키를 사용하도록 수정되었습니다.

그러나 사람이 나에게 제안 또는 예제를 줄 수있는 외부 링크 위의 예에서

private static void SignXmlWithCertificate(XmlDocument xmlDoc, X509Certificate2 cert, Session session, String alias) 
     { 
      SignedXml signedXml = new SignedXml(xmlDoc); 

      List<ObjectAttribute> template = new List<ObjectAttribute>(); 
      template.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY)); 
      template.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)); 
      template.Add(new ObjectAttribute(CKA.CKA_LABEL, alias)); 
      List<ObjectHandle> foundObjects = session.FindAllObjects(template); 
      ObjectHandle privateKey = foundObjects[0]; 

      signedXml.SigningKey = privateKey; //Here is where I stuck. 

을 SignedXML.SigningKey하는 HSM에서 ObjectHandle의 PrivateKey를 변환합니다. 그들은 개인 키를 결합한 인증서를 사용합니다. 그런 다음 그들은 이렇게 사용할 수 있습니다.

signedXml.SigningKey = cert.PrivateKey; 

그러나 사용중인 인증서에 개인 키의 내용이 없습니다. 제게 제안 해주세요.

답변

0

System.Security.Cryptography.RSA 클래스에서 상속 된 사용자 지정 클래스를 구현하고 해당 구현에서 Pkcs11Interop을 사용하고 사용자 지정 클래스의 인스턴스를 SigningKey으로 사용해야합니다.

당신은 스스로를 구현하거나 PKCS # 11 기반 X.509 인증서 저장소를 사용하기 쉽게 제공하고 System.Security.Cryptography.RSA 클래스에서 상속 Pkcs11RsaProvider 클래스가 포함 Pkcs11Interop.X509Store 라이브러리를 사용할 수 있습니다. SignedXml 클래스의 사용법을 보여주는 code sample도 있습니다.

+0

안녕 Jariq, 당신은 내가 RSA 클래스 바로 같은 모든 속성과 메서드로 새로운 상속 클래스를 만들 필요가 의미 를 확인하기 위해? 어디에 개인 키를 넣을 수 있습니까? 좀 더 안내하거나 간단한 샘플 코드를 제공해주십시오. – ktikar

+0

@ktikar 예. 상속 된 클래스를 생성해야합니다. 가장 중요한 부분은'SignHash' 메소드를 오버라이드하고 Pkcs11Interop으로 구현하는 것입니다. 그런 구현으로 독립형 라이브러리를 출시 할 계획이지만 현재 다른 유료 프로젝트로 바쁘다. – jariq

+0

제안 해 주셔서 감사합니다. 시도해 볼게. – ktikar

1

는이

public class CustomSignedXml: SignedXml 
    { 
    public CustomSignedXml(XmlDocument xmlDoc):base(xmlDoc) 
    { 
    } 
    internal void ComputeSignature(ISignerProvider signerProvider) 
    { 
     var methodInfo = typeof (SignedXml).GetMethod("BuildDigestedReferences", 
      BindingFlags.Instance | BindingFlags.NonPublic); 
     methodInfo.Invoke(this, null); 
     SignedInfo.SignatureMethod = XmlDsigRSASHA1Url; 
     // See if there is a signature description class defined in the Config file 
     SignatureDescription signatureDescription = 
      CryptoConfig.CreateFromName(SignedInfo.SignatureMethod) as SignatureDescription; 
     if (signatureDescription == null) 
      throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated"); 

     var hashAlg = signatureDescription.CreateDigest(); 
     if (hashAlg == null) 
      throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed"); 
     var methodInfo2 = typeof (SignedXml).GetMethod("GetC14NDigest", BindingFlags.Instance | BindingFlags.NonPublic); 
     var hashvalue = (byte[]) methodInfo2.Invoke(this, new object[] {hashAlg}); 

     m_signature.SignatureValue = signerProvider.Sign(hashvalue); 
    } 
} 

처럼 System.Security.Cryptography.Xml.SignedXml로부터 상속 한 사용자 정의 클래스를 구현해야하고이

public class Pkcs11SignerProvider : ISignerProvider 
{ 
    private string _thumbprint; 
    public string DllPath { get; set; } 
    public string TokenSerial { get; set; } 
    public string TokenPin { get; set; } 
    public string PrivateKeyLabel { get; set; } 

    public Pkcs11SignerProvider(string dllPath, string tokenSerial, string tokenPin, string privateKeyLabel) 
    { 
     DllPath = dllPath; 
     TokenSerial = tokenSerial; 
     TokenPin = tokenPin; 
     PrivateKeyLabel = privateKeyLabel; 
    } 

    public byte[] Sign(byte[] data) 
    { 
     using (var pkcs11 = new Pkcs11(DllPath, AppType.SingleThreaded)) 
     { 

      var slots = pkcs11.GetSlotList(SlotsType.WithTokenPresent); 
      var slot = slots.FirstOrDefault(slot1 => slot1.GetTokenInfo().SerialNumber == TokenSerial); 
      if (slot == null) 
       throw new Exception("there is no token with serial " + TokenSerial); 
      using (var session = slot.OpenSession(SessionType.ReadOnly)) 
      { 
       session.Login(CKU.CKU_USER, TokenPin); 

       var searchTemplate = new List<ObjectAttribute> 
       { 
        new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY), 
        new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA) 
       }; 
       if (!string.IsNullOrEmpty(PrivateKeyLabel)) 
        searchTemplate.Add(new ObjectAttribute(CKA.CKA_LABEL, PrivateKeyLabel)); 

       var foundObjects = session.FindAllObjects(searchTemplate); 
       var privateKey = foundObjects.FirstOrDefault(); 

       using (var mechanism = new Mechanism(CKM.CKM_RSA_PKCS)) 
       { 
        return session.Sign(mechanism, privateKey, data); 
       } 

      } 

     } 
    } 

} 
처럼 Pkcs11Interop하여 구현 다음이

public interface ISignerProvider 
{ 
    byte[] Sign(byte[] data); 
} 

같은 인터페이스를 작성해야

다음이 메소드를 호출하여 xml에 서명합니다.

public static void Sign(XmlDocument xmlDoc, ISignerProvider signerProvider) 
    { 
     if (xmlDoc == null) 
      throw new ArgumentException("xmlDoc"); 
     if (xmlDoc.DocumentElement == null) 
      throw new ArgumentException("xmlDoc.DocumentElement"); 
     var signedXml = new CustomSignedXml(xmlDoc); 
     var reference = new Reference { Uri = "" }; 
     var env = new XmlDsigEnvelopedSignatureTransform(); 
     reference.AddTransform(env); 
     signedXml.AddReference(reference); 
     signedXml.ComputeSignature(signerProvider); 
     var xmlDigitalSignature = signedXml.GetXml(); 
     xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true)); 
    } 

이 코드는

 public static bool Verify(XmlDocument document, X509Certificate2 certificate) 
    { 
     // Check arguments. 
     if (document == null) 
      throw new ArgumentException("Doc"); 
     if (certificate == null) 
      throw new ArgumentException("Key"); 

     // Create a new SignedXml object and pass it 
     // the XML document class. 
     var signedXml = new SignedXml(document); 

     // Find the "Signature" node and create a new 
     // XmlNodeList object. 
     var nodeList = document.GetElementsByTagName("Signature"); 

     // Throw an exception if no signature was found. 
     if (nodeList.Count <= 0) 
     { 
      throw new CryptographicException("Verification failed: No Signature was found in the document."); 
     } 

     // This example only supports one signature for 
     // the entire XML document. Throw an exception 
     // if more than one signature was found. 
     if (nodeList.Count >= 2) 
     { 
      throw new CryptographicException("Verification failed: More that one signature was found for the document."); 
     } 

     // Load the first <signature> node. 
     signedXml.LoadXml((XmlElement)nodeList[0]); 

     return signedXml.CheckSignature(certificate, true); 
    } 
+0

안녕 Gholamreza, 정말 친절하게 도와 주셔서 감사합니다. 시도해 볼게. – ktikar