Ask*_* B. 6 c# ssl client-certificates x509certificate2
我正在尝试GET使用客户端证书向外部生产服务器发出简单请求.他们已将我们的证书添加到他们的服务器,我已成功通过Postman(Chrome应用程序和Windows本机应用程序)和标准浏览器发出请求:

Postman的Chrome应用版本使用Chrome内置的证书查找器.本机Postman应用程序需要一个.crt和.key文件,我从.p12文件中提取.
换句话说,证书在商店中成功找到,并且在从文件中使用时也可以工作(在Windows本机应用程序中,表明它应该可以在.NET中使用).
在我的简单C#(.NET Framework 4.5.1)控制台应用程序中,我能够从商店(或从文件)获取证书,并成功使用它来加密和解密文件(我认为它具有完全访问权限)来自我的申请):
private static X509Certificate2 GetCertificate(string thumbprint)
{
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
X509Certificate2Collection coll =
store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint,
validOnly: true);
X509Certificate2 certificate = coll.Count == 0 ? null : coll[0];
return certificate;
}
Run Code Online (Sandbox Code Playgroud)
我提出请求到服务器使用两种HttpClient或HttpWebRequest:
//A global setting to enable TLS1.2 which is disabled in .NET 4.5.1 and 4.5.2 by default,
//and disable SSL3 which has been deprecated for a while.
//The server I'm connecting to uses TLS1.2
ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3;
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12;
X509Certificate cert = GetCertificate(thumbprint);
string url = "https://sapxi.example.com/XISOAPAdapter/MessageServlet";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ClientCertificates.Add(cert);
request.Method = WebRequestMethods.Http.Get;
WebResponse basicResponse = request.GetResponse(); //This is where the exception is thrown
string responseString = new StreamReader(basicResponse.GetResponseStream()).ReadToEnd();
Run Code Online (Sandbox Code Playgroud)
两者HttpClient或HttpWebRequest抛出相同的例外:
(WebException)基础连接已关闭:发送时发生意外错误.
(IOException)无法从传输连接读取数据:远程主机强制关闭现有连接.
(SocketException)远程主机强制关闭现有连接
启用跟踪,我得到一个输出,其中找到证书和私钥(我已经过滤掉了详细消息):
System.Net Error: 0 : [29136] Can't retrieve proxy settings for Uri 'https://sapxi.example.com/XISOAPAdapter/MessageServlet'. Error code: 12180.
System.Net Information: 0 : [29136] Associating HttpWebRequest#21454193 with ServicePoint#60068066
System.Net Information: 0 : [29136] Associating Connection#3741682 with HttpWebRequest#21454193
System.Net.Sockets Information: 0 : [29136] Socket#33675143 - Created connection from 192.168.168.177:56114 to 131.165.*.*:443.
System.Net Information: 0 : [29136] Connection#3741682 - Created connection from 192.168.168.177:56114 to 131.165.*.*:443.
System.Net Information: 0 : [29136] TlsStream#43332040::.ctor(host=sapxi.example.com, #certs=1)
System.Net Information: 0 : [29136] Associating HttpWebRequest#21454193 with ConnectStream#54444047
System.Net Information: 0 : [29136] HttpWebRequest#21454193 - Request: GET /XISOAPAdapter/MessageServlet HTTP/1.1
System.Net Information: 0 : [29136] ConnectStream#54444047 - Sending headers
{
Host: sapxi.example.com
Connection: Keep-Alive
}.
System.Net Information: 0 : [29136] SecureChannel#20234383::.ctor(hostname=sapxi.example.com, #clientCertificates=1, encryptionPolicy=RequireEncryption)
System.Net Information: 0 : [29136] Enumerating security packages:
System.Net Information: 0 : [29136] Negotiate
System.Net Information: 0 : [29136] NegoExtender
System.Net Information: 0 : [29136] Kerberos
System.Net Information: 0 : [29136] NTLM
System.Net Information: 0 : [29136] TSSSP
System.Net Information: 0 : [29136] pku2u
System.Net Information: 0 : [29136] WDigest
System.Net Information: 0 : [29136] Schannel
System.Net Information: 0 : [29136] Microsoft Unified Security Protocol Provider
System.Net Information: 0 : [29136] Default TLS SSP
System.Net Information: 0 : [29136] CREDSSP
System.Net Information: 0 : [29136] SecureChannel#20234383 - Attempting to restart the session using the user-provided certificate:
*my certificate is here* (Issuer = CN=TRUST2408 OCES CA II, O=TRUST2408, C=DK)
System.Net Information: 0 : [29136] SecureChannel#20234383 - Left with 1 client certificates to choose from.
System.Net Information: 0 : [29136] SecureChannel#20234383 - Trying to find a matching certificate in the certificate store.
System.Net Information: 0 : [29136] SecureChannel#20234383 - Locating the private key for the certificate:
*my certificate is here*
System.Net Information: 0 : [29136] SecureChannel#20234383 - Certificate is of type X509Certificate2 and contains the private key.
System.Net Information: 0 : [29136] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent = Outbound, scc = System.Net.SecureCredential)
System.Net Information: 0 : [29136] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = (null), targetName = sapxi.example.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [29136] InitializeSecurityContext(In-Buffer length=0, Out-Buffer length=171, returned code=ContinueNeeded).
System.Net Information: 0 : [29136] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 278cca8:6d23888, targetName = sapxi.example.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [29136] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [29136] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 278cca8:6d23888, targetName = sapxi.example.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [29136] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [29136] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 278cca8:6d23888, targetName = sapxi.example.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [29136] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=ContinueNeeded).
System.Net Information: 0 : [29136] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 278cca8:6d23888, targetName = sapxi.example.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [29136] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=CredentialsNeeded).
System.Net Information: 0 : [29136] SecureChannel#20234383 - We have user-provided certificates. The server has specified 8 issuer(s). Looking for certificates that match any of the issuers.
System.Net Information: 0 : [29136] SecureChannel#20234383 - Selected certificate:
*my certificate is here*
System.Net Information: 0 : [29136] SecureChannel#20234383 - Left with 1 client certificates to choose from.
System.Net Information: 0 : [29136] SecureChannel#20234383 - Trying to find a matching certificate in the certificate store.
System.Net Information: 0 : [29136] SecureChannel#20234383 - Locating the private key for the certificate:
*my certificate is here*
System.Net Information: 0 : [29136] SecureChannel#20234383 - Certificate is of type X509Certificate2 and contains the private key.
System.Net Information: 0 : [29136] AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent = Outbound, scc = System.Net.SecureCredential)
System.Net Information: 0 : [29136] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 278cca8:6d23888, targetName = sapxi.example.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [29136] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=349, returned code=ContinueNeeded).
System.Net.Sockets Error: 0 : [29136] Socket#33675143::UpdateStatusAfterSocketError() - ConnectionReset
System.Net.Sockets Error: 0 : [29136] Exception in Socket#33675143::Receive - An existing connection was forcibly closed by the remote host.
System.Net Error: 0 : [29136] Exception in HttpWebRequest#21454193:: - The underlying connection was closed: An unexpected error occurred on a send..
Run Code Online (Sandbox Code Playgroud)
上面的部分再次重复,然后最终抛出异常链.我用一个例子替换了服务器的真实URL和IP.
来自的线
我们有用户提供的证书.服务器指定了8个发行者.寻找与任何发行人匹配的证书.
至
证书的类型为X509Certificate2,包含私钥.
让我觉得证书是在HttpWebRequests内部工作中正确找到的.
我不知道这个输出有什么问题.
在Wireshark中,我比较了Postman请求和我的C#代码,我看到的唯一区别是该Client Verify部分(包括整个证书)不是从C#发送的,而是通过Postman(和浏览器)发送的.
对我而言,我的应用程序看起来完全忽略了客户端证书.
当我不提供客户端证书(//request.ClientCertificates.Add(cert))时,我在Wireshark中获得完全相同的输出,这似乎证实了这种怀疑.在Visual Studio的跟踪输出中,我只是获取Left with 0 client certificates to choose from.并且没有在商店中搜索证书或类似的东西.
值得注意的是,Wireshark表明Postman成功使用了TLS1.2 - 我的应用程序代码也使用了TLS1.2.
我得到了这个工作,设置IIS Express以要求证书,然后调用它.在页面上,我可以看到Request.ClientCertificates属性中的证书.在wireshark中,它不会发送证书验证,所以某些内容仍然不同.
但是这个页面在我的本地计算机上运行,使用IIS Express促使我安装的自签名证书.我还没有在具有有效证书的生产服务器上设置项目,并查看它是否表现相同.
我不确定这究竟是什么意思,但我想我可以确认我没有忘记一些基本的东西,这可能是一个边缘情况,或者HttpWebRequest是C#中的库无法正确处理的一些协议.
HttpClient的SendAsync()有WebRequestHandlerServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12)request.ClientCertificates.Add(serverCert).
//Automatically verifying all server certificates (don't use this in production)
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) =>
{
return true; //This is not reached
};
ServicePointManager.Expect100Continue = true;
request.AllowAutoRedirect = true;
request.PreAuthenticate = true;
request.KeepAlive = false;
request.UserAgent = null;
request.CachePolicy = new HttpRequestCachePolicy(
HttpCacheAgeControl.MaxAge, TimeSpan.FromSeconds(0));
//And several more that I didn't expect any effect from
Run Code Online (Sandbox Code Playgroud)
如果有帮助,他们的服务器正在运行SAP XI,这是拒绝我访问的应用程序.我不知道这个设置是否与其他设置非常不同,但由于Postman能够成功地完成请求,我不怀疑它是非常不同的.在最坏的情况下,它只是一个高于平均水平的安全协议,仍然遵循标准.
我的主要想法是设置简单的ASP页面/ API(需要客户端证书)并将其放在我们的生产服务器上.另一个想法是寻找替代品HttpClient.或者更糟糕的是,创建我自己的,并尝试复制我看到Postman所做的事务流程.但基本上我的想法已经不多了.任何帮助表示赞赏.
如果我必须提出具体问题,我认为这是:
如何使用C#1.2在C#中使用我的客户端证书向SAP XI服务器发出GET请求?
另外,我不确定是否可以显示生产服务器的URL或IP.当然,没有人能够以任何方式自己连接,因为他们不允许您将证书添加到他们的服务器.所以这恐怕不会完全重现.我猜这个服务器属于KMD是没有害处的.
但是如果我能够成功连接到我自己的页面/服务并在那里看到客户端证书,那么我认为我将以任何一种方式超越目标,所以我认为这是要走的路.
对不起问题的长度,但这样我提供了很多背景研究和细节,应该有助于回答'和未来的人诊断一个非常相似的问题.我也尝试在我的问题中包含一些常见问题.
当我弄清楚的时候,如果没有得到任何答案,我当然会自己回答这个问题.
提前致谢.
在研究如何从我的本地托管页面将套接字数据捕获到 Wireshark 时,我无意中发现了一篇文章,指出在“较新版本的 Windows”(如 Windows 10)中,“证书验证”不是通过 TLS 1.2 发送的。
所以我将协议更改为 TLS 1.0 并且请求通过:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
Run Code Online (Sandbox Code Playgroud)
对于 TLS 1.1,我遇到了一个例外,与那篇文章中的人所说的不同:
(WebException) 请求被中止:无法创建 SSL/TLS 安全通道。
为什么这有效,我目前没有时间调查,因为我已经远远落后于调试这个问题的计划,但对我来说,这听起来像是一个错误,就像另一个用户在另一个问题中声称的那样。
我发现Microsoft 的一篇文章大意如下:
仅当服务器以不恰当的方式降级 TLS 会话时才会出现此问题(例如,在收到服务器不支持的 TLS 协议版本时发送 TCP 重置)
但由于我从 TLS 1.2 开始,并且服务器明确接受 TLS 1.2(通过 Postman 和 Chrome),因此它一定是 TLS 1.2 协议的一小部分,但没有以相同的方式或其他方式实现。我仍然不明白 Postman 本机 Windows 应用程序如何设法使用 TLS 1.2。
可能值得注意的是,Internet Explorer 首先尝试 TLS 1.2,然后在 2 次重置后(就像我的客户端),它只是降级到 TLS 1.0 并通过。对我来说,这听起来与文章中讨论的 Internet Explorer 更新非常相似:
我意识到这不是一个很好的答案(当涉及到“为什么”的细节时),但至少它给出了一个提示,告诉人们如果遇到类似的问题可以尝试什么。
如果有人理解这个问题,甚至可能知道我如何支持 TLS 1.2,那么我将非常感激。
| 归档时间: |
|
| 查看次数: |
4348 次 |
| 最近记录: |