runtime: Linux - SslStream.AuthenticateAsClient is not presenting client certificates to server

This issue exists on Linux only

When establishing a connection to a TCP server where a client certificate is required, the client certificate does not get passed to the server side. The connection then gets aborted by the server, resulting in an exception as below.

Using NetMon, we can observe during that handshake that the server successfully sends its certificate to the client, but the client never presents the client certificate to the server. At this point, the server will send an RST and the connection is killed.

I’ve isolated the repro to using just a TcpClient and TcpServer + SslStream - see https://gist.github.com/iamjasonp/27cd1ebce287f8b51d0e for the rudimentary repro.

Platforms tested

  • .NET Desktop - ✅
  • .NET Core - Windows: ✅
  • .NET Core - Linux: ❌

First chance exception caught:

'System.Security.Authentication.AuthenticationException' in System.dll
Additional information: The remote certificate is invalid according to the validation procedure.

Server call stack:

System.dll!System.Net.Security.SslState.ForceAuthentication(bool receiveFirst, byte[] buffer, System.Net.AsyncProtocolRequest asyncRequest)
System.dll!System.Net.Security.SslState.ProcessAuthentication(System.Net.LazyAsyncResult lazyResult)
System.dll!System.Net.Security.SslStream.AuthenticateAsServer(System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, bool clientCertificateRequired, System.Security.Authentication.SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
TcpRepro-Server.exe!Examples.System.Net.SslTcpServer.ProcessClient(System.Net.Sockets.TcpClient client) 
TcpRepro-Server.exe!Examples.System.Net.SslTcpServer.RunServer() 
TcpRepro-Server.exe!Examples.System.Net.SslTcpServer.Main(string[] args)

This also looks to be the root cause of the issue in https://github.com/dotnet/wcf/issues/619#issuecomment-173177433

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 15 (10 by maintainers)

Most upvoted comments

@realityexists What is the value of clientCert.HasPrivateKey? If it’s false then there’s logic to search the CurrentUser\My and (on non-Linux) LocalMachine\My stores to find a matching cert which has a private key; which you may have installed in Windows but not Linux. If it’s true (e.g. the cert file is a PFX with a private key) then it should work since the private key is already known.

I’m running into this issue again under Ubuntu 16.04. dotnet --version = 2.0.0

I’m trying to connect to a Dovecot IMAP server configured to require client SSL certificates. Dovecot logs show that no certificate is sent when the client is running on Linux, but it is sent (and authentication succeeds) when running on Windows 7.

Minimal repro client code:

var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect("192.168.x.x", 993);

var ssl = new SslStream(new NetworkStream(socket, true), false, (sender, certificate, chain, errors) => true);
var clientCert = X509Certificate.CreateFromCertFile("pathtocertfile");
ssl.AuthenticateAsClient("myserver", new X509CertificateCollection(new [] { clientCert }),
	SslProtocols.Tls12, false);