2010-10-14 46 views
9

我已經看過關於這個問題的其他文章,並沒有一個似乎解決了我的情況。SignedXml checksignature返回false

我一直在嘗試驗證上週的SAML斷言,並且我有2個客戶端發送了SAML,但我無法驗證它。

主要過程是我們得到一個base64編碼的斷言,我解碼它。將其加載到PreserveWhitespace = true的XmlDocment中。

的驗證方法是

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)

這兩個客戶端都會通過checkignature返回false,但是當我使用我的證書創建自己的簽名saml時,它將返回true。

我在這裏錯過了什麼?

編輯:有兩個客戶都是在Java和我張貼的SetSigningKeyFromKeyInfo方法

+1

讓我猜測,您收到的斷言是以非.NET語言生成的,如Java? – 2010-10-14 17:11:39

+0

什麼'SetSigningKeyFromKeyInfo(signedXml);'做什麼? – 2010-10-14 17:13:36

+0

當您對base64進行解碼時,您是否可以將xml轉儲到一個文件並將其與您自己的斷言之一進行比較以檢查(微妙的)結構不一致? – 2010-10-14 17:17:16

回答

7

我處理了簽名的XML的很多過去。我只能說這是一場噩夢。基本上,當您簽署XML時,它會經歷一個稱爲規範化(C14N)的過程。它需要將XML文本轉換爲可簽名的字節流。空白&命名空間處理等XML中C14N標準很難理解,更難以正確實施。甚至有多種類型的C14N。

.NET實現對接受的內容非常有選擇性。很有可能您的其他實現不能以與.NET相同的方式工作。這確實很難過。例如,如果您可以在簽名前從源XML中刪除空格和名稱空間,那可能會有所幫助。此外,如果您可以確保兩個實施使用相同的C14N設置。

否則,很多調試等待着你。您可以調試到框架中,或者使用反射手動調用其內部方法,以查看它是如何計算XML片段和簽名的。並對其他實現做同樣的事情。基本上你需要看到兩種情況下簽名的確切字節流。這是簽名前轉換的最後一步。如果這些字節流匹配,那麼根據我的經驗,您將不會遇到RSA簽名部分的問題。如果這些與您的情況不符,至少您會看到問題出在哪裏。

+4

我真的希望這不是正確的答案。 – Hovis 2015-04-29 22:14:00

1

我剛剛有一個類似的問題,並失去了很多時間,也許這可以幫助某人。

我的環境是100%.Net 4.5,我的代碼只使用SignedXml類。但是SAML聲明在一個地方被接受,並在另一個地方被拒絕。

原來,一個地方是通過一個用PreserveWhitespace = true初始化的XmlDocument實例加載斷言,而另一個則不是。

而且這個斷言已經很漂亮了,所以它有回車符和很多縮進空格。 刪除所有回車和縮進空間解決了我的問題。