title: Problems using SslStream in a TLS web socket server
body: <p>I followed <a href="https://stackoverflow.com/questions/1689450/how-to-create-a-self-signed-certificate-with-the-private-key-inside-in-a-file-in">this example</a> to create my test certificates. I used <code>Certificate.cer</code> for the server and <code>Certificate.pfx</code> for the client:</p>
  
  <p><code>makecert -r -pe -n "CN=Test Certificate" -sky exchange Certificate.cer -sv Key.pvk -eku 1.3.6.1.5.5.7.3.1,1.3.6.1.5.5.7.3.2</code></p>
  
  <p><code>"C:\Program Files (x86)\Windows Kits\8.1\bin\x64\pvk2pfx.exe" -pvk Key.pvk -spc Certificate.cer -pfx Certificate.pfx</code></p>
  
  <p>I am trying to create a web socket server and properly validate certificates from both the client and server sides of the communication. Here is my entire console application which I am currently building:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Net;
  using System.Net.Security;
  using System.Net.Sockets;
  using System.Net.WebSockets;
  using System.Security.Authentication;
  using System.Security.Cryptography.X509Certificates;
  using System.Text;
  using System.Threading.Tasks;
  
  namespace WebSockets
  {    
      class Program
      {
          static void Main(string[] args)
          {
              CreateWebSocketClient(CreateWebSocketServer(1337), 1338);
              Console.WriteLine("Press any key to exit.");
              Console.ReadKey();
          }
  
          private static IPEndPoint CreateWebSocketServer(int port)
          {
              var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
              IPEndPoint endpoint = new IPEndPoint(IPAddress.Loopback, port);
              socket.Bind(endpoint);
              socket.Listen(Int32.MaxValue);
              socket.BeginAccept((result) =&gt;
              {
                  var clientSocket = socket.EndAccept(result);
                  Console.WriteLine("{0}: Connected to the client at {1}.", DateTime.Now, clientSocket.RemoteEndPoint);
                  using (var stream = new SslStream(new NetworkStream(clientSocket), false, (sender, certificate, chain, sslPolicyErrors) =&gt;
                      {
                          return true;
                      }, (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) =&gt;
                      {
                          return new X509Certificate2("Certificate.pfx");
                      }, EncryptionPolicy.RequireEncryption))
                  {
                      stream.AuthenticateAsServer(new X509Certificate2("Certificate.pfx"), true, SslProtocols.Tls12, true);
                      stream.Write("Hello".ToByteArray());
                      Console.WriteLine("{0}: Read \"{1}\" from the client at {2}.", DateTime.Now, stream.ReadMessage(), clientSocket.RemoteEndPoint);
                  }
              }, null);
              Console.WriteLine("{0}: Web socket server started at {1}.", DateTime.Now, socket.LocalEndPoint);
              return endpoint;
          }
  
          private static void CreateWebSocketClient(IPEndPoint remoteEndpoint, int port)
          {
              var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
              IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Loopback, port);
              socket.Bind(localEndpoint);
              socket.BeginConnect(remoteEndpoint, (result) =&gt;
              {
                  socket.EndConnect(result);
                  Console.WriteLine("{0}: Connected to the server at {1}.", DateTime.Now, remoteEndpoint);
                  using (var stream = new SslStream(new NetworkStream(socket), false, (sender, certificate, chain, sslPolicyErrors) =&gt;
                      {
                          return true;
                      }, (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) =&gt;
                      {
                          return new X509Certificate2("Certificate.cer");
                      }, EncryptionPolicy.RequireEncryption))
                  {
                      stream.AuthenticateAsClient(remoteEndpoint.ToString(), new X509Certificate2Collection(new X509Certificate2[] { new X509Certificate2("Certificate.cer") }), SslProtocols.Tls12, true);
                      stream.Write("Hello".ToByteArray());
                      Console.WriteLine("{0}: Read \"{1}\" from the server at {2}.", DateTime.Now, stream.ReadMessage(), remoteEndpoint);
                  }
              }, null);
          }
      }
  
      public static class StringExtensions
      {
          public static Byte[] ToByteArray(this String value)
          {
              Byte[] bytes = new Byte[value.Length * sizeof(Char)];
              Buffer.BlockCopy(value.ToCharArray(), 0, bytes, 0, bytes.Length);
              return bytes;
          }
  
          public static String FromByteArray(this Byte[] bytes)
          {
              Char[] characters = new Char[bytes.Length / sizeof(Char)];
              Buffer.BlockCopy(bytes, 0, characters, 0, bytes.Length);
              return new String(characters).Trim(new Char[] { (Char)0 });
          }
  
          public static int BufferSize = 0x400;
  
          public static String ReadMessage(this SslStream stream)
          {
              var buffer = new Byte[BufferSize];
              stream.Read(buffer, 0, BufferSize);
              return FromByteArray(buffer);
          }
      }
  }
  </code></pre>
  
  <p>Communication between server and client works fine when you run it, but I am not sure how I should implement the callbacks, specifically because <code>sslPolicyErrors = RemoteCertificateNotAvailable</code> when the <a href="https://msdn.microsoft.com/en-us/library/system.net.security.remotecertificatevalidationcallback%28v=vs.110%29.aspx" rel="nofollow noreferrer">RemoteCertificateValidationCallback</a> is called on the server side and <code>sslPolicyErrors = RemoteCertificateNameMismatch | RemoteCertificateChainErrors</code> when the <a href="https://msdn.microsoft.com/en-us/library/system.net.security.remotecertificatevalidationcallback%28v=vs.110%29.aspx" rel="nofollow noreferrer">RemoteCertificateValidationCallback</a> is called on the client side. Also, <code>certificate</code> and <code>chain</code> are null on the server side but appear on the callback from the client side. Why is that? What are the problems with my implementation and how can I make my implementation validate SSL certificates properly? I have tried searching online about the <code>SslStream</code> but I have yet to see a full, X509-based TLS server-client implementation that does the type of certificate validation I need.</p>