Signedxml Checksignature возвращает false
-
30-09-2019 - |
Вопрос
Я посмотрел на другие посты здесь, касающимся этой проблемы, и никто из них не может решать мою ситуацию.
Я пытался проверить утверждение SAML на прошлой неделе, и у меня есть 2 клиента, которые отправили мне SAML, но я не могу это подтвердить.
Основной процесс заключается в том, что мы получаем закодированное утверждение BASE64, и я декодирую его. Загрузите его в Xmldocment с PreserveWacteSpace = True.
Метод проверки
public static bool Verify(X509Certificate2 cert, XmlElement xmlElement, SignedXml signedXml)
{
bool flag;
try
{
KeyInfo keyInfo = new KeyInfo();
var clause = new KeyInfoX509Data(cert);
keyInfo.AddClause(clause);
XmlElement signatureElement = GetSignatureElement(xmlElement);
if (signatureElement == null)
{
string message = "The XML does not contain a signature.";
throw new SAMLSignatureException(message);
}
signedXml.LoadXml(signatureElement);
if (keyInfo != null)
{
signedXml.KeyInfo = keyInfo;
}
SetSigningKeyFromKeyInfo(signedXml);
flag = signedXml.CheckSignature(cert.PublicKey.Key);
}
catch (Exception exception)
{
throw new SAMLSignatureException("Failed to verify the XML signature.", exception);
}
return flag;
}
private static void SetSigningKeyFromKeyInfo(SignedXml signedXml)
{
IEnumerator enumerator = signedXml.KeyInfo.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Current is KeyInfoX509Data)
{
var current = (KeyInfoX509Data) enumerator.Current;
if (current.Certificates.Count != 0)
{
var certificate = (X509Certificate) current.Certificates[0];
var certificate2 = new X509Certificate2(certificate);
AsymmetricAlgorithm key = certificate2.PublicKey.Key;
signedXml.SigningKey = key;
return;
}
}
else
{
if (enumerator.Current is RSAKeyValue)
{
var value2 = (RSAKeyValue) enumerator.Current;
signedXml.SigningKey = value2.Key;
return;
}
if (enumerator.Current is DSAKeyValue)
{
var value3 = (DSAKeyValue) enumerator.Current;
signedXml.SigningKey = value3.Key;
return;
}
}
}
throw new SAMLSignatureException("No signing key could be found in the key info.");
}
У меня есть сертификат от клиента, в котором я прочитал из Web.config (его хранится в виде закодированной строки Base64) XMLELEMENT, является подписанным элементом, SignedXML является объектом SignedXML, который был создан с новым stignedxml (xmlelement)
Оба клиента получают ложь возвращены Checksignature Tate, но когда я создаю свой собственный подписанный SAML с моим сертификатом, он вернется.
Что я здесь не хватает?
Редактировать: Да, оба клиента на Java, и я опубликовал метод SetsigningKeyFromkeyInfo
Решение
Я имел дело с подписанным XML много в прошлом. Все, что я могу сказать, это то, что это был кошмар. В основном, когда вы подписываете XML, он проходит через процесс, называемый канонизацией (C14n). Это необходимо включить текст XML в байтовый поток, который можно подписать. Удаление пробела и пространства имен, среди прочего, в стандартах XML C14N трудно понять, даже сложнее реализовать право. Есть даже несколько типов C14N.
Реализация .NET очень избирательная о том, что она принимает. Вполне возможно, что ваша другая реализация не работает точно так же, как .NET One. Это действительно очень грустно. Если вы можете устранить пробелы и пространства имен от вашего источника XML перед подписью, например, это может помочь. Также, если вы можете убедиться, что оба реализация используют одни и те же настройки C14N.
В противном случае вас ждет много отладки. Вы можете отладить в рамки или вызывать его внутренние методы вручную с отражением, чтобы увидеть, как он рассчитывает фрагмент XML и подпись. И сделать то же самое с другой реализацией. По сути, вам нужно увидеть точные байтовые потоки, которые подписываются в обоих случаях. Это последний шаг преобразования перед подписанием. Если эти байтовые потоки совпадают, то у вас не будет проблем с выпиской RSA в своем опыте. Если те не совпадают, как в вашем случае, по крайней мере, вы увидите, где проблема.
Другие советы
У меня просто была похожая проблема и потеряла много времени, может быть, это может помочь кому-то.
Моя среда на 100% .NET 4.5, и мой код использует только класс SignedXML. Но самное утверждение было принято в одном месте и отказано в другой.
Оказалось, что одно место загружало утверждение через экземпляр XMLDocум для инициализированного PreserveWhitespace = true
, в то время как другой не был.
И утверждение было довольно напечатано, поэтому у него было возвращение каретки и много места вступа. Удаление всех возвращений каретки и помещения отступа исправили мою проблему.
Имел подобную проблему с самлом как типорами. Самл должен был быть декодирован из Base64, но сначала я использовал:
var saml = System.Text.Encoding.Default.GetString(Convert.FromBase64String(samlToken))
Но это использовало декодирование ASCII и имела проблемы со специальными персонажами. Это означает, что XML был немного отличным от того, когда он был подписан, и поэтому он не удался. Изменил его на:
var saml = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(samlToken))
И это работало на всех случаях.
Так что будьте уверены, что вы используете правильное кодирование!