使用HttpWebRequest和HttpListener发送和接收SSL消息

时间:2019-04-09 15:12:25

标签: c# ssl x509 webrequest httplistener

在Windows平台上,我必须向服务器(服务器A)发送安全消息(双面安全性)。片刻之后,其他一些过程(客户端B)将向我发送第一条消息的处理结果,并且也是双面安全的。

我知道,描述相当长,但是我认为,如果这个问题收到正确的答案,那么我的许多必须发送和接收安全消息的人都可以使用它。

安全性

  • 对于发送到服务器的消息,我使用HttpWebRequest
  • 要接收回复,我使用HttpListener。

为了确认我的身份,我从当局那里收到了一份证书,仅供我使用,并已被授权:

  • 根CA-G3
  • 中级CA-G3
  • MyCertificate.CRT和MyCertificate.Private.Key

服务器A使用由证书颁发机构颁发的证书来标识自己

  • 根CA-G2
  • 中级CA-G2

所有文件均为PEM格式。

我已使用MMC.Exe-证书将所有CA证书导入Windows密钥库的本地计算机部分。 MyCertificate.Crt未导入。

系统提供了Ping / Pong机制:如果我向服务器A发送(空)Ping消息,则客户端B将向我发送Pong消息。

消息以SOAP格式完成

发送PING

创建并填充WebRequest:

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是一个空(非null)字符串。恕我直言,这意味着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
}

问题

尽管服务器A似乎接受了Ping(我收到了一个空的非空响应),但侦听器似乎从未收到回复。

我知道客户端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, ...)
}

0 个答案:

没有答案