Доброго всем времени суток.
Возникла следующая проблема(FW 2.0, C#):
нужно послать запрос на сервер "
https://XXX.YYY" — авторизация посредством сертификата X509 (сертификат сохранен в хранилище Windows, корневой — там же). Если ипользовать
HttpWebRequest (код — ниже), то 'выбрасывает' System.Net.WebException — 'Запрос был прерван. Не удалось создать защищенный канал SSL/TLS' НО! Если писать напрямую в
System.Net.Security.SslStream — все замечательно работает.
У меня руки кривые или есть кардинальное отличие в принципах работы HttpWebRequest и SslStream?
Пример кода:
X509Certificate _cert;
var store = new X509Store();
store.Open(OpenFlags.ReadOnly);
var coll = store.Certificates.Find(X509FindType.FindBySerialNumber, "FF FF FF", true);
_cert = coll[0];
store.Close();
HttpWebRequest webreq;
HttpWebResponse webresp = null;
webreq = (HttpWebRequest)WebRequest.Create("https://XXX.YYY");
webreq.Method = "POST";
webreq.ClientCertificates.Add(_cert);
webreq.Headers.Add("SOAPAction", "\"\"");
webreq.ContentType = "text/xml;charset=UTF-8";
string sReq = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "XML-ник с запросом";
byte[] data = Encoding.ASCII.GetBytes(sReq);
webreq.ContentLength = data.Length;
webreq.GetRequestStream().Write(data, 0, data.Length);
webresp = (HttpWebResponse)webreq.GetResponse(); // System.Net.WebException
Причем на стороне Сервера говорят — мол у них по логам запрос приходит без сертификата.
А вот это работает 'на ура':
X509Certificate _cert;
var store = new X509Store();
store.Open(OpenFlags.ReadOnly);
var coll = store.Certificates.Find(X509FindType.FindBySerialNumber, "FF FF FF", true);
_cert = coll[0];
store.Close();
TcpClient sslClient = new TcpClient();
sslClient.Connect("XXX.YYY", 443);
SslStream sslStream = new SslStream(sslClient.GetStream(), false,
sslStream.AuthenticateAsClient("XXX.YYY", new X509CertificateCollection(new X509Certificate[] { _cert }),
SslProtocols.Tls, false);
sslStream.Write(Encoding.UTF8.GetBytes("POST /services HTTP1.0\r\n" +
"Host: demo.moneta.ru\r\n" +
"SOAPAction: \"\"\r\n" +
"text/xml: charset=UTF-8\r\n" +
"Content-Length: " + req.Length.ToString() + "\r\n" +
"\r\n" + "XML-ник с запросом"));
byte[] buffer = new byte[2048];
StringBuilder messageData = new StringBuilder();
int bytes = -1;
do
{
bytes = sslStream.Read(buffer, 0, buffer.Length);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
decoder.GetChars(buffer, 0, bytes, chars, 0);
messageData.Append(chars);
if (messageData.ToString().IndexOf("<EOF>") != -1)
{
break;
}
} while (bytes != 0);
В чем принципиальная разница этих двух решений — ума не приложу
А самое интересное —
Curl тоже без проблем отрабатывает! Вот ему уж точно все FrameWork-и и WSE 'до фонаря' (правда, сертификаты ему напрямую в виде файлов передаются, но не думаю, что проблема в этом)
Заранее спасибо всем, кто откликнется.