【问题标题】:c# Validating an X509Certificate2: am I doing this right?c# Validating an X509Certificate2: 我这样做对吗?
【发布时间】:2016-12-09 15:29:45
【问题描述】:

使用框架 4.5.1 和以下要求,我这样做对吗?

  1. 证书中的 URL 必须与给定的 URL 匹配
  2. 证书必须有效且受信任
  3. 证书不得过期

以下通过,但这是否足够?

特别是对 chain.Build(cert) 的调用是否满足上面的#2

    protected bool ValidateDigitalSignature(Uri uri)
    {
        bool isValid = false;
        X509Certificate2 cert = null;
        HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
        using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
        {
            response.Close();
        }

        isValid = (request.ServicePoint.Certificate != null);
        if(isValid)
            cert = new X509Certificate2(request.ServicePoint.Certificate);
        if (isValid)
        {
            X509Chain chain = new X509Chain();
            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
            chain.Build(cert);
            isValid = (chain.ChainStatus.Length == 0);
        }
        if (isValid)
        {
            var dnsName = cert.GetNameInfo(X509NameType.DnsName, false);

            isValid = (Uri.CheckHostName(dnsName) == UriHostNameType.Dns
                && uri.Host.Equals(dnsName, StringComparison.InvariantCultureIgnoreCase));
        }
        if (isValid)
        {
            //The certificate must not be expired
            DateTimeOffset today = DateTimeOffset.Now;
            isValid = (today >= cert.NotBefore && today <= cert.NotAfter);
        }
        return isValid;
    }

【问题讨论】:

    标签: c# ssl x509certificate2


    【解决方案1】:

    如果您尝试验证 HTTPS 证书是否有效,HttpWebRequest 可以为您完成。

    要让 HttpWebRequest 检查撤销状态,您需要在调用 GetResponse() 之前设置全局 ServicePointManager.CheckCertificateRevocationList = true(我认为它是 GetResponse,而不是调用 Create())。 p>

    然后会检查:

    • 到受信任根的证书链
    • 证书未过期(以及其他类似情况)
    • 请求的主机名与它应该匹配的主机名匹配

    你问的三点是哪一个。最难的是让主机名匹配正确,因为

    1. 可能有多个 SubjectAlternativeName DNS 条目,在 .NET 中查询它们并不是一个好方法。
    2. 任何 SubjectAlternativeName DNS 条目都允许在其中包含通配符 (*)。但主题 CN 值不是(并且 .NET API 不会指示您返回的名称类型)。
    3. IDNA 等的名称标准化。

    事实上,HttpWebRequest 唯一不会自动为您做的事情(除非您设置全局)是检查撤销。你可以通过

    HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
    request.ServerCertificateValidationCallback = ValidationCallback;
    
    private static bool ValidationCallback(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
    {
        // Since you want to be more strict than the default, reject it if anything went wrong.
        if (sslPolicyErrors != SslPolicyErrors.None)
        {
            return false;
        }
    
        // If the chain didn't suppress any type of error, and revocation
        // was checked, then it's okay.
        if (chain.ChainPolicy.VerificationFlags == X509VerificationFlags.None &&
            chain.ChainPolicy.RevocationMode == X509RevocationMode.Online)
        {
            return true;
        }
    
        X509Chain newChain = new X509Chain();
        // change any other ChainPolicy options you want.
        X509ChainElementCollection chainElements = chain.ChainElements;
    
        // Skip the leaf cert and stop short of the root cert.
        for (int i = 1; i < chainElements.Count - 1; i++)
        {
            newChain.ChainPolicy.ExtraStore.Add(chainElements[i].Certificate);
        }
    
        // Use chainElements[0].Certificate since it's the right cert already
        // in X509Certificate2 form, preventing a cast or the sometimes-dangerous
        // X509Certificate2(X509Certificate) constructor.
        // If the chain build successfully it matches all our policy requests,
        // if it fails, it either failed to build (which is unlikely, since we already had one)
        // or it failed policy (like it's revoked).        
        return newChain.Build(chainElements[0].Certificate);
    }
    

    而且,值得注意的是,正如我在此处输入的示例代码,您只需要检查chain.Build() 的返回值,因为如果任何证书过期或诸如此类,那将是错误的。您可能还想检查构建链中的根证书(或中间证书,或其他)是否为预期值(证书固定)。

    如果 ServerCertificateValidationCallback 返回 false,则会在 GetResponse() 上引发异常。

    您应该试用您的验证器以确保其正常工作:

    【讨论】:

    • 我对此有点困惑。是 CheckCertificateRevocationList 需要做的所有事情吗,然后本文的其余部分解释了如果您不想使用 CheckCertificateRevocationList 需要做什么,或者它说明了即使您设置了 CheckCertificateRevocationList 还需要做什么?
    • @alex.peter 只需设置 CheckCertificateRevocationList 即可。这可以通过与已撤销的端点交谈来验证,例如最后的列表。
    • 谢谢,那么给出的代码就是你需要做的额外的事情,以防你不使用 CheckCertificateRevocation 列表
    猜你喜欢
    • 1970-01-01
    • 2012-08-13
    • 2023-03-19
    • 1970-01-01
    • 2022-07-11
    • 2015-01-13
    • 2015-06-09
    • 2014-06-28
    • 1970-01-01
    相关资源
    最近更新 更多