Вопрос

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

Я пытался проверить утверждение 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))

И это работало на всех случаях.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top