httpwebrequest с использованием pfx? - PullRequest
2 голосов
/ 10 ноября 2010

Я бы хотел воспроизвести следующий фрагмент vbscript с использованием 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)
....

Все мои попытки сделать это были а) неработоспособны и б) немного длиннее, чем приведенный выше фрагмент.

var xml = (new XElement("request"
    , new XElement("ticket", "generated ticket")).ToString();

var cert = 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);
}

Я последовательно получаю 403 с этим последним кодом. Я не уверен почему, но я склоняюсь к разрешениям. Что конкретно требуется, прежде чем я смогу создать сертификат из файла cer? Нужно ли применять разрешения через winhttpcertcfg?

Мне первоначально дали pfx, который был импортирован с использованием сертификата MMC. Кажется, что нет способа добавить pfx в качестве сертификата клиента, поэтому я экспортировал pfx как сертификат DER x509 для использования с методом CreateFromCertFile (). Есть ли способ использовать только pfx?

Конечно, оригинальный VBScript работает нормально - я просто хотел бы получить представление о том, что потребуется для его преобразования. Не кажется, что это будет слишком сложно, но пока у меня было немного тяжелое время.

[Update]

Очевидно, можно использовать pfx на диске (при условии, что у вас есть пароль), однако [this] http://support.microsoft.com/kb/948154, похоже, предполагает, что лучше полагаться на хранилище сертификатов. Поскольку это похоже на то, что делал оригинальный vbscript, я изменил приведенный выше код, чтобы получить сертификат из магазина:

var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

X509Certificate2 cert = store.Certificates.Find(X509FindType.FindBySubjectName
, "XXXX", false)[0];

Я добавил предоставленный "Все" доступ к сертификату через инструмент WinHttpCertCfg. Все еще не повезло. К сожалению, это также возвращает 403 с сервера. Проходя по коду, я вижу, что сертификат найден и успешно создан. Я также могу убедиться, что он добавлен в качестве сертификата клиента. По какой-то причине мне просто не повезло с использованием HttpWebResponse.

Тем не менее, использование взаимодействия работает нормально. Как бы мне не хотелось полагаться на что-то, не относящееся к фреймворку, компонент WinHttpRequest, кажется, намного проще в использовании. Я могу сделать то же самое с примерно 1/4 кода, и это прекрасно интегрируется с остальной частью приложения.

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);
...