Pregunta

He mirado en otros puestos de aquí sobre este tema y ninguno de ellos parece abordar mi situación.

he estado tratando de verificar una aserción SAML para la última semana y tengo 2 clientes que me han enviado SAML, pero no puedo verificarlo.

El proceso principal es que obtenemos una afirmación de base64 y decodificarlo. Cargarlo en un XmlDocment con PreserveWhitespace = true.

El método verificar es

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

Tengo el certificado del cliente que he leído desde Web.Config (almacenado su cadena como base64) XmlElement es el elemento firmado, SignedXml es un objeto SignedXml que se creó con el nuevo SignedXml (XmlElement)

Tanto los clientes obtengan falsa devuelto por CheckSignature pero cuando creo mi propia saml firmado con mi certificado se volverán realidad.

¿Qué me estoy perdiendo aquí?

EDIT: Sí, tanto de los clientes están en Java y he publicado el método SetSigningKeyFromKeyInfo

¿Fue útil?

Solución

Me trató de XML firmado mucho en el pasado. Todo lo que puedo decir es que era una pesadilla. Básicamente, cuando se suscribe XML, pasa por un proceso llamado canónicos (C14N). Se tiene que convertir texto XML a un flujo de bytes que puede ser firmada. Los espacios en blanco y espacio de nombres de manejo, entre otros, en XML estándares C14N son difíciles de entender, aún más difícil de poner en práctica la derecha. Incluso hay varios tipos de C14N.

La aplicación .NET es muy selectivo sobre lo que acepta. Es muy posible que su otra aplicación no funciona de la misma manera exacta como la que .NET. Esto es muy triste. Si usted puede eliminar espacios en blanco y espacios de nombres XML de su fuente antes de firmar, por ejemplo, que podría ayudar. Además, si usted podría asegurarse de que ambas implementaciones utilizan la misma configuración C14N.

De lo contrario una gran cantidad de depuración le espera. Se podría depurar en el marco, o llamar a sus métodos internos de la mano con la reflexión, para ver cómo se calcula el fragmento de XML y la firma. Y hacer lo mismo con la otra aplicación. Básicamente lo que necesita para ver los flujos de bytes exactos que se firman en ambos casos. Este es el paso final de la conversión antes de la firma. Si los flujos de bytes partido, entonces usted no tendrá ningún problema con la parte RSA firma, en mi experiencia. Si los no coinciden, al igual que en su caso, al menos verá dónde está el problema.

Otros consejos

Sólo tenía un problema similar y perdí mucho tiempo, tal vez esto puede ayudar a alguien.

Mi entorno es 100% .Net 4.5, y mi código utiliza sólo la clase SignedXml. Sin embargo, una aserción SAML fue aceptado en un lugar y se negó a otro.

Resultó que un solo lugar estaba cargando la afirmación través de una instancia XmlDocument inicializado con PreserveWhitespace = true, mientras que el otro no lo era.

Y la afirmación había sido bastante impresa, por lo que tuvo retornos de carro y una gran cantidad de espacios de sangría. La eliminación de todos los retornos de carro y los espacios de sangría fijos mi problema.

Si hubiera un problema similar con Saml como Timores. El Saml necesitaba ser decodificado desde Base64 pero primero i utiliza:

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

Sin embargo, esta decodificación ASCII utilizados y problemas tenía con caracteres especiales. Lo que significa que el XML era ligeramente diferente a cuando se firmó y es por eso que falló. Cambiado a:

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

y funcionó para todos los casos.

Así que asegúrese de que está utilizando la codificación correcta!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top