给定对象标识符,我们如何从ASN.1 DER编码的二进制文件中读取相应的值

本文关键字:二进制文件 编码 读取 DER 对象标识符 我们 ASN | 更新日期: 2023-09-27 18:10:43

我正试图从Microsoft安全目录(*.cat)文件中读取与对象标识符对应的值,该文件实际上是DER编码的ASN.1对象。我使用弹性城堡来创建一个Asn1Object。当我执行。tostring()时,我可以在转储文本中看到我的ASCII数据,针对对象标识符"1.3.6.1.4.1.311.12.2.1",但是否有一种方法可以通过传递此OID来检索数据?

我看到一个类Org.BouncyCastle.Asn1。微软,但我不确定如何使用这个类。任何帮助,感谢!到目前为止,我只有这个,我称之为文件。ReadAllBytes并传递给我在下面编写的函数,在此我可以调用ToString()并查看.cat

中的所有数据
private Asn1Object asn1Object(byte[] data)
        {                
                Asn1InputStream asn1InputStream = new Asn1InputStream(data);
                if(asn1InputStream != null)
                {
                    return asn1InputStream.ReadObject().;
                }
                else
                {
                    return null;
                }
        }

给定对象标识符,我们如何从ASN.1 DER编码的二进制文件中读取相应的值

简短的回答:您需要递归地遍历树以找到包含DerObjectIdentifier的DerSequence,然后返回DerObjectIdentifier的下一个兄弟。

长答案:查看ASN1/DER结构,在对象图中似乎没有单个条目具有OID和值。对于一个特定的OID,它将是DerSequence中的第一个子对象,而该值将是第二个子对象。

一个递归方法,将找到包含与您的OID匹配的DerObjectIdentifier的DerSequence,并返回下一个兄弟是:

public static Asn1Object FindAsn1Value(string oid, Asn1Object obj)
{
    Asn1Object result = null;
    if (obj is Asn1Sequence)
    {
        bool foundOID = false;
        foreach (Asn1Object entry in (Asn1Sequence)obj)
        {
            var derOID = entry as DerObjectIdentifier;
            if (derOID != null && derOID.Id == oid)
            {
                foundOID = true;
            }
            else if (foundOID)
            {
                return entry;
            } 
            else
            {
                result = FindAsn1Value(oid, entry);
                if (result != null)
                {
                    return result;
                }
            }
        }
    }
    else if (obj is DerTaggedObject)
    {
        result = FindAsn1Value(oid, ((DerTaggedObject)obj).GetObject());
        if (result != null)
        {
            return result;
        }
    }
    else
    {
        if (obj is DerSet)
        {
            foreach (Asn1Object entry in (DerSet)obj)
            {
                result = FindAsn1Value(oid, entry);
                if (result != null)
                {
                    return result;
                }
            }
        }
    }
    return null;
}

要调用它,您需要使用您提供的方法加载Asn1Object,然后调用上面所示的FindAsn1Value。这将返回您所追求的Asn1Object(在我的测试cat文件的情况下,这个值是一个DerOctetString)。

Asn1Object asn = asn1Object(File.ReadAllBytes(@"test_file.cat"));
Asn1Object value = FindAsn1Value("1.3.6.1.4.1.311.12.2.1", asn);
if (value is DerOctetString)
{
    UnicodeEncoding unicode = new UnicodeEncoding(true, true);
    Console.WriteLine("DerOctetString = {0}", unicode.GetString(((DerOctetString)value).GetOctets()));
}

我不确定该OID的值是否始终是一个DerOctetString,也不确定我的解码选择是否一定是正确的,但是它给了我最易读的版本,我的测试正在使用的值。

更新

如果相同的OID在层次结构中出现多次,并且您需要返回所有可能的值,那么另一种方法可以是:

public static List<Asn1Object> FindAsn1Values(string oid, Asn1Object obj)
{
    Asn1Object result = null;
    List<Asn1Object> results = new List<Asn1Object>();
    if (obj is Asn1Sequence)
    {
        bool foundOID = false;
        foreach (Asn1Object entry in (Asn1Sequence)obj)
        {
            var derOID = entry as DerObjectIdentifier;
            if (derOID != null && derOID.Id == oid)
            {
                foundOID = true;
            }
            else if (foundOID)
            {
                results.Add(entry);
            } 
            else
            {
                result = FindAsn1Values(oid, entry);
                if (result.Count > 0)
                {
                    results.AddRange(result);
                }
            }
        }
    }
    else if (obj is DerTaggedObject)
    {
        result = FindAsn1Values(oid, ((DerTaggedObject)obj).GetObject());
        if (result.Count > 0)
        {
            results.AddRange(result);
        }
    }
    else
    {
        if (obj is DerSet)
        {
            foreach (Asn1Object entry in (DerSet)obj)
            {
                result = FindAsn1Values(oid, entry);
                if (result.Count > 0)
                {
                    results.AddRange(result);
                }
            }
        }
    }
    return results;
}