2009-10-29 33 views
11

Estoy intentando autenticar a mí mismo contra el servicio Web usando mi certificado de cliente, pero, por alguna razón (lo explico), que no quieren cargar el certificado en la tienda, en lugar leerlo desde el disco .no certificado de cliente en el almacén de certificados

la siguiente:

// gw is teh WebService client 
X509Certificate cert = new X509Certificate(PathToCertificate); 
_gw.ClientCertificates.Add(ClientCertificate()); 
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true; 
_gw.DoSomeCall(); 

Siempre devuelve 403 - el servicio no me autorizan. Pero, cuando guardo ese certificado en CertStore, funciona. (Como se indica en MSDN.)

¿Es posible usar el certificado no en la tienda?

(la razón es, que me dieron servicio de Windows (cliente) a veces llamada de servicio web (servidor), y después de tiempo no especificado los servicios "olvida de mis certificados y imposible autorizo ​​contra el servidor, sin razón aparente)

Respuesta

22

¿Qué tipo de archivo es PathToCertificate? Si solo se trata de un archivo .cer, no contendrá la clave privada para el certificado y se producirá un error al intentar usar ese certificado para SSL/TLS.

Sin embargo, si tiene un archivo PKCS7 o PKCS12 que incluye la clave pública y privada para el certificado, su código funcionará (puede necesitar usar la sobrecarga que toma una contraseña si la clave privada tiene una).

Para probar esto, fui a http://www.mono-project.com/UsingClientCertificatesWithXSP y creado mi archivo client.p12 ajustarse a dichas instrucciones. También creé un servidor HTTPS simple usando HttpListener para probar.

Luego compila el programa siguiente en 'client.exe' y correr como:

client.exe https://<MYSSLSERVER>/ client.p12 password 

donde client.p12 es el archivo PKCS12 generados antes y 'contraseña' es la contraseña me puse para la clave privada del certificado.

using System; 
using System.IO; 
using System.Net; 
using System.Security.Cryptography.X509Certificates; 
using System.Text; 

public class HttpWebRequestClientCertificateTest : ICertificatePolicy { 

    public bool CheckValidationResult (ServicePoint sp, X509Certificate certificate, 
      WebRequest request, int error) 
    { 
      return true; // server certificate's CA is not known to windows. 
    } 

    static void Main (string[] args) 
    { 
      string host = "https://localhost:1234/"; 
      if (args.Length > 0) 
        host = args[0]; 

      X509Certificate2 certificate = null; 
      if (args.Length > 1) { 
        string password = null; 
        if (args.Length > 2) 
          password = args [2]; 
        certificate = new X509Certificate2 (args[1], password); 
      } 

      ServicePointManager.CertificatePolicy = new HttpWebRequestClientCertificateTest(); 

      HttpWebRequest req = (HttpWebRequest) WebRequest.Create (host); 
      if (certificate != null) 
        req.ClientCertificates.Add (certificate); 

      WebResponse resp = req.GetResponse(); 
      Stream stream = resp.GetResponseStream(); 
      StreamReader sr = new StreamReader (stream, Encoding.UTF8); 
      Console.WriteLine (sr.ReadToEnd()); 
    } 
} 

Deseo saber si desea que cargue el código del servidor y los certificados utilizados en ambos lados de la prueba.

+0

¿Conoce cómo hacer el mismo trabajo en Windows .NET? Por algún motivo, no puedo hacer que funcione sin registrar el certificado en la tienda x509 – galets

1

¿Necesita una contraseña para el certificado? Si es así, hay un campo para él en el constructor.

X509Certificate cert = new X509Certificate(PathToCertificate,YourPassword); 
2

usted tiene el potencial para al menos dos problemas ...

Primera ...

Su archivo de certificado de cliente no puede contener una clave privada a menos que se accede con una contraseña. Debería utilizar un certificado PKCS # 12 (* .pfx) con una contraseña para que su cliente tenga acceso a la clave privada. Su código de cliente deberá proporcionar la contraseña al abrir el certificado ya que otros ya lo han publicado. Hay varias maneras de crear esto, lo más sencillo es utilizar la siguiente línea de comandos para generar primera vez el certificado, a continuación, utilizar el administrador de certificados de MMC para exportar los certificados de clave privada:

Process p = Process.Start(
    "makecert.exe", 
    String.Join(" ", new string[] { 
     "-r",//      Create a self signed certificate 
     "-pe",//     Mark generated private key as exportable 
     "-n", "CN=" + myHostName,// Certificate subject X500 name (eg: CN=Fred Dews) 
     "-b", "01/01/2000",//  Start of the validity period; default to now. 
     "-e", "01/01/2036",//  End of validity period; defaults to 2039 
     "-eku",//     Comma separated enhanced key usage OIDs 
     "1.3.6.1.5.5.7.3.1," +// Server Authentication (1.3.6.1.5.5.7.3.1) 
     "1.3.6.1.5.5.7.3.2", //  Client Authentication (1.3.6.1.5.5.7.3.2) 
     "-ss", "my",//    Subject's certificate store name that stores the output certificate 
     "-sr", "LocalMachine",// Subject's certificate store location. 
     "-sky", "exchange",//  Subject key type <signature|exchange|<integer>>. 
     "-sp",//     Subject's CryptoAPI provider's name 
     "Microsoft RSA SChannel Cryptographic Provider", 
     "-sy", "12",//    Subject's CryptoAPI provider's type 
     myHostName + ".cer"//  [outputCertificateFile] 
    }) 
); 

Segundo ...

Su próximo problema será el servidor. El servidor debe permitir este certificado. Tiene la lógica correcta, pero en el lado equivocado del cable, mueva esta línea al servidor web que maneja la solicitud. Si no puede, debe tomar el '.archivo CER' salvado anteriormente para el servidor y agregarlo a la lista de confianza del equipo servidor:

ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true; 
+0

-1. El servidor no necesita saber la clave privada del certificado del cliente. Solo necesita confiar en la CA que firmó el certificado del cliente. Al negociar SSL3/TLS, el servidor envía una lista con el DN de todas las CA permitidas. En ese punto, el cliente debería ver que la CA del certificado del cliente. está en la lista y lo envía. – Gonzalo

+0

Correcto, nunca dije que el SERVIDOR necesita la clave privada. Debe confiar en el certificado o permitirlo explícitamente con código. En cuanto al resto de su comentario "... el servidor envía una lista con el DN de todas las CA ..." eso simplemente no es cierto. –

+1

¿No es cierto? Consulte http://tools.ietf.org/html/rfc5246#page-53, sección 7.4.4: certificate_authorities Una lista de nombres completos [X501] de certificate_authorities aceptables, representados en formato DER-encoded. Estos nombres completos pueden especificar un nombre distinguido deseado para una CA raíz o para una CA subordinada; por lo tanto, este mensaje se puede usar para describir las raíces conocidas, así como un espacio de autorización deseado. Si la lista certificate_authorities está vacía, entonces el cliente PUEDE enviar cualquier certificado del ClientCertificateType apropiado, unles – Gonzalo

2

El potencial problema podría ser el almacenamiento en caché de las sesiones SSL (caché Schannel). Solo la primera solicitud negocia el protocolo de enlace SSL. Las solicitudes posteriores utilizarán la misma ID de sesión y esperan que el servidor la acepte. Si el servidor borra SessionId, las solicitudes fallarán con el error 403. Para deshabilitar el caché de sesión SSL local (y forzar la negociación SSL para cada solicitud) tiene que abrir las ventanas carpeta de registro:

[HKEY_LOCAL_MACHINE] [Sistema] [CurrentControlSet] [control] [SecurityProviders] [SCHANNEL]

y añadir la clave llamado ClientCacheTime (DWORD) con el valor 0.

Este tema se trata aquí:

http://support.microsoft.com/?id=247658

+0

Esto es bastante grande. Si no sabe esto, puede pasar mucho tiempo pensando que está reduciendo su solución de "prueba y error" a su forma más simple, mientras realmente rompe las cosas sin sospechar nada. – Chazt3n

Cuestiones relacionadas