附加客户端证书时为什么会显示“无法创建SSL / TLS安全通道”?

时间:2019-02-08 02:57:10

标签: c# security ssl ssl-certificate

当我的代码尝试将请求发送到服务器时,我会看到此消息,该请求要求该请求必须随附带有私有密钥的客户证书 (这可能是{{3} }。使用通过SoapUI发送的请求,我已经验证了证书是否有效。我的代码是否可能以错误的方式附加了证书?

代码看起来像这样(它可能包含很多难以捉摸的解决方案所不需要的东西):

// build stuff
var httpClientHandler = new HttpClientHandler
{
    AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip,
    ClientCertificateOptions = ClientCertificateOption.Manual
};
var certificate = new X509Certificate(certName, password, X509KeyStorageFlags.UserKeySet);
httpClientHandler.ClientCertificates.Add(certificate);
var request = new HttpRequestMessage(HttpMethod.Post, url)
{
    Content = new StringContent(requestBody, Encoding.UTF8, "application/xml")
};
var httpClient = new HttpClient(httpClientHandler);
httpClient                   
    .DefaultRequestHeaders
    .Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

// Enable protocols
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;

// fire! (here's where the exception is thrown)
var response = await httpClient.SendAsync(request).ConfigureAwait(false);

1 个答案:

答案 0 :(得分:1)

在这种情况下,问题出在证书上-特别是私钥。

我使用的是.cer证书,其行为与.pfx文件不同。 SoapUI和curl都可以与.cer一起正常工作,但是加载.cer的C#代码会丢失私钥。 (为什么我们连接的服务器需要私钥是一个不同的问题-我的理解是不应该-感谢对此的任何想法。)类似地,.cer个文件通过MMC快照加载到存储中,也会丢失私钥。我还不知道为什么。

尽管我最初成功地将.pfx文件加载到证书存储中,但是当我开始使用其他帐户运行应用程序时,返回了“无法创建SSL / TLS安全通道”错误(说明{{3 }}和here)。本质上,证书存储将私钥保存在文件系统位置,只有将证书加载到存储中的用户才能访问。

相反,我直接从文件系统加载了证书,如下所示:

var certBytes = File.ReadAllBytes(certFileName);
var certificate = new X509Certificate2(certBytes, password, X509KeyStorageFlags.Exportable);

var httpClientHandler = new HttpClientHandler();
httpClientHandler.ClientCertificates.Add(certificate);
var request = new HttpRequestMessage(HttpMethod.Post, url)
{
    Content = new StringContent(requestBody, Encoding.UTF8, "application/xml")
};

var httpClient = new HttpClient(httpClientHandler);

httpClient                   
    .DefaultRequestHeaders
    .Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

// fire!
var response = await httpClient.SendAsync(request).ConfigureAwait(false);