I am attempting to add References to my Security Header and am running into a fairly generic error:
Malformed Reference Element
I have tried the following with similar results:
ID
of the element as the URI
of the Reference
object.XmlElement
object to the Reference
through the LoadXml()
method. I am retrieving the XmlElement
reference by using the overloaded GetIdElement
found on this StackOverflow post.When I pass in an empty string as the URI
, the ComputeSignature()
method of the SignedXml
works as expected. However, I need to add up to 3 references to the Security Header.
UPDATE #1
Thanks to this blog post, I was able to create the simplified version from that and I believe what is causing my problem is the use of the Namespace
attributes and prefixes.
UPDATE #2
It appears as though the Namespace declaration on the Id
attribute of the <Timestamp>
element is causing this error to occur.
UPDATE #3
I think I got this working. See my answer post below.
Working Sample:
Please note the Id XAttribute
with the Namespace defined does not work; while the Id XAttribute
without the Namespace defined does work.
private void CreateSecurityAndTimestampXML(string fileName)
{
TimestampID = "TS-E" + GUID.NewGuid();
DateTime SecurityTimestampUTC = DateTime.UtcNow;
XDocument xdoc = new XDocument(
new XElement(wsse + "Security",
new XAttribute(XNamespace.Xmlns + "wsse", wsse.NamespaceName),
new XAttribute(XNamespace.Xmlns + "wsu", wsu.NamespaceName),
new XElement(wsu + "Timestamp",
// new XAttribute(wsu + "Id", TimestampID), // <-- Does Not Work
new XAttribute("Id", TimestampID), // <-- Works
new XElement(wsu + "Created", SecurityTimestampUTC.ToString(_timestampFormat)),
new XElement(wsu + "Expires", SecurityTimestampUTC.AddMinutes(10).ToString(_timestampFormat))
)
)
);
using (XmlTextWriter tw = new XmlTextWriter(fileName, new UTF8Encoding(false)))
{
xdoc.WriteTo(tw);
}
}
// Snippet
string[] elements = { TimestampID };
foreach (string s in elements)
{
Reference reference = new Reference()
{
Uri = "#" + s
};
XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();
env.InclusiveNamespacesPrefixList = _includedPrefixList;
reference.AddTransform(env);
xSigned.AddReference(reference);
}
// Add Key Info Here.
// Compute the Signature.
xSigned.ComputeSignature();
It looks like, at least for the time being, the answer to getting this working is as follows.
Instead of using the SignedXml
class, create a new SignedXmlWithId
object, using the class detailed here.
// Create a new XML Document.
XmlDocument xdoc = new XmlDocument();
xdoc.PreserveWhitespace = true;
// Load the passed XML File using its name.
xdoc.Load(new XmlTextReader(fileName));
// Create a SignedXml Object.
//SignedXml xSigned = new SignedXml(xdoc);
SignedXmlWithId xSigned = new SignedXmlWithId(xdoc); // Use this class instead of the SignedXml class above.
// Add the key to the SignedXml document.
xSigned.SigningKey = cert.PrivateKey;
xSigned.Signature.Id = SignatureID;
xSigned.SignedInfo.CanonicalizationMethod =
SignedXml.XmlDsigExcC14NWithCommentsTransformUrl;
//Initialize a variable to contain the ID of the Timestamp element.
string elementId = TimestampID;
Reference reference = new Reference()
{
Uri = "#" + elementId
};
XmlDsigExcC14NTransform env = new XmlDsigExcC14NTransform();
env.InclusiveNamespacesPrefixList = _includedPrefixList;
reference.AddTransform(env);
xSigned.AddReference(reference);
// Add Key Information (omitted)
// Compute Signature
xSigned.ComputeSignature();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With