ASN.1

ⓟrogramming/Programming 2010. 11. 4. 22:35
336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

ASN.1은 CMIP, SNMP, X.400, X.500, EDI등 많은 Application에서 광범위 하게 사용되나 이에 대한 국내 웹 사이트의 정보가 전무하여 작은 경험이나마 공유하여 도움이 되고자 한다.

System간의 차이

Sun과 Windows간의 Data를 주고 받는 Application을 작성해본 사람들은 알겠지만 동일한 Data를 주고 받으면 Computer System에 따라 분석하는 것이 다르기 때문에 엉뚱한 값을 받게 된다.  예를 들어, 100이라는 값을 Sun에서 Windows 시스템으로 동일한 32 bit integer를 사용하여 보내면 Windows에서는 매우 큰 수로 인식하게 된다. (1,677,721,600) 이를 전문 용어로 Endian이라 하는데, Sun에서는 Motorola계열의 Big Endian을 사용하여 100을 [00 00 00 64]와 같이 인식한다.  이와는 반대로 Intel 진영인 Little Endian의 Windows에서는100을 [64 00 00 00]와 같이 인식한다.  따라서 어느 한쪽에서 Byte단위로 Swapping을 해주어야 한다.


이는 물론 Integer가 32 bit인 경우에 해당 되는 것이고 64-bit machine이나 8-bit, 16-bit인 경우에는 또 이야기가 달라진다.  Byte Alignment에 의해서 Structure의 구조를 주고 받을 때는 영향을 받으며 Compiler에 따라서 약간의 차이점 또한 생기게 된다.  이는 동일한 Language를 사용하는 경우며, 만약 C++와 Ada Application이 통신한다고 가정하면 그 문제는 더 더욱 복잡해 진다.

 

1 Conversion

System의 수가 늘어감에 따라 위와 같은 1대1의 Conversion 노력은 벽에 부닫치게 되었다.  왼쪽 그림에서 보는 것 과 같이 시스템간의 네트워크가 발전하면서 연동이 필요한 급증함을 알 수 있다.  6개의 장비가 있는 경우에 15가지의 Conversion이 개발 되어야 하며 각 시스템은 5개의 Conversion에 대한 노력을 기울여야 한다.  N 시스템이 있는 경우 각 Vendor는 N-1의 Conversion이 필요하게 된다.  이러 한계를 극복하기 위한 것이 ASN.1의 등장이다.  각 시스템에서는 ASN.1이라는 하나의 표준에 대한 Conversion만을 개발하면 모든 장비와 Data를 주고 받을 수 있게 된다.  멋지지 않는가.  이렇게 해서 만들어 진 것이 1988년 ITU ASN.1 규격이다. 



이렇게 해서 제정된 규격은 1990년, 1994년 그리고 1997에 Upgrade되어져 있으며 오늘날에 이르고 있다.  해당 규격은 아래와 같다.


버전

규격

제목

1988

X.208

Specification of Abstract Syntax Notation


X.209

Specification of Basic Encoding Rules for Abstract Notation One (ASN.1)



 

1990

ISO 8824

 


ISO 8825

 



 

1994

X.680

Specification of Basic Notation


X.681

Information Object Specification


X.682

Constraint Specification


X.683

Parameterization of ASN.1 Specification


X.690

ASN.1 Encoding Rules: Specification of Basic Encoding Rules, Canonical Encoding Rules, and Distinguished Encoding Rules


X.691

ASN.1 Encoding Rules: Specification of Packed Encoding Rules




1997

위와 동일

(1997년 버전)




TMN에서 사용되는 CMIP의 대부분의 규격은 ASN.1 1988년을 사용하고 있다.  1988년 버전은 초기 작품이라 Value 부분에 대한 부분은 parser를 개발 하기 거의 불가능하도록 되어 있는 등 많은 문제점을 안고 있다.  ASN.1 1997에서는 value Assignment에 대한 문제점을 포함한 많은 문제들이 해결되어 1988년에 비해 많이 사용 가능한 규격으로 생각된다.  1997년 버전에서는 Open Type의 개념이 소개 되는 대신 ANY type을 삭제하였다.  하지만, 이전의 규격이 ANY type을 많이 사용하기 때문에 1997년 버전에 ANY를 추가하여 사용하는 방법을 (비록 규격에는 위배되지만) Tool개발 업체에서 채택하는 것을 볼 수 있다.

자세한 내용은 Olivier Dubuisson의 책이나 ITU의 웹 사이트를 참조하길 바란다.

http://www.oss.com/asn1/dubuisson.html

http://www.itu.int/ITU-T/studygroups/com07/changing-ASN.html.



Abstract Syntax와 Transfer Syntax의 개념을 C와 비교하면 이해하기 매우 쉽다.  Abstract Syntax는 C에서 Type에 해당되는 것이다.  Transfer Syntax는 C에는 개념이 없으며 그 이유는 간단하다.  예를 들어 int i 라고 선언된 변수의 값을 저장하는 것은 C Compiler를 만드는 개발자에 자유게 맡긴다.  단지 i에 대한 연산을 하거나 화면에 보여주는 경우에 올바르게 보여주면 되는 것이다.  하지만 ASN.1의 경우에는 각 System간의 통신을 해야 하기 때문에 int i 의 값이 어떤 식으로 encoding이 되는지에 대한 규격이 필요하다.  이를 transfer syntax라고 하여 integer의 값은 어떻게 주고 받고, real값은 어떻게 주고 받는 등의 규약이 정해져 있다.  처음으로 돌아가서 C에서 굳이 Transfer Syntax의 개념과 유사한 것을 찾는다면 int i의 값이 저장되어 있는 형태라고 말할 수 있겠다.

Abstract Syntax는 사람을 위한 규격으로서 ITU문서에 적혀있는 것은 모두 Abstract Syntax를 사용한다.  (X.208, X.680~X.683).  이 ASN.1 규격을 사용하여 실제 값을 주고 받을 때 Transfer Syntax를 사용하게 되며 이에는 BER, PER, LWER 등이 있다. (X.208, X.690~1)

좀 더 실제적인 예제는 아래의 TLV Encoding 부분을 참조한다.


ASN.1을 공부하면서 헷갈리는 것이 있는데 그 중의 하나가 SEQUENCE와 SET이다.  SEQUENCE는 C의 struct와 동일한 개념이다.  SET의 개념은 C에는 없고, 굳이 찾는 다면 C의 struct에서 순서가 무의미한 type으로 보면 된다.


Seq ::= SEQUENCE {

  first INTEGER,

  second INTEGER

}


Set ::= SET {

first INTEGER,

  second INTEGER

}


seqVa1 Seq ::= { 10, 20 }

seqVal2 Seq ::= { 20, 10 }


setVal1 Set ::= { 10, 20 }

setVal2 Set ::= { 20, 10 }


seqVal1과 seqVal2의 경우에는 서로 다른 값이지만 setVal1과 setVal2는 동일한 값이다.



이 둘은 이름만 비슷하지 전혀 다는 개념이다.  SEQUENCE는 C의 struct이고 SEQUENCE OF는 C의 Array선언 [ ] 에 해당된다.


Name ::= SEQUENCE OF INTEGER는 int Name[ ] 과 동일한 의미이다.


SET과 SET OF도 유사하다.



SEQUENCE와 SET과 차이처럼 Array내 값의 순서가 의미를 가지느냐 여부의 차이이다.


SeqOf ::= SEQUENCE OF INTEGER

SetOf ::= SET OF INTEGER


seqOfVal1 SeqOf ::= { 10, 20, 30 }

seqOfVal2 SeqOf ::= { 20, 30, 10 }


setOfVal1 SeqOf ::= { 10, 20, 30 }

setOfVal2 SeqOf ::= { 20, 30, 10 }


seqOfVal1와 seqOfVal2는 다른 값이지만 setOfVal1와 setOfVal2는 동일한 값이다.



CHOICE는 C의 union과 동일한 개념이다.  CHOICE에 값을 선언할 때 선언되어 있는 Element중 하나를 사용하면 된다.


Choice ::= CHOICE {

  int INTEGER,

  string PrintableString

}


chocieVal1 Choice ::= int : 10

choiceVal2 Choice ::= string : “asn.1 is fun”


위의 예제는 1997년 ASN.1 표준을 따른 것이며 : 앞의 int와 string은 Choice의 Alternative의 identifier를 가리킨다.


 

송수신의 사용되는 Transfer Syntax은 TLV 형식을 취한다.  T는 Type이고, L은 Length 그리고 V는 Value이다.  Integer Type의 예를 들어보면 간단하다.


i ::= INTEGER 10


T

L

V

INTEGER

V 길이

10


실제 전송되는 값은 T L V에 해당된다.

T는 INTEGER에 해당하는 값으로 채워지게 된다.  Type에는 4가지의 Type이 있는데

자세한 내용은 나중에 생각하기로 하고 INTEGER에 대한 값이 들어간다고 만 생각하자.

Value는 Integer 10을 나타내는 값이 들어가고 L인 Length는 INTEGER i의 길이에 대한 정보를 담고 있게 된다.  주의해야 할 것은 i라는 정보는 전송되지 않는다는 점이다.  변수 이름인 i는 사람을 위한 것이다.

+Boolean이나 Enumerated와 같이 Simple한 Type의 경우에는 T L V 중 T의 값이 변하게 되지만, Sequence, Set, Choice와 같은 경우에는 다른 Simple Type을 포함하는 형태로 전송되어 진다.


Seq ::= SEQUENCE {

  first INTEGER,

  second INTEGER

}


seqVa1 Seq ::= { 10, 20 }


Seq의 경우에 T L V의 V부분에 SEQUENCE의 element에 해당되는 INTEGER인 first와 second의 내용이 TLV 형태로 들어가게 된다.

이를 그림으로 나타내면 아래와 같다.


T

L

V


SEQUENCE

V 길이*

T

L

V



INTEGER

V 길이

10



INTEGER

V 길이

20


SEQUENCE의 L 부분은 element인 first와 second의 길이 모두를 나타낸다.

TLV Encoding에서 제일 특이한 Type이 Choice인데 Choice에 해당하는 Type은 없다.  Choice는 alternative중에서 하나를 사용하기 때문에, 실제로 전송되는 값에는 선택된 alternative의 Type만으로 T L V의 형태를 띄게 된다.  Sequence의 Embedded Format과는 사뭇 다르게 된다.


재미 있는 경우를 보면, NULL Type이나 SEQUENCE OF, SET OF 그리고 Optional을 사용하는 경우, Length가 0인 경우도 발생한다는 사실이다.  결과적으로 T L(0) 만 나타나게 된다.



TAG은 Data를 상호간에 전송 시 Encoded data를 수신할 때 나타나는 문제점을 해결하기 위함이다.  간단한 예를 들어보면 쉽게 이해할 수 있다.  아래와 같은 SEQUENCE의 경우를 보자.


Seq ::= SEQUENCE {

  one INTEGER OPTIONAL,

  two INTEGER OPTIONAL

}


seqVal ::= Seq { one 10 }


위의 값이 Encoding 되면 T(SEQ) L T(INTEGER) L V(10)으로 보내어진다.  허나 이를 수신하는 측에서는 T(INTEGER)가 one인지 two인지 알 수 있는 방법이 없게 된다.  이를 위해서 소개된 개념이 Tag이다.  이와 같이 수신측에서 decoding 할 수 없는 규격의 경우에는 아래와 같이 Tag 정보를 추가해 사용한다.


Seq ::= SEQUENCE {

  one [1] INTEGER OPTIONAL,

  two [2] INTEGER OPTIONAL

}


seqVal ::= Seq { one 10 }


위의 경우에는 T(SEQ) L T([1]) L V(10)처럼 3번째의 Tag정보가 INTEGER 대신 [1]의 정보가 보내어진다.  수신측에서는 [1]이 one을 의미하는 것을 알기 때문에 V(10)이 integer type이라는 것을 알 수 있으며, 결과적으로 decoding에 전혀 문제가 없게 된다.


이와 유사하게 Set과 Choice의 경우에도 Tag이 사용된다.


Seq ::= SEQUENCE {

  one [1] INTEGER OPTIONAL,

  two [2] INTEGER OPTIONAL

}


seqVal ::= Seq { one 10 }


Tag 설명 부분에서 위의 seqVal이 T(SEQ) L T([1]) L V(10)으로 encoding되어 진다고 하였는데 이는 IMPLICIT TAG인 경우에 해당한다.  Implicit이 의미하는 것은 [1]의 Tag정보만으로 실제의 type을 알 수 있기 때문에 굳이 실제의 Type을 사용하지 않는다는 것으로 의미한다.

이와는 달리 Tag의 정보를 사용하고 실제 Type의 정보 또한 보내도록 하는 Option을 사용할 수 있다.  이를 EXPLICIT TAG이라고 하고 이 경우에는 encoding이 아래와 같이 되어진다.


T(SEQ) L T([1]) L T(INTEGER) V(10)


예상한대로 IMPLICIT TAG와 EXPLICIT TAG을 사용하는 규격간에는 동일한 값이라도 encoding이 다르게 된다는 것을 인식해야 한다.


AUTOMATIC TAG은 1997년에 소개된 개념으로써 위와 같은 경우에 일일이 수작업으로 규격에 TAG을 붙이는 것이 귀찮기 때문에 자동적으로 Tag을 붙이는 기능이다.  ITU에서는 이 기능의 사용을 적극적으로 권하고 있지만 TMN 규격들이 이전에 선언되었기 때문에 사용되는 일은 거의 없다.



동일한 ASN.1 규격의 사용

ASN.1 규격은 두개 이상의 Node가 정보를 주고 받기 위하여 만들어 진 것이다.  ASN.1 규격이란 이 정보가 어떤 형태를 가지는 것을 적어 놓은 것이다.  따라서 ASN.1 규격은 통신을 하는 모든 Node가 동일한 혹은 Compatible한 ASN.1 규격을 가지고 있어야 한다.



ASN.1 규격을 직접 만들거나, 정해진 ASN.1 규격을 구현을 위해 사용하는 경우에, 사용하는 Tool의 제한 사항 등으로 인해 나름대로의 수정이 필요하게 된다.  이때 고민하게 되는 것이 수정된 ASN.1 규격이 과연 기존의 ASN.1 규격과 통신 시 문제를 발생시키지 않을까 하는 걱정이 생기게 된다.


이름은 사람을 위한 것

ASN.1 규격상 모든 이름은 사람을 위한 것이다.  예를 들어, i ::= INTEGER 10에서 i란 이름은 사람을 위한 것이기 때문에 해당규격에서 모든 i를 newname으로 바꾸어도 상관없다.


Defined Type과 직접 사용

아래의 예제와 같이 INTEGER를 직접 사용하던지, Integer란 Type을 define하여 사용하던지 이는 동일하다.  Element가 Sequence나 Set의 경우에도 동일하게 적용된다.


Seq ::= SEQUENCE {

  one INTEGER,

  two INTEGER

}


Integer ::= INTEGER

Seq ::= SEQUENCE {

  one Integer,

  two INTEGER

}



사용하지 않는 규격의 가지치기

Workstation이나 Windows의 환경에서는 메모리에 대한 제한이 거의 없지만 Embedded 환경에서 ASN.1관련 작업을 하는 경우에는 메모리에 대한 부담을 가지게 된다.  이런 경우에는 ASN.1 규격상에서 절대로 사용하지 않는 부분을 제게 하는 것을 고려해 봄 직하다.  하지만, ASN.1 규격이라는 것이 모두 연결되어 있기 때문에 제거하는 것이 쉽지는 않다.


Select ::= CHOICE {

  this SomeSequence,

  that SomeSequence,

  never SequenceNeverUsed

}


never가 구현하는 application에서 사용하지 않는다는 것을 확신할 수 있으면 SequenceNeverUsed의 type선언과 여기서 파생되는 사용하지 않는 선언을 모두 삭제할 수 있다.  사용하지 않더라고 그대로 사용하면 parsing에 필요한 code들이 생성되기 때문에 그 만큼의 ROM을 필요로 하기 때문이다.

만약, 실제 상황에서 제거된 element가 수신되는 경우에는 어떤 일이 발생할까 ?  간단하다.  수신 측에서 분석이 불가능하다는 Parsing error가 발생하게 된다.



동일한 Defined Type의 통합

아래와 같이 동일한 definition이나 다른 이름을 사용하는 경우가 간혹 있다.  이는 가지치기를 한 후에 더 많이 생겨날 수 있는 가능성이 있는데 이 경우에 하나의 type으로 통일하여주면 formating과 parsing에 필요한 code들을 줄일 수 있다.


Select ::= CHOICE {

  this ThisSequence,

  that ThatSequence

}


ThisSequence ::= SEQUENCE {

  one INTEGER,

  two INTEGER

}


ThatSequence ::= SEQUENCE {

  one INTEGER,

  two INTEGER

}


위의 Choice는 아래와 같이 바꿀 수 있다.


Select ::= CHOICE {

  this ThisSequence,

  that ThisSequence

}



통신을 하기 위해서는 주어진 규격에 맞추어 값을 채우고 이를 ASN.1 Transfer Syntax에 맞는 형태의 byte stream을 만들어 주어야 한다.  그래야 PDU 형태로 송신을 할 수 있기 때문이다.  ASN.1 Compiler는 사용자의 ASN.1 규격을 읽어드려, 이에 대한 Validity를 확인하고, header file과 두 가지 종류의 c file을 만들어 낸다 - Formatter & Parser.  Header file은 사용자가 해당 type을 선언하여 사용할 때 사용하고 Formatter는 사용자의 값을 bit stream으로 바꾸어 주는 역할을 한다.  Parser는 이와 반대로 bit stream을 header file의 structure값으로 변환 시켜주는 기능을 수행한다.

이해를 위해 예를 들어 본다.  이는 특정 ASN.1 Compiler에 해당되는 내용이 아니며, ASN.1 Compiler마다 처리 방법은 각각 다르게 나타난다.


Seq ::= SEQUENCE {

  first INTEGER,

  second INTEGER

}


seqVa1 Seq ::= { 10, 20 }


[ Header File ]

"asn1header.h"


struct Seq {

  int first;

  int second;

}


사용자는 위의 header을 읽어드려서 송신을 위한 아래의 ASN.1 값을 만들게 된다.

[ 사용자 Code ]

#include "asn1header.h"


struct Seq asn1value = { 10, 20 };


이를 송신하기 위해서 ASN.1 Value를 bit stream으로 바꾸게 된다.

생성된 c code를 살펴보면 ASN.1의 각 type마다 formatter/parser가 생성됨을 알 수 있다.

사용되는 interface는 아래와 같다.


/* returns length */

int format_Seq(struct Seq *value; char *bitStream);

사용자는 준비된 asn1value를 formatter에 넣어주면 bitStream에 ASN.1 encoded가 생성되고 그 길이가 return되어진다.  Encoding되어진 값은 LAN과 같은 통신 채널을 통해 상대편 Node에 전해진다.


ASN.1 Encoded 값을 수신 받으면 아래의 parser를 이용하여 program에서 사용 가능한 structure의 형태로 바꾸게 된다.


Parser_Seq(char *bitStream, int len, struct Seq *value);


실제의 ASN.1 header, formatter, parser는 당연히 이보다 훨씬 더 복잡하게 되어 있다.  위의 예제는 ASN.1 Compiler에서 사용되는 개념만을 전달하기 위한 것으로, 이해를 위해서 최대한 단순화 시킨 것이다.


Object Identifier는 이름 그대로 OSI에서 사용되고 있는 Object를 나타내기 위한 ID이다.

Object Identifier는 { 2 9 3 5 2 0 }과 같이 생겼으며 아래와 같이 이름이나 이름과 숫자를 혼용하

여 사용되어 진다.  { joint-itu-ccitt ms(9) smi(3) asn1Module(2) attributes(0) }

ASN.1에는 OBJECT IDENTIFIER type이 지원된다.



Object Identifier는 Tree구조로 되어 있다.  가끔씩 ASN.1 규격을 보다 보면 번호

만 있는 경우가 있다.  이 번호가 어떤 object를 알고 싶은 경우가 있다.  하지만

이것이 만만한 일이 아니다.  규격을 다 검색할 수 도 없고… 이러한 경우, 찾고

자 하는 Object ID를 아래의 Site에 찾아 볼 수 있다.  Object Identifier Tree의 형

태가 궁금한 경우에도 Top에서 재미 삼아 보는 것도 도움이 될 듯 싶다.


http://asn1.elibel.tm.fr/en/oid/index.htm

http://www.alvestrand.no/objectid/top.html



ANY Type, EXTERNAL Type, SubType, Macro, 그리고 Object, Parameter 개념

등을 포함하여 많은 내용이 설명되어 있지 않다.  ASN.1에 대한 이해에 도움이

되자는 취지이기에 당연한 것일지도 모르겠다.  위의 개념을 포함한 모든 ASN.1

개념을 이해하는 것은 상당한 노력이 필요하다.  관심이 있는 분들은 아래의

Reference를 참조하기 바란다.



ASN.1 - Communication between heterogeneous systems

http://www.oss.com/asn1/dubuisson.html

현 ITU ASN.1 Project 리더로서 활동하고 있는 French Telecom의 Olivier

Dubuisson의 저서로써 무료로 배포하는 책이지만 지금까지 접한 책 중에 ASN.1에 관해 가장 상세하게 설명되어 있는 책이다.  많은 예제가 포함되어 ASN.1의 실제 사용에 대한 감각을 쉽게 얻을 수 있을 것으로 예상된다.  강력히 추천한다.


ASN.1 Complete

http://www.oss.com/asn1/larmouth.html

ASN.1에 dedicate되어 있는 또 하나의 책으로써 마찬가지로 무료로 배포되어 진다.



http://asn1.elibel.tm.fr/

http://www-sop.inria.fr/rodeo/personnel/hoschka/asn1.html

http://www.oss.com/asn1/




ASN.1 규격을 가지고 작업하다 보면 IMPORT된 type reference나 value reference를 찾는데 애를 먹게 되는 경우가 있다.  만약 ITU 규격에 선언되어 있는 것이라면 ITU ASN.1 Module Database를 사용하면 쉽게 찾을 수 있다.

또한 ASN.1 Definition이 필요한 경우 ITU규격에서 긁어와 사용해야 하는데 불편하다. 가끔씩 오류도 있고.  요즘에는 일반적으로 많이 사용되는 ASN.1 definition의 경우에는 Tool Vendor에서 제공되나, 부족한 경우에는 이곳에서 필요한 ASN.1 Definition을 가져 다 사용하면 수정 없이 그대로 사용 가능하다.


http://www.itu.int/ITU-T/asn1/database/index.html

http://www.itu.int/ITU-T/asn1/   Search 사용



<자료 출처: http://www.nexto.co.kr/tmn/asn1.htm>

'ⓟrogramming > Programming' 카테고리의 다른 글

Processes VS Threads  (0) 2018.01.23
DLL 인젝션 기법(기초)  (0) 2010.07.26
블로그 이미지

뚱땡이 우주인

,