SignedXml и несколько XMLDSIGN.
От: alex303  
Дата: 26.08.15 11:10
Оценка:
Приветствую.
если в xml-е несколько узлов подписано несколькими подписями (всмысле не один Signature + много Referencе'ов, а много Signature). То наблюдается крайне странная картина: если узел Signature является дочерним узлом по отношению к подписываемому, то валидируется только первая подпись — остальные якобы невалидны. Если же узел Signature вынести за пределы подписываемого узла, то валидируются все подписи.
Воспрос — это баг или фича? Куда копать.

простенький пример.

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Xml;

namespace MultiSign
{
    class Program
    {
        private static readonly RSACryptoServiceProvider KEY = new RSACryptoServiceProvider();

        static void Main(string[] args)
        {
            var doc = MakeDocument();
            SignNodes(doc, "//test");
            // doc.Save("test_signed.xml");
            Console.WriteLine("Verifing document:");
            VerifyDocument(doc);
            Console.WriteLine("Verifing nodes:");
            VerifyNodesAsSingleDocument(doc, "//test");
            Console.ReadLine();
        }

        private static XmlDocument MakeDocument()
        {
            var doc = new XmlDocument() { PreserveWhitespace = true };
            doc.LoadXml("<root>"
                        + "  <sub>"
                        + "    <test id='1'>"
                        + "      <data>data1</data>"
                        + "    </test>"
                        + "  </sub>"
                        + "  <sub>"
                        + "    <test id='2'>"
                        + "      <data>data2</data>"
                        + "    </test>"
                        + "  </sub>" 
                        + "  <sub>" 
                        + "    <test id='3'>" 
                        + "      <data>data3</data>" 
                        + "    </test>" 
                        + "  </sub>" 
                        + "</root>");
            return doc;
        }

        private static void SignNodes(XmlDocument doc, string xpath)
        {
            var nodes = doc.SelectNodes(xpath);
            foreach (XmlNode node in nodes)
            {
                SignNode(node);
            }
        }

        private static void SignNode(XmlNode node)
        {
            var doc = node.OwnerDocument;
            var signedXml = new SignedXml(doc) { SigningKey = KEY };
            var reference = new Reference { Uri = "#" + node.Attributes["id"].Value };
            reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
            signedXml.AddReference(reference);
            signedXml.ComputeSignature();

            node.AppendChild(doc.ImportNode(signedXml.GetXml(), true)); // add signature as child of signed node. Will fail on second+ signatures
            //doc.DocumentElement.AppendChild(doc.ImportNode(signedXml.GetXml(), true)); // add signature somewhere else. All works good.
        }

        private static void VerifyDocument(XmlDocument doc)
        {
            var signs = doc.GetElementsByTagName("Signature");
            foreach (XmlElement sign in signs)
            {
                var signedXml = new SignedXml(doc);
                signedXml.LoadXml(sign);
                Console.WriteLine("verified: '{0}'", signedXml.CheckSignature(KEY));
            }
        }

        private static void VerifyNodesAsSingleDocument(XmlDocument doc, string xpath)
        {
            var nodes = doc.SelectNodes(xpath);
            foreach (XmlNode node in nodes)
            {
                var tempDoc = new XmlDocument();
                tempDoc.AppendChild(tempDoc.ImportNode(node, true));
                VerifyDocument(tempDoc);
            }
        }
    }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.