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