I apologize in advance for the rather lengthy block of code, but it\'s the smallest compilable example I could produce. I already omitted all error checking from the origina
You have a bug in your test code. The second foreach loops again over xmlDoc
instead of signedDoc
. Fixing this will change the outcome to fail for all nodes.
Why they fail I don't yet know.
I couldn't find out why they fail with your code but I found a way to make it work. The difference: All signatures are direct childs of the root element:
public static void Main()
{
// ...
var signedDoc = new XmlDocument { PreserveWhitespace = true };
signedDoc.Load("test_signed.xml");
foreach (XmlElement root in signedDoc.GetElementsByTagName("PackageRoot"))
{
foreach (XmlElement signature in root.GetElementsByTagName("Signature"))
{
var success = signature.VerifySignature(certificate);
Console.WriteLine(success ? " successful!" : " failed!");
}
}
Console.WriteLine("Done.");
Console.ReadLine();
}
public static void Sign(this XmlElement element, X509Certificate2 certificate)
{
var identifier = Guid.NewGuid().ToString("N");
element.SetAttribute("Id", identifier);
var signedXml = new SignedXml(element) { SigningKey = certificate.PrivateKey };
signedXml.AddReference(new Reference("#" + identifier));
signedXml.ComputeSignature();
var xmlDigitalSignature = signedXml.GetXml();
element.OwnerDocument.DocumentElement.AppendChild(
element.OwnerDocument.ImportNode(xmlDigitalSignature, true));
}
public static bool VerifySignature(this XmlElement element, X509Certificate2 certificate)
{
var signedXml = new SignedXml(element.OwnerDocument);
signedXml.LoadXml(element);
return signedXml.CheckSignature(certificate, true);
}
One important detail to notice: PreserveWhitespace
needs to be set to true
for signedDoc
, too.