ASN.1是一種跨平臺的資料序列化的介面描述語言。可能很多人沒有聽說過ASN.1, 但是相信有過跨平臺程式設計經驗的同學可能都聽過protocol buffers和Apache Thrift,雖然ASN.1和上面兩個語言相比不是那麼出名,但是ASN.1的出現要比他們早的多,早在1984年ASN.1就出現了。
和他們相比ASN.1並沒有提供單一的開源實現,而是作為一種規範來供第三方供應商實現的。ASN.1主要用在定義各種基礎協定中,比如常用的LDAP,PKCS,GSM,X.500等。
ASN.1是一種和平臺、語言無關的描述語言,可以使用很多ASN.1的翻譯工具,將ASN.1翻譯成為C, C++, Java等程式碼。
既然ASN.1是一個描述語言,那麼我們先來看一個直觀的例子。ASN.1的基礎是module, 我們看一下ASN.1中module的例子:
StudentCards DEFINITIONS AUTOMATIC TAGS ::= BEGIN
StudentCard ::= SEQUENCE {
dateOfBirthday DATE,
student StudentInfo
}
StudentInfo ::= SEQUENCE {
studentName VisibleString (SIZE (3..50)),
homeAddress Address,
contactPhone NumericString (SIZE (7..12))
}
Address::= SEQUENCE {
street VisibleString (SIZE (5 .. 50)) OPTIONAL,
city VisibleString (SIZE (2..30)),
state VisibleString (SIZE(2) ^ FROM ("A".."Z")),
zipCode NumericString (SIZE(5 | 9))
}
END
上面的例子中,我們使用ASN.1定義了一個StudentCard,最外層的以BEGIN和END包圍的就是module。StudentCards是module的名字,首字母必須大寫。
其中::=
是一個賦值符號。
module中可以有多個type, type的名字也必須首字母大寫,例如上面的StudentCard,StudentInfo等等。
每個type中定義了它的組成元件,元件的名字首字母必須小寫,這些元件的名字又叫做identifiers。
上面的dateOfBirthday後面接的DATE是ASN.1中內建的型別。而student後面的StudentInfo是一個自定義型別,並且同樣包含在module中。
StudentInfo中的studentName是一個VisibleString,這個String的限制是size在3到50之間。
上面我們定義module的時候在module後面加上了AUTOMATIC TAGS
,這是什麼意思呢?
在ASN.1中,tags是ASN.1訊息中每個元件的內部識別符號,以Address為例,我們希望給Address中的每個屬性都指定一個內部的識別符號,如下所示:
Address::= SEQUENCE {
street [0] VisibleString (SIZE (5 .. 50)) OPTIONAL,
city [1] VisibleString (SIZE (2..30)),
state [2] VisibleString (SIZE(2) ^ FROM ("A".."Z")),
zipCode [3] NumericString (SIZE(5 | 9))
}
這裡面的[0] [1]
就是識別符號,當然,我們可以在定義module的時候手動指定這些tags,但是如果我們使用AUTOMATIC TAGS
,這些識別符號會自動建立,從而避免了手動建立識別符號可能帶來的問題。
通過上面的講解,我們對ASN.1有了一個基本的概念。如果想要對ASN.1進行更加深入的研究,那麼我們首先要知道ASN.1中的內建型別。
一般來說ASN.1中有下面的資料型別:
BOOLEAN和程式語言中的布林值是一致的,它有兩個可能得值:TRUE和FALSE。下面是具體而用法:
removed BOOLEAN ::= TRUE
INTEGER表示的是一個整數,如下所示,表示的是一個年例範圍是0到100,最終的取值是18:
age INTEGER (0..100) ::= 18
位元組的位表示方法,可以給一個byte中的每一個bit進行設值:
Status ::= BIT STRING {
married(0),
handsome(1),
kind(2)
}
myStatus Status ::= {handsome, kind}
上面的例子中,我們設定了Status,並且使用Status賦值給了一個變數myStatus。
8進位製表示的字串:
octetExample ::= OCTET STRING
表示日期,格式是"YYYY-MM-DD":
birthday DATE ::= "1990-11-18"
表示日期中的時間,格式是"HH:MM:SS":
startTime TIME-OF-DAY ::= "09:30:00"
時間加日期的格式,它的格式"YYYY-MM-DDTHH:MM:SS",如下所示:
endTime DATE-TIME ::= "2022-01-10T18:30:23"
REAL表示的是一個浮點數,可以如下表示:
Amount ::= REAL
ENUMERATED表示的是一個列舉,可以如下表示:
Colors ::= ENUMERATED {black, red, white}
myColor Colors ::= white
SEQUENCE表示的是專案的序列合集,如下所示:
StudentInfo ::= SEQUENCE {
name VisibleString,
phone NumericString
}
max StudentInfo ::= {name "J.Max", phone "18888888888"}
SEQUENCE OF表示的是一個list:
breakTimes SEQUENCE OF TIME-OF-DAY ::= {"10:00:00", "12:00:00", "14:45:00"}
CHOICE表示從眾多的item中選擇一個:
Identity ::= CHOICE {
name VisibleString,
phone VisibleString,
idCard VisibleString
}
jack Identity ::= name: "jack"
IA5String表示的是ASCII字元,並且包含有控制字元。
SampleString ::= IA5String
VisibleString表示的是ASCII字元,其中不包含有控制字元。
SampleString ::= VisibleString
NumericString表示的是數位和空格。
SomeNumber ::= NumericString
UTF8String表示的是Unicode字元
UnicodeString ::= UTF8String
是一個空值,用來佔位。
ASN.1中可以定義很多個欄位,有些欄位可能會有一些限制,比如手機號只能用數位,名字有長度限制等。
這些限制在ASN.1中叫做Constraints,一般來說有下面的一些限制:
FROM提供了一個資料值的讀取範圍,如下:
PermittedChars ::= IA5String (FROM("ABCDEFG1244"))
PermittedChars只允許從"ABCDEFG1244"選擇。
PATTERN表示的是正規表示式,如下所示:
phoneNumber ::= IA5String (PATTERN "1[0-9]#10")
上面列出的是一個簡單的手機號碼的正規表示式。
SIZE可以表示字串的長度或者陣列的長度:
Name ::= IA5String (SIZE (4..7))
NameList ::= SEQUENCE SIZE (1..25) OF Name
使用..
可以表示一個範圍:
Age ::= INTEGER (0..100)
從提供的值列表中挑選一個:
Colors ::= UTF8String ("Blue" | "White")
以上就是ASN.1資料結構描述語言的基本介紹了,有了這些基礎,我們就可以很容易讀懂使用ASN.1來描寫的資料結構了。
更多內容請參考 http://www.flydean.com/46-asn-1/
最通俗的解讀,最深刻的乾貨,最簡潔的教學,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!