C# 如何在SslStream.authenticatesClient期间从X509Certificate对象中提取域名?(.NET4)

C# 如何在SslStream.authenticatesClient期间从X509Certificate对象中提取域名?(.NET4),c#,.net,x509certificate,ssl,x509,C#,.net,X509certificate,Ssl,X509,我有一个由SslStream.AuthenticateTaseClient调用的RemoteCertificateValidationCallback函数,它被传递一个X509Certificate对象 我想从该证书中提取名称,这样,如果我将该字符串传递到AuthenticateTaseClient,它就会被传递。(假设没有其他问题。) (注意:Subject属性包含域名,但它位于“CN=…,s=…”等格式的字符串中。) 另请参见:(针对Java提出了一个类似的问题,但在这些答案中我找不到类似的

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

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

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

另请参见:(针对Java提出了一个类似的问题,但在这些答案中我找不到类似的.NET类。)

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

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

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

使用方法获取证书的DER数据。然后创建X509Certificate2对象的实例,并使用()方法加载原始证书数据。然后使用属性访问各个主题字段。注意-您还需要检查Subject Alternative Name extension,但遗憾的是,在.NET Framework类中没有简单的方法可以做到这一点(您可能会发现有必要使用第三方PKI库进行适当的证书验证和管理)

我使用以下方法解析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;
    }
//
///递归地在提供的AD字符串中搜索所有组。
/// 
///要为组分析的AD返回的字符串。
///用作数据分隔符的字符串。例如“,”
///如果未找到组,则为null-或者-数据为null或空。
公共静态列表解析(字符串数据、字符串分隔符)
{
if(data==null)返回null;
如果(!delimiter.EndsWith(“=”)delimiter=delimiter+“=”;
//data=data.ToUpper();//我为什么要添加这个?
如果(!data.Contains(delimiter))返回null;
//基本情况
var result=新列表();
int start=data.IndexOf(分隔符)+3;
int length=data.IndexOf(',,start)-start;
if(length==0)返回null;//组为空
如果(长度>0)
{
添加(data.Substring(start,length));
//只需要在找到逗号时递归,因为可能会有更多的组
var rec=Parse(data.Substring(start+length),分隔符);
if(rec!=null)result.AddRange(rec);//无法将null传递到AddRange():(
}
else//在当前组后找不到逗号,因此只需使用剩余的整个字符串即可
{
result.Add(data.Substring(start));
}
返回结果;
}

因此,给它一个字符串,如“CN=my common name,CN=other common name,O=my organization”,它将返回一个包含这两个常用名称的列表。

我用以下方法完成了它:

var cert2 = new X509Certificate2(cert);
string hostName = cert2.GetNameInfo(X509NameType.DnsName, false);
您还可以检查证书是否有效:

bool valid = cert2.Verify();

(请参阅X509Certificate2类的说明)

对于我的证书字符串,通过这样的小调整,它工作得更好

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;
        } 

谢谢,但我仍在取回CN=etc的内容。我用一些示例代码编辑了Q。@billpg看起来需要解析名称:(-此类类似于SubjectName或IssuerName属性的扩展,SubjectName或IssuerName属性是向其颁发证书的个人或实体的名称。X.500是分布式目录服务的国际标准。可分辨名称使用以下格式:[X500:/C=CountryCode/O=Organization/OU=OrganizationUnit/CN=CommonName]@billpg我仍然建议您使用第三方库方便地管理证书。谢谢。我希望.NET的SslStream内部使用的代码有一个公共接口。知道我想要的代码在其中有点让人恼火,但我不能调用它。:)为什么不简单地用逗号拆分,然后用等号拆分每个子字符串呢?这段代码对于这项任务来说似乎太复杂了。这只是一个递归解决方案的示例。有很多方法可以拆分字符串。很抱歉打扰您,但请看一看:您已经接受了只有一个向上投票的答案,而我的答案是+23和+23绝对简单多了(虽然我猜有点晚了……)你会考虑改变接受的答案吗?我不是为了我自己,而是为了其他用户的利益。“伊米尔哦,好吧。对不起,亚当。
var name = Parse(_cert.Subject, "CN").FirstOrDefault();
var email = Parse(_cert.Subject, "E").FirstOrDefault();