2010-10-14 14 views
9

He visto otras publicaciones aquí con respecto a este problema y ninguno de ellos parece abordar mi situación.SignedXml checksignature devuelve falso

He intentado verificar una afirmación de SAML durante la última semana y tengo 2 clientes que me han enviado SAML pero no puedo verificarlo.

El proceso principal es obtener una aserción codificada en base64 y decodificarla. Cargarlo en un XmlDocment con PreserveWhitespace = true.

El método es verificar

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 que SignedXml se creó con el nuevo SignedXml (xmlElement)

Ambos clientes obtienen un falso devuelto por el signo de verificación, pero cuando creo mi propio saml firmado con mi certificado, se devuelve verdadero.

¿Qué me falta aquí?

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

+1

Déjeme adivinar, ¿la afirmación que recibe ha sido generada en un lenguaje que no es de.net, como Java? –

+0

¿Qué hace 'SetSigningKeyFromKeyInfo (signedXml);' do? –

+0

Cuando ha codificado base64 la aserción, ¿puede volcar el xml en un archivo y compararlo con una de sus propias afirmaciones para verificar inconsistencias estructurales (sutiles)? –

Respuesta

7

que se ocupó de XML firmado es mucho en el pasado. Todo lo que puedo decir es que fue una pesadilla. Básicamente, cuando firmas XML, pasa por un proceso llamado canonicalización (C14N). Tiene que convertir el texto XML en una secuencia de bytes que se puede firmar. Espacio en blanco & manejo del espacio de nombres, entre otros, en XML Los estándares C14N son difíciles de entender, incluso más difíciles de implementar correctamente. Incluso hay varios tipos de C14N.

La implementación de .NET es muy selectiva sobre lo que acepta. Es muy posible que su otra implementación no funcione exactamente de la misma manera que .NET. Esto es muy triste de hecho. Si puede eliminar espacios en blanco y espacios de nombres de su XML fuente antes de firmar, por ejemplo, eso podría ayudar. Además, si puede asegurarse de que ambas implementaciones utilicen la misma configuración de C14N.

De lo contrario, mucha depuración lo espera. Puede depurar en el marco, o llamar a sus métodos internos a mano con reflexión, para ver cómo calcula el fragmento XML y la firma. Y haz lo mismo con la otra implementación. Básicamente, debe ver las secuencias de bytes exactas que se firman en ambos casos. Este es el último paso de la conversión antes de firmar. Si esas secuencias de bytes coinciden, entonces no tendrás problemas con la parte de firma de RSA en mi experiencia. Si no coinciden, como en su caso, al menos verá dónde está el problema.

+4

Realmente me gustaría que esta no fuera la respuesta correcta. – Hovis

1

Acabo de tener un problema similar y he perdido mucho tiempo, tal vez esto pueda ayudar a alguien.

Mi entorno es 100% .Net 4.5 y mi código usa solo la clase SignedXml. Pero una afirmación de SAML fue aceptada en un lugar y rechazada en otro.

Resultó que un lugar estaba cargando la aserción a través de una instancia XmlDocument inicializada con PreserveWhitespace = true, mientras que la otra no.

Y la afirmación había sido bastante impresa, por lo que tenía retornos de carro y una gran cantidad de espacios de indentación. Al eliminar todos los retornos de carro y los espacios de sangría corrigieron mi problema.

Cuestiones relacionadas