2010-10-14 27 views
9

Ich habe andere Beiträge hier in Bezug auf dieses Problem angeschaut und keine von ihnen scheint meine Situation anzusprechen.SignedXml checksignature gibt false zurück

Ich habe versucht, eine SAML-Assertion für die letzte Woche zu überprüfen, und ich habe 2 Clients, die mir SAML gesendet haben, aber ich kann es nicht überprüfen.

Der Hauptprozess ist eine Base64 codierte Behauptung und ich entziffere sie. Laden Sie es in ein XmlDocment mit PreserveWhitespace = true.

die Verifizierungsmethode ist

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."); 
    } 

I das Zertifikat von dem Client, die ich in von Web.Config gelesen (als seine gespeicherten Base64 codierten String) XMLELEMENT ist das unterzeichnete Element ist SignedXml ein Objekt, das SignedXml wurde mit neuen SignedXml (xmlElement)

erstellt Beide Clients erhalten falsche von Checksignature zurückgegeben, aber wenn ich meine eigene signierte saml mit meinem Zertifikat erstellen, wird True zurückgegeben.

Was fehlt mir hier?

EDIT: Ja beide der Kunden sind auf Java und ich fuhr die SetSigningKeyFromKeyInfo Methode

+1

Lassen Sie mich raten, die Behauptung, die Sie erhalten, wurde in einer Nicht-Sprache, wie Java, generiert? –

+0

Was macht 'SetSigningKeyFromKeyInfo (signedXml);'? –

+0

Wenn Sie die Assertion mit Base64 dekodieren, können Sie das XML in eine Datei speichern und es mit einer Ihrer eigenen Assertionen vergleichen, um nach (subtilen) strukturellen Inkonsistenzen zu suchen? –

Antwort

7

ich mit signierten XML behandelt ist viel in der Vergangenheit. Alles was ich sagen kann ist, dass es ein Albtraum war. Wenn Sie XML signieren, durchläuft es im Grunde einen Prozess, der als canonicalization (C14N) bezeichnet wird. Es muss XML-Text in einen Bytestream umwandeln, der signiert werden kann. Whitespace & Namespace-Handling, unter anderem in XML C14N Standards sind schwer zu verstehen, noch schwieriger zu implementieren, richtig. Es gibt sogar mehrere Arten von C14N.

Die .NET-Implementierung ist sehr selektiv, was es akzeptiert. Es ist durchaus möglich, dass Ihre andere Implementierung nicht genau so funktioniert wie die .NET-Implementierung. Das ist in der Tat sehr traurig. Wenn Sie Leerzeichen und Namespaces vor dem Signieren aus dem Quell-XML entfernen können, könnte das beispielsweise hilfreich sein. Auch wenn Sie sicherstellen könnten, dass beide Implementierungen die gleichen C14N-Einstellungen verwenden.

Sonst wartet viel Debugging auf Sie. Sie können das Framework debuggen oder seine internen Methoden manuell mit Reflektion aufrufen, um zu sehen, wie es das XML-Fragment und die Signatur berechnet. Und machen Sie das gleiche mit der anderen Implementierung. Grundsätzlich müssen Sie die genauen Bytestreams sehen, die in beiden Fällen signiert sind. Dies ist der letzte Schritt der Konvertierung vor der Unterzeichnung. Wenn diese Bytestreams übereinstimmen, haben Sie nach meiner Erfahrung keine Probleme mit dem RSA-Signaturteil. Wenn diese nicht übereinstimmen, wie in Ihrem Fall, werden Sie zumindest sehen, wo das Problem liegt.

+4

ist. Ich wünschte wirklich, das wäre nicht die richtige Antwort. – Hovis

1

Ich hatte gerade ein ähnliches Problem und habe viel Zeit verloren, vielleicht kann das jemandem helfen.

Meine Umgebung ist 100% .Net 4.5, und mein Code verwendet nur die SignedXml-Klasse. Aber eine SAML-Behauptung wurde an einem Ort akzeptiert und an einem anderen abgelehnt.

Es stellte sich heraus, dass eine Stelle die Assertion durch eine XmlDocument-Instanz geladen wurde, die mit PreserveWhitespace = true initialisiert wurde, während die andere nicht war.

Und die Behauptung wurde schön gedruckt, so hatte es Wagenrücklauf und viele Einbuchtungsräume. Durch das Entfernen aller Wagenrücklaufzeichen und der Einzugräume wurde mein Problem behoben.