2015-02-16 13 views
7

Non riesco a trovare i certificati client che funzionano con il mio progetto SslStream. Non importa quello che faccio, non riesco a far sì che effettivamente usi il certificato client, nonostante tutti i certificati siano validi e affidabili, e ho importato il certificato CA per quelli che ho generato io stesso, e non lo fa lavoro. Devo mancare qualcosa, ma ci sono passato decine di volte, ho revisionato documentazione, esempi e ore di ricerca su google, e non riesco a farlo funzionare. Che cosa sto facendo di sbagliato?.Net SslStream con certificato client

Il Cliente:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Net.Security; 
using System.Net.Sockets; 
using System.Reflection; 
using System.Security.Cryptography.X509Certificates; 
using System.Text; 

namespace SslClient 
{ 
    class SslClientProgram 
    { 
     static void Main(string[] args) 
     { 
      TcpClient client = new TcpClient("localhost", 443); 

      SslStream stream = new SslStream(client.GetStream(), false, VerifyServerCertificate, null); 

      Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); 
      string location = assembly.Location; 
      int pos = location.LastIndexOf('\\'); 
      location = location.Substring(0, pos); 
      X509Certificate2 certificate = new X509Certificate2(location + "\\my.client.certificate.pfx", "password"); 

      stream.AuthenticateAsClient("my.host.name", new X509Certificate2Collection(certificate), System.Security.Authentication.SslProtocols.Tls, false); 

      StreamReader reader = new StreamReader(stream); 
      StreamWriter writer = new StreamWriter(stream); 

      while (true) 
      { 
       string line = System.Console.ReadLine(); 
       writer.WriteLine(line); 
       writer.Flush(); 
       if (line == "close") break; 
       line = reader.ReadLine(); 
       System.Console.WriteLine("Received: {0}", line); 
      } 

      stream.Close(); 
     } 

     private static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 
     { 
      return true; 
     } 
    } 
} 

Server:

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Net.Security; 
using System.Net.Sockets; 
using System.Reflection; 
using System.Security.Cryptography.X509Certificates; 
using System.Text; 

namespace SslServer 
{ 
    class SslServerProgram 
    { 
     static void Main(string[] args) 
     { 
      TcpListener server = new TcpListener(System.Net.IPAddress.Loopback, 443); 

      server.Start(); 

      TcpClient client = server.AcceptTcpClient(); 

      SslStream stream = new SslStream(client.GetStream(), false, VerifyClientCertificate, null); 

      Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); 
      string location = assembly.Location; 
      int pos = location.LastIndexOf('\\'); 
      location = location.Substring(0, pos); 
      X509Certificate2 certificate = new X509Certificate2(location + "\\my.server.certificate.pfx", "password"); 

      stream.AuthenticateAsServer(certificate, false, System.Security.Authentication.SslProtocols.Tls, false); 

      if (stream.RemoteCertificate != null) 
      { 
       System.Console.WriteLine(stream.RemoteCertificate.Subject); 
      } 
      else 
      { 
       System.Console.WriteLine("No client certificate."); 
      } 

      StreamReader reader = new StreamReader(stream); 
      StreamWriter writer = new StreamWriter(stream); 

      bool clientClose = false; 
      while (!System.Console.KeyAvailable) 
      { 
       System.Console.WriteLine("Waiting for data..."); 
       string line = reader.ReadLine(); 
       System.Console.WriteLine("Received: {0}", line); 

       if (line == "close") 
       { 
        clientClose = true; 
        break; 
       } 

       writer.WriteLine(line); 
       writer.Flush(); 
      } 

      if (!clientClose) System.Console.ReadKey(); 

      stream.Close(); 
      server.Stop(); 
     } 

     private static bool VerifyClientCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) 
     { 
      return true; 
     } 
    } 
} 

Non importa quello che provo, il server dice sempre: "No certificato client."

risposta

6

Come risulta, AuthenticateAsServer è la chiave qui - in particolare, il secondo parametro.

Se clientCertificateRequired è false, ignorerà completamente i certificati client, anche se specificata dal cliente, ma se è true, li permetterà, ma non un'eccezione se non è specificato alcun certificato client.

Sciocco me - ho pensato clientCertificateRequired insieme al vero significato che sarebbe effettivamente richiesto, perché la documentazione di .NET lo descrive come:

"Un valore booleano che specifica se il client mosto fornire un certificato per l'autenticazione. "* (sottolineatura mia)

la mia aspettativa era che se fosse true, e ho non ha inviato un certificato client, quindi fallirebbe. Questo è un caso chiaro di documentazione non completamente accurata da parte di Microsoft.

Aggiornamento: Il latest documentation per il parametro clientCertificateRequired include la frase "Si noti che questo è solo una richiesta - se non viene fornito alcun certificato, il server accetta ancora la richiesta di connessione."