Короткий answer: Вам нужно будет рекурсивно пройтись по дереву, чтобы найти DerSequence, содержащий DerObjectIdentifier, а затем возвратить DerObjectIdentifiers следующего брата.
Длинный ответ: Если посмотреть на структуру ASN1/DER, на графе объектов, который имеет OID и значение, не отображается ни одна запись. Похоже, что для определенного OID это будет первый дочерний объект в DerSequence, а значение будет вторым дочерним объектом.
Рекурсивный метод, который будет найти DerSequence, содержащий DerObjectIdentifier соответствие вашего OID и вернуть вам следующий родственный является:
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 и не является ли обязательно правильно мой выбор декодирования, однако он дал мне самую читаемую версию значения, что мой тест работал с.
Update
Если же 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;
}
Объект, который получить вернулся является объектом DerSet. Кроме того, есть ли способ прочитать следующее поле с тем же OID? Я вижу 6 полей в коте с тем же OID, и мне, вероятно, нужен третий. –
Кроме того, объект DerSet не реализует метод GetOctets. :( –
Если есть несколько значений одного и того же OID, то вместо того, чтобы возвращать один результат, вместо этого вы можете вернуть список для возможных значений этого OID. Я обновлю свой ответ на этот альтернативный метод. будучи DerSet, это коллекция Asn1Object's, вам придется перебирать их, чтобы понять, что они содержат. –
nemuca