Domanda

Ho guardato in altri posti qui riguardo a questo problema e nessuno di loro sembrano affrontare la mia situazione.

Ho cercato di verificare un SAML per l'ultima settimana e ho 2 clienti che mi hanno inviato SAML ma non posso verificarlo.

Il processo principale è che otteniamo una base64 codificato affermazione e mi decodificarlo. Caricarlo in un XmlDocment con PreserveWhitespace = true.

Il metodo di verifica è

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

Ho il certificato da parte del cliente che ho letto in da web.config (la sua memorizzati stringa come Base64) xmlelement è l'elemento firmato, SignedXml è un oggetto SignedXml che è stato creato con il nuovo SignedXml (XmlElement)

Entrambi i clienti a ottenere falsa restituito da checksignature ma quando creo il mio SAML firmato con il mio certificato che torneranno vero.

Che cosa mi manca qui?

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

È stato utile?

Soluzione

I affrontato di XML firmato molto in passato. Tutto quello che posso dire è che è stato un incubo. In sostanza, quando si firma XML, passa attraverso un processo chiamato canonica (C14N). Ha bisogno di convertire il testo XML a un flusso di byte che può essere firmato. Lo spazio bianco & namespace manipolazione, tra gli altri, in XML standard C14N sono difficili da capire, ancora più difficile da implementare destra. Ci sono anche diversi tipi di C14N.

L'applicazione .NET è molto selettivo su quello che accetta. E 'del tutto possibile che la vostra altra implementazione non funziona esattamente allo stesso modo di quello .NET. Questo è molto triste davvero. Se è possibile eliminare gli spazi e gli spazi dei nomi dalla sorgente XML prima di firmare, per esempio, che potrebbe aiutare. Anche se si potrebbe fare in modo che entrambe le implementazioni utilizzano le stesse impostazioni C14N.

In caso contrario, un sacco di debug vi aspetta. Si potrebbe eseguire il debug nel quadro, o chiamare i suoi metodi interni a mano con la riflessione, per vedere come si calcola il frammento XML e la firma. E fare lo stesso con l'altra applicazione. Fondamentalmente è necessario per vedere i flussi di byte esatte che sono firmati in entrambi i casi. Questa è la fase finale della conversione prima firma. Se quelli di byte flussi partita, quindi non avrete problemi con la parte RSA firma nella mia esperienza. Se quelli non corrispondono, come nel tuo caso, almeno vedrete dove è il problema.

Altri suggerimenti

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

Il mio ambiente è al 100% .Net 4.5, e il mio codice usa solo la classe SignedXml. Ma un SAML è stata accettata in un posto e si è rifiutato a un altro.

scoperto che un luogo caricava l'asserzione attraverso un'istanza XmlDocument inizializzata con PreserveWhitespace = true, mentre l'altra non era.

E l'affermazione era stata pretty-stampata, quindi aveva ritorni a capo e un sacco di spazi di indentazione. Rimozione di tutti i ritorni a capo e gli spazi di rientro fisso il mio problema.

Ha avuto un problema simile con Saml come Timores. SAML doveva essere decodificata di Base64 ma prima ho usato:

var saml = System.Text.Encoding.Default.GetString(Convert.FromBase64String(samlToken))

Ma questo decodifica ASCII utilizzati e problemi avuto con i caratteri speciali. Il che significa che l'XML è stato un po 'diverso da quando è stato firmato ed è per questo non è riuscito. Cambiato a:

var saml = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(samlToken))

e ha funzionato per tutti i casi.

Quindi, essere sicuri che si sta utilizzando la codifica giusta!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top