Monday, 17 March 2014

Mutual SSL Handshake .NET, SSL Client Authentication

Few days back I was working on this Mutual SSL Handshake Issue. I was stuck on this for quite sometime. Lack of information and very limited number people actually using this, caused me to work for lot of hours, which was supposed to be a very tiny piece of work.

I was supposed to talk to a webserver from my webserver (IIS 7.5) using the SSL certificate client authentication.

Because of limited information out there I figured few things on my own and thought of creating this blog about it so that people who are working on this can get some benefit out of it.
  1. Client certificate should have following Key Usages. Digital Certificate, Key Encipherment and extended usage of Client Authentication.
  2. The private key should be exportable and not protected.
  3. The root signers of your certificate should be on the target webserver’s trust store.
  4. Server certificate’s root signers should be on your server’s trust store.
  5. You don’t need to import your certificate to your certificate store. Instead I recommend to use the .PFX file instead. Because your IIS server’s users don’t have enough permission to read the private key of your certificate. Whereas by using the PFX file we don’t need any permission whatsoever. PFX file contains all the certificates Root, Intermediate, Shared and Client Certificate.

Once the certificate part is done use the following code to perform the Client authentication in code. HttpWebRequest will take care of everything else. Please feel free to comment.

private static void FromFile()
 var certificate = "CertificateFile.pfx";
 var certpwd = "password";
 var URL = "Host_URL";
 var certs = new X509Certificate2Collection();
 certs.Import(certificate, certpwd, X509KeyStorageFlags.DefaultKeySet);

 var webrequest = WebRequest.Create(URL) as HttpWebRequest;

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
 ServicePointManager.Expect100Continue = false;
 ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AlwaysGoodCert);


 webrequest.Credentials = CredentialCache.DefaultNetworkCredentials;
 webrequest.Method = WebRequestMethods.Http.Get;
 webrequest.ContentType = "application/json; charset=utf-8";

 var responseStream = webrequest.GetResponse().GetResponseStream();

private static bool AlwaysGoodCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
 return true;