學習資料:ASN.1編碼規(guī)則詳解
一.簡介
ASN.1(Abstract Syntax Notation dotone),抽象語法標記1。是定義抽象數據類型形式的標準,是用于描述數據表示、表示、傳輸、編碼的記法。
ASN.1只包含信息結構,不處理具體業(yè)務數據,它不是一個編程語言。
ASN.1沒有限定編碼方法,各種ASN.1編碼規(guī)則提供了由ASN.1描述其抽象句法的數據的值的傳送語法(具體表達),常見的編碼規(guī)則有:基本編碼規(guī)則(BER),規(guī)范編碼規(guī)則(CER,CanonicalEncoding Rules)、唯一編碼規(guī)則(DER,DistinguishedEncoding Rules)、壓縮編碼規(guī)則(PER,PackedEncoding Rules)和XML編碼規(guī)則(XER,XMLEncoding Rules)。這些編碼規(guī)則描述了如何將定義在ASN.1中的值譯成適合傳輸的電碼。
ASN.1在OSI的ISO8824/ITU X.208(說明語法)和ISO8825/ITU X.209(說明基本編碼規(guī)則)規(guī)范。
幾個概念:
(1)實際語法
指諸如C、ObjectiveCaml等這樣實際編程語言;
(2)抽象語法(AbstractSyntax)
指ASN.1,是協(xié)議采用ASN.1規(guī)范描述的描述文本。描繪了與任何表示數據的編碼技術無關的通用數據結構。抽象語法使得人們能夠定義數據類型,并指明這些類型的值。抽象語法只描述數據的結構形式,與具體的編碼格式無關,同時也不涉及這些數據結構在計算機內如何存放。
(3)傳輸語法(TransferSyntax)
指表示層交換數據的表示方法,是實際通訊系統(tǒng)間的碼流。當數據在兩個表示層實體之間傳輸時,這些數據的實際比特模式表示方法就是傳送語法。
(4)編碼
指將抽象語言法轉換成實際通訊系統(tǒng)間比特流;
(5)編碼規(guī)則
將抽象語言法轉換成實際通訊系統(tǒng)間比特流所遵循的語法規(guī)則;
二.相關背景知識
1.為了順利完成應用音的通訊,需使用以下概念:
(1)抽象語法:定義了數據的常用結構(包括不同的數據類型),并且建立了和應用層對話所用的構架。
(2)實際語法:本地的,并且定義本地系統(tǒng)的數據表示方法。
(3)傳輸語法:定義兩個系統(tǒng)間的表示層間交換數據的表示方法。
(4)編碼規(guī)則:提供從本地實際語法到傳輸語法和其相反操作的方法。(從抽象語法到傳輸語法,由ASN.1編譯器按照編解碼規(guī)則實現)
2.應用層Application Layer
應用層向表示層發(fā)送數據時,同時告知表示層自己的ASN.1名字(即對象標識符),ASN.1名字標記了一個ASN.1語法——用以解釋數據中各字段的含義。通過參考ASN.1定義,表示可以得知數據單元的類型和長度,以及傳輸時應當采用的編碼方法。
3.表示層Presentation Layer
兩個系統(tǒng)在傳輸數據前需要協(xié)商共用的編碼方式,事實上編碼方式在應用層發(fā)出的數據中已經確定,應用數據中包含抽象語法/傳輸語法的組合關系,告訴表示層數據的結構、含義以及傳輸語法規(guī)則。表示層參考抽象語法,將應用數據轉換為傳輸語法定義的比特流。
4.邊界對齊
同樣一條消息,在計算機內存中是以Byte為單位存儲的,在鏈路上則是以bit為單位傳送的。
如果一個信元的第一個bit也恰好是Byte流中某Byte的開始bit時,我們稱之為開始于邊界對齊的;
如果信元的最后一個bit也恰好是Byte流中某Byte的最后一個bit時,則可以稱之為結束于邊界對齊的。
對于不是結束于邊界對齊的情況,一般要進行補位。有兩種方式:
(1)對每個信元的結束立即進行補位,保證下一個信元是開始于邊界對齊的;
(2)從信元結束的位置開始新的信元,到消息結束時再進行一次補位操作。(用于無線空口中)
5.大小端(BigEndian vs Little Endian)
(1).大端方式,也叫網絡序,從左往右,第一個8位表示高位,例如0X0102,用比特流表示是0000000100000010。
(2).小端方式,也叫主機序,與大端方式相反,數字0X0102用比特流表示則是0000001000000001,低8位在前,高8位在后。
Motorola的PPC系列、IP協(xié)議中使用大端方式;VAX計算機、Intel的x86系列中使用小端方式。
三.ASN.1的基本語法規(guī)則
1.ASN.1使用巴科斯范式(BNF):
在雙引號中的字("word")代表著這些字符本身。而double_quote用來代表雙引號。
在雙引號外的字(有可能有下劃線)代表著語法部分。
尖括號(< > )內包含的為必選項。
方括號([ ] )內包含的為可選項。
大括號({ } )內包含的為可重復0至無數次的項。
豎線(| )表示在其左右兩邊任選一項,相當于"OR"的意思。
::=是“被定義為”的意思。
這是用BNF來定義的Java語言中的For語句的實例:
FOR_STATEMENT::=
"for""(" ( variable_declaration |
(expression ";" ) | ";" )
[expression ] ";"
[expression ]
")"statement
2.在ASN.1中,符號的定義沒有先后次序:只要能夠找到該符號的定義即可。
3.所有的標識符、參考、關鍵字都要以一個字母開頭,后接字母(大、小寫都可以)、數字或者連字符“-”(但不能以連字符“-”結尾,也不能連續(xù)出現兩個連字符),不能出現下劃線“_”。
4.關鍵字一般都是全部大寫。
5.在標識符中,只有類型和模塊名字是以大寫字母開頭的,其它標識符都是以小寫字母開頭。
6.ASN.1中實數實際定義為三個整數:尾數、基數和指數。沒有小數表示方式。
7.ASN.1不對空格、制表符、換行符和注釋做翻譯。但是在定義符號(或者分配符號Assignment)“::=”中不能有分隔符。
四.ASN.1中的類型
類型是一個非空的值的集合,可以被編碼后傳輸。相比與高級語言中復雜的數據結構,ASN.1中的類型主要是為了數據的傳輸。
1.ASN.1中的類型分為基本類型(內建數據類型)和組合類型,組合類型由一個或多個基本類型構成。
內建數據類型
類型
含義
NULL
只包含一個值NULL,用于傳送一個報告或者作為CHOICE類型中某些值
INTEGER
全部整數(包括正數和負數)
REAL
實數,表示浮點數
ENUMERATED
標識符的枚舉(實例狀態(tài)機的狀態(tài))
BITSTRING
比特串
OCTETSTRING
字節(jié)串
OBJECT IDENTIFIER,
RELATIVE-OID
一個實體的標識符,它在一個全世界范圍樹狀結構中注冊
EXTERNAL,EMBEDDED PDV
表示層上下文交換類型
…String(除了BITSTRING、OCTETSTRING外)
各種字符串,有NumericString、PrintableString、VisibleStirng、ISO64String、IA5String、TeletexStirng、T61String、VideotexString、GraphicString、GeneralString、UniversalString、BMPString和UTF8String
CHARACTERSTRING
允許為字符串協(xié)商一個明確的字符表
UTCTime,GeneralizedTime
日期
組合類型
類型
含義
CHOICE
在類型中選擇(相當于C中的聯合)
SEQUENCE
由不同類型的值組成一個有序的結構(相當于C中的結構體)
SET
由不同類型的值組成一個無序的結構
SEQUENCEOF
由相同類型的值組成一個有序的結構(相當于C中的數組)
SETOF
由相同類型的值組成一個無序的結構
2.類型定義
<新類型的名字>::= <類型描述>
例:
Married ::= BOOLEAN
Age ::= INTEGER
Picture ::= BIT STRING
Form ::= SEQUENCE
{
name PrintableString,
age Age,
married Married,
marriage-certificate PictureOPTIONAL
}
Married類型是一個基本類型BOOLEAN,Form類型是一組基本類型的有序序列
注意:在SEQUENCE和SET等(好像應該是所有組合類型的)定義中,最后一個成員結尾沒有逗號“,”。
為了接收方能正確解碼,發(fā)送方為每個值的類型附加一個數,稱為tag,在描述中以“[]”標識。缺省情況下,編碼器會使用universal的tag。在給合類型中,為了明確各個成員,有必要指明每個成員的Tag:
Coordinates ::= SET
{
x [1] INTEGER, //這證明好像也可以用類來直接聲明變量
y [2]INTEGER,
z [3]INTEGER OPTIONAL
}
Tag會在傳輸規(guī)則使用到,用于在比特流中指明數據的具體類型。
為了準確描述一個類型,我們需要對值的集合進行一定的限制。這用到子類型約束,在類型之后用圓括號進行標識。
如:
Lottery-number::= INTERGER(1..49)表示取1-49任一一個值
Lottery-draw ::=SEQUENCESIZE(6) OF Lottery-number指定了該SEQUENCE類型由6個Lottery-number類型有序組成。
Upper-case-words::= IA5String (FROM(“A”..”Z”))表示按ASCII取A-Z中任一一個,IA5String是ASCII字符串類型
為了方便在新的版本中往現有類型中添加新成員,可用“…”來標記可能以后是其它類型的地方:
Type ::= SEQUENCE
{
component1 INTERGER,
component2 BOOLEAN,
…
}
以后新的版本中,描述可能為:
Type ::= SEQUENCE
{
component1 INTERGER,
component2 BOOLEAN,
…,
[[component3REAL]], -- version 2
…
}
注意:新加入的類型成員要嵌套在“[[]]”中,--version 2指定新版本號
3.值定義
<新的值的名字><該值的類型> ::=<值描述>
其中:
<新的值的名字>是以小寫字母開頭的標識符;
<該值的類型>可以是一個類型的名字,也可以是類型描述;
<值描述>是基于整數、字符串、標識符的組合。
如:
counter Lottery-number ::= 45
sextuple Lottery-draw ::= { 7, 12, 23, 31, 33, 41 }
4.信息對象類和信息對象
<信息對象類>::= CLASS <類描述>
WITHSYNTAX <信息描述>
用于表達比注釋更為正式的一些信息
5.模塊定義
<模塊名字> DEFINITIONS <缺省Tag>::=
BEGIN
EXPORTS <導出描述>
IMPORTS <導入描述>
<模塊體描述>
END
一般協(xié)議由一個或者多個模塊組成,模塊用來收集數據結構定義。
模塊名字必須以大寫字母開頭。模塊能以一種“全局指針”(UniversalPointer)的方式來引用,稱為對象標識符(ObjectIdentifier),用花括號標識在名字之后。
如:
Module2 { isomember-body(2) f(250) type-org(1) ft(16)
asn1-book(9)chapter5(0) module2(1) }
DEFINITIONS AUTOMATICTAGS ::=
BEGIN
EXPORTS Type2;
IMPORTS Type1, valueFROM Module1 {iso member-body(2)
f(250) type-org(1)ft(16) asn1-book(9) chapter5(0) module1(0)};
Type2 ::= SEQUENCE OFChoice
Choice ::= CHOICE
{
a INTEGER (0..value),
b Type1
}
END
(1).AUTOMATICTAGS是指缺省Tag,說明不關注模塊的Tag。
(2).IMPORTS聲明在其它模塊定義但在本模塊會用到的類型或者值。
EXPORT聲明在本模塊之外可以訪問的類型或者值。
IMPORTS的語法為:
IMPORTS <名字>,value FROM <其它模塊的ObjectIdentifier >;
EXPORTS的語法為:
EXPORTS<名字>;
(3).對象標識符(OBJECTIDENTIFIER,OID)類型用層次的形式來表示標準規(guī)范。標識符樹通過一個點分的十進制符號來定義,這個符號以組織,子部分然后是標準的類型和各自的子標識符開始.
例如:MD5的OID是1.2.840.113549.2.5表示為"iso(1)member-body (2) US (840) rsadsi(113549) digestAlgorithm (2) md5 (5)",所以當解碼程序看到這個OID時,就知道是MD5散列。
OID在公鑰算法標準中很流行,它指出證書綁定了哪種散列算法。
OID在傳輸時編碼規(guī)則:
前兩部分如果定義為x.y,那么它們將合成一個字40*x+ y,其余部分單獨作為一個字節(jié)進行編碼。
每個字首先被分割為最少數量的沒有頭零數字的7位數字.這些數字以big-endian格式進行組織,并且一個接一個地組合成字節(jié).除了編碼的最后一個字節(jié)外,其他所有字節(jié)的最高位(位8)都為1。
MD5OID的編碼:
<1>.將1.2.840.113549.2.5轉換成字數組{42,840, 113549, 2, 5}。
<2>.然后將每個字分割為帶有最高位的7位數字,{{0x},{0x86,0x48},{0x86,0xF7,0x0D},{0x02},{0x05}}。
<3>.最后完整的編碼為0x0608 86 48 7 0D 02 05。
6.模塊和分配(Assignment)
(1).定義一個新類型
TypeReference ::=CHOICE
{
integer INTEGER,
boolean BOOLEAN
}
(2).給類型賦值
在ASN.1中給類型賦的值不會被編碼(ASN.1語法只是一種語法規(guī)則用來描述業(yè)務數據,而不會被當成業(yè)務數據),這種值常用作DEFAULT,上下界或者信息對象中。
value-referenceTypeReference ::= integer:12
如果兩個類型在語法上是完全一樣的,則這兩種類型的值可以相互賦值。如:
Pair::= SEQUENCE
{
x INTEGER,
y INTEGER
}
Couple::= SEQUENCE
{
x INTEGER,
y INTEGER
}
pairPair ::= {x 5, y 13}
coupleCouple ::= pair
(3).值集合
在語義上,一個值集合相當于一個添加約束后的類型。如:
PrimeNumbers INTEGER ::= {2 | 3 | 5 | 7 | 11 | 13}