SSL, SOAP, X509...
От: iandreev  
Дата: 14.09.09 11:01
Оценка:
Доброго всем времени суток.
Возникла следующая проблема(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 'до фонаря' (правда, сертификаты ему напрямую в виде файлов передаются, но не думаю, что проблема в этом)

Заранее спасибо всем, кто откликнется.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.