为什么服务器可能收不到附加到使用 HttpClient 的请求的证书?
Why might the server not receive a certificate attached to a request using HttpClient?
我们正在尝试连接到一个端点,该端点仅验证是否已正确附加证书。
我们的代码很简单:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using (var handler = new HttpClientHandler())
{
var rawcert = File.ReadAllText(@"C:\OpenSSL\bin\cert.pem");
var rawkey = File.ReadAllText(@"C:\OpenSSL\bin\private.key");
var provider = new CertificateFromFileProvider(rawcert, rawkey);
var certificate = provider.Certificate;
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(certificate);
handler.ServerCertificateCustomValidationCallback +=
(HttpRequestMessage req, X509Certificate2 cert2, X509Chain chain, SslPolicyErrors err) =>
{
Trace.WriteLine($"Sender: {req}");
Trace.WriteLine($"cert: {cert2}");
Trace.WriteLine($"chain: {chain}");
Trace.WriteLine($"sslPolicyErrors: {err}");
return true;
};
using (var client = new HttpClient(handler))
{
var response = await client.GetStringAsync("https://{uri}/mtlsTest");
return response;
}
}
(这是一个用于概念验证的沙盒环境,因此我们现在很乐意使用 ValidationCallback 的快捷方式。)
我们可以看到附加的证书在回调中显示格式正确(来源和主题符合预期),但我们从服务器收到的响应表明没有附加证书。为什么会这样?
我们还尝试将证书导出为 pfx
并附加该证书而不是原始 pem
文件,结果相同。
更新
感谢@bartonjs 和@Crypt32 下面的有用评论,我们已经尝试添加私钥(使用来自@stef-heyenrath 的方便的 Nuget Package),但是尽管这导致了我们的证书添加到显示 HasPrivateKey=true
:
的处理程序
... 当 ValidationCallback 触发时,X509Certificate2
跟踪 HasPrivateKey=false
:
...我们得到与以前相同的错误 - 服务器从不确认收到证书。
如果我们使用 open ssl 将 .pem
和私钥打包成 .pfx
:
pkcs12 -inkey private.key -in cert.pem -export -out cert.pfx
...然后我们再次得到相同的结果,服务器找不到证书。同样,如果我们在个人商店中安装证书并从那里加载它(相同的结果)。使用 Wireshark 进行的检查表明根本就没有附加证书。
为什么会这样?上面的完整修改后的代码。
最初的问题是我们的测试主机提供的证书格式错误。
另一个问题(一旦我们有一个好的证书可以使用)是 OpenSSL.X509Certificate2Provider
NuGet 包的 CertificateFromFileProvider
方法的输出。
无论出于何种原因,创建的证书都无法正常工作。采用相同的输入文件并生成 .pfx
和 OpenSSL 导致 X509Certificate2
工作正常。
我们正在尝试连接到一个端点,该端点仅验证是否已正确附加证书。
我们的代码很简单:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
using (var handler = new HttpClientHandler())
{
var rawcert = File.ReadAllText(@"C:\OpenSSL\bin\cert.pem");
var rawkey = File.ReadAllText(@"C:\OpenSSL\bin\private.key");
var provider = new CertificateFromFileProvider(rawcert, rawkey);
var certificate = provider.Certificate;
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(certificate);
handler.ServerCertificateCustomValidationCallback +=
(HttpRequestMessage req, X509Certificate2 cert2, X509Chain chain, SslPolicyErrors err) =>
{
Trace.WriteLine($"Sender: {req}");
Trace.WriteLine($"cert: {cert2}");
Trace.WriteLine($"chain: {chain}");
Trace.WriteLine($"sslPolicyErrors: {err}");
return true;
};
using (var client = new HttpClient(handler))
{
var response = await client.GetStringAsync("https://{uri}/mtlsTest");
return response;
}
}
(这是一个用于概念验证的沙盒环境,因此我们现在很乐意使用 ValidationCallback 的快捷方式。)
我们可以看到附加的证书在回调中显示格式正确(来源和主题符合预期),但我们从服务器收到的响应表明没有附加证书。为什么会这样?
我们还尝试将证书导出为 pfx
并附加该证书而不是原始 pem
文件,结果相同。
更新
感谢@bartonjs 和@Crypt32 下面的有用评论,我们已经尝试添加私钥(使用来自@stef-heyenrath 的方便的 Nuget Package),但是尽管这导致了我们的证书添加到显示 HasPrivateKey=true
:
... 当 ValidationCallback 触发时,X509Certificate2
跟踪 HasPrivateKey=false
:
...我们得到与以前相同的错误 - 服务器从不确认收到证书。
如果我们使用 open ssl 将 .pem
和私钥打包成 .pfx
:
pkcs12 -inkey private.key -in cert.pem -export -out cert.pfx
...然后我们再次得到相同的结果,服务器找不到证书。同样,如果我们在个人商店中安装证书并从那里加载它(相同的结果)。使用 Wireshark 进行的检查表明根本就没有附加证书。
为什么会这样?上面的完整修改后的代码。
最初的问题是我们的测试主机提供的证书格式错误。
另一个问题(一旦我们有一个好的证书可以使用)是 OpenSSL.X509Certificate2Provider
NuGet 包的 CertificateFromFileProvider
方法的输出。
无论出于何种原因,创建的证书都无法正常工作。采用相同的输入文件并生成 .pfx
和 OpenSSL 导致 X509Certificate2
工作正常。