通过SSL调用REST Web服务

mar*_*c_s 5 c# rest ssl web-services certificate

我很难连接到一个只能通过我的.NET应用程序通过HTTPS/SSL工作的REST Web服务.

我收到了证书和私钥作为两个单独的文件 - certificate.pem包含证书的webservice.key文件和包含私钥的文件.这些都是包含BASE64编码二进制数据的文本文件.

提供商还向我发送了一个PDF,显示如何使用CURL和这两个文件调用该Web服务,并且工作得很好:

curl.exe -k -v "https://(URL)" --cert certificate.pem --key webservice.key
Run Code Online (Sandbox Code Playgroud)

我需要使用该-k选项,因为在证书层次结构中的某处似乎有一个自签名证书.如果没有此选项,则呼叫将失败.

为了从.NET应用程序(现在是控制台应用程序)调用此Web服务,我使用OpenSSL(在Windows上)*.pfx使用此命令将这两个文件合并到一个文件中:

openssl pkcs12 -export -out webservice.pfx -in certificate.pem -inkey webservice.key 
Run Code Online (Sandbox Code Playgroud)

这似乎也有效 - 没有报告错误,文件已创建,大小约为3K,它是一个完全二进制文件.

现在,我尝试从我的.NET代码中调用该Web服务,如下所示:

try
{
    // use the SSL protocol (instead of TLS)
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;

    // ignore any certificate complaints
    ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => { return true; };

    // create HTTP web request with proper content type
    HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
    request.ContentType = "application/xml;charset=UTF8";

    // grab the PFX as a X.509 certificate from disk
    string certFileName = Path.Combine(certPath, "webservice.pfx");

    // load the X.509 certificate and add to the web request
    X509Certificate cert = new X509Certificate(certFileName, "(top-secret password)");
    request.ClientCertificates.Add(cert);
    request.PreAuthenticate = true;

    // call the web service and get response
    WebResponse response = request.GetResponse();

    Stream responseStream = response.GetResponseStream();
}
catch (Exception exc)
{
    // log and print out error
}
Run Code Online (Sandbox Code Playgroud)

但是,我可以尝试任何我喜欢的东西(摆弄各种设置,在ServicePointManagerHttpWebRequest,但我只是继续得到这些错误:

WebException:基础连接已关闭:发送时发生意外错误.

IOException:无法从传输连接读取数据:远程主机强制关闭现有连接.

SocketException:远程主机强制关闭现有连接

并没有回应 - 即使与CURL的服务沟通工作得很好.....

我错过了什么?所有这些证书,私钥,服务点管理器选项等让我感到有点困惑和神秘 - 只是太多的旋钮和开关转动,设置或关闭 - 这里有什么正确的设置?

更新:

如果我使用

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
Run Code Online (Sandbox Code Playgroud)

然后错误就是:

WebException:请求已中止:无法创建SSL/TLS安全通道.

解决方案

最后,通过查看curl@Alexandru和@JurajMajer 的输出和大量帮助,我能够使用此代码:

try
{
    // use the TLS protocol 
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

    // create HTTP web request with proper content type
    HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
    request.ContentType = "application/xml;charset=UTF8";

    // grab the PFX as a X.509 certificate from disk
    string certFileName = Path.Combine(certPath, "webservice.pfx");

    // load the X.509 certificate and add to the web request
    X509Certificate2 cert = new X509Certificate2(certFileName, "(top-secret password)");
    request.ClientCertificates.Add(cert);
    request.PreAuthenticate = true;

    // call the web service and get response
    WebResponse response = request.GetResponse();

    Stream responseStream = response.GetResponseStream();

    string xmlContents = new StreamReader(responseStream).ReadToEnd();
}
catch (Exception exc)
{
    // log and print out error
}
Run Code Online (Sandbox Code Playgroud)

Ale*_*dru 4

您已将构造函数与 PKCS#12 证书一起使用X509Certificate(String, String),但该构造函数仅适用于 PKCS#7 证书,正如 MSDN 所说...

使用 PKCS7 签名文件的名称和访问证书的密码初始化 X509Certificate 类的新实例。

PKCS#7 不包括您需要的证书/私钥对的私钥(密钥)部分。这意味着鉴于您的证书的性质,您将需要使用 PKCS#12 证书。

您可能想尝试使用X509Certificate2(String, String)现有 PKCS#12 证书的构造函数,因为此构造函数与包含证书私钥的 PKCS#12 (PFX) 文件一起使用,正如 MSDN 所说...

此构造函数使用证书文件名和访问证书所需的密码创建一个新的 X509Certificate2 对象。它与包含证书私钥的 PKCS12 (PFX) 文件一起使用。使用正确的密码调用此构造函数会解密私钥并将其保存到密钥容器中。

  • 听到这个消息我感到非常高兴。我从我们一起的旅程中学到了一些新东西。:) (2认同)