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.Collecti ons.Generic;
using System.Text;
using System.Xml;
using System.Security .Cryptography.X 509Certificates ;
using System.Security .Cryptography.X ml;
using System.Security .Cryptography;
using System.Xml.Sche ma;
namespace ConsoleApplicat ion1
{
class Program
{
private static XmlElement GoodElement()
{
// Create a test xml document
XmlDocument oDoc = new XmlDocument();
oDoc.LoadXml(@" <somedoc><a>< b Id=""signme"">T his should be
signed</b></a></somedoc>");
// Get a specific element in the xml document
XmlElement elem = (XmlElement)oDo c.SelectNodes("//b")[0];
return elem;
}
private static XmlElement BadElement()
{
// Create a test xml document
XmlDocument oDoc = new XmlDocument();
oDoc.LoadXml(@" <somedoc
xmlns:pre=""htt p://some.url/schema""><pre:a ><pre:b Id=""signme"">T his should
be signed</pre:b></pre:a></somedoc>");
// Get a specific namespace prefixed element in the xml document
XmlNamespaceMan ager xman = new XmlNamespaceMan ager(oDoc.NameT able);
xman.AddNamespa ce("pre", "http://some.url/schema");
XmlElement elem = (XmlElement)oDo c.SelectNodes("//pre:b", xman)[0];
return elem;
}
private static void Reproduce()
{
XmlElement elem = BadElement();
Console.WriteLi ne("Signing and validating this XML: " + elem.OuterXml);
Console.WriteLi ne();
// Sign the element
RSACryptoServic eProvider key = new RSACryptoServic eProvider();
SignedXml sx = new SignedXml(elem) ;
sx.SigningKey = key;
sx.AddReference (new Reference("#sig nme")); // Sign this node
sx.ComputeSigna ture();
// Hold the signature
XmlElement signature = sx.GetXml();
// Validate
SignedXml sx2 = new SignedXml(elem) ;
sx2.LoadXml(sig nature);
bool test = sx2.CheckSignat ure(key);
Console.WriteLi ne("Result of validation: " + test);
Console.ReadLin e();
// 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.