从专有名称中提取通用名称

Fun*_*der 16 .net c# parsing ldap x509

是否在.NET中调用从rfc-2253编码的专有名称解析CN?我知道有一些第三方库可以做到这一点,但我更愿意使用本机.NET库.

字符串编码DN的示例

CN = L.Eagle,O = Sue \,Grabbit和Runn,C = GB

CN = Jeff Smith,OU = Sales,DC = Fabrikam,DC = COM

dig*_*edi 9

如果您使用的是X509Certificate2,则可以使用本机方法提取DNS名称.DNS名称通常等效于主证书的"主题"字段中的公用名称RDN:

x5092Cert.GetNameInfo(X509NameType.SimpleName, false);
Run Code Online (Sandbox Code Playgroud)


Gre*_*ray 8

深入研究.NET源代码之后,似乎有一个内部实用程序类,可以将专有名称解析为它们的不同组件。不幸的是,该实用工具类并未公开,但是您可以使用反射来访问它:

string dn = "CN=TestGroup,OU=Groups,OU=UT-SLC,OU=US,DC=Company,DC=com";
Assembly dirsvc = Assembly.Load("System.DirectoryServices");
Type asmType = dirsvc.GetType("System.DirectoryServices.ActiveDirectory.Utils");
MethodInfo mi = asmType.GetMethod("GetDNComponents", BindingFlags.NonPublic | BindingFlags.Static);
string[] parameters = { dn };
var test = mi.Invoke(null, parameters);
//test.Dump("test1");//shows details when using Linqpad 

//Convert Distinguished Name (DN) to Relative Distinguished Names (RDN) 
MethodInfo mi2 = asmType.GetMethod("GetRdnFromDN", BindingFlags.NonPublic | BindingFlags.Static);
var test2 = mi2.Invoke(null, parameters);
//test2.Dump("test2");//shows details when using Linqpad 
Run Code Online (Sandbox Code Playgroud)

结果将如下所示:

//test1 is array of internal "Component" struct that has name/values as strings
Name   Value 
CN     TestGroup 
OU     Groups 
OU     UT-SLC
OU     US 
DC     company 
DC     com 


//test2 is a string with CN=RDN 
CN=TestGroup 
Run Code Online (Sandbox Code Playgroud)

请注意,这不是内部实用程序类,在将来的发行版中可能会更改。


kbr*_*ton 6

当我找到你的时候,我自己也有同样的问题.在BCL没找到任何东西; 然而,我偶然发现了这篇CodeProject的文章,该文章正好击中了头部.

我希望它也会帮助你.

http://www.codeproject.com/Articles/9788/An-RFC-2253-Compliant-Distinguished-Name-Parser

  • 我刚刚在这里发布了它作为NuGet包:https://www.nuget.org/packages/DNParser/(只是要明确:我不是作者,但我喜欢NuGet包). (4认同)

Mit*_*tch 6

如果您使用的是 Windows,@MaxKiselev 的答案非常有效。在非 Windows 平台上,它返回每个属性的 ASN1 转储。

.Net Core 5+ 包含 ASN1 解析器,因此您可以使用 .Net Core 以跨平台方式访问 RDN AsnReader

辅助类:

public static class X509DistinguishedNameExtensions
{ 
    public static IEnumerable<KeyValuePair<string, string>> GetRelativeNames(this X500DistinguishedName dn)
    {
        var reader = new AsnReader(dn.RawData, AsnEncodingRules.BER);
        var snSeq = reader.ReadSequence();
        if (!snSeq.HasData)
        {
            throw new InvalidOperationException();
        }

        // Many types are allowable.  We're only going to support the string-like ones
        // (This excludes IPAddress, X400 address, and other wierd stuff)
        // https://www.rfc-editor.org/rfc/rfc5280#page-37
        // https://www.rfc-editor.org/rfc/rfc5280#page-112
        var allowedRdnTags = new[]
        {
            UniversalTagNumber.TeletexString, UniversalTagNumber.PrintableString,
            UniversalTagNumber.UniversalString, UniversalTagNumber.UTF8String,
            UniversalTagNumber.BMPString, UniversalTagNumber.IA5String,
            UniversalTagNumber.NumericString, UniversalTagNumber.VisibleString,
            UniversalTagNumber.T61String
        };
        while (snSeq.HasData)
        {
            var rdnSeq = snSeq.ReadSetOf().ReadSequence();
            var attrOid = rdnSeq.ReadObjectIdentifier();
            var attrValueTagNo = (UniversalTagNumber)rdnSeq.PeekTag().TagValue;
            if (!allowedRdnTags.Contains(attrValueTagNo))
            {
                throw new NotSupportedException($"Unknown tag type {attrValueTagNo} for attr {attrOid}");
            }
            var attrValue = rdnSeq.ReadCharacterString(attrValueTagNo);
            var friendlyName = new Oid(attrOid).FriendlyName;
            yield return new KeyValuePair<string, string>(friendlyName ?? attrOid, attrValue);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法示例:

// Subject: CN=Example, O=Organization
var cert = new X509Certificate2("foo.cer");
var names = this.cert.SubjectName.GetRelativeNames().ToArray();
// names has [ { "CN": "Example" }, { "O": "Organization" } ]
Run Code Online (Sandbox Code Playgroud)

由于这不涉及任何字符串解析,因此不会错误处理转义或注入。它不支持解码包含非字符串元素的 DN,但这些似乎非常罕见。


Sea*_*all 5

Win32 函数算吗?您可以将 PInvoke 与DsGetRdnW. 有关代码,请参阅我对另一个问题的回答: https: //stackoverflow.com/a/11091804/628981


Max*_*lev 5

您可以使用 AsnEncodedData 类从 ASN.1 编码的专有名称中提取通用名称:

var distinguishedName= new X500DistinguishedName("CN=TestGroup,OU=Groups,OU=UT-SLC,OU=US,DC=Company,DC=com");
var commonNameData = new AsnEncodedData("CN", distinguishedName.RawData);
var commonName = commonNameData.Format(false);
Run Code Online (Sandbox Code Playgroud)

此方法的缺点是,如果您指定无法识别的 OID 或专有名称中缺少用 OID 标识的字段,Format方法将返回一个十六进制字符串,其中包含完整专有名称的编码值,因此您可能需要验证结果。

此外,文档似乎没有指定 AsnEncodedData 构造函数的 rawData 参数是否允许包含除了指定为第一个参数的 OID 之外的其他 OID,因此它可能会在非 Windows 操作系统或未来版本的 .NET Framework 中中断。


geo*_*ffc 0

您不能只检索 CN 属性值吗?

正如您正确地注意到的那样,请使用其他人的类,因为有很多有趣的边缘情况(转义逗号、转义其他字符)使得解析 DN 看起来很容易,但实际上相当棘手。

我通常使用 Novell(现在的 NetID)身份管理器附带的 Java 类。所以这没有帮助。