2011-03-31 86 views
9

当我签署包含名称空间前缀 和名称空间引用的XML文档并验证它时,会发生此问题。在这种情况下,验证总是失败 (返回false)。当我从XML中删除名称空间前缀和名称空间引用时,签名和验证工作正常。使用SignedXml自定义名称空间的问题

你能帮我吗?

这里是我的代码:从SignedXml

namespace Xmldsig 
{ 
    using System; 
    using System.Security.Cryptography; 
    using System.Security.Cryptography.Xml; 
    using System.Xml; 

    public sealed class SignaturePropertiesSignedXml : SignedXml 
    { 
     private XmlDocument doc; 
     private XmlElement signaturePropertiesRoot; 
     private XmlElement qualifyingPropertiesRoot; 

     private string signaturePropertiesId; 

     public SignaturePropertiesSignedXml(XmlDocument doc) 
      : base(doc) 
     { 
      return; 
     } 

     public SignaturePropertiesSignedXml(XmlDocument doc, string signatureId, string propertiesId) 
      : base(doc) 
     { 
      this.signaturePropertiesId = propertiesId; 
      this.doc = null; 
      this.signaturePropertiesRoot = null; 
      if (string.IsNullOrEmpty(signatureId)) 
      { 
       throw new ArgumentException("signatureId cannot be empty", "signatureId"); 
      } 
      if (string.IsNullOrEmpty(propertiesId)) 
      { 
       throw new ArgumentException("propertiesId cannot be empty", "propertiesId"); 
      } 

      this.doc = doc; 
      base.Signature.Id = signatureId; 

      this.qualifyingPropertiesRoot = doc.CreateElement("QualifyingProperties", "http://www.w3.org/2000/09/xmldsig#"); 
      this.qualifyingPropertiesRoot.SetAttribute("Target", "#" + signatureId); 

      this.signaturePropertiesRoot = doc.CreateElement("SignedProperties", "http://www.w3.org/2000/09/xmldsig#"); 
      this.signaturePropertiesRoot.SetAttribute("Id", propertiesId); 


      qualifyingPropertiesRoot.AppendChild(signaturePropertiesRoot); 
      DataObject dataObject = new DataObject 
      { 
       Data = qualifyingPropertiesRoot.SelectNodes("."), 
       Id = "idObject" 
      }; 
      AddObject(dataObject); 


     } 

     public void AddProperty(XmlElement content) 
     { 
      if (content == null) 
      { 
       throw new ArgumentNullException("content"); 
      } 

      XmlElement newChild = this.doc.CreateElement("SignedSignatureProperties", "http://www.w3.org/2000/09/xmldsig#"); 

      newChild.AppendChild(content); 
      this.signaturePropertiesRoot.AppendChild(newChild); 
     } 

     public override XmlElement GetIdElement(XmlDocument doc, string id) 
     { 
      if (String.Compare(id, signaturePropertiesId, StringComparison.OrdinalIgnoreCase) == 0) 
       return this.signaturePropertiesRoot;    

      if (String.Compare(id, this.KeyInfo.Id, StringComparison.OrdinalIgnoreCase) == 0) 
       return this.KeyInfo.GetXml(); 

      return base.GetIdElement(doc, id); 
     } 
    } 
} 

的类签名XML

namespace Xmldsig 
{ 
    using System; 
    using System.Collections.Generic; 
    using System.ComponentModel; 
    using System.Data; 
    using System.Linq; 
    using System.Text; 
    using System.Windows.Forms; 
    using System.Xml; 
    using System.IO; 
    using System.Security.Cryptography; 
    using System.Security.Cryptography.Xml; 
    using System.Security.Cryptography.X509Certificates; 
    using Security.Cryptography; 
    using System.Security.Principal; 
    using System.Collections; 

    public class VerifyResult 
    { 
     public string Timestamp { get; set; } 
     public X509Certificate2 SigningCertificate { get; set; } 
    } 

    public class XmldsigClass 
    { 
     public static XmlDocument SignDocument(XmlDocument doc, string RefUri) 
     { 
      string idSignProperties = "idSignedProperties"; 
      SignaturePropertiesSignedXml signer = new SignaturePropertiesSignedXml(doc, "Uzb_sig_v001", idSignProperties); 

      X509Certificate2 cert = GetCertificate(); 

      RSA key = (RSACryptoServiceProvider)cert.PrivateKey; 
      signer.SigningKey = key; 
      signer.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#"; 
      signer.SignedInfo.SignatureMethod = @"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; 

      // create a timestamp property 
      XmlElement timestamp = doc.CreateElement("SigningTime", SignedXml.XmlDsigNamespaceUrl); 
      timestamp.InnerText = DateTimeToCanonicalRepresentation(); 
      signer.AddProperty(timestamp); 


      var certificateKeyInfo = new KeyInfo(); 
      certificateKeyInfo.Id = "idKeyInfo"; 
      certificateKeyInfo.AddClause(new KeyInfoX509Data(cert)); 
      signer.KeyInfo = certificateKeyInfo; 

      Reference reference = new Reference(RefUri); 
      reference.DigestMethod = @"http://www.w3.org/2001/04/xmlenc#sha256"; 
      reference.AddTransform(new XmlDsigEnvelopedSignatureTransform()); 
      signer.AddReference(reference); 


      Reference propertiesRefki = new Reference(); 
      propertiesRefki.Uri = "#idKeyInfo"; 
      propertiesRefki.DigestMethod = @"http://www.w3.org/2001/04/xmlenc#sha256"; 
      signer.AddReference(propertiesRefki); 

      Reference reference2 = new Reference(); 
      reference2.Uri = "#" + idSignProperties; 
      reference2.DigestMethod = @"http://www.w3.org/2001/04/xmlenc#sha256"; 
      signer.AddReference(reference2); 


      signer.ComputeSignature();    

      doc.DocumentElement.AppendChild(signer.GetXml()); 

      return doc; 
     } 


     public static bool CheckSignature(XmlDocument xmlDoc) 
     { 
      SignedXml signedXml = new SignedXml(xmlDoc); 
      XmlNodeList elementsByTagName = xmlDoc.GetElementsByTagName("Signature"); 
      signedXml.LoadXml((XmlElement)elementsByTagName[0]); 
      bool sigCheck = signedXml.CheckSignature(); 

      return sigCheck; 
     } 

     private static X509Certificate2 GetCertificate() 
     { 

      X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser); 
      store.Open(OpenFlags.ReadOnly); 
      X509Certificate2 card = null; 
      foreach (X509Certificate2 cert in store.Certificates) 
      { 
       if (!cert.HasPrivateKey) continue; 
       AsymmetricAlgorithm aa = cert.PrivateKey; 
       ICspAsymmetricAlgorithm caa = aa as ICspAsymmetricAlgorithm; 
       if (caa == null) continue; 
       if (caa.CspKeyContainerInfo.HardwareDevice) 
       { 
        card = cert; 
        break; 
       } 
      } 
      store.Close(); 

      return card; 
     } 

     private static string DateTimeToCanonicalRepresentation() 
     { 
      var ahora = DateTime.Now.ToUniversalTime(); 
      return ahora.Year.ToString("0000") + "-" + ahora.Month.ToString("00") + 
        "-" + ahora.Day.ToString("00") + 
        "T" + ahora.Hour.ToString("00") + ":" + 
        ahora.Minute.ToString("00") + ":" + ahora.Second.ToString("00") + 
        "Z"; 
     } 
    }  
} 

在这里,我打电话签名方法

继承类

 XmlDocument xmlDoc = new XmlDocument(); 
     xmlDoc.PreserveWhitespace = true; 
     if (openFileDialog1.ShowDialog() == DialogResult.OK) 
     { 
      xmlDoc.Load(openFileDialog1.FileName); 

      XmlDocument resxml = Xmldsig.XmldsigClass.SignDocument(xmlDoc, "#Uzb_doc_v001"); 


      var name = openFileDialog1.FileName + ".xml"; 
      xmlDoc.Save(name); 

      var bytes = System.IO.File.ReadAllBytes(name); 
      System.IO.File.WriteAllBytes(name, bytes.Skip(3).ToArray()); 
      MessageBox.Show("Signed"); 
     } 

而对于验证

 XmlDocument xmlDoc = new XmlDocument(); 
     xmlDoc.PreserveWhitespace = true; 
     if (openFileDialog1.ShowDialog() == DialogResult.OK) 
     { 
      xmlDoc.Load(openFileDialog1.FileName); 

      bool b = Xmldsig.XmldsigClass.CheckSignature(xmlDoc); 

      MessageBox.Show(b.ToString()); 
     } 

这里是我的签名的XML

<?xml version="1.0" encoding="utf-8" standalone="no"?> 
<uz:CreditcardEnveloppe xmlns:uz="http://aaaa.com/CreditcardEnveloppe/transport" Id="Uzb_doc_v001" Version="1.0"> 
    <uz:creditcard> 
    <uz:number>19834209</uz:number> 
    <uz:expiry>02/02/2002</uz:expiry> 
    </uz:creditcard> 
    <Signature Id="sig_v001" xmlns="http://www.w3.org/2000/09/xmldsig#"> 
    <SignedInfo> 
     <CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> 
     <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" /> 
     <Reference URI="#Uzb_doc_v001"> 
     <Transforms> 
      <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> 
     </Transforms> 
     <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> 
     <DigestValue>RnpNXyhxQcjr/SWqVlWY31S1xpj2opZhlsT4d1iyBKI=</DigestValue> 
     </Reference> 
     <Reference URI="#idKeyInfo"> 
     <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> 
     <DigestValue>O0Z2BU5ODwgOZOhpFvkcSaO/jmWFykBwnxMUD5a5SwM=</DigestValue> 
     </Reference> 
     <Reference URI="#idSignedProperties"> 
     <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" /> 
     <DigestValue>UVjk8Jkq0Y6OxFqiB4q/4vqli/KJT5pYEPzlNTkfIhY=</DigestValue> 
     </Reference> 
    </SignedInfo> 
    <SignatureValue>prOZXn..</SignatureValue> 
    <KeyInfo Id="idKeyInfo"> 
     <X509Data> 
     <X509Certificate>MIIE7TCCA9WgAwIBAgISESBS...</X509Certificate> 
     </X509Data> 
    </KeyInfo> 
    <Object Id="idObject"> 
     <QualifyingProperties Target="#sig_v001"> 
     <SignedProperties Id="idSignedProperties"> 
      <SignedSignatureProperties> 
      <SigningTime>2011-03-30T06:01:48Z</SigningTime> 
      </SignedSignatureProperties> 
     </SignedProperties> 
     </QualifyingProperties> 
    </Object> 
    </Signature> 
</uz:CreditcardEnveloppe> 

谢谢提前!

+1

你能提供的'X509Certificate'和'SignatureValue'标签的完整内容,所以我们可以测试它? – 2011-03-31 06:22:05

+0

相关:http://stackoverflow.com/questions/381517/net-signed-xml-prefix – 2012-12-06 21:58:57

回答

2

将XmlDsigExcC14NTransform添加到所有符合条件的引用可解决该问题。我认为在.NET Framework中出现问题会导致此问题。

reference2.AddTransform(new XmlDsigExcC14NTransform());

+3

对我来说,这增加了几个节点到XML,但没有添加所需的'ds:'命名空间前缀。也许我误解了你的答案;多一点代码将会有所帮助。 – 2012-12-06 22:08:25