SslStream client unable to complete handshake with stunnel server
Asked Answered
P

1

6

I have a fully operational system where openssl based clients interact with an openssl server. Each client have its own certificate that is validated by the server. Certificates have been generated with openssl (X509, pem). They are self-signed.

I now want to write a test client based on SslStream. I used the client example from the SslStream class documentation.

My SslStream client is unable to complete the handshake. stunnel complains about the client not sending its certificate. This is confirmed in Wireshark (Certificates Length: 0 in handshake messages).

My client displays the following exception:

Inner exception: The message received was unexpected or badly formatted

This is how I load my certificate:

X509Certificate cert = new X509Certificate2(filename, password);
X509CertificateCollection certColl = new X509CertificateCollection();
certColl.Add(cert);

I tried retrieving certificate various properties (ex: GetSerialNumberString()). It works. The Verify method returns false. This is the next thing I am going to investigate.

How I setup my SslStream does not seem to matter (same result):

sslStream.AuthenticateAsClient(serverName);

SslStream sslStream = new SslStream(
  client.GetStream(),
  false,
  new RemoteCertificateValidationCallback(ValidateServerCertificate), 
  new LocalCertificateSelectionCallback(SelectLocalCertificate));

Same with authentication:

sslStream.AuthenticateAsClient(serverName);

sslStream.AuthenticateAsClient(serverName,
  certColl,
  SslProtocols.Tls,
  true);

SelectLocalCertificate gets called (twice) and returns my certificate. ValidateServerCertificate currently never gets called (to my surprise).

How can I debug that? Even better if you can nail my problem.

UPDATE

I have added a function to perform chain validation based on the X509Chain example from the documentation. It displays all sorts of information on the certificate, including two intriguing messages:

Element certificate is valid: False
Element error status length: 1

In the end, I don't really have more details than when I call verify.

The output of openssl verify cert.pem does not report anything unusual.

error 18 at 0 depth lookup:self signed certificate
OK

UPDATE

I extracted the private key and certificate from the pem, and I generated a cert.pfx (pkcs12). I had no issues importing cert.pfx in my personal key store. In my certificate details, I can see a small icon indicating an attached private key.

I modified my client to retrieve the certificate from my personal store. But I am getting the same exact failure.

Po answered 13/7, 2012 at 16:42 Comment(2)
For SSL client auth you need a certificate and a key. You should check if the PEM file contains both, otherwise you are missing an important part.Ilbert
The PEM contains the certificate under a ----BEGIN CERTIFICATE----- block and the private key under a -----BEGIN RSA PRIVATE KEY----- block.Po
P
4

The solution was to import my CA root certificate on my Windows machine. My client is now able to complete the handshake!

Found the solution by searching for a more complete SslStream example. Thanks to http://geekswithblogs.net/luskan/archive/2007/10/01/115758.aspx.

Po answered 13/7, 2012 at 20:36 Comment(2)
You must install the root CA certificate in the Windows Store in Trusted Authorities folder and you also have to load the client certificate from the windows store, it did not work while loading the client certificate from file. So both client and server Root CA must be in Windows store. ThanksZwieback
Windows/.NET does not allow you to use a private key if it is not in the certificate store. It is by design.Intrench

© 2022 - 2024 — McMap. All rights reserved.