Hello all,
It seems that digitally signing XML documents using the SignedXml class has
a bug - or at least a behavior I cannot explain.
The problem occurs when I sign XML documents containing namespace prefixes
and namespace references and then validate it. The validation always fails
(returns false) in this case. When I remove the namespace prefixes and
namespace references from the XML, signing and validating works fine.
It seems that the problem has been recognized in .NET framework 1.1 (see
http://support.microsoft.com/kb/888999/en-us), however I am using .NET 2.0,
and the problem still exists.
I have made a boiled down reproduction of the behavior, it should be easy to
paste into a console application to test. You just need to add a reference to
System.Security.
Any advice on this issue would be greatly appreciated.
---BEGIN CODE
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography;
using System.Xml.Schema;
namespace ConsoleApplication1
{
class Program
{
private static XmlElement GoodElement()
{
// Create a test xml document
XmlDocument oDoc = new XmlDocument();
oDoc.LoadXml(@"<somedoc><a><b Id=""signme"">This should be
signed</b></a></somedoc>");
// Get a specific element in the xml document
XmlElement elem = (XmlElement)oDoc.SelectNodes("//b")[0];
return elem;
}
private static XmlElement BadElement()
{
// Create a test xml document
XmlDocument oDoc = new XmlDocument();
oDoc.LoadXml(@"<somedoc
xmlns:pre=""http://some.url/schema""><pre:a><pre:b Id=""signme"">This should
be signed</pre:b></pre:a></somedoc>");
// Get a specific namespace prefixed element in the xml document
XmlNamespaceManager xman = new XmlNamespaceManager(oDoc.NameTable);
xman.AddNamespace("pre", "http://some.url/schema");
XmlElement elem = (XmlElement)oDoc.SelectNodes("//pre:b", xman)[0];
return elem;
}
private static void Reproduce()
{
XmlElement elem = BadElement();
Console.WriteLine("Signing and validating this XML: " + elem.OuterXml);
Console.WriteLine();
// Sign the element
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
SignedXml sx = new SignedXml(elem);
sx.SigningKey = key;
sx.AddReference(new Reference("#signme")); // Sign this node
sx.ComputeSignature();
// Hold the signature
XmlElement signature = sx.GetXml();
// Validate
SignedXml sx2 = new SignedXml(elem);
sx2.LoadXml(signature);
bool test = sx2.CheckSignature(key);
Console.WriteLine("Result of validation: " + test);
Console.ReadLine();
// Use GoodElement in first line of this method: test is true, ok!
// Use BadElement in first line of this method: Fails with false! Why?
}
static void Main(string[] args)
{
Reproduce();
}
}
}
--- END CODE
/ Peter.