Эндрю! Я уверен, что отвечу на многие ваши вопросы.
Хорошо, во-первых, второй пример не будет работать, потому что вы изменили XML таким образом, что подпись не будет совпадать.
Итак, после советов по поиску этого кода в Google, я наткнулся на эту страницу , в которой описано, как просмотреть протоколирование для SignedXml. Мясо добавить это в App.config под тегом:
<system.diagnostics>
<sources>
<source name="System.Security.Cryptography.Xml.SignedXml" switchName="XmlDsigLogSwitch">
<listeners>
<add name="logFile" />
</listeners>
</source>
</sources>
<switches>
<add name="XmlDsigLogSwitch" value="Verbose" />
</switches>
<sharedListeners>
<add name="logFile" type="System.Diagnostics.TextWriterTraceListener" initializeData="XmlDsigLog.txt"/>
</sharedListeners>
<trace autoflush="true">
<listeners>
<add name="logFile" />
</listeners>
</trace>
</system.diagnostics>
Из этого и вашего кода я смог сделать вывод, что канонизация не работает правильно для второй подписи. В частности, не удалось удалить сам тег подписи. Это важно при проверке подписи, поскольку сама подпись не является частью подписанной информации. Если бы это было так, вы были бы здесь до тех пор, пока не сгорит солнце, пытаясь найти подпись, которая содержит себя.
Теперь я считаю, что это ошибка в реализации C #, но я не такой умный, как люди, которые пишут C #, поэтому я могу ошибаться. Но здесь есть обходной путь. Я добавил свой собственный класс, который расширяет XmlDsigExcC14NTransform, что было предложено несколькими результатами Google, но для немного другой проблемы. В методе LoadInput этого класса я удаляю узел. Оттуда все работало счастливо!
public class SigKillXmlDsigExcC14NTransform : XmlDsigExcC14NTransform
{
public SigKillXmlDsigExcC14NTransform() { }
public override void LoadInput(Object obj)
{
XmlElement root = ((XmlDocument)obj).DocumentElement;
NameTable nt = new NameTable();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
nsmgr.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#");
XmlNodeList childSignatures = root.SelectNodes("./ds:Signature", nsmgr);
// Sometimes C# fails to remove the child node. Let's hold his hand and do it for him.
foreach (XmlNode oneChild in childSignatures)
{
oneChild.ParentNode.RemoveChild(oneChild);
}
base.LoadInput(obj);
}
}
Оттуда вы добавляете одну строку к исходному коду, а остальное остается прежним.
CryptoConfig.AddAlgorithm(typeof(SigKillXmlDsigExcC14NTransform), "http://www.w3.org/2001/10/xml-exc-c14n#");
А теперь первый пример работает!