Отправка и получение сообщений SSL с использованием HttpWebRequest и HttpListener - PullRequest
0 голосов
/ 09 апреля 2019

На платформе Windows я должен отправить защищенное сообщение (двусторонняя защита) на сервер (Сервер A).Через несколько мгновений какой-то другой процесс (Клиент B) отправит мне обработанные результаты первого сообщения, также двухсторонней защиты.

Я знаю, описание довольно длинное, но я думаю, что если этот вопрос получитПравильный ответ, он может быть использован многими, кто должен отправлять и получать защищенные сообщения.

Безопасность

  • Для сообщения на сервер я использую HttpWebRequest
  • Чтобы получить ответ, я использую HttpListener.

Чтобы идентифицировать меня, я получил от органов власти только сертификат, который будет использоваться мной, который разрешен:

  • Root CA-G3
  • Промежуточный CA-G3
  • MyCertificate.CRT и MyCertificate.Private.Key

Сервер A идентифицирует себя, используя сертификат, выданныйцентры сертификации

  • Root CA-G2
  • Промежуточный CA-G2

Все файлы в формате PEM.

Я импортировалвсе сертификаты CA на локальный компьютериз хранилища ключей Windows, используя MMC.Exe - Сертификаты.MyCertificate.Crt не импортируется.

В системе предусмотрен механизм Ping / Pong: если я отправлю (пустое) сообщение Ping на сервер A, клиент B отправит мне сообщение Pong.

Обмен сообщениями осуществляется в формате SOAP

Отправка PING

Создание и заполнение веб-запроса:

const string requestUriString = "https://...nl:443/deliver";
HttpWebRequest webRequest = WebRequest.CreateHttp(requestUriString);
webRequest.Headers.Add(@"SOAP:Action");
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";

// Create the Soap Envelope
string soapEnvelopeXmlText = CreateOutXmlMessage(); // see below
XmlDocument soapEnvelopeDocument = new XmlDocument();
soapEnvelopeDocument.LoadXml(soapEnvelopeXmlText);

// Fill the webRequest with the soap envelope:
using (System.IO.Stream stream = webRequest.GetRequestStream())
{
    soapEnvelope.Save(stream);
}

// Add Security to the webRequest
string certificateFile = Path.Combine(certificateFolder, "MyCertificate.Crt");
X509Cerficiate certificate = X509Certificate.CreateFromCertFlie(certificateFile);

Отправьте запрос, дождитесь ответа и интерпретируйте его:

using (WebResponse response = webRequest.GetResponse())
{
    // interpret the response:
    using (var reader = new StreamReader(response.GetResponseStream()))
    {
        string responseText= reader.ReadToEnd();
        this.Process(responseText);
    }
}

responseText - пустая (ненулевая) строка.IMHO, это означает, что PING был отправлен правильно.

Получение PONG

Перед отправкой Ping необходимо запустить HttpListener.

Я ожидаюответы должны быть получены через порт 443, через порт 443. Клиент отправит его, используя адрес типа https:mycompany.com:443/reply

using (HttpListener httpListener = new HttpListener())
{
    httpListener.Prefixes.Add(@"https://*:443/reply");
    httpListener.Start();

    // start listening on a separate task.
    // this enables proper stopping:
    Task.Factory.StartNew(async () =>
    {
        while (true) await ListenAsync(httpListener);
    },
    TaskCreationOptions.LongRunning);
}

async Task ListenAsync(HttpListener httpListener)
{
    // Listen by getting the context:
    HttpListenerContext context = await this.httpListener.GetContextAsync();

    // Problem: the code never comes to this point
    ... interpret context
}

Проблемы

Хотя кажется, что Ping принят серверомA (я получаю пустой ненулевой ответ), кажется, что ответ никогда не получен слушателем.

Я знаю, что клиент B пытается отправить мне ответ, потому что если я использую вместо этого Apache Tomcatчтобы прослушать, я получаю сообщение журнала о том, что что-то получено через порт 443. Хотя я не вижу содержимого этого сообщения, я знаю, что оно правильно расшифровано, поскольку в сообщении журнала понимается тип ответа (ebXML).

Наконец, не важно для вопроса, но если вы действительно хотите знать: содержание SOAP xml:

private string CreateOutXmlMessage()
{
  const string formatStr = @"<?xml version=""1.0"" encoding=""utf-8""?>
  <SOAP-ENV:Envelope xmlns:SOAP-ENV=""http://schemas.xmlsoap.org/soap/envelope/"" 
    xmlns:eb=""http://www.oasis-open.org/committees/ebxml-msg/schema/msg-header-2_0.xsd"" 
    xmlns:xlink=""http://www.w3.org/1999/xlink""  
    xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" 

    xsi:schemaLocation=""http://schemas.xmlsoap.org/soap/envelope/ http://www.oasis-open.org/committees/ebxml-msg/schema/envelope.xsd"">

    <SOAP-ENV:Header xsi:schemaLocation=""http://www.oasis-open.org/committees/ebxml-msg/schema/msg-header-2_0.xsd http://www.oasis-open.org/committees/ebxml-msg/schema/msg-header-2_0.xsd"">

      <eb:MessageHeader SOAP-ENV:mustUnderstand=""1"" eb:version=""2.0"">
      <eb:From>
        <eb:PartyId eb:type=""{0}"">{1}</eb:PartyId>
        <eb:Role>{2}</eb:Role>
      </eb:From>

      <eb:To>
        <eb:PartyId eb:type=""{3}"">{4}</eb:PartyId>
        <eb:Role>{5}</eb:Role>
      </eb:To>

      <eb:CPAId>{6}</eb:CPAId>
      <eb:ConversationId>{7}</eb:ConversationId>
      <eb:Service>urn:oasis:names:tc:ebxml-msg:service</eb:Service>
      <eb:Action>{8}</eb:Action>

      <eb:MessageData>
        <eb:MessageId>{9}</eb:MessageId>
        <eb:Timestamp>{10:O}</eb:Timestamp>
      </eb:MessageData>

      </eb:MessageHeader>
    </SOAP-ENV:Header>

    <SOAP-ENV:Body>
      <eb:Manifest eb:id=""Manifest"" eb:version=""2.0""/>
    </SOAP-ENV:Body>
  </SOAP-ENV:Envelope>";

  return String.Format(formatStr, ...)
}
...