2010-10-14 3 views
9

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

Я пытался проверить утверждение 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 строка) XmlElement является подписанный элемент, signedXml представляет собой объект, который SignedXml был создан с помощью нового SignedXml (xmlElement)

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

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

EDIT: Да оба клиентов на Java, и я отправил метод SetSigningKeyFromKeyInfo

+1

Позвольте мне угадать, утверждение, которое вы получаете, было сгенерировано на языке нетбуков, например Java? –

+0

Что делает 'SetSigningKeyFromKeyInfo (signedXml);' do? –

+0

Когда у вас есть base64decoded утверждение, можете ли вы выгрузить xml в файл и сравнить его с одним из ваших собственных утверждений, чтобы проверить (тонкие) структурные несоответствия? –

ответ

7

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

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

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

+4

Я действительно хочу, чтобы это был неправильный ответ. – Hovis

1

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

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

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

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

Смежные вопросы