2
votes

I am working on a larger C# sockets app that will use both server and client authentication via SSL. In order to test the other parts of the app on my local machine I need to disable certification validation. I've tried overriding ServerCertificateValidatioNCallback as suggested in a few other places but I continue to get an exception. I'm testing using self-signed certificates created using OpenSSL.

The articles with solutions I have tried:

The exception I am getting:

StackTrace:    at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslStream.AuthenticateAsServer(X509Certificate serverCertificate, Boolean clientCertificateRequired, SslProtocols enabledSslProtocols, Boolean checkCertificateRevocation)

I've reduced my server code down to the following:

 ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
 X509Certificate2 cert = new X509Certificate2("server.pfx", "password");

 IPAddress ip = IPAddress.Parse("127.0.0.1");
 TcpListener server = new TcpListener(ip, 8000);
 server.Start();

 TcpClient client = server.AcceptTcpClient();
 Console.WriteLine(client.Client.RemoteEndPoint.ToString() + ":" + ((IPEndPoint)client.Client.RemoteEndPoint).Port + " connected");
 SslStream ssl = new SslStream(client.GetStream(), false);
 ssl.AuthenticateAsServer(cert, true, SslProtocols.Tls, false);

And the client code is as follows:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
TcpClient client = new TcpClient("127.0.0.1", 8000);
X509Certificate2Collection coll = new X509Certificate2Collection();
coll.Add(new X509Certificate2("client.pfx", "password"));
byte[] data = Encoding.UTF8.GetBytes("Hello from the client!");

using (SslStream ssl = new SslStream(client.GetStream(), false))
{
  ssl.AuthenticateAsClient("127.0.0.1", coll, SslProtocols.Tls, false);
  ssl.Write(data, 0, data.Length);
  data = new Byte[8192];
  int bytes = 0;
  string resp = "";

  do
  {
    bytes = ssl.Read(data, 0, data.Length);
    if (bytes > 0) resp += System.Text.Encoding.ASCII.GetString(data, 0, bytes);
  }
  while (bytes > 0);

  Console.WriteLine("Response: " + resp);
}

client.Close();

The exception occurs on AuthenticateAsServer and AuthenticateAsClient. The design of the application requires use of client certificates.

I've tried importing the PFX files into the certificate store, made no difference in the outcome.

I've also tried re-creating the self-signed certificates and private keys using makecert and converting to PFX using pvk2pfx.exe, made no difference in the outcome. My thinking was that perhaps it was an issue that they were created on another machine.

1

1 Answers

5
votes

Apparently this line is not enough:

ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };

I had to change my SslStream from: (server)

SslStream ssl = new SslStream(client.GetStream(), false);

and (client)

using (SslStream ssl = new SslStream(client.GetStream(), false))

To: (server)

SslStream ssl = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateCert));

and (client)

using (SslStream ssl = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateCert)))

and add the following method:

public static bool ValidateCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
    return true; // Allow untrusted certificates.
}

Apparently this takes precedence over the: ServicePointManager.ServerCertificateValidationCallback delegate.

So apparently, I now need to figure out how to amend ValidateCert to selectively allow untrusted certificates vs not.