'Malformed Reference Element' when adding a reference based on an Id attribute with SignedXml class
Asked Answered
A

4

28

Unable to sign element by Id attribute when there's a namespace prefix:

void Main()
{
    var doc = new XmlDocument();
    doc.LoadXml("<root xmlns:u=\"myuri\"><test u:Id=\"_0\">Zebra</test></root>");

    SignedXml signedXml = new SignedXml(doc);
    signedXml.SigningKey = new RSACryptoServiceProvider();

    Reference reference = new Reference("#_0");
    signedXml.AddReference(reference);

    signedXml.ComputeSignature();
}

ComputeSignature() will fail here with 'Malformed Reference Element' how should this be done?

Asymptotic answered 24/2, 2011 at 0:44 Comment(0)
A
60

The approach we used was to subclass System.Security.Cryptography.Xml.SignedXml class...

public class SignedXmlWithId : SignedXml
{
    public SignedXmlWithId(XmlDocument xml) : base(xml)
    {
    }

    public SignedXmlWithId(XmlElement xmlElement) 
        : base(xmlElement)
    {       
    }

    public override XmlElement GetIdElement(XmlDocument doc, string id)
    {
        // check to see if it's a standard ID reference
        XmlElement idElem = base.GetIdElement(doc, id);

        if (idElem == null)
        {
            XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
            nsManager.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");

            idElem = doc.SelectSingleNode("//*[@wsu:Id=\"" + id + "\"]", nsManager) as XmlElement;
        }

        return idElem;
    }
}
Asymptotic answered 24/6, 2011 at 12:35 Comment(5)
I had the same error, but the problem was that the value for SecurePart\Id started with number (only characters are allowed).Trisa
@JanFriedrich you should post a working answer, I'll willing accept that if correct.Asymptotic
@JanFriedrich, that was my issue as well. I was working with an ID for a SAML request. Had to conform to the XML ID convention. See w3.org/TR/xml-id which is an NCNAME w3.org/TR/xml-names11/#NT-NCName, which the starting character is restricted. I used a GUID with no braces, just prepended it with an _ for the ID.Perishing
I had the same issue but no control over the ID since that was generated by another system. As a fix I just overrode GetIdElement to run the same code as the base implementation (copied from source.dot.net), but with the NCName validation snippet removed.Algiers
This was the insight I needed to finally create the signature for our payload! Thank you thank you thank you.Mccloud
F
3

var reference = new Reference(""); // This will sign the entire document

Fowle answered 24/2, 2011 at 1:20 Comment(2)
But I need to supply the id of the element to sign..the actual xml is a soap envelope and using Ids seems to be the way that it's done.Asymptotic
ok, the xml has atttibute "u:Id", if you change it to "<test Id='0'>...", then ComputeSignature should work. If you can not change the input then you will have use a "#xpointer" reference.Fowle
S
2

It should be noted that you will need to use SignedXmlWithId object instead of SignedXml object in order to be able to use the overridden GetIdElement() method. Once I did that, I was able to sign an XmlElement and get around the Malformed Reference Element error.

See my post about this topic here.

Staphylorrhaphy answered 2/3, 2016 at 22:44 Comment(0)
E
0

SignedXml does not recognize u:Id as a valid XML ID, and the XML Signature does require it to be an XML ID.

You can either use the Schema (http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd if your trying to use a WS-Security Id) or add an DTD to the XML fragment. ( ]> for an XML fragment). Adding a DTD to just your LoadXml will make SignedXml recognize the Id, but since SOAP does not allow DTD's, don't include the DTD in your on-the-wire SOAP.

Elianore answered 25/3, 2011 at 15:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.