2010-10-14 14 views
9

Ho visto altri post qui riguardo a questo problema e nessuno di loro sembra affrontare la mia situazione.SignedXml checksign restituisce false

Ho cercato di verificare un'asserzione SAML per la scorsa settimana e ho 2 client che mi hanno inviato SAML ma non riesco a verificarlo.

Il processo principale è che otteniamo un'asserzione codificata Base64 e la decodifico. Caricalo in un XmlDocment con PreserveWhitespace = true.

La verifica metodo è

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

aver il certificato dal client che ho letto dalla Web.Config (suo memorizzato come stringa base64 codificato) xmlelement rappresenta l'elemento firmato, SignedXml è un oggetto che SignedXml è stato creato con nuovo SignedXml (xmlElement)

Entrambi i client ottengono false restituite tramite assegno di controllo ma quando creerò il mio saml firmato con il mio certificato restituirà true.

Cosa mi manca qui?

EDIT: Sì entrambi i clienti sono su Java e ho postato il metodo SetSigningKeyFromKeyInfo

+1

Lasciami indovinare, l'asserzione che ricevi è stata generata in un linguaggio non -.net, come Java? –

+0

Cosa significa 'SetSigningKeyFromKeyInfo (signedXml);' do? –

+0

Quando si assegna a base64 l'asserzione, si può scaricare l'xml in un file e confrontarlo con una delle proprie asserzioni per verificare le incoerenze strutturali (sottili)? –

risposta

7

ho affrontato con XML firmato un sacco in passato. Tutto quello che posso dire è che è stato un incubo. Fondamentalmente, quando si firma XML, passa attraverso un processo chiamato canonicalization (C14N). Deve trasformare il testo XML in un flusso di byte che può essere firmato. Lo spazio degli spazi & per la gestione degli spazi dei nomi, tra gli altri, negli standard XML C14N è difficile da capire, anche più difficile da implementare correttamente. Esistono anche più tipi di C14N.

L'implementazione .NET è molto selettiva su ciò che accetta. È possibile che l'altra implementazione non funzioni esattamente nello stesso modo di quella .NET. Questo è davvero molto triste. Se è possibile eliminare spazi bianchi e spazi dei nomi dal codice XML sorgente prima di firmare, ad esempio, ciò potrebbe essere di aiuto. Inoltre, se si è sicuri che entrambe le implementazioni utilizzino le stesse impostazioni C14N.

In caso contrario, molti debugging ti aspettano. È possibile eseguire il debug nel framework, o richiamare i suoi metodi interni a mano con la reflection, per vedere come calcola il frammento XML e la firma. E fare lo stesso con l'altra implementazione. Fondamentalmente è necessario vedere i flussi di byte esatti che sono firmati in entrambi i casi. Questo è il passaggio finale della conversione prima della firma. Se questi flussi di byte corrispondono, non avrai problemi con la parte di firma RSA nella mia esperienza. Se quelli non corrispondono, come nel tuo caso, almeno vedrai dove si trova il problema.

+4

Vorrei davvero che questa non fosse la risposta giusta. – Hovis

1

Ho appena avuto un problema simile e ho perso un sacco di tempo, forse questo può aiutare qualcuno.

Il mio ambiente è 100% .Net 4.5 e il mio codice utilizza solo la classe SignedXml. Ma un'asserzione SAML è stata accettata in un posto e rifiutata in un altro.

Si è scoperto che un posto stava caricando l'asserzione attraverso un'istanza XmlDocument inizializzata con PreserveWhitespace = true, mentre l'altra no.

E l'affermazione era stata piuttosto stampata, quindi aveva ritorni a capo e molti spazi di indentazione. Rimuovere tutti i ritorni a capo e gli spazi di indentazione risolto il mio problema.