【问题标题】:How to get certificate from specific binding C#如何从特定绑定 C# 获取证书
【发布时间】:2016-04-05 11:15:19
【问题描述】:

我在互联网上找到了从 iis 获取所有证书的唯一方法,我这样做如下 (c#):

var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
store.Certificates;

现在我尝试获取特定绑定的特定证书,如何在 C# 中进行?

【问题讨论】:

    标签: c# iis ssl binding


    【解决方案1】:

    证书本身绝对不包含有关 IIS 中使用的绑定的信息,因此您无法从机器中检索证书并期望它们具有与 IIS 相关的任何信息。您需要从 IIS 查询该信息。

    为此,您需要添加对可在%windir%\system32\inetsrv\Microsoft.Web.Administration.dll 下找到的库的引用(注意:必须安装 IIS 7 或更新版本)。在此之后,您可以执行以下操作来获取证书:

    ServerManager manager = new ServerManager();
    Site yourSite = manager.Sites["yourSiteName"];
    
    X509Certificate2 yourCertificate = null;
    
    foreach (Binding binding in yourSite.Bindings)
    {
        if (binding.Protocol == "https" && binding.EndPoint.ToString() == "127.0.0.1" /*your binding IP*/)
        {
            var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            yourCertificate = store.Certificates.Find(X509FindType.FindByThumbprint, ToHex(binding.CertificateHash), true)[0];
            break;
        }
    }
    
    public static string ToHex(byte[] ba)
    {
        var hex = new StringBuilder(ba.Length * 2);
        foreach (byte b in ba) 
        {
            hex.AppendFormat("{0:x2}", b);
        }
    
        return hex.ToString();
    }
    

    【讨论】:

    • 那个 NuGet 包不是微软官方的,应该避免。
    • 完整路径为%windir%\system32\inetsrv\Microsoft.Web.Administration.dll。请使用它。
    • @LexLi 完成。我觉得奇怪的是,微软没有做到这一点更容易。
    • Microsoft 不会拒绝那些 NuGet 包,所以它们会把事情搞砸。我有一篇关于 MWA 的博文,blog.lextudio.com/2015/05/…
    • 您好,非常感谢您的回答。行:yourCertificate = store.Certificates.Find(X509FindType.FindByThumbprint, System.Convert.ToBase64String(binding.CertificateHash), true)[0];返回给我以下异常:索引超出范围。必须是非负数且小于集合的大小。参数名称:索引。你知道为什么以及如何解决它吗?
    【解决方案2】:

    我认为卡米洛的回答有一个小问题。据我所见(经过测试),找到证书的代码不起作用,因为System.Convert.ToBase64String(binding.CertificateHash) 没有返回有效的证书指纹。

    我的版本:

        /// <summary>
        /// Returns the https certificate used for a given local IIS website.
        /// </summary>
        /// <param name="sWebsite">Website url, e.g., "https://myserver.company.com"</param>
        /// <returns>certificate, null if not found</returns>
        private X509Certificate2 FindIisHttpsCert(string sWebsite)
        {
          Uri uriWebsite = new Uri(sWebsite);
          using (ServerManager sm = new ServerManager())
          {
            string sBindingPort = string.Format(":{0}:", uriWebsite.Port);
            Binding bdBestMatch = null;
            foreach (Site s in sm.Sites)
            {
              foreach (Binding bd in s.Bindings)
              {
                if (bd.BindingInformation.IndexOf(sBindingPort) >= 0)
                {
                  string sBindingHostInfo = bd.BindingInformation.Substring(bd.BindingInformation.LastIndexOf(':') + 1);
                  if (uriWebsite.Host.IndexOf(sBindingHostInfo, StringComparison.InvariantCultureIgnoreCase) == 0)
                  {
                    if ((bd.Protocol == "https") && ((bdBestMatch == null) || (bdBestMatch.BindingInformation.Length < bd.BindingInformation.Length)))
                      bdBestMatch = bd;
                  }
                }
              }
            }
            if (bdBestMatch != null)
            {
              StringBuilder sbThumbPrint = new StringBuilder();
              for (int i = 0; i < bdBestMatch.CertificateHash.Length; i++)
                sbThumbPrint.AppendFormat("{0:X2}", bdBestMatch.CertificateHash[i]);
    
              X509Store store = new X509Store(bdBestMatch.CertificateStoreName, StoreLocation.LocalMachine);
              store.Open(OpenFlags.ReadOnly);
              X509Certificate2Collection coll = store.Certificates.Find(X509FindType.FindByThumbprint, sbThumbPrint.ToString(), true);
              if (coll.Count > 0)
                return coll[0];
            }
          }
          return null; // if no matching site was found
        }
    

    如果多个 https 站点托管在同一台服务器上(经过测试),此功能也可以工作,并且如果站点使用 443 以外的端口(未经测试)应该可以工作。要获取绑定信息,请使用 %windir%\system32\inetsrv\Microsoft.Web.Administration.dll,如 Camilo 的回答。

    【讨论】:

    • 我遇到了同样的错误,您的代码运行良好!
    【解决方案3】:

    我已经尝试了解决方案,但遇到了找不到证书的问题。最终需要根据绑定正确指定证书存储:

    ServerManager manager = new ServerManager();
    Site yourSite = manager.Sites["yourSiteName"];
    
    X509Certificate2 yourCertificate = null;
    
    foreach (Binding binding in yourSite.Bindings)
    {
        if (binding.Protocol == "https" && binding.EndPoint.ToString() == "127.0.0.1" /*your binding IP*/)
        {
            var store = new X509Store(binding.CertificateStoreName, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            var certs = store.Certificates.Find(X509FindType.FindByThumbprint, ToHex(binding.CertificateHash), true);
    
            if (certs.Count > 0)
                yourCertificate = certs[0];
            break;
        }
    }
    
    public static string ToHex(byte[] ba)
    {
        var hex = new StringBuilder(ba.Length * 2);
        foreach (byte b in ba) 
        {
            hex.AppendFormat("{0:x2}", b);
        }
    
        return hex.ToString();
    }
    

    【讨论】:

      【解决方案4】:

      以下链接应该会有所帮助:

      基本上 store.Certificates 返回特定商店中所有证书的集合,然后您可以搜索所需的证书。如果您知道所需证书的主题名称,该链接显示了如何执行此操作。

      How to get X509Certificate from certificate store and generate xml signature data?

      【讨论】:

        猜你喜欢
        • 2019-10-08
        • 2018-02-26
        • 2011-11-29
        • 1970-01-01
        • 2019-11-28
        • 2020-02-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多