2011-05-25 11 views
10

Estoy escribiendo un analizador de respuestas SAML 2.0 para manejar la autenticación POST en ASP.Net (en C# y MVC, pero eso es menos relevante).Cómo verificar un X509Certificate2 contra una cadena X509Certificate2Collection

Así que tengo un archivo .p7b para validar con y que se puede leer en un X509Certificate2Collection y una afirmación de muestra - una respuesta SAML codificada en base 64.

Idealmente quiero usar el construido en WSSecurityTokenSerializer, pero that fails, entonces estoy buscando una manera que funcione.

estoy leyendo el código XML directamente en su lugar:

// get the base 64 encoded SAML 
string samlAssertionRaw = GetFromHttpRequest(); 

// load a new XML document 
var assertion = new XmlDocument { PreserveWhitespace = true }; 
assertion.LoadXml(samlAssertionRaw); 

// use a namespace manager to avoid the worst of xpaths 
var ns = new XmlNamespaceManager(assertion.NameTable); 
ns.AddNamespace("samlp", @"urn:oasis:names:tc:SAML:2.0:protocol"); 
ns.AddNamespace("saml", @"urn:oasis:names:tc:SAML:2.0:assertion"); 
ns.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl); 

// get the signature XML node 
var signNode = assertion.SelectSingleNode(
    "/samlp:Response/saml:Assertion/ds:Signature", ns); 

// load the XML signature 
var signedXml = new SignedXml(assertion.DocumentElement); 
signedXml.LoadXml(signNode as XmlElement); 

// get the certificate, basically: 
// signedXml.KeyInfo.OfType<KeyInfoX509Data>().First(). 
//  Certificates.OfType<X509Certificate2>().First() 
// but with added checks 
var certificate = GetFirstX509Certificate(signedXml); 

// check the key and signature match 
if (!signedXml.CheckSignature(certificate, true)) 
{ 
    throw new SecurityException("Signature check failed."); 
} 

// go on and read the SAML attributes from the XML doc 

que funciona mucho, pero todo lo que está haciendo es comprobar que la firma y la clave pública X509Certificate2 en el partido de la respuesta SAML. De ninguna manera verifica de quién es, y debo hacerlo antes de aceptar la autenticación SAML.

Parece haber dos formas de verificar el certificado encontrado en la respuesta de SAML: puedo hacer certificate.Verify() o puedo hacer el control con la firma signedXml.CheckSignature(certificate, false).

Sin embargo ambos devuelven falso.

Creo que esto se debe a que están siendo revisados ​​en la tienda de máquinas o posiblemente en línea (no estoy seguro de cómo verificar). Quiero verificarlos contra el X509Certificate2Collection recuperado del archivo .p7b en su lugar - los certificados registrados en la máquina deben ignorarse y solo deben verificarse los certificados .p7b.

No parece haber ninguna forma de pasar el X509Certificate2Collection a los métodos Verify o CheckSignature.

¿Es esta la comprobación correcta de la respuesta de SAML?

¿Hay alguna forma de utilizar los certificados .p7b de la manera que quiero?

+0

¿Qué hace GetFirstX509Certificate? – theycallmemorty

+0

Hice una pregunta similar aquí: http://security.stackexchange.com/questions/3905/verify-saml-response-is-from-a-trusted-source pero finalmente terminé en su publicación porque estoy teniendo el mismo problema con CheckSignature – theycallmemorty

+0

@theycallmemorty - Intento explicar en los comentarios, pero hace 'signedXml.KeyInfo [0] .Certificates [0] como X509Certificate2', pero con controles y conversiones. – Keith

Respuesta

5

Ha intentado utilizar un X509Chain personalizado configurado para buscar un ExtraStore de certificados durante el proceso de validación. Algo así como lo siguiente:

// Placeholder for the certificate to validate 
var targetCertificate = new X509Certificate2(); 
// Placeholder for the extra collection of certificates to be used 
var certificates = new X509Certificate2Collection(); 

var chain = new X509Chain(); 

chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; 
chain.ChainPolicy.ExtraStore.AddRange(certificates); 

bool isValidCertificate = chain.Build(targetCertificate); 

En el ejemplo de la comprobación de revocación también se desactiva, pero si usted tiene en línea o fuera de línea para el acceso a la CRL se podía activarlo.


El ExtraStore debería permitir incluir certificados intermedios que no están en el almacén de la máquina/usuario. Sin embargo, es posible que el certificado raíz de confianza deba estar en la máquina o en el almacén de usuarios, dependiendo del especificado en X509Chain, porque de lo contrario obtendrá un error UntrustedRoot. Si ni siquiera la raíz puede estar disponible en una máquina o tienda de usuario, podrías intentar subir por la cadena resultante y garantizar que el único error que tienes se deba a una raíz que no es de confianza y, al mismo tiempo, garantizar que la raíz de la cadena sea lo que tú esperaría basado en el X509Certificate2Collection que tiene para la validación.

Como alternativa, puede crear su propia X509CertificateValidator personalizada para validar un certificado teniendo en cuenta únicamente el proporcionado X509Certificate2Collection.

+0

Sí, lo he intentado - 'chain.Build' vuelve como no válido porque mi' X509Certificate2Collection' no es válido. Sin embargo, no estoy buscando validar la colección, y me complace tomar el contenido del '.p7b' como autorizado. Solo quiero verificar el certificado SAML con la colección' .p7b'. – Keith

+0

Creo que el problema podría estar relacionado con 'chain.ChainPolicy.ExtraStore.AddRange' - No estoy buscando agregar a la máquina existente o tienda de usuario, necesito comenzar de nuevo con solo las claves en el archivo' .p7b' . – Keith

+0

¿Cuál es el 'ChainStatus' que obtiene después de realizar la compilación? Tenía entendido que el 'ExtraStore' no agregaría nada a las tiendas de la máquina o del usuario y solo incluiría los certificados especificados en el proceso de validación. –

Cuestiones relacionadas