2012-08-31 10 views
5

Gibt es eine Möglichkeit, eine XML-Datei mit RSA zu signieren und das Namespacepräfix "ds: Signature" anstelle von "Signature" zu haben? Ich habe viele Stunden damit verbracht, dies zu lösen, und von dem, was ich sehen kann, gibt es keine Lösung.XML-Signatur DS-Präfix?

Es scheint, dass es in der Klasse System.Security.Cryptography.Xml.Signatur fest codiert ist.

XmlElement element = document.CreateElement("Signature", "http://www.w3.org/2000/09/xmldsig#"); 

Wenn jemand eine Lösung weiß, ich brauche es so bewirken, dass die Software zu unterzeichnen Import überprüft er es mit „ds: Unterschrift“, so mit „ds“ die Software-Präfix überprüft es wie folgt aus:

public static bool VerifySignature(XmlDocument doc, RSA key, string prefix) 
    { 
     SignedXml xml = new SignedXml(doc); 
     string str = "Signature"; 
     if (!string.IsNullOrEmpty(prefix)) 
     { 
      str = string.Format("{0}:{1}", prefix, str); 
     } 
     XmlNodeList elementsByTagName = doc.GetElementsByTagName(str); 
     xml.LoadXml((XmlElement)elementsByTagName[0]); 
     return xml.CheckSignature(key); 
    } 

    VerifySignature(xmlDoc, rsa, "ds"); 

normalerweise unterzeichnet es wie folgt aus:

<kk>blabla<Signature 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/2000/09/xmldsig#rsa-sha1" /><Reference URI=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><DigestValue>rVL2nKjPTBhL9IDHYpu69OiE8gI=</DigestValue></Reference></SignedInfo><SignatureValue>CfXW9D/ErmHjzxIjy0/54/V3nst6j/XXcu7keR17LApfOZEpxjEvAlG3VnBZIi3jxQzU6t9RkmfDyngcRZccJByuuA6YDwFTQxZNRgu2GRoZxMKWnkm+MtQ0jH0Fo78GivCxV+iIewZvsrUQLzG01cXuZSH/k2eeMUaEooJaLQiYpO2aNVn5xbosTPtGlsACzFWz34E69/ZeeLZbXLc3jpDO+opxdYJ5e+Tnk/UM2Klt+N+m7Gh/sUNTPgkDiwP3q3y3O9tvCT0G2XmQaWBP4rw9TIoYHQtucm2b8R2JeggbeRKOetbRYV218RT8CK2Yuy0FIUlQXdabKyp9F96Yc55g8eNe10FGtgietH2iqquIVFLCA8fu3SZNLDPMoyHnVNKdBvI35+S8hrAaybEkMvo7iYnUSY5KrlGSfGGtfQXdaISutAzcnGPDFXgZXPNzNy7eL0u+Lt3yWWkj7wh6Zeh4fH2+nXDWYCWbLpegAEX4ZWSI5Ts6D1TplMJTGH1F0GyflehH4u+W4Lc3TvkB4dWjEuiKgnpl3hcvoj2CWFaeAxXMd/64tU/YMm8+1gSBjkVH6oV+QlI/m0z6M8FPVEVC2as0wLG2woVwmzVLcaQKyPi7NN4eO9ea7QNfaRHaofU4LQO/Y3FNJOP+uMfYlGJKWSr3qv29+BQjeNldNJY=</SignatureValue></Signature></kk> 

und ich brauche es es wie dies zu tun:

<kk>blabla<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /><ds:Reference URI=""><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><ds:DigestValue>rVL2nKjPTBhL9IDHYpu69OiE8gI=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>CfXW9D/ErmHjzxIjy0/54/V3nst6j/XXcu7keR17LApfOZEpxjEvAlG3VnBZIi3jxQzU6t9RkmfDyngcRZccJByuuA6YDwFTQxZNRgu2GRoZxMKWnkm+MtQ0jH0Fo78GivCxV+iIewZvsrUQLzG01cXuZSH/k2eeMUaEooJaLQiYpO2aNVn5xbosTPtGlsACzFWz34E69/ZeeLZbXLc3jpDO+opxdYJ5e+Tnk/UM2Klt+N+m7Gh/sUNTPgkDiwP3q3y3O9tvCT0G2XmQaWBP4rw9TIoYHQtucm2b8R2JeggbeRKOetbRYV218RT8CK2Yuy0FIUlQXdabKyp9F96Yc55g8eNe10FGtgietH2iqquIVFLCA8fu3SZNLDPMoyHnVNKdBvI35+S8hrAaybEkMvo7iYnUSY5KrlGSfGGtfQXdaISutAzcnGPDFXgZXPNzNy7eL0u+Lt3yWWkj7wh6Zeh4fH2+nXDWYCWbLpegAEX4ZWSI5Ts6D1TplMJTGH1F0GyflehH4u+W4Lc3TvkB4dWjEuiKgnpl3hcvoj2CWFaeAxXMd/64tU/YMm8+1gSBjkVH6oV+QlI/m0z6M8FPVEVC2as0wLG2woVwmzVLcaQKyPi7NN4eO9ea7QNfaRHaofU4LQO/Y3FNJOP+uMfYlGJKWSr3qv29+BQjeNldNJY=</ds:SignatureValue></ds:Signature></kk> 
+0

Können Sie nicht XML-DOM-Inhalte nach alles ändern Unterzeichnung und kombiniere es in einen DOM-Baum? –

+1

Wenn Sie einen der XML-Inhalt nach der Signatur ändern, wird der Signaturwert nicht übereinstimmen ... –

+0

Der Punkt besteht darin, den Signaturknoten zu ändern, nicht den signierten. –

Antwort

8

wenn jemand eine Lösung weiß, ich brauche es so bewirken, dass die Software zu unterzeichnen importieren sie es mit prüft „ds: Unterschrift“, so mit „ds“ Präfix

Das Präfix sollte unwichtig sein - alles was zählt sollte sein, in welchem ​​Namespace das Element ist. Es sollte keine Rolle spielen wie der Namespace ausgedrückt wird. Wenn das der Fall ist, zeigt das Brüche im Bestätigungscode, würde ich sagen.

Wenn Sie jedoch wirklich dies tun möchten, gibt es einen Grund, warum Sie nicht nur das Element mit einem mit dem gleichen Inhalt ersetzen möchten, aber mit dem Präfix Sie wollen? In LINQ to XML sollte das nicht schwer sein.

+2

Ich habe den ersten Beitrag bearbeitet, um zu sehen, wie die Software, die das XML empfängt, es verifiziert ..., Sie können das Elementpräfix nicht ersetzen, weil dann der Signaturwert abweichen würde ... –

7

fand ich die Lösung here

using System; 
using System.Reflection; 
using System.Security.Cryptography.Xml; 
using System.Security.Cryptography; 
using System.Collections.Generic; 
using System.Text; 
using System.Xml; 

namespace mysign 
{ 
public class PrefixedSignedXML : SignedXml 
{ 
    public PrefixedSignedXML(XmlDocument document) 
     : base(document) 
    { } 

    public PrefixedSignedXML(XmlElement element) 
     : base(element) 
    { } 

    public PrefixedSignedXML() 
     : base() 
    { } 

    public void ComputeSignature(string prefix) 
    { 
     this.BuildDigestedReferences(); 
     AsymmetricAlgorithm signingKey = this.SigningKey; 
     if (signingKey == null) 
     { 
      throw new CryptographicException("Cryptography_Xml_LoadKeyFailed"); 
     } 
     if (this.SignedInfo.SignatureMethod == null) 
     { 
      if (!(signingKey is DSA)) 
      { 
       if (!(signingKey is RSA)) 
       { 
        throw new CryptographicException("Cryptography_Xml_CreatedKeyFailed"); 
       } 
       if (this.SignedInfo.SignatureMethod == null) 
       { 
        this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; 
       } 
      } 
      else 
      { 
       this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; 
      } 
     } 
     SignatureDescription description = CryptoConfig.CreateFromName(this.SignedInfo.SignatureMethod) as SignatureDescription; 
     if (description == null) 
     { 
      throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated"); 
     } 
     HashAlgorithm hash = description.CreateDigest(); 
     if (hash == null) 
     { 
      throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed"); 
     } 
     this.GetC14NDigest(hash, prefix); 
     this.m_signature.SignatureValue = description.CreateFormatter(signingKey).CreateSignature(hash); 
    } 

    public XmlElement GetXml(string prefix) 
    { 
     XmlElement e = this.GetXml(); 
     SetPrefix(prefix, e); 
     return e; 
    } 

    //Invocar por reflexión al método privado SignedXml.BuildDigestedReferences 
    private void BuildDigestedReferences() 
    { 
     Type t = typeof(SignedXml); 
     MethodInfo m = t.GetMethod("BuildDigestedReferences", BindingFlags.NonPublic | BindingFlags.Instance); 
     m.Invoke(this, new object[] { }); 
    } 

    private byte[] GetC14NDigest(HashAlgorithm hash, string prefix) 
    { 
     //string securityUrl = (this.m_containingDocument == null) ? null : this.m_containingDocument.BaseURI; 
     //XmlResolver xmlResolver = new XmlSecureResolver(new XmlUrlResolver(), securityUrl); 
     XmlDocument document = new XmlDocument(); 
     document.PreserveWhitespace = true; 
     XmlElement e = this.SignedInfo.GetXml(); 
     document.AppendChild(document.ImportNode(e, true)); 
     //CanonicalXmlNodeList namespaces = (this.m_context == null) ? null : Utils.GetPropagatedAttributes(this.m_context); 
     //Utils.AddNamespaces(document.DocumentElement, namespaces); 

     Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject; 
     //canonicalizationMethodObject.Resolver = xmlResolver; 
     //canonicalizationMethodObject.BaseURI = securityUrl; 
     SetPrefix(prefix, document.DocumentElement); //establecemos el prefijo antes de se que calcule el hash (o de lo contrario la firma no será válida) 
     canonicalizationMethodObject.LoadInput(document); 
     return canonicalizationMethodObject.GetDigestedOutput(hash); 
    } 

    private void SetPrefix(string prefix, XmlNode node) 
    { 
     foreach (XmlNode n in node.ChildNodes) 
      SetPrefix(prefix, n); 
     node.Prefix = prefix; 
    } 
} 
} 
+0

hat bei mir nicht funktioniert, Signaturblock beendet das Gleiche ohne das Präfix – tarrball

0

setPrefix Code wie folgt aussieht richtig sein:

private void SetPrefix(String prefix, XmlNode node) { 
     foreach (XmlNode n in node.ChildNodes) 
     { 
      SetPrefix(prefix, n); 
      n.Prefix = prefix; 
     } 
    } 
+0

hast du die Frage nicht verstanden. Ich habe bereits eine Lösung gegeben –

+1

@GeorgeDima Ich spiele damit herum, und das Ändern des Signaturblocks in der XML scheint den Signaturwert nicht zu beeinflussen. Daher sollte dies sicher sein, nachdem die Signatur generiert wurde.Bist du sicher, dass das nicht für dich funktioniert hat? –

+1

ja, nur meine hier gepostete lösung funktionierte für mich, ich meine es verifizieren zu lassen. –

1

ich diese Lösungen ausprobiert, aber sie haben nicht geklappt. Wenn wir uns jedoch den .NET-Quellcode ansehen (http://referencesource.microsoft.com/), können wir sehen, dass dies leicht durch Bereitstellen einer abgeleiteten XmlDocument-Klasse für SignedXml erreicht werden kann, wo Namespace hinzugefügt werden kann. Wenn Sie jedoch das Präfix "ds" in "SignedInfo" und in den Nachkommen haben, wird die Siganture fehlschlagen. Hier ist das Beste, was ich, ohne die Unterschrift tun konnte:


XmlDsigDocument.cs

using System; 
using System.Collections.Generic; 
using System.Security.Cryptography.Xml; 
using System.Text; 
using System.Xml; 

namespace CustomSecurity 
{ 
class XmlDsigDocument : XmlDocument 
{ 
    // Constants 
    public const string XmlDsigNamespacePrefix = "ds"; 

    /// <summary> 
    /// Override CreateElement function as it is extensively used by SignedXml 
    /// </summary> 
    /// <param name="prefix"></param> 
    /// <param name="localName"></param> 
    /// <param name="namespaceURI"></param> 
    /// <returns></returns> 
    public override XmlElement CreateElement(string prefix, string localName, string namespaceURI) 
    { 
     // CAntonio. If this is a Digital signature security element, add the prefix. 
     if (string.IsNullOrEmpty(prefix)) 
     { 
      // !!! Note: If you comment this line, you'll get a valid signed file! (but without ds prefix) 
      // !!! Note: If you uncomment this line, you'll get an invalid signed file! (with ds prefix within 'Signature' object) 
      //prefix = GetPrefix(namespaceURI); 

      // The only way to get a valid signed file is to prevent 'Prefix' on 'SignedInfo' and descendants. 
      List<string> SignedInfoAndDescendants = new List<string>(); 
      SignedInfoAndDescendants.Add("SignedInfo"); 
      SignedInfoAndDescendants.Add("CanonicalizationMethod"); 
      SignedInfoAndDescendants.Add("InclusiveNamespaces"); 
      SignedInfoAndDescendants.Add("SignatureMethod"); 
      SignedInfoAndDescendants.Add("Reference"); 
      SignedInfoAndDescendants.Add("Transforms"); 
      SignedInfoAndDescendants.Add("Transform"); 
      SignedInfoAndDescendants.Add("InclusiveNamespaces"); 
      SignedInfoAndDescendants.Add("DigestMethod"); 
      SignedInfoAndDescendants.Add("DigestValue"); 
      if (!SignedInfoAndDescendants.Contains(localName)) 
      { 
       prefix = GetPrefix(namespaceURI); 
      } 
     } 

     return base.CreateElement(prefix, localName, namespaceURI); 
    } 

    /// <summary> 
    /// Select the standar prefix for the namespaceURI provided 
    /// </summary> 
    /// <param name="namespaceURI"></param> 
    /// <returns></returns> 
    public static string GetPrefix(string namespaceURI) 
    { 
     if (namespaceURI == "http://www.w3.org/2001/10/xml-exc-c14n#") 
      return "ec"; 
     else if (namespaceURI == SignedXml.XmlDsigNamespaceUrl) 
      return "ds"; 

     return string.Empty; 
    } 
} 
} 

Dieses auf der SignedXml Creation verwendet wird:

// Create a new XML document. 
    XmlDsigDocument doc = new XmlDsigDocument(); 

    // Load the passed XML file using its name. 
    doc.Load(new XmlTextReader(FileName)); 

    // Create a SignedXml object. 
    SignedXml signedXml = new SignedXml(doc); 

Sie vollen Quelldateien sehen können unter:

https://social.msdn.microsoft.com/Forums/en-US/cd595379-f66a-49c8-8ca2-62acdc58b252/add-prefixds-signedxml?forum=xmlandnetfx

0

Ich stimme zu, dass Präfix nicht wichtig sein sollte, aber ...

XML wird viel einfacher in C#, wenn Sie XPath verwenden:

var s = signedXml.GetXml(); 
XmlNodeList nodes = s.SelectNodes("descendant-or-self::*"); 
foreach (XmlNode childNode in nodes) 
{ 
    childNode.Prefix = "dsig"; 
} 
0

Der Code George Dima Werke liefern.

Ich werde erklären, wie es funktioniert.

Wenn Sie die ComputeSignature-Methode aufrufen, generiert dies den Signaturwert, indem der Wert des Knotens SignedInfo verdaut wird.

Der von George Dima bereitgestellte Code fügt das Präfix dem SignedInfo-Knoten und seinen untergeordneten Elementen hinzu, BEVOR der Digest-Wert abgerufen wird. Dadurch wird das Präfix für die gesamte XML-Struktur nicht hinzufügen

dies die Methode ist, die den Digest-Wert des SignedInfo Knoten erzeugt

private byte[] GetC14NDigest(HashAlgorithm hash, string prefix) 
{   
    XmlDocument document = new XmlDocument(); 
    document.PreserveWhitespace = true; 
    XmlElement e = this.SignedInfo.GetXml(); 
    document.AppendChild(document.ImportNode(e, true));   
    Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject; 

    SetPrefix(prefix, document.DocumentElement); //HERE'S WHERE THE PREFIX IS ADDED TO GET THE DIGEST VALUE 
    canonicalizationMethodObject.LoadInput(document); 
    return canonicalizationMethodObject.GetDigestedOutput(hash); 
} 

So haben Sie jetzt den Digest-Wert des SignedInfo Knoten mit dem Präfix und dieser Wert wird Verwendung erhält die Unterschrift Wert sein, aber immer noch mit dem Präfix noch nicht über die xML, also, wenn Sie ihn nur tun

signedXml.GetXml(); 

Sie das xml ohne das Präfix erhalten und von Natürlich, weil der Signaturwert unter Berücksichtigung der ds pre berechnet wurde reparieren Sie eine ungültige Signatur haben so was Sie den Wert des Präfix der GetXml vorbei, es zu tun haben wird, nennen, in diesem Fall „ds“ wie dieses

signedXml.GetXml("ds");