I've been spinning my wheels for a few days now not making any progress, and suggestions I've found thus far online haven't quite done the trick, so here goes:
I have a WCF service which ties into... not sure what type of web service you'd call this on the other end, kind of REST-ish. The URL to the method looks like this "https://partner.someservice.com/SomeMethod.asp". I cram some query string args onto the end of that and POST the request to their server.
The error in VS just shows 403, but when I've used Fiddler I see 403.7. Before importing the cert into my browsers I saw 403.7 as well. I can inspect my request object and see the ClientCertificates with [1] cert specified, so I'm pretty sure it is getting attached.
I've imported the .pfx file into both my machine and local user cert stores. I've run the winhttpcertcfg utility a number of times in a number of ways, basically following the instructions I've seen on MSDN and SO posts.
winhttpcertcfg -g -c LOCAL_MACHINE\MY -s [cert] -a [user/aspnet/auth'd users]
winhttpcertcfg.exe -i [cert.pfx] -c LOCAL_MACHINE\MY -p [pwd]
I've imported the .pfx file into Chrome. If I hit that URL in Chrome, I get a prompt to select my cert, and then I can proceed to the URL just fine. Same behavior in IE.
So this seems to be specific to me running in VS, although I'm not sure what option I haven't checked or what permission I haven't granted. Under project properties on my WCF service, I have tried "Use Visual Studio Development Server" and "Use Local IIS Web server" but get the same behavior from each. What am I missing?
Some code:
private static string DoPost(string postData)
{
string result = null;
var httpWebRequest = (HttpWebRequest)WebRequest.Create(GetEndpoint());
var encoding = new ASCIIEncoding();
var bytes = encoding.GetBytes(postData);
httpWebRequest.Method = "POST";
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
httpWebRequest.ContentLength = bytes.Length;
httpWebRequest.ClientCertificates.Add(clientCertificate);
using (var stream = httpWebRequest.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length);
stream.Close();
using (var httpWebResponse = httpWebRequest.GetResponse())
using (var responseStream = httpWebResponse.GetResponseStream())
{
if (responseStream != null)
{
using (var reader = new StreamReader(responseStream))
{
result = reader.ReadToEnd();
}
}
}
}
return result;
}
And the code obtaining the cert (in a utility class written by another dev, and this seems to work just fine in production):
public static X509Certificate2 GetCertificateBySerial(string serial)
{
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
var certColl = store.Certificates.Find(X509FindType.FindBySerialNumber, serial, false);
store.Close();
if (certColl.Count == 0)
{
throw new Exception(String.Format("A certificate with a serial number of \"{0}\" is not installed on the server.", serial));
}
return certColl[0];
}