2010-11-03 47 views
12

Estoy intentando acceder a un servicio web SOAP hospedado públicamente (no WCF) sobre https, y me aparece un error que nunca he visto antes. Primero, aquí están los hechos:¿Cómo forzar al cliente de WCF a enviar el certificado del cliente?

  • Este servicio requiere certificados del cliente. Tengo un certificado firmado por la misma CA como el certificado del servidor.
  • Sé que la URL está disponible, ya que puedo acceder a ella en Internet Explorer. IE abre la ventana "elegir certificado", y si lo selecciono (e ignoro el error de servidor-nombre-host-no-coincide-certificado), continúa y me da un error HTTP 500.
  • Si abro el sitio en Chrome, después de seleccionar el certificado e ignorar el error, aparece un mensaje de error normal sobre WSA Action = null.
  • Si abro el sitio en FireFox, después de ignorar el error, aparece una página sobre cómo el servidor no pudo validar mi certificado. Nunca me pidió que eligiera uno, así que tiene mucho sentido.

Ahora, la excepción:

Error occurred while executing test 12302: System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'ihexds.nist.gov:9085'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel. 
    at System.Net.HttpWebRequest.GetResponse() 
    at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) 

he rastreado la interacción con Wireshark, sino porque yo no soy un experto en el protocolo TLS, yo podía faltar pistas sobre lo que está pasando . Aquí, sin embargo, es lo que veo:

  1. C -> S Cliente Hola
    • Contiene cosas como un número aleatorio, fecha/hora, suites con clave soportados, etc
  2. S - > C servidor Hola, certificado, de solicitud de certificado, el servidor Hola Hecho
    • Contiene el certificado del servidor, y una solicitud de un certificado de cliente
  3. C -> S certificado, el cliente de intercambio de claves, Cambio Cipher Spec, cifrada Handshake mensaje
    • Aquí está la parte INTERESANTE - La primera parte de este paquete es el apretón de manos certificado, en el que asumirá el certificado de cliente haría ser, pero no hay certificados presentes (longitud de los certificados: 0).
  4. S -> C Alerta (Nivel: Fatal, Descripción: Certificado malo)
    • Bueno, sí, no había certificado enviado.

Mi unión está configurado de la siguiente manera:

<binding name="https_binding"> 
    <textMessageEncoding /> 
    <httpsTransport useDefaultWebProxy="false" /> 
</binding> 

Mi comportamiento está configurado de la siguiente manera:

<behavior name="clientcred"> 
    <clientCredentials> 
     <clientCertificate findValue="69b6fbbc615a20dc272a79caa201fe3f505664c3" storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint" /> 
     <serviceCertificate> 
      <authentication certificateValidationMode="None" revocationMode="NoCheck" /> 
     </serviceCertificate> 
    </clientCredentials> 
    <messageInspector /> 
</behavior> 

Mi punto final está configurado para utilizar tanto la unión y el comportamiento. ¿Por qué WCF se niega a enviar el certificado cuando crea la conexión https?

Respuesta

9

He resuelto el problema, pero no entiendo por qué este cambio de configuración lo solucionó. He cambiado esta línea:

<httpsTransport useDefaultWebProxy="false" /> 

a esto:

<httpsTransport useDefaultWebProxy="false" requireClientCertificate="true" /> 

y mágicamente se comenzó a trabajar. Entendí que el "mando" requireClientCertificate era para el lado del servidor, así que no lo había intentado durante mi discusión. Aparentemente estaba equivocado.

+0

Odio WCF tanto. Esta solución funcionó para mí, gracias montones, pero todo es tan complicado. Mátame ahora. – robnick

-1

Podría ser un problema negociar qué protocolo de seguridad usar.Específicamente estoy pensando que al servidor no le gustará que WCF intente usar TLS 1.0.

Para ver si este es el caso, trate de añadir lo siguiente antes de llamar al servicio

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3 

Esto se podría añadir ya sea en código de cliente o colocándolo en una IEndpointBehavior

+0

Intenté esto y no cambió los resultados. Sé que el servidor admite TLS 1.0 (y solo un cifrado específico, de hecho, pero ese cifrado está en la lista enviada al servidor en el protocolo de enlace). – Mark

+0

No si el intercambio llegó tan lejos como un mensaje ChangeCipherSpec. Eso significa que todo sobre el protocolo ha sido acordado. – EJP

2

No debería haber sido una CertificateRequest del servidor, nombrando tipos de certificaciones y CA aceptables. Si su certificado no coincide con los que no se enviará.

+0

Hubo una solicitud de certificado (ver n. ° 2), y de hecho contenía una lista de CA y tipos de certificados. De hecho, tengo un certificado apropiado, y es el especificado en el comportamiento. – Mark

+0

Si todo eso es cierto, habría un mensaje de Certificado del cliente después de CertificateRequest del servidor. La conclusión ineludible es que parte de esto no es verdad. Debe verificarlo todo: específicamente, que el certificado (a) está disponible para la aplicación y (b) cumple con todas las restricciones expresadas en CertificateRequest. – EJP

+0

Es comprobablemente cierto ... Tengo la captura WireShark aquí. Terminé resolviendo el problema, pero realmente no entiendo por qué lo que cambié lo solucionó. Lo publicaré en una respuesta separada. – Mark

Cuestiones relacionadas