Контрольная подпись SignedXml возвращает false - PullRequest
10 голосов
/ 14 октября 2010

Я просматривал другие посты, касающиеся этой проблемы, и, похоже, ни одна из них не касается моей ситуации.

Я пытался проверить утверждение SAML за последнюю неделю, и у меня есть 2 клиентакоторый отправил мне SAML, но я не могу проверить это.

Основной процесс - мы получаем утверждение в кодировке base64, и я его декодирую.Загрузите его в XmlDocment с PreserveWhitespace = 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).string) xmlelement - это подписанный элемент, signatureXml - это объект SignedXml, который был создан с новым SignedXml (xmlElement)

Оба клиента получают false, возвращаемое контрольной подписью, но когда я создаю свой собственный подписанный saml со своим сертификатом, он возвращает true.

Что мне здесь не хватает?

РЕДАКТИРОВАТЬ: Да, оба клиента на Java, и я опубликовал метод SetSigningKeyFromKeyInfo

Ответы [ 3 ]

8 голосов
/ 29 сентября 2012

В прошлом я много работал с подписанным XML. Все, что я могу сказать, это то, что это был кошмар. По сути, когда вы подписываете XML, он проходит процесс, называемый канонизацией (C14N). Необходимо преобразовать текст XML в поток байтов, который можно подписать. Обработка пробелов и пространств имен, среди прочего, в стандартах XML C14N трудна для понимания, и еще труднее реализовать правильно. Есть даже несколько типов C14N.

.NET-реализация очень избирательна в отношении того, что она принимает. Вполне возможно, что ваша другая реализация не работает точно так же, как .NET. Это действительно очень грустно. Например, если вы можете удалить пробелы и пространства имен из исходного XML-кода перед подписанием, это может помочь. Также, если вы можете быть уверены, что обе реализации используют одинаковые настройки C14N.

В противном случае вас ждет много отладок. Вы можете выполнить отладку в платформе или вызвать ее внутренние методы вручную с помощью отражения, чтобы увидеть, как она вычисляет фрагмент XML и сигнатуру. И сделать то же самое с другой реализацией. В основном вам нужно увидеть точные потоки байтов, которые подписаны в обоих случаях. Это последний шаг конвертации перед подписанием. Если эти потоки байтов совпадают, то, по моему опыту, у вас не будет проблем с подписью RSA. Если они не совпадают, как в вашем случае, по крайней мере, вы увидите, в чем проблема.

2 голосов
/ 13 мая 2016

У меня только что была похожая проблема, и я потерял много времени, может быть, это кому-нибудь поможет.

Моя среда на 100% .Net 4.5, и мой код использует только класс SignedXml.Но утверждение SAML было принято в одном месте и отклонено в другом.

Оказалось, что одно место загружало утверждение через экземпляр XmlDocument, инициализированный с помощью PreserveWhitespace = true, а другое - нет.

И утверждение было довольно напечатано, поэтому оно имело возврат каретки и много отступов.Удаление всех возвратов каретки и отступов решило мою проблему.

1 голос
/ 20 июля 2018

У Сэмла была та же проблема, что и у Тимора.Saml нужно было декодировать из Base64, но сначала я использовал:

var saml = System.Text.Encoding.Default.GetString(Convert.FromBase64String(samlToken))

Но это использовало декодирование ASCII и имело проблемы со специальными символами.Это означает, что XML немного отличался от того, когда он был подписан, и именно поэтому он потерпел неудачу.Изменил его на:

var saml = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(samlToken))

, и он работал для всех случаев.

Поэтому убедитесь, что вы используете правильную кодировку!

...