【问题标题】:Can a .p12 file with CA certificates be used in C# without importing them to certificate store可以在 C# 中使用带有 CA 证书的 .p12 文件而不将它们导入证书存储区吗
【发布时间】:2020-08-23 21:32:48
【问题描述】:

我有一个 .p12 证书文件,其中包含 3 个证书。其中2个是CA证书。

如果我使用 curl(Win10 上为 7.70),我可以: curl -s -S -i --cert Swish_Merchant_TestCertificate_1234679304.p12:swish --cert-type p12 --tlsv1.2 --header "Content-Type:application/json" https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests --data-binary @jsondata.json

Curl 连接服务器时会使用 p12 文件中的 CA 证书。

另一方面,如果我尝试在 .net core (3.1) 中执行类似操作,则会失败并显示错误消息“收到的消息意外或格式错误。”

var handler = new HttpClientHandler();
var certs = new X509Certificate2Collection();
certs.Import(@"Swish_Merchant_TestCertificate_1234679304.p12", "swish", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
foreach (var cert in certs)
{
    handler.ClientCertificates.Add(cert);
}
var client = new HttpClient(handler);
var url = "https://mss.cpc.getswish.net/swish-cpcapi/api/v1/paymentrequests";
var request = new HttpRequestMessage()
{
    RequestUri = new Uri(url),
    Method = HttpMethod.Post,
};
request.Content = new StringContent(System.IO.File.ReadAllText(@"jsondata.json"), Encoding.UTF8, "application/json");
request.Headers.Add("accept", "*/*");
var response = await client.SendAsync(request);

使用 Wireshark 我看到 curl 从 p12 文件发送所有三个证书,而 .net 核心只发送一个。见下图。

如果我将 CA 证书安装到“当前用户”的“个人证书”中,那么 .net 核心也会发送所有三个证书并且它可以工作。

问题:我是否必须在使用 .net 核心时安装 CA 证书(到证书存储中),或者有没有办法让它像 curl 一样使用 p12 中的证书文件?

Wireshark 卷曲:

Wireshark .net 核心:

【问题讨论】:

    标签: c# curl .net-core certificate x509certificate


    【解决方案1】:

    简短回答:否*。

    Wordier 介绍:SslStreamClientCertificates 集合中挑选一个证书,使用 TLS 服务器发送的关于适当根的数据(过去是,但现在不再普遍)(如果没有可用的,则选择HasPrivateKey 为真的第一件事)。在选择过程中,每个候选证书都被单独检查,并要求系统解析链。在 Windows 上,选定的证书随后被发送到系统库以“我们现在正在执行 TLS”,这 (IIRC) 是限制的来源。 (macOS 和 Linux 构建的 .NET Core 只是尝试保持行为平等)

    一旦选择了证书,就会有最后一个链式遍历来确定握手中要包含哪些证书,它是在没有来自ClientCertificates 集合的任何其他上下文的情况下完成的。

    如果您知道您的集合代表一个链,那么您最好的答案是将 CA 元素导入您的用户 CertificateAuthority 存储。该存储不会向 CA 证书授予任何信任,它实际上只是在构建链时使用的缓存。

    另外,你不想要 PersistKeySet,可能也不想要 MachineKeySet:What is the rationale for all the different X509KeyStorageFlags?

    var handler = new HttpClientHandler();
    
    using (X509Store store = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser))
    {
        store.Open(OpenFlags.ReadWrite);
    
        var certs = new X509Certificate2Collection();
        certs.Import(@"Swish_Merchant_TestCertificate_1234679304.p12", "swish", X509KeyStorageFlags.DefaultKeySet);
    
        foreach (X509Certificate2 cert in certs)
        {
            if (cert.HasPrivateKey)
            {
                handler.ClientCertificates.Add(cert);
            }
            else
            {
                store.Add(cert);
            }
        }
    }
    
    var client = new HttpClient(handler);
    ...
    

    * 如果你的系统已经导入了 CA 链,它就可以工作。或者,如果 CA 链使用授权信息访问扩展来发布 CA 证书的可下载副本,则链引擎会找到它,并且一切正常。

    【讨论】:

    • 在生产环境中,我应该(尝试)在应用程序启动时将证书添加到存储中,而不是每次我拨打电话时,对吧?
    • @Björn 您应该(尝试)尽可能多地添加证书,因为文件可能会更改。如果仅在进程停止时发生这种情况,那么在启动时就可以了。否则事情会更复杂。 (“每次”都是多余的,但会起作用。)
    猜你喜欢
    • 2020-11-06
    • 2021-08-04
    • 2013-05-25
    • 2016-10-17
    • 2011-06-23
    • 2012-02-26
    • 1970-01-01
    • 2012-04-06
    • 2018-06-30
    相关资源
    最近更新 更多