How to use certificate callback in SslStream.AuthenticateAsClient method?

My C # .NET SSL connection works when I import a certificate manually in IE (Tools / Internet Options / Content / Certificates), but how can I download the certificate by code? Here is my code:

TcpClient client = new TcpClient(ConfigManager.SSLSwitchIP, Convert.ToInt32(ConfigManager.SSLSwitchPort)); SslStream sslStream = new SslStream( client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null ); sslStream.AuthenticateAsClient("Test"); 

The above code works fine if I import the certificate file manually into Internet Explorer. But if I remove my certificate from IE and use the following code instead, I get an authentication exception:

 sslStream.AuthenticateAsClient("Test", GetX509CertificateCollection(), SslProtocols.Default, false); 

and here is the GetX509CertificateCollection method:

 public static X509CertificateCollection GetX509CertificateCollection() { X509Certificate2 certificate1 = new X509Certificate2("c:\\ssl.txt"); X509CertificateCollection collection1 = new X509CertificateCollection(); collection1.Add(certificate1); return collection1; } 

What to do to dynamically upload my certificate?

+3
source share
3 answers

To build on the answer from the outside, here's how I use a single CA certificate and a custom chain in a validation callback to avoid Microsoft storage.

I did not understand how to use this chain ( chain2 below) by default, so there is no need for a callback. That is, install it in the ssl socket, and the connection will "just work". And I did not understand how to set it in such a way that it goes in the callback. That is, I have to build a chain for each callback call. I think these are architectural flaws in .Net, but I could have missed something obvious.

The name of the function does not matter. Below VerifyServerCertificate is the same callback as RemoteCertificateValidationCallback . You can also use it for ServerCertificateValidationCallback in the ServicePointManager .

 static bool VerifyServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) { try { String CA_FILE = "ca-cert.der"; X509Certificate2 ca = new X509Certificate2(CA_FILE); X509Chain chain2 = new X509Chain(); chain2.ChainPolicy.ExtraStore.Add(ca); // Check all properties chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag; // This setup does not have revocation information chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; // Build the chain chain2.Build(new X509Certificate2(certificate)); // Are there any failures from building the chain? if (chain2.ChainStatus.Length == 0) return true; // If there is a status, verify the status is NoError bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError; Debug.Assert(result == true); return result; } catch (Exception ex) { Console.WriteLine(ex); } return false; } 
+4
source

Quick Google pointed me to a piece of text from the SslStream class.

Authentication is handled by a security support provider (SSPI) channel. The client is given the opportunity to control server certificate verification by RemoteCertificateValidationCallback delegate when creating the SslStream. The server can also control the validation by providing a RemoteCertificateValidationCallback delegate. The method referenced refers to the certificate of the remote party and any SSPI errors encountered while validating the certificate. Note that if the server specifies a delegate, the delegate method is invoked regardless of whether the server requested client authentication. If the server did not request client authentication, the server delegate method receives a null certificate and an empty array of certificate errors.

So just implement the delegate and do the verification yourself.

+3
source

I wrote another way to add my certificate to trusted root certificate authorities (root) before trying to authenticate as a client through an SSLStream object:

 public static void InstallCertificate() { X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadWrite); string fileName = "sslcert.pem"; X509Certificate2 certificate1; try { certificate1 = new X509Certificate2(fileName); } catch (Exception ex) { throw new Exception("Error loading SSL certificate file." + Environment.NewLine + fileName); } store.Add(certificate1); store.Close(); } 

And then:

 InstallCertificate(); sslStream.AuthenticateAsClient("Test"); 

It works great without any warnings or errors. But the basic question remains unresolved:

How to use a certificate for authentication as a client without installing it on Windows?

+2
source

All Articles