httpwebrequest using a pfx?
I'd like to reproduce the following chunk of vbscript using C#.
sURL = "https://server/service.dll"
sXML = "<request version=""1.0""><ticket>generated ticket</ticket></request>"
dim winHTTPReq: Set winHTTPReq = CreateObject("WinHttp.WinHttpRequest.5.1")
winHttpReq.Open "POST", sURL, false
winHTTPReq.SetRequestHeader "Content-Type", "application/x-some-type"
sCertificate = "LOCAL_MACHINE\MY\Vendor Supplied PFX"
winHTTPReq.SetClientCertificate sCertificate
WinHttpReq.Send(sXML)
....
All my attempts to do so have been a) non-functional and b) a bit longer than the snippet above.
var xml = (new XElement("request"
, new XElement("ticket", "generated ticket")).ToString();
var cert 开发者_如何学JAVA= X509Certificate.CreateFromCertFile("c:\\Exported Vendor Supplied PFX.cer");
ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };
var request = (HttpWebRequest)WebRequest.Create("https://server/service.dll");
request.ClientCertificates.Add(cert);
request.ContentType = "application/x-some-type";
request.Method = "POST";
byte[] bytes = Encoding.UTF8.GetBytes(xml);
request.ContentLength = bytes.Length;
using (var requestStream = request.GetRequestStream())
requestStream.Write(bytes, 0, bytes.Length);
using (var response = (HttpWebResponse)request.GetResponse())
if (response.StatusCode != HttpStatusCode.OK) {
string message = String.Format(
"POST failed. Received HTTP {0}",
response.StatusCode);
throw new ApplicationException(message);
}
I consistently get a 403 with this latter code. I'm not sure why but I'm leaning towards permissions. Is there anything in particular that is required before I can create a certificate from a cer file? Do I need to apply permissions via winhttpcertcfg?
I was originally given a pfx which was imported using the Certificate MMC. There doesn't appear to be a way to add a pfx as a client certificate, consequently I've exported the pfx as a DER x509 cer for use with the CreateFromCertFile() method. Is there a way to only use the pfx?
Of course, the original VBScript works fine - I'd just like to get an idea of what it would take to convert it. It doesn't seem like it'd be too difficult but so far I've had a bit of a rough time.
[Update]
Apparently it's possible to use a pfx on disk (provided you have a password) however [this]http://support.microsoft.com/kb/948154 seems to suggest that it's better to rely on a certificate store. Since this is similar to what the original vbscript was doing I modified the code above to pull the cert from a store:
var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2 cert = store.Certificates.Find(X509FindType.FindBySubjectName
, "XXXX", false)[0];
I added granted "Everyone" access to the cert via the WinHttpCertCfg tool. Still no luck. Unfortunately this also returns a 403 from the server. Walking though the code I can see that the certificate is being found and created successfully. I can also verify that it's added as a client certificate. For whatever reason I just haven't had any luck using HttpWebResponse.
However, using interop works fine. As much as I hate to rely on something not native to the framework, the WinHttpRequest component seems to be so much easier to use. I can accomplish the same thing with roughly 1/4th the code and this integrates fine with the rest of the app.
xml = "<request version=\"1.0\"><ticket>generated ticket</ticket></request>";
var req = new WinHttp.WinHttpRequest();
req.Open("POST", "https://server/service.dll", false);
req.SetRequestHeader("Content-Type", "application/x-some-type");
req.SetClientCertificate(@"LOCAL_MACHINE\MY\Vendor Supplied PFX");
req.Send(xml);
Console.WriteLine(string.Format("{0} {1}", req.Status, req.StatusText));
Console.WriteLine(req.ResponseText);
精彩评论