【问题标题】:Use a particular CA for a SSL connection使用特定 CA 进行 SSL 连接
【发布时间】:2023-06-20 10:47:01
【问题描述】:

我正在阅读Support Certificates In Your Applications With The .NET Framework 2.0,试图确定如何为 SSL 连接设置 CA。

Validating Certificates下的文章写到一半,MSDN 给出了一些代码:

static void ValidateCert(X509Certificate2 cert)
{
    X509Chain chain = new X509Chain();

    // check entire chain for revocation 
    chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;

    // check online and offline revocation lists
    chain.ChainPolicy.RevocationMode = X509RevocationMode.Online | 
                                           X509RevocationMode.Offline;

    // timeout for online revocation list 
    chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 30);

    // no exceptions, check all properties
    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;

    // modify time of verification
    chain.ChainPolicy.VerificationTime = new DateTime(1999, 1, 1);

    chain.Build(cert);
    if (chain.ChainStatus.Length != 0)
        Console.WriteLine(chain.ChainStatus[0].Status);
    }

然后:

// override default certificate policy
ServicePointManager.ServerCertificateValidationCallback =
    new RemoteCertificateValidationCallback(VerifyServerCertificate);

我觉得我错过了一些非常明显的东西。例如,我不想要回调 - 我只想说,“建立 SSL 连接,这是要信任的 CA”。但我在上面的代码中没有看到。

X509Chain 似乎没有 add 方法来添加 CA 或信任根。 CA不应该在回调之前设置吗?但我在上面的代码中没有看到。

在 Java 中,在加载您要使用的特定 CA(例如,请参阅 Use PEM Encoded CA Cert on filesystem directly for HTTPS request?)后使用 TrustManager(或 TrustManagerFactory)来完成。

问题:如何设置 CA 以用于 .Net 或 C# 中的 SSL 连接?

【问题讨论】:

    标签: c# validation ssl x509certificate ca


    【解决方案1】:

    以下代码将避开 Windows 证书存储并使用文件系统上的 CA 验证链。

    函数的名称无关紧要。下面,VerifyServerCertificateSslStream 类中的 RemoteCertificateValidationCallback 是相同的回调。也可以用于ServicePointManager中的ServerCertificateValidationCallback

    static bool VerifyServerCertificate(object sender, X509Certificate certificate,
        X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        try
        {
            String CA_FILE = "ca-cert.der";
            X509Certificate2 ca = new X509Certificate2(CA_FILE);
    
            X509Chain chain2 = new X509Chain();
            chain2.ChainPolicy.ExtraStore.Add(ca);
    
            // Check all properties
            chain2.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
    
            // This setup does not have revocation information
            chain2.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
    
            // Build the chain
            chain2.Build(new X509Certificate2(certificate));
    
            // Are there any failures from building the chain?
            if (chain2.ChainStatus.Length == 0)
                return false;
    
            // If there is a status, verify the status is NoError
            bool result = chain2.ChainStatus[0].Status == X509ChainStatusFlags.NoError;
            Debug.Assert(result == true);
    
            return result;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }
    
        return false;
    }
    

    想出了如何默认使用这个链(下面的chain2),这样就不需要回调了。也就是说,将它安装在 ssl 套接字上,连接将“正常工作”。而且我没有弄清楚如何安装它以便将其传递到回调中。也就是说,我必须为回调的每次调用构建链。我认为这些是 .Net 中的架构缺陷,但我可能会遗漏一些明显的东西。

    【讨论】:

    • 本地 CA 证书是一种无法验证或撤销的证书。就在最近,Heartbleed 漏洞利用在许多站点上暴露了证书,导致大量撤销 - 许多站点仍然不安全。如果您从其 URL 源而不是本地驱动器加载证书,您的解决方案将是有效的,确保它是有效的。为避免性能损失,您可以缓存证书,但是 - 这就是 Windows 证书存储已经为您做的事情。
    • if (chain2.ChainStatus.Length == 0) 应该返回 False,而不是 true
    最近更新 更多