ASN
ASN.1 – Abstract Syntax Notation dot one,抽象記法1。數字1被ISO加在ASN的后邊,是為了保持ASN的開放性,可以讓以后功能更加強大的ASN被命名為ASN.2等,但至今也沒有出現。
描述了一種對數據進行表示、編碼、傳輸和解碼的數據格式。它提供了一整套正規的格式用於描述對象的結構,而不管語言上如何執行及這些數據的具體指代,也不用去管到底是什么樣的應用程序。
基本語法規則
- 在ASN.1中,符號的定義沒有先后次序:只要能夠找到該符號的定義即可,而不必關心在使用它之前是否被定義過。
- 所有的標識符、參考、關鍵字都要以一個字母開頭,后接字母(大、小寫都可以)、數字或者連字符“-”。不能出現下划線“_”。不能以連字符“-”結尾,不能出現兩個連字符(注釋格式)。
- 關鍵字一般都是全部大寫的,除了一些字符串類型(如PrintableString,UTF8String,等。因為這些都是由原類型OCTET STRING衍生出來的)。
- 在標識符中,只有類型和模塊名字是以大寫字母開頭的,其它標識符都是以小寫字母開頭的。
- 帶小數點的小數形式不能在ASN.1中直接使用,在ASN.1中實數實際定義為三個整數:尾數、基數和指數
- 注釋以兩個連字符“--”開始,結束於行的結尾或者該行中另一個雙連字符。
- 如同大多數計算機語言,ASN.1不對空格、制表符、換行符和注釋做翻譯。但是在定義符號(或者分配符號Assignment)“::=”中不能有分隔符,否則不能正確處理。
類型定義與類型
- <新類型的名字> ::= <類型描述>
其中:
<新類型的名字>是一個以大寫字母開頭的標識符;
<類型描述>是基於內建類型或在其它地方定義的類型。
- 值定義:<新的值的名字> <該值的類型> ::= <值描述>
其中:
<新的值的名字>是以小寫字母開頭的標識符;
<該值的類型>可以是一個類型的名字,也可以是類型描述;
值描述>是基於整數、字符串、標識符的組合。
- ASN.1的編碼格式有很多種: BER、CER、DER、XER,可以編碼成XML格式,不僅僅是常用的二進制流。BER、CER、DER,是ASN.1的三種最常用的編碼格式
CER、DER、CRT、PEM的關系
-
所有X.509都是DER編碼,DER是指ASN.1的編碼規則,.der證書文件一般是二進制文件。
-
CER可用於PKCS#7證書(p7b)的編碼,但一般是指證書的文件后綴,.cer證書可以是純BASE64文件或二進制文件。
-
PEM通常也是指文件的后綴,為內容使用BASE64編碼且帶頭帶尾的特定格式,二進制的文件不應該命名為pem。
-
CRT是微軟的證書后綴名,和.CER是一回事。
微軟的CryptAPI很強大,證書的各種格式都可以識別,比如純BASE64編碼的、標准PEM格式的、非標識PEM格式的(不是64字節換行、沒有頭尾等)、二進制格式的
BER編碼
描述了如何將ASN.1 類型的值編碼成字節串的方法。BER的語法傳輸格式一直是TLV三元組<Type, Length,Value>
- tag(標志域): 指明數據類型,占用一個字節常見的類型有
BER_TYPE_BOOLEAN 0x01
BER_TYPE_INTEGER 0x02
BER_TYPE_BIT_STRING 0x03
BER_TYPE_OCTET_STRING 0x04
BER_TYPE_NULL 0x05
BER_TYPE_OID 0x06
BER_TYPE_SEQUENCE 0x30
BER_TYPE_SNMP_SET 0xA3
- 長度域(length):指明值域的長度,長度不等,一般為一到三個字節。其格式可分為短格式(后面的值域長度<=127),長格式.
(1)定長方式
length=30 表示為1E(16進制),30長度域為 0001 1110 沒有超過127;
- 長格式 :表示方法為1(bit)K(7bit)K個八位長度(K Byte)
length = 169 轉換為 81 A9(169長度超過127,長度域為1000 0001 1010 1001;169是后8位的值,前8位的第一個1表示這是一個長格式的表示方法,前8位的后7位表示后面有多少個字節表示針對的長度000 0001后面有一個字節表示真正的長度 1010 1001是表示長度為169)
length=1500=>82 05 DC(1000 0010 0000 0101 1101 1100,先看第一個字節,表示長格式,后面有2 個字節表示長度,這兩個字節是0000 0101 1101 1100 表示1500)
(2).不定長方式
Length所在八位組固定編碼為0x80,但在Value編碼結束后以兩個0x00結尾。這種方式使得可以在編碼沒有完全結束的情況下,可以先發送部分消息給對方。
Length所在八位組固定編碼為0x80,但在Value編碼結束后以兩個0x00結尾。這種方式使得可以在編碼沒有完全結束的情況下,可以先發送部分消息給對方。
-
值域(value)
-
整型Integer的編碼 integer::=0x02 length{byte} (表示重復),最高位代表符號位,去掉多余的0。對於正數,如果最高比特位為0則直接編碼;如果為1,則在最高比特位之前增加一個全0的八位組。
-
最高位為0:
0BBBBBBB
-
最高位為1:
00000000|1BBBBBBB
-
- 例: 對於負數,先取絕對值進行編碼,再取反,最后加1
1500=>02 02 05 DC
40000=>02 03 00 9C 40
-129=>129=>0000 0000 1000 0001->1111 1111 0111 1110 ->(加1)->FF 7F 最終為02 02 FF 7F
-
布爾值的編碼由1個字節組成。FALSE為00; TRUE為FF。
- TRUE的編碼: 01 01 FF
- FALSE 的編碼: 01 01 00
-
字符串類型的編碼 string::=0x04 length{byte}* 例如:04 06 70 75 62 6c 69 63表示字符串public
-
位串(BITSTRING)類型 :編碼規則:位串的第一位放到第一個負載字節的第8位;位串的第二位放到第一個負載字節的第7位; 依此類推.填充滿第一個負載字節,就繼續填充第二個負載字節.如果最后一個負載字節未被填充滿,空的位用0來填充, 0的個數存放到頭部用來表示填充數據的那個字節里.
位串{1,0,0,0,1,1,1,0,1,0,0,1}
開始填充負載字節.第一個字節填充后為10001110= 0x8E; 第 二個字節填充后為10010000 = 0x90, 低位4個0為填充的空位.則,負載為2個字節加上表示填充0個數的一個字節0x04總共3個字節.則完整的編碼為:0x03 03 04 8E 90.
-
空類型的編碼 null::=0x05 0x00
-
objectID::=0x06 length {subidentifier}*
-
首兩個ID被合並為一個字節X*40+Y
-
每個字首先被分割為最少數量的沒有頭零數字的7位數字.這些數字以big-endian格式進行組織,並且一個接一個地組合成字節.
舉例: 30331 = 1* 128^2 + 108 * 128 + 123 分割成7位數字(0x80)后為{1,108,123}
- 除了編碼的最后一個字節外,其他所有字節的最高位(位8)都為1.
設置最高位后變成{129,236,123}.如果該字只有一個7位數字,那么最高為0
MD5 OID的編碼:
1. 將1.2.840.113549.2.5轉換成字數組 {42, 840, 113549, 2, 5}.
2.然后將每個字分割為帶有最高位的7位數字,{{0x2A},{0x86,0x48},{0x86,0xF7,0x0D},{0x02},{0x05}}
3. 最后完整的編碼為 0x06 08 2A 86 48 86 F7 0D 02 05.
- sequence組合類型的編碼 sequence::=0x30 length{asndata}*
如:30 05 02 01 10 05 00表示一個sequence結構,內含兩個成員,其中一個為整型16,另一個為空類型(NULL)。
例:考慮如下序列
User ::== SEQUENCE{
ID INTEGER,
Active BOOLEAN
}
當取值為{32,TRUE}時,編碼為 0x30 06 02 01 20 01 01 FF 在ASN.1文檔里,使用空格來表示編碼的屬性.
0x30 06
02 01 20
01 01 FF