2015-09-01 9 views
0

Я пытаюсь прочитать значение, соответствующее идентификатору объекта, из файла каталога безопасности Microsoft (* .cat), который на самом деле является объектом ASN.1, закодированным DER. Я использую bouncy castle для создания Asn1Object. Когда я выполняю .ToString(), я могу видеть мои данные в ASCII в сбрасываемом тексте, против идентификатора объекта «1.3.6.1.4.1.311.12.2.1», но есть ли способ получить данные в частности, передав этот OID?Учитывая идентификатор объекта, как мы считываем соответствующее значение из двоичного файла с кодировкой DER, закодированного в ASN.1?

Я вижу класс Org.BouncyCastle.Asn1.Microsoft, но я не уверен, как использовать этот класс. Любая помощь ценится! До сих пор я только это, когда я называю File.ReadAllBytes и перейти к функции, которую я написал ниже, на этом я могу вызвать ToString() и просмотреть все данные в .cat

private Asn1Object asn1Object(byte[] data) 
     {     
       Asn1InputStream asn1InputStream = new Asn1InputStream(data); 

       if(asn1InputStream != null) 
       { 
        return asn1InputStream.ReadObject().; 
       } 
       else 
       { 
        return null; 
       } 

     } 

ответ

1

Короткий 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; 
} 
+0

Объект, который получить вернулся является объектом DerSet. Кроме того, есть ли способ прочитать следующее поле с тем же OID? Я вижу 6 полей в коте с тем же OID, и мне, вероятно, нужен третий. –

+0

Кроме того, объект DerSet не реализует метод GetOctets. :( –

+0

Если есть несколько значений одного и того же OID, то вместо того, чтобы возвращать один результат, вместо этого вы можете вернуть список для возможных значений этого OID. Я обновлю свой ответ на этот альтернативный метод. будучи DerSet, это коллекция Asn1Object's, вам придется перебирать их, чтобы понять, что они содержат. – nemuca