【问题标题】:Root certificate isn't sent along with client certificate using HTTP client .NET 6根证书不与使用 HTTP 客户端 .NET 6 的客户端证书一起发送
【发布时间】:2022-07-01 21:52:55
【问题描述】:

我有一个 p12 文件,其中包含三个证书(和一个私钥)

  1. 客户端证书
  2. 中级证书
  3. 根证书

使用 openssl s_client 连接成功,但是使用 HTTP 客户端连接不成功。

在 Wireshark 中检查有效负载我可以看到只发送了两个证书 (1,2) 并且缺少根 (3)。

我已在我的和根证书中的当前用户和本地计算机中安装了证书,但结果没有任何改变。证书应该安装在哪里?

有趣的是,使用var chain = new X509Chain(); chain.Build(certificate) 可以正确找到所有中间证书。

更新: 我尝试添加从链中解析的所有证书,但结果是一样的。

代码

using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

const string thumbprint = "";

using var store = new X509Store(StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var certificate = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, false)[0];

var clientHandler = new HttpClientHandler
{
    ClientCertificateOptions = ClientCertificateOption.Manual,
    SslProtocols = SslProtocols.Tls12,
    ClientCertificates = { certificate }
};

var client = new HttpClient(clientHandler)
{
    BaseAddress = new Uri("url")
};

var response = await client.GetAsync(string.Empty);
// Exception:
//  The SSL connection could not be established, see inner exception.' -> 
//  AuthenticationException: Authentication failed because the remote party sent a TLS alert: 'HandshakeFailure'.

我一直关注this SO-post,但它对我不起作用。

更新 我从执行 OpenSSL s_client 时使用的 crt 文件中删除了根证书,并更仔细地阅读了所有输出。看来它从来没有工作过......

139645152049040:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:s3_pkt.c:1493:SSL alert number 40
139645152049040:error:140790E5:SSL routines:ssl23_write:ssl handshake failure:s23_lib.c:177:

我正在关注输出的最后一部分

SSL handshake has read 5917 bytes and written 2674 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384
Server public key is 2048 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES256-GCM-SHA384
    Session-ID:
    Session-ID-ctx:
    Master-Key: 13838C2676F91215679A69B491D9117198CAD86B24CDBBFE6357A0D34B58317DD6F9C57FAFE99264CB73A94204280300
    Key-Arg   : None
    Krb5 Principal: None
    PSK identity: None
    PSK identity hint: None
    Start Time: 1654810361
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---

这给我的印象是一切都很好。我将联系证书和服务的提供者,因为我怀疑客户端证书 CA 不在服务器的允许列表中(在 openssl 输出中找不到它),@Oliver 在评论中指出。

很抱歉浪费您的时间,感谢您的 dito!

更新: @crypt32 他们现在已经在服务器上成功安装了必要的证书,并且可以使用 openssl

  1. 所有三个证书
  2. 中级和客户
  3. 仅限客户端 (私钥作为 pem 文件的一部分包含在上述所有文件中)

.NET(来自 Windows)仍然无法工作。

【问题讨论】:

  • AFAIK 永远不会发送根证书。机器(或应用程序)有自己的根证书存储,并使用这些来检查证书链。这就是为什么根证书是特殊的,因为它们需要以不同的方式提供给用户(例如操作系统或应用程序安装/更新)。大多数应用程序使用底层操作系统的证书存储,一个反例是拥有自己存储的 Firefox。
  • 发送中间证书是有用的。是的,你需要创建一个Chain,这有什么问题?
  • 没有错。我忘了写我尝试将所有证书(中间证书和根证书)添加到 HttpClientHandler 但结果没有区别的问题。

标签: c# httpclient x509certificate .net-6.0 client-certificates


【解决方案1】:

证书应该安装在哪里?

在您要连接的服务器上。

这背后的想法是您将叶子和所有中间 CA 证书发送到服务器。服务器在收到时建立证书链。如果服务器无法找到根证书,则客户端证书不受服务器信任,验证检查将失败。请求中存在根证书没有什么意义,因为服务器不会仅仅因为您发送它就自动信任您的根。根证书必须显式安装在受信任根存储中的服务器上。

RFC 5246 §7.4.2 的摘录适用于服务器和客户端证书:

certificate_list
      This is a sequence (chain) of certificates.  The sender's
      certificate MUST come first in the list.  Each following
      certificate MUST directly certify the one preceding it.  Because
      certificate validation requires that root keys be distributed
      independently, the self-signed certificate that specifies the root
      certificate authority MAY be omitted from the chain, under the
      assumption that the remote end must already possess it in order to
      validate it in any case.

换句话说,你没有什么可以或应该做的。

【讨论】:

  • 但是使用openssl s_client -connect <host name>:443 -cert cert.cer 可以工作,然后所有三个证书都通过(因为它们都在文件中)。我可以尝试从证书文件中删除根目录。
  • 这只是 OpenSSL 的实现。 Microsoft SChannel 不发送根证书。
  • 我刚刚在没有根证书的情况下进行了测试,它成功了。这让我更加好奇为什么在发送所有必需的证书时它在 .NET 中不起作用。
  • @joacar 你应该检查服务器日志。没有其他详细信息,没有人可以告诉您出了什么问题。顺便说一句,请确保您的应用程序是否有权访问系统存储中的私钥。要么,应用程序必须以管理员权限运行,要么具有明确的权限。
  • 感谢@Crypt32。我用其他信息更新了我的帖子,我认为服务器确实缺少根证书。
【解决方案2】:

您可以将此添加到您的客户端处理程序初始化中:

clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };

【讨论】:

  • 投反对票,因为该主题与服务器证书无关,这根本不安全。接受任意证书从来都不是一个好主意。
猜你喜欢
  • 2013-06-06
  • 1970-01-01
  • 2015-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-28
相关资源
最近更新 更多