【问题标题】:How to extract the domain name out of an X509Certificate object during SslStream.AuthenticateAsClient? (.NET4)如何在 SslStream.AuthenticateAsClient 期间从 X509Certificate 对象中提取域名? (.NET4)
【发布时间】:2012-01-14 23:24:38
【问题描述】:

我有一个由 SslStream.AuthenticateAsClient 调用的 RemoteCertificateValidationCallback 函数,它传递了一个 X509Certificate 对象。

我想从该证书中提取名称,这样如果我将该字符串传递给 AuthenticateAsClient,它就会通过。 (假设没有其他问题。)

(注意:Subject 属性包含域名,但它位于“CN=..., S=...”等格式的字符串中。)

另请参阅:How to extract CN from X509Certificate in Java?(针对 Java 提出了类似的问题,但我在这些答案中找不到类似的 .NET 类。)

(跟进尤金的回答。)
这个我试过了……

var cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2();
cert2.Import(certificate.GetRawCertData());

...但是 cert2.SubjectName.Name 仍然具有 CN= 等格式。我做错了吗?

【问题讨论】:

  • 很抱歉打扰你,但请看一下:你已经接受了只有一个赞成票的答案,而我的答案是 +23,而且肯定更简单、更安全(虽然我猜是有点晚了......)你会考虑改变接受的答案吗?我问这个不是为了我自己,而是为了其他用户的利益。
  • @IMil 哦,那好吧。对不起亚当。

标签: c# .net x509certificate ssl x509


【解决方案1】:

使用GetRawCertData方法获取证书的DER数据。然后创建 X509Certificate2 对象的实例并使用 Import() 方法加载原始证书数据。然后使用SubjectName 属性访问各个主题字段。注意 - 您还需要检查主题备用名称扩展,但不幸的是,在 .NET Framework 类中没有简单的方法来执行此操作(您可能会发现有必要使用第三方 PKI 库来进行正确的证书验证和管理)。

【讨论】:

  • 感谢您,但我仍然收到 CN= 等内容。我用一些示例代码编辑了 Q。
  • @billpg 看起来您需要解析名称 :( -- 此类类似于 SubjectName 或 IssuerName 属性的扩展,即颁发证书的人或实体的名称X.500 是分布式目录服务的国际标准。可分辨名称使用以下格式:[X500:/C=CountryCode/O=Organization/OU=OrganizationUnit/CN=CommonName]
  • @billpg 我仍然建议您使用第三方库来方便地管理证书。
  • 谢谢。我希望.NET 的 SslStream 在内部使用的代码有一个公共接口。知道我想要的代码在里面有点让人抓狂,但我不能调用它。 :)
【解决方案2】:

我使用以下方法解析从AD返回的字符串,它可能有助于解析您接收的数据:

    /// <summary>
    /// Recursively searches the supplied AD string for all groups.
    /// </summary>
    /// <param name="data">The string returned from AD to parse for a group.</param>
    /// <param name="delimiter">The string to use as the seperator for the data. ex. ","</param>
    /// <returns>null if no groups were found -OR- data is null or empty.</returns>
    public static List<string> Parse(string data, string delimiter)
    {
        if (data == null) return null;

        if (!delimiter.EndsWith("=")) delimiter = delimiter + "=";

        //data = data.ToUpper(); // why did i add this?
        if (!data.Contains(delimiter)) return null;

        //base case
        var result = new List<string>();
        int start = data.IndexOf(delimiter) + 3;
        int length = data.IndexOf(',', start) - start;
        if (length == 0) return null; //the group is empty
        if (length > 0)
        {
            result.Add(data.Substring(start, length));

            //only need to recurse when the comma was found, because there could be more groups
            var rec = Parse(data.Substring(start + length), delimiter);
            if (rec != null) result.AddRange(rec); //can't pass null into AddRange() :(
        }
        else //no comma found after current group so just use the whole remaining string
        {
            result.Add(data.Substring(start));            
        }

        return result;
    }

所以给它一个像“CN=my common name,CN=another common name,O=my orginization”这样的字符串,它会返回一个包含两个通用名称的列表。

【讨论】:

  • 为什么不简单地用逗号分割,然后用等号分割每个子字符串呢?这段代码对于这项任务来说似乎太复杂了。
  • 这只是递归解决方案的一个示例。有很多方法可以切断字符串。
【解决方案3】:

我是通过以下方式完成的:

var cert2 = new X509Certificate2(cert);
string hostName = cert2.GetNameInfo(X509NameType.DnsName, false);

您也可以检查证书是否有效:

bool valid = cert2.Verify();

(有关 X509Certificate2 类的说明,请参阅 this question

【讨论】:

    【解决方案4】:

    对于我的证书字符串,通过这样的小调整效果更好

    public static List<string> Parse(string data, string delimiter)
            {
                if (data == null) return null;
                if (!delimiter.EndsWith("=")) delimiter = delimiter + "=";
                if (!data.Contains(delimiter)) return null;
                //base case
                var result = new List<string>();
                int start = data.IndexOf(delimiter) + delimiter.Length;
                int length = data.IndexOf(',', start) - start;
                if (length == 0) return null; //the group is empty
                if (length > 0)
                {
                    result.Add(data.Substring(start, length));
                    //only need to recurse when the comma was found, because there could be more groups
                    var rec = Parse(data.Substring(start + length), delimiter);
                    if (rec != null) result.AddRange(rec); //can't pass null into AddRange() :(
                }
                else //no comma found after current group so just use the whole remaining string
                {
                    result.Add(data.Substring(start));
                }
                return result;
            } 
    

    ...

    var name = Parse(_cert.Subject, "CN").FirstOrDefault();
    var email = Parse(_cert.Subject, "E").FirstOrDefault();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-24
      • 2010-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-05
      • 1970-01-01
      • 2020-11-13
      相关资源
      最近更新 更多