如何解析X509Certificate2中的主题替代名称?

noc*_*ura 14 .net certificate x509certificate2

有没有一种简单的方法从X509Certificate2对象获取主题备用名称?

        foreach (X509Extension ext in certificate.Extensions)
        {
            if (ext.Oid.Value.Equals(/* SAN OID */"2.5.29.17"))
            {
                byte[] raw = ext.RawData;
                // ?????? parse to get type and name ????????
            }
        }
Run Code Online (Sandbox Code Playgroud)

Mar*_*ett 19

对于可打印版本,请使用扩展名的Format方法.

X509Certificate2 cert = /* your code here */;

foreach (X509Extension extension in cert.Extensions)
{
    // Create an AsnEncodedData object using the extensions information.
    AsnEncodedData asndata = new AsnEncodedData(extension.Oid, extension.RawData);
    Console.WriteLine("Extension type: {0}", extension.Oid.FriendlyName);
    Console.WriteLine("Oid value: {0}",asndata.Oid.Value);
    Console.WriteLine("Raw data length: {0} {1}", asndata.RawData.Length, Environment.NewLine);
    Console.WriteLine(asndata.Format(true));
}
Run Code Online (Sandbox Code Playgroud)

  • 我需要添加.Extensions,如下所示:foreach(cert.Extensions中的X509Extension扩展) (3认同)
  • 从您链接到的 Format 方法的文档中:“*不要依赖此方法的输出,因为它用于漂亮打印,并且不能保证其输出格式。*”*相同证书*的输出差异示例提供。 (2认同)

小智 13

要从证书中获取"主题备用名称":

X509Certificate2 cert = /* your code here */;

Console.WriteLine("UpnName : {0}{1}", cert.GetNameInfo(X509NameType.UpnName, false), Environment.NewLine);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,即使证书具有多个subjectAltNames,它也仅返回单个值。@Mark Brackett的方法返回所有值。 (3认同)
  • 或者,如果您想要的话,您可能想使用“X508NameType.DnsName”。无论如何,“GetNameInfo”是正确的方法,而不是解析证书。 (2认同)

Seb*_*ski 11

这是一个不需要解析返回文本的解决方案AsnEncodedData.Format()(但需要 .NET 5 或System.Formats.Asn1 NuGet 包):

using System.Formats.Asn1;

...

public static List<string> GetAlternativeDnsNames(X509Certificate2 cert)
{
    const string SAN_OID = "2.5.29.17";

    var extension = cert.Extensions[SAN_OID];
    if (extension is null)
    {
        return new List<string>();
    }

    // Tag value "2" is defined by:
    //
    //    dNSName                         [2]     IA5String,
    //
    // in: https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.6
    var dnsNameTag = new Asn1Tag(TagClass.ContextSpecific, tagValue: 2, isConstructed: false);

    var asnReader = new AsnReader(extension.RawData, AsnEncodingRules.BER);
    var sequenceReader = asnReader.ReadSequence(Asn1Tag.Sequence);

    var resultList = new List<string>();

    while (sequenceReader.HasData)
    {
        var tag = sequenceReader.PeekTag();
        if (tag != dnsNameTag)
        {
            sequenceReader.ReadEncodedValue();
            continue;
        }

        var dnsName = sequenceReader.ReadCharacterString(UniversalTagNumber.IA5String, dnsNameTag);
        resultList.Add(dnsName);
    }

    return resultList;
}
Run Code Online (Sandbox Code Playgroud)


Rui*_*lho 5

适用于所有语言的解决方案 .NET
该解决方案是上述 Minh Nguyen 解决方案的改进,因此它可以在所有语言中工作

private static List<string> GetSujectAlternativeName(X509Certificate2 cert)
        {
            var result = new List<string>();


            var subjectAlternativeName = cert.Extensions.Cast<X509Extension>()
                                                .Where(n => n.Oid.Value== "2.5.29.17") //n.Oid.FriendlyName=="Subject Alternative Name")
                                                .Select(n => new AsnEncodedData(n.Oid, n.RawData))
                                                .Select(n => n.Format(true))
                                                .FirstOrDefault();

            if (subjectAlternativeName != null)
            {
                var alternativeNames = subjectAlternativeName.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);

                foreach (var alternativeName in alternativeNames)
                {
                    var groups = Regex.Match(alternativeName, @"^(.*)=(.*)").Groups; // @"^DNS Name=(.*)").Groups;

                    if (groups.Count > 0 && !String.IsNullOrEmpty(groups[2].Value))
                    {
                        result.Add(groups[2].Value);
                    }
                }
            }

            return result;
        }
Run Code Online (Sandbox Code Playgroud)