简体   繁体   English

通过SSL调用REST Web服务

[英]Calling a REST web service over SSL

I'm struggling to connect to a REST web service that's working only over HTTPS / SSL from my .NET application. 我很难连接到一个只能通过我的.NET应用程序通过HTTPS / SSL工作的REST Web服务。

I received the certificate and private key to use as two separate files - a certificate.pem file which contains the certificate, and the webservice.key file which contains the private key. 我收到了证书和私钥作为两个单独的文件 - 包含证书的certificate.pem文件和包含私钥的webservice.key文件。 Those are both text files with BASE64 encoded binary data contained in them. 这些都是包含BASE64编码二进制数据的文本文件。

The provider also sent me a PDF showing how to call that web service using CURL and those two files, and that works just fine: 提供商还向我发送了一个PDF,显示如何使用CURL和这两个文件调用该Web服务,并且工作得很好:

curl.exe -k -v "https://(URL)" --cert certificate.pem --key webservice.key

I need to use the -k option since there seems to be a self-signed certificate somewhere in the hierarchy of certs. 我需要使用-k选项,因为在证书层次结构中的某处似乎有一个自签名证书。 Without this option, the call fails. 如果没有此选项,则呼叫将失败。

In order to call this web service from a .NET application (a console app for now), I used OpenSSL (on Windows) to combine these two files into a *.pfx file using this command: 为了从.NET应用程序(现在是控制台应用程序)调用此Web服务,我使用OpenSSL(在Windows上)使用此命令将这两个文件合并为*.pfx文件:

openssl pkcs12 -export -out webservice.pfx -in certificate.pem -inkey webservice.key 

This seems to have worked, too - no errors were reported, the file was created and is about 3K in size and it's a totally binary file. 这似乎也有效 - 没有报告错误,文件已创建,大小约为3K,它是一个完全二进制文件。

Now, I tried to call that web service from my .NET code something like this: 现在,我尝试从我的.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
}

However, I can try whatever I like (fiddling around with various settings, on the ServicePointManager and the HttpWebRequest , but I just keep getting these errors: 但是,我可以尝试任何我喜欢的东西(摆弄各种设置,在ServicePointManagerHttpWebRequest ,但我只是不断收到这些错误:

WebException: The underlying connection was closed: An unexpected error occurred on a send. WebException:基础连接已关闭:发送时发生意外错误。

IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. IOException:无法从传输连接读取数据:远程主机强制关闭现有连接。

SocketException: An existing connection was forcibly closed by the remote host SocketException:远程主机强制关闭现有连接

and no response - even though communicating with the service with CURL has worked just fine..... 并没有回应 - 即使与CURL的服务沟通工作得很好.....

What am I missing?? 我错过了什么? I'm a bit puzzled and mystified by all those certificates, private keys, service point manager options and so on - just waaaaay too many knob and switches to turn, set or turn off - what are the RIGHT settings here?? 所有这些证书,私钥,服务点管理器选项等让我感到有点困惑和神秘 - 只是太多的旋钮和开关转动,设置或关闭 - 这里有什么正确的设置?

Update: 更新:

If I use 如果我使用

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;

then the error just simply is: 然后错误就是:

WebException: The request was aborted: Could not create SSL/TLS secure channel. WebException:请求已中止:无法创建SSL / TLS安全通道。

SOLUTION : 解决方案

In the end, with looking at the output from curl and a lot of help from @Alexandru and @JurajMajer, I was able to get this to work with this code: 最后,通过查看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
}

Try to enable Network Tracing in App.config on the client - instructions here . 尝试在客户端上的App.config中启用网络跟踪 - 此处的说明 That should create network.log with more debug info. 这应该创建具有更多调试信息的network.log。 In my test environment I have one pfx which works and one which doesn't. 在我的测试环境中,我有一个pfx工作,一个没有。

network.log for working pfx: network.log for working pfx:

SecureChannel#9343812 - We have user-provided certificates. The server has specified 34 issuer(s). Looking for certificates that match any of the issuers. SecureChannel#9343812 - Left with 1 client certificates to choose from. SecureChannel#9343812 - Trying to find a matching certificate in the certificate store. SecureChannel#9343812 - Locating the private key for the certificate: SecureChannel#9343812 - Certificate is of type X509Certificate2 and contains the private key.

network log for non-working pfx: 非工作pfx的网络日志:

SecureChannel#26756241 - We have user-provided certificates. The server has specified 34 issuer(s). Looking for certificates that match any of the issuers. SecureChannel#26756241 - Left with 0 client certificates to choose from.

So for me the problem is my non-working certificate was issued by CA not in list. 所以对我来说问题是我的非工作证书是由CA发布的不在列表中。

Interesting points (possible problems): 有趣的点(可能的问题):

1.) Server sends the list of known issuers for client certificate. 1.)服务器发送客户端证书的已知发行者列表。

2.) Client code is looking for certificate and private key in certificate store event though both are in pfx. 2.)客户端代码正在证书存储事件中查找证书和私钥,尽管两者都在pfx中。

You've used the X509Certificate(String, String) constructor with a PKCS#12 certificate, but that constructor only works for PKCS#7 certificates, as MSDN says it... 您已经将X509Certificate(String, String)构造函数与PKCS#12证书一起使用,但该构造函数仅适用于PKCS#7证书,因为MSDN说它...

Initializes a new instance of the X509Certificate class using the name of a PKCS7 signed file and a password to access the certificate. 使用PKCS7签名文件的名称和密码访问证书,初始化X509Certificate类的新实例。

PKCS#7 does not include the private (key) part of a certificate/private-key pair, which you will need. PKCS#7不包括您需要的证书/私钥对的私有(密钥)部分。 This means you will need to use your PKCS#12 certificate given the nature of your certificate. 这意味着鉴于证书的性质,您需要使用PKCS#12证书。

You may want to try the X509Certificate2(String, String) constructor with your existing PKCS#12 certificate, as this constructor is used with PKCS#12 (PFX) files that contain the certificate's private key, as MSDN says... 您可能希望使用现有的PKCS#12证书尝试X509Certificate2(String, String)构造函数,因为此构造函数与包含证书私钥的PKCS#12(PFX)文件一起使用,如MSDN所说...

This constructor creates a new X509Certificate2 object using a certificate file name and a password needed to access the certificate. 此构造函数使用证书文件名和访问证书所需的密码创建新的X509Certificate2对象。 It is used with PKCS12 (PFX) files that contain the certificate's private key. 它与包含证书私钥的PKCS12(PFX)文件一起使用。 Calling this constructor with the correct password decrypts the private key and saves it to a key container. 使用正确的密码调用此构造函数会解密私钥并将其保存到密钥容器中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM