c#验证X509Certificate2:我这样做了吗?

时间:2016-12-09 15:29:46

标签: c# ssl x509certificate2

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

  1. 证书中的URL必须与给定的URL匹配
  2. 证书必须有效且值得信赖
  3. 证书不得过期
  4. 以下过关,但这是否足够?

    特别是对 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;
        }
    

1 个答案:

答案 0 :(得分:2)

如果您尝试验证HTTPS证书是否有效,HttpWebRequest可以为您执行此操作。

要使HttpWebRequest检查撤销状态,您需要在调用ServicePointManager.CheckCertificateRevocationList = true之前设置全局GetResponse()(我认为它的GetResponse,而不是通话创建())。

然后检查:

  • 证书链接到受信任的根
  • 证书未过期(及其他此类事项)
  • 请求主机名与
  • 匹配

你提到的所有三点都是。最难的是让主机名匹配正确,因为

  1. 可能有几个SubjectAlternativeName DNS条目,并且在.NET中询问它们不是一个好方法。
  2. 任何SubjectAlternativeName DNS条目都允许包含通配符(*)。但主题CN值不是(并且.NET API不指示您返回的名称类型)。
  3. IDNA的名称规范化等等。
  4. 事实上,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()的返回值,因为如果任何证书过期或诸如此类,那将是false。您还可能需要检查构建链中的根证书(或中间产品或其他内容)是否为预期值(证书固定)。

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

    您应该尝试使用验证器以确保其有效: