Frage

Gibt es eine Möglichkeit das Präfix über die Unterzeichnung eines signierten XML-Dokuments (SignedXml Klasse in .NET) zu setzen?

Also statt:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#>
...
</Signature>

Ich konnte folgende Voraussetzungen erfüllt sein:

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#>
...
</ds:Signature>
War es hilfreich?

Lösung

Zunächst einmal gibt es wirklich keinen guten Grund, dies zu tun. Die beiden Formen sind funktionell gleichwertig. Jeder gut erzogene XML-Prozessor wird mit ihnen umgeht absolut identisch. Also, wenn Sie versuchen, eine Anwendung zu sprechen, die XML-Namespaces nicht richtig implementieren ist, ist es besser (IMO) nur das Standardformular in Ruhe zu lassen. (Und auch in diesem Fall wäre es besser, wenn überhaupt möglich, die fehlerhafte Anwendung zu bekommen fixierte statt.)

Das heißt, Sie manuell das Präfix auf der XmlElement festlegen können, die von SignedXml.GetXml () und seine untergeordneten Elemente mit XPath wie folgt zurückgegeben:

XmlElement signature = signedXml.GetXml();
foreach (XmlNode node in signature.SelectNodes(
    "descendant-or-self::*[namespace-uri()='http://www.w3.org/2000/09/xmldsig#']"))
{
    node.Prefix = "ds";
}

Andere Tipps

Es kann nicht getan werden. Wenn Sie die XML ändern , nachdem es unterzeichnet wurde kann es nicht in der Lage sein, überprüft werden, was der Fall im Beispiel oben war. IMO ist dies ein Fehler in MSFT digitaler Signatur-Implementierung, die Sie mit leben müssen.

Eine Menge Leute werden sagen, dass es keinen Grund gibt, dies zu tun, und sie sind technisch korrekt. Aber wenn man mit einem großen Anbieter handelt (das heißt eine Landesregierung oder Bank), viel Glück bekommen sie es an ihrem Ende zu ändern. Die meisten Referenzimplementierungen umfassen sie.

UPDATE: Die Unterschrift Zeichen alles im SignedInfo Element, also wenn Sie das Element nach der Tat gehen die Aktualisierung, dann ist die Signatur nicht mehr gültig. Sie haben „manipuliert“ mit der Meldung.

Es kann getan werden, aber es ist notwendig, die SignedXml Klasse zu ändern, das Präfix hinzuzufügen, bevor der Digest-Wert des SignedInfo Knoten zu bekommen.

Die ComputeSignature Methode wird ändern Sie den Präfix Parameter hinzuzufügen

public void ComputeSignature(string prefix){...}

Wenn diese Methode aufgerufen wird der Signaturwert berechnet, indem der Wert des SignedInfo Knoten zu verdauen, wenn Sie diesen Wert erhalten, ohne die „ds“ Präfix und dann das Präfix hinzufügen Sie eine ungültige Signatur erhalten wird, so müssen Sie fügen Sie das Präfix vor dem Digest-Wert des SignedInfo Knoten zu bekommen.

Dieser Digest-Wert wird in dem Verfahren erzeugt GetC14NDigest, so wird diese Methode ändern, den Präfix Parameter hinzuzufügen und das Präfix vor Erhalten des Digest-Wertes

hinzufügen
private byte[] GetC14NDigest(HashAlgorithm hash, string prefix)
{
    XmlDocument document = new XmlDocument();
    document.PreserveWhitespace = false;
    XmlElement e = this.SignedInfo.GetXml(); //get the signedinfo nodes
    document.AppendChild(document.ImportNode(e, true));        
    Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject;       
    SetPrefix(prefix, document.DocumentElement); /*Set the prefix before getting the HASH*/
    canonicalizationMethodObject.LoadInput(document);
    return canonicalizationMethodObject.GetDigestedOutput(hash);
}

Ok, so dass Sie nun die Unterschrift Wert der SignedInfo Knoten mit dem „ds“ Präfix haben, dass gesagt wird man noch nicht die xml mit dem Präfix noch tun haben, also, wenn Sie nur die GetXml Methode aufrufen, erhalten Sie die xml ohne das Präfix und natürlich, weil der Signaturwert berechnet wurde, um die ds Berücksichtigung Präfix Sie eine ungültige Signatur haben. Um dies zu vermeiden und die XML-Struktur mit dem Präfix erhalten haben Sie die GetXml Methode zu ändern, fügen Sie das Präfix-Parameter und rufen die setPrefix Methode Wich wird die „ds“ Präfix zu allen Knoten in der Signature Xml hinzufügen

public XmlElement GetXml(string prefix)
{
    XmlElement e = this.GetXml();
    SetPrefix(prefix, e); //return the xml structure with the prefix
    return e;
}

Ich lasse hier die Klasse mit diesen Änderungen

CUSTOM CLASS

internal sealed class CustomSignedXml : SignedXml
{
    XmlElement obj = null;
    public CustomSignedXml (XmlDocument xml)
        : base(xml)
    {
    }

    public CustomSignedXml (XmlElement xmlElement)
        : base(xmlElement)
    {

    }

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

    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);
    }         

    private byte[] GetC14NDigest(HashAlgorithm hash, string prefix)
    {

        XmlDocument document = new XmlDocument();
        document.PreserveWhitespace = false;
        XmlElement e = this.SignedInfo.GetXml();
        document.AppendChild(document.ImportNode(e, true));               

        Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject;            
        SetPrefix(prefix, document.DocumentElement); //Set the prefix before getting the HASH
        canonicalizationMethodObject.LoadInput(document);
        return canonicalizationMethodObject.GetDigestedOutput(hash);
    }

    private void BuildDigestedReferences()
    {
        Type t = typeof(SignedXml);
        MethodInfo m = t.GetMethod("BuildDigestedReferences", BindingFlags.NonPublic | BindingFlags.Instance);
        m.Invoke(this, new object[] { });
    }

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

Und die Art und Weise, es zu benutzen

CustomSignedXml signedXml = new CustomSignedXml();
.
.//your code
. 

//compute the signature with the "ds" prefix

signedXml.ComputeSignature("ds");

//get the xml of the signature with the "ds" prefix

XmlElement xmlDigitalSignature = signedXml.GetXml("ds");
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top