2015-02-16 20 views
7

Ich habe kein Glück, Client-Zertifikate mit meinem SslStream-Projekt arbeiten. Egal, was ich mache, ich kann es nicht dazu bringen, das Client-Zertifikat tatsächlich zu verwenden, obwohl alle Zertifikate gültig und vertrauenswürdig sind, und ich habe das CA-Zertifikat für die von mir generierten Zertifikate importiert, und das tut es einfach nicht Arbeit. Ich muss etwas vermissen, aber ich war dutzende Male drüber, habe die Dokumentation, Beispiele und Stunden der Google-Suche durchgesehen, und ich kann es einfach nicht zum Laufen bringen. Was mache ich falsch?.Net SslStream mit Client-Zertifikat

Der Kunde:

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; 
     } 
    } 
} 

Der 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; 
     } 
    } 
} 

Egal, was ich versuche, sagt der Server immer "kein Client-Zertifikat."

Antwort

6

Wie sich herausstellt, ist AuthenticateAsServer der Schlüssel hier - genauer gesagt, der zweite Parameter.

Wenn clientCertificateRequired ist false, wird es vollständig Client-Zertifikate ignorieren, auch wenn man von dem Client angegeben wird, aber wenn es true ist, wird es ihnen erlauben, aber nicht werfen eine Ausnahme, wenn kein Client-Zertifikat angegeben ist.

Dumme mir - ich dachte clientCertificateRequired Satz wahr bedeutete, dass es erforderlich tatsächlich wäre, weil die Dokumentation .Net beschreibt sie als:

„Ein boolescher Wert, der muss spezifiziert ob der Client ein Zertifikat für die Authentifizierung liefern. "* (Hervorhebung von mir)

Meine Erwartung war, dass, wenn es ist true, und ich habe kein Client-Zertifikat gesendet, dann würde es fehlschlagen. Dies ist ein klarer Fall von weniger als vollständig genauer Dokumentation von Seiten von Microsoft.

Update: Die latest documentation für die clientCertificateRequired Parameter enthält die Phrase "Beachten Sie, dass dies nur eine Anfrage ist - wenn kein Zertifikat zur Verfügung gestellt wird, akzeptiert der Server immer noch die Verbindungsanfrage."

Verwandte Themen