синтаксический анализ asn.1 с помощью bouncycastle

У меня есть данные в кодировке asn.1. У меня есть некоторые успехи в расшифровке его с помощью bouncycastle, но я попал в стену с довольно сложным примером. Это должно быть выполнимо, но дальше ничего не получится, надеюсь, вы можете мне помочь, вот пример данных:

A1 81 A9 02 02 1C 1F 02 01 15 30 81 9F 55 02 01 14 A0 81 98 A4 81 95 6B 10 30 0E 80 04 00 00 01 1F A1 06 30 04 80 02 33 32 63 06 30 04 80 02 33 32 61 0E 30 0C 80 0A 30 32 32 33 37 38 33 36 31 30 62 06 30 04 80 02 33 32 64 02 87 00 6B 13 30 11 80 04 00 00 01 1F A1 09 30 07 80 05 23 23 37 30 30 4E 01 02 0A 01 16 67 12 30 10 A3 0E 81 0C 2B 34 38 32 32 33 37 38 33 36 31 30 68 0F 30 0D A3 0B 82 09 32 32 38 36 35 33 33 39 38 65 09 30 07 80 05 23 23 37 30 30 7E 12 A0 10 18 0E 32 30 31 36 30 33 30 32 32 32 30 31 33 36

CSTA Browser decoded:

rOSE.roiv-apdu
{ -- SEQUENCE -- 
    invokeID = 7199,
    operation-value = 21 (cSTAEventReport),
    argument
    { -- SEQUENCE -- 
        crossRefIdentifier = '01 14'H,
        eventSpecificInfo.callControlEvents.delivered
        { -- SEQUENCE -- 
            connection.both
            { -- SEQUENCE -- 
                callID = '00 00 01 1F'H,
                deviceID.staticID
                { -- SEQUENCE -- 
                    deviceIdentifier.dialingNumber = "32" '33 32'H
                }
            },
            alertingDevice.deviceIdentifier
            { -- SEQUENCE -- 
                deviceIdentifier.dialingNumber = "32" '33 32'H
            },
            callingDevice.deviceIdentifier
            { -- SEQUENCE -- 
                deviceIdentifier.dialingNumber = "0223783610" '30 32 32 33 37 38 33 36 31 30'H
            },
            calledDevice.deviceIdentifier
            { -- SEQUENCE -- 
                deviceIdentifier.dialingNumber = "32" '33 32'H
            },
            lastRedirectionDevice.notKnown NULL,
            originatingNIDConnection.both
            { -- SEQUENCE -- 
                callID = '00 00 01 1F'H,
                deviceID.staticID
                { -- SEQUENCE -- 
                    deviceIdentifier.dialingNumber = "##700" '23 23 37 30 30'H
                }
            },
            localConnectionInfo = 2 (alerting),
            cause = 22 (newCall),
            networkCallingDevice.deviceIdentifier
            { -- SEQUENCE -- 
                deviceIdentifier.explicitPublic.international = "+48223783610" '2B 34 38 32 32 33 37 38 33 36 31 30'H
            },
            networkCalledDevice.deviceIdentifier
            { -- SEQUENCE -- 
                deviceIdentifier.explicitPublic.national = "228653398" '32 32 38 36 35 33 33 39 38'H
            },
            associatedCallingDevice.deviceIdentifier
            { -- SEQUENCE -- 
                deviceIdentifier.dialingNumber = "##700" '23 23 37 30 30'H
            },
            extensions
            { -- SEQUENCE -- 
                security
                { -- SEQUENCE -- 
                    timestamp = "20160302220136" '32 30 31 36 30 33 30 32 32 32 30 31 33 36'H
                }
            }
        }
    }
}

Дамп bouncycastle производит что-то вроде этого:

00 AC A1 81 A9 02 02 5F B9 02 01 15 30 81 9F 55 02 01 91 A0 81 98 A4 81 95 6B 10 30 0E 80 04 00 00 03 98 A1 06 30 04 80 02 33 32 63 06 30 04 80 02 33 32 61 0E 30 0C 80 0A 30 32 32 33 37 38 33 36 31 30 62 06 30 04 80 02 33 32 64 02 87 00 6B 13 30 11 80 04 00 00 03 98 A1 09 30 07 80 05 23 23 37 30 30 4E 01 02 0A 01 16 67 12 30 10 A3 0E 81 0C 2B 34 38 32 32 33 37 38 33 36 31 30 68 0F 30 0D A3 0B 82 09 32 32 38 36 35 33 33 39 38 65 09 30 07 80 05 23 23 37 30 30 7E 12 A0 10 18 0E 32 30 31 36 30 33 30 34 31 35 32 32 34 30 
buf:Tagged [1] IMPLICIT 
    Sequence
        Integer(24505)
        Integer(21)
        DER Sequence
            DER ApplicationSpecific[21] (0191)
            Tagged [0]
                Tagged [4] IMPLICIT 
                    Sequence
                        DER ApplicationSpecific[11]
                            Sequence
                                Tagged [0] IMPLICIT 
                                    DER Octet String[4] 
                                Tagged [1]
                                    DER Sequence
                                        Tagged [0] IMPLICIT 
                                            DER Octet String[2] 
                        DER ApplicationSpecific[3]
                            Sequence
                                Tagged [0] IMPLICIT 
                                    DER Octet String[2] 
                        DER ApplicationSpecific[1]
                            Sequence
                                Tagged [0] IMPLICIT 
                                    DER Octet String[10] 
                        DER ApplicationSpecific[2]
                            Sequence
                                Tagged [0] IMPLICIT 
                                    DER Octet String[2] 
                        DER ApplicationSpecific[4]
                            Tagged [7] IMPLICIT 
                                DER Octet String[0] 
                        DER ApplicationSpecific[11]
                            Sequence
                                Tagged [0] IMPLICIT 
                                    DER Octet String[4] 
                                Tagged [1]
                                    DER Sequence
                                        Tagged [0] IMPLICIT 
                                            DER Octet String[5] 
                        DER ApplicationSpecific[14] (02)
                        DER Enumerated(22)
                        DER ApplicationSpecific[7]
                            Sequence
                                Tagged [3]
                                    Tagged [1] IMPLICIT 
                                        DER Octet String[12] 
                        DER ApplicationSpecific[8]
                            Sequence
                                Tagged [3]
                                    Tagged [2] IMPLICIT 
                                        DER Octet String[9] 
                        DER ApplicationSpecific[5]
                            Sequence
                                Tagged [0] IMPLICIT 
                                    DER Octet String[5] 
                        DER ApplicationSpecific[30]
                            Tagged [0]
                                GeneralizedTime(20160304152240GMT+01:00) 

и я пытаюсь его разобрать:

protected void parse() {
    logger.trace("Executing parse()");

    try {

        ASN1InputStream input = new ASN1InputStream(asn1Data);
        ASN1Primitive p;

        if ((p = input.readObject()) != null) {
            ASN1TaggedObject o1 = ASN1TaggedObject.getInstance(p);
            ASN1Sequence s1 = ASN1Sequence.getInstance(o1.getObject());
            invokeID = Integer.parseInt(s1.getObjectAt(0).toString());
            operationValue = Integer.parseInt(s1.getObjectAt(1).toString());

            DERSequence ders = (DERSequence) DERSequence.getInstance(s1.getObjectAt(2));
            DERApplicationSpecific das = (DERApplicationSpecific) ders.getObjectAt(0);
            crossRefIdentifier = das.getContents();



     //here are some experiments, but can't get the right objects I could parse / walk through

            ASN1TaggedObject o2 = ASN1TaggedObject.getInstance(ders.getObjectAt(1));
            DERTaggedObject dto = (DERTaggedObject) o2.getObject();

            ASN1Sequence s2 = ASN1Sequence.getInstance(dto.getObject());
            DERApplicationSpecific das1 = (DERApplicationSpecific) s2.getObjectAt(0);
            ASN1Sequence s3 = (ASN1Sequence) das1.getObject();

            }
    } catch (Exception ex) {
        logger.warn("exception while parsing ASN1 data", ex);
    }

}

как вы можете видеть, я смог декодировать некоторые базовые теги (например, invokeID, operation-value и crossRefIdentifier), но не могу углубиться в дерево (callId, callNumber ...). Если у вас есть опыт в этом вопросе, я был бы признателен за вашу помощь.


person norbi771    schedule 05.03.2016    source источник


Ответы (1)


Это очень сложный объект ASN.1. Есть несколько мест, где может возникнуть ошибка с другим образцом из-за различий в структуре. Вот пример.

using System;
using System.Collections;
using System.IO;
using Org.BouncyCastle.Asn1;

namespace Asn1ParseBouncy
{
    class Program
    {
        static void Main(string[] args)
        {
            var bytes2Parse = File.ReadAllBytes(@"c:\a.req");

            // (0,169) CONTEXT SPECIFIC(1)
            DerTaggedObject rootObj = (DerTaggedObject)Asn1Object.FromByteArray(bytes2Parse);

            if (rootObj.TagNo == 1)
            {
                ParseAtRootLevel(rootObj);
            }
            else
            {
                throw new Exception("Expected Tag number to be 1");
            }
        }

        private static void ParseAtRootLevel(DerTaggedObject rootObj)
        {
            // SEQUENCE under CONTEXT SPECIFIC(1)
            var seq = (Asn1Sequence)rootObj.GetObject();

            IEnumerator e = seq.GetEnumerator();
            bool hasNext;
            hasNext = e.MoveNext();

            // (3,2) INTEGER -> invokeID 
            {
                Asn1Encodable obj;

                if (!hasNext)
                {
                    throw new Exception("more entries expected in sequence");
                }
                obj = (Asn1Encodable)e.Current;

                // TODO: put in a property of class that represents whole ASN.1 message
                var invokeID = DerInteger.GetInstance(obj);

                hasNext = e.MoveNext();

            }

            // (7,1) INTEGER -> operation-value
            {
                Asn1Encodable obj;

                if (!hasNext)
                {
                    throw new Exception("more entries expected in sequence");
                }
                obj = (Asn1Encodable)e.Current;

                // TODO: put in a property of class that represents whole ASN.1 message
                var operationValue = DerInteger.GetInstance(obj);

                hasNext = e.MoveNext();

            }

            // (10,159) SEQUENCE -> argument
            {
                Asn1Encodable obj;

                if (!hasNext)
                {
                    throw new Exception("more entries expected in sequence");
                }
                obj = (Asn1Encodable)e.Current;

                var argumentSeq = Asn1Sequence.GetInstance(obj);

                // argumentData is parsed asn.1 object - argument 
                var argumentData = ParseArgumentData(argumentSeq);

                hasNext = e.MoveNext();
            }

            if (hasNext)
            {
                throw new Exception("no more entries expected in sequence");
            }
        }

        private static object ParseArgumentData(Asn1Sequence argumentSeq)
        {
            IEnumerator e = argumentSeq.GetEnumerator();
            bool hasNext;
            hasNext = e.MoveNext();

            // (13,2) APPLICATION (21) -> crossRefIdentifier  
            {
                Asn1Encodable obj;

                if (!hasNext)
                {
                    throw new Exception("more entries expected in sequence");
                }
                obj = (Asn1Encodable)e.Current;

                var crossRefIdentifierAppSpecific = (DerApplicationSpecific)obj;
                if (crossRefIdentifierAppSpecific.ApplicationTag != 21)
                    throw new Exception("Expected application tag 21");

                // TODO: put in a property of class that represents whole ASN.1 message
                var crossRefIdentifier = crossRefIdentifierAppSpecific.GetContents();

                hasNext = e.MoveNext();

            }

            // (17,152) CONTEXT SPECIFIC (0) -> eventSpecificInfo.callControlEvents.delivered  
            {
                Asn1Encodable obj;

                if (!hasNext)
                {
                    throw new Exception("more entries expected in sequence");
                }
                obj = (Asn1Encodable)e.Current;

                var eventSpecificInfo = ((DerTaggedObject)obj);

                if (eventSpecificInfo.TagNo != 0)
                    throw new Exception("Expected Context specific tag number to be 0");

                // TODO: put in a property of class that represents whole ASN.1 message
                var eventSpecificInfoData = ParseEventSpecificInfo(eventSpecificInfo);

                hasNext = e.MoveNext();

            }

            if (hasNext)
            {
                throw new Exception("no more entries expected in sequence");
            }

            // TODO: return parsed values in some class
            return null;
        }

        private static object ParseEventSpecificInfo(DerTaggedObject obj)
        {
            // still (17,152) CONTEXT SPECIFIC (0)
            var connectionBothData = ParseConnectionBoth(obj);

            return connectionBothData;
        }

        private static object ParseConnectionBoth(DerTaggedObject connectionBoth)
        {
            // (20,149) CONTEXT SPECIFIC (4)->connection.both
            var connectionBothTagged = (DerTaggedObject)connectionBoth.GetObject();

            if (connectionBothTagged.TagNo != 4)
                throw new Exception("Expected Context specific tag number to be 4");

            // Sequence under (20,149) CONTEXT SPECIFIC (4) -> connection.both
            var connectionBothSeq = (DerSequence)connectionBothTagged.GetObject();

            IEnumerator e = connectionBothSeq.GetEnumerator();
            bool hasNext;
            hasNext = e.MoveNext();

            // callID   
            {
                Asn1Encodable obj;

                if (!hasNext)
                {
                    throw new Exception("more entries expected in sequence");
                }
                obj = (Asn1Encodable)e.Current;

                // (23,16) APPLICATION (11)
                // TODO: put in a property of class that represents whole ASN.1 message
                var callIDTagged = (DerApplicationSpecific)obj;
                if (callIDTagged.ApplicationTag != 11)
                    throw new Exception("Expected tag number 11");

                // (25,14) SEQUENCE
                var callIdSeq = callIDTagged.GetObject().GetDerEncoded();

                // TODO: parse CallIdSeq -> (27,4) ContextSpecific(0), (33,6) ContextSpecific(1)

                hasNext = e.MoveNext();

            }

            // TODO: continue with (41,6) Application (3)
            // TODO: continue with (49,14) Application (1)
            // TODO: continue with (65,6) Application (2)
            // etc.

            // TOOD: return something useful
            throw new NotImplementedException();
        }
    }
}

Я поместил примечания в образец кода в соответствии с дампом из редактора ASN.1 < a href = "https://i.stack.imgur.com/B3NYd.jpg" rel = "nofollow noreferrer"> дамп вашего образца

Вы могли бы значительно облегчить себе жизнь, если бы у вас было определение объекта в ASN.1. С помощью двоичных заметок вы можете создавать классы для анализа объекта данных ASN.1.

person pepo    schedule 06.03.2016
comment
Спасибо за рекомендацию. BinaryNotes сгенерировал для меня классы ... Теперь я просто ищу информацию или пример того, как их использовать. - person norbi771; 08.03.2016
comment
Это написано в документации на стр. 12. - person pepo; 08.03.2016
comment
Спасибо, выглядит многообещающе. К сожалению, более сложные методы вызывают исключения (обычно нулевой указатель). Поскольку я пытаюсь связаться с PBX, я поговорил с поставщиком PBX и ищу полный пакет asn.1. Похоже, что то, что я уже нашел, нельзя использовать в моих целях. Мне любопытно, будет ли BinaryNotes обрабатывать эти файлы asn.1. В файлах asn.1 я нашел простой метод MonitorStart, сгенерировавший очень простой вывод: 03 03 00 33 32, который представляет собой лишь небольшую подстроку кода, который я должен был получить. - person norbi771; 09.03.2016
comment
Боюсь, я больше не смогу вам помочь с этой проблемой. Мне нужен доступ ко всему, что у вас есть (тестовая среда, АТС ...). Что касается BinaryNotes, мы изменили его, чтобы генерировать классы с использованием надувного замка (это похоже на пример, который я написал), поэтому, возможно, было бы лучше отладить и найти проблемы. BinaryNotes анализирует нотацию ASN.1 на структуры xml, а затем использует преобразования xslt для создания классов кода. По умолчанию он генерирует свои собственные классы с аннотациями, но, возможно, стоит изучить и изменить, чтобы сгенерировать прочные классы. - person pepo; 09.03.2016
comment
Я понимаю и благодарю за ваши усилия. Возможно, когда я получу asn1 от поставщика, вы можете попытаться сгенерировать для меня анализируемые классы bouncycastle только для одного метода, которым является EventReport. Менее сложные конструкции, необходимые для моего проекта, я уже сделал сам, и, честно говоря, почти завершил и этот. В какой-то момент у меня возникла проблема с чтением двоичных октетов из DERTaggedObject, но после некоторых проб и ошибок и другого преобразования объектов я наконец прочитал то, что хотел. Мой класс не очень похож на ООП, но должен быть достаточно хорош, чтобы просто читать события, полученные от АТС. - person norbi771; 09.03.2016
comment
Конечно, без проблем. Просто отредактируйте свой вопрос и поместите туда определение ASN.1. - person pepo; 09.03.2016
comment
@ norbi771 Если это УАТС, возможно, стандарты, которым она соответствует, взяты из ITU. Если это так, то схема будет похоронена где-то глубоко внутри набора стандартов МСЭ. В конце концов, мир телефонии и ITU в первую очередь создали ASN.1. Возможно, если бы поставщик мог сказать вам, каким стандартам он соответствует, вы могли бы получить схему самостоятельно в ITU. - person bazza; 19.03.2016