So the http service I was trying to access is a secure one and my org was issued a client certificate. There are three ways that I tried to attach a client certificate with the request.
1) Providing direct links to cert files: You can do this via this sample code. Pretty self explanatory. The additional cert you see below is the intermediate certificate agency cert that I had to additionally download.
X509Certificate2Collection certCollect = new X509Certificate2Collection();
X509Certificate2 cert = new X509Certificate2(@"C:\Users\...\x509_verisign-certificate.cer");
X509Certificate2 cert1 = new X509Certificate2(@"C:\Users
\..\Certificate_From_SErvice.cer.pfx", "{client certificate password}");
certCollect.Add(cert);
certCollect.Add(cert1);
2) Exported combined cert file (.cer.p7b format): If you have imported the client/intermediate certificate onto your computer then you can export combined certificate (with all intermediariy certificate) + private key into a .cer.p7b file format. You can use this one file instead of the two used above. Here the code to make it work:
X509Certificate2Collection certCollect = new X509Certificate2Collection();
FileInfo file = new FileInfo(@"C:\Users\...\exported_certificate.cer.p7b");
BinaryReader br = new BinaryReader(File.OpenRead(file.FullName));
byte[] raw = br.ReadBytes((int)file.Length);
SignedCms cms = new SignedCms();
cms.Decode(raw);
certCollect.AddRange(cms.Certificates);
3) Referencing a imported certificate on the workstation: You can reference a imported certificate using the below code. There a various ways to uniquely identify a certificate using 'subject name' or 'serial id' etc. I have accessed it via the subject name.
X509Store store = new X509Store("MY", StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
X509Certificate2Collection fcollection =
(X509Certificate2Collection)collection.Find(X509FindType.FindBySubjectName, "{certificate name}", false);
X509Certificate2Collection icollection =
(X509Certificate2Collection)collection.Find(X509FindType.FindBySubjectName, "VeriSign
Class 1 Individual Subscriber CA - G2", false);
X509Certificate2Enumerator certEnum = fcollection.GetEnumerator();
certEnum.MoveNext();
X509Certificate2 primCertFromStore = certEnum.Current;
certEnum = icollection.GetEnumerator();
certEnum.MoveNext();
X509Certificate2 issuerCertFromStore = certEnum.Current;
certCollect.Add(primCertFromStore);
certCollect.Add(issuerCertFromStore);
// use the below code to test if the retrieved certificate is the one you intend to.
//X509Certificate2UI.DisplayCertificate(primCertFromStore);
//X509Certificate2UI.DisplayCertificate(issuerCertFromStore);
store.Close();
You can add the certificate to the request using the below code sample:
....
.......
// Handle any certificate errors on the certificate from the server.
string uri = "request uri";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.ProtocolVersion = HttpVersion.Version11;
request.KeepAlive = true;
request.Method = "POST";
request.Accept = "*/*";
request.ClientCertificates.AddRange(certCollect);
string str = "POST DATA";
byte[] postBytes = Encoding.UTF8.GetBytes(str);
request.ContentType = "TEXT/XML";
request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR
2.0.50727; .NET CLR 1.1.4322; InfoPath.1)";
request.ContentLength = postBytes.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();